diff options
Diffstat (limited to 'cmd/vartan/compile.go')
-rw-r--r-- | cmd/vartan/compile.go | 108 |
1 files changed, 89 insertions, 19 deletions
diff --git a/cmd/vartan/compile.go b/cmd/vartan/compile.go index 7e594a8..b8b97b1 100644 --- a/cmd/vartan/compile.go +++ b/cmd/vartan/compile.go @@ -3,10 +3,10 @@ package main import ( "encoding/json" "fmt" + "io" "io/ioutil" "os" "path/filepath" - "strings" verr "github.com/nihei9/vartan/error" "github.com/nihei9/vartan/grammar" @@ -84,20 +84,31 @@ func runCompile(cmd *cobra.Command, args []string) (retErr error) { return err } - var reportFileName string - { - _, grmFileName := filepath.Split(grmPath) - reportFileName = fmt.Sprintf("%v-report.json", strings.TrimSuffix(grmFileName, ".vartan")) - } - - cgram, err := grammar.Compile(gram, grammar.EnableReporting(reportFileName)) + cgram, report, err := grammar.Compile(gram, grammar.EnableReporting()) if err != nil { return err } - err = writeCompiledGrammar(cgram, *compileFlags.output) + err = writeCompiledGrammarAndReport(cgram, report, *compileFlags.output) if err != nil { - return fmt.Errorf("Cannot write a compiled grammar: %w", err) + return fmt.Errorf("Cannot write an output files: %w", err) + } + + var implicitlyResolvedCount int + for _, s := range report.States { + for _, c := range s.SRConflict { + if c.ResolvedBy == grammar.ResolvedByShift.Int() { + implicitlyResolvedCount++ + } + } + for _, c := range s.RRConflict { + if c.ResolvedBy == grammar.ResolvedByProdOrder.Int() { + implicitlyResolvedCount++ + } + } + } + if implicitlyResolvedCount > 0 { + fmt.Fprintf(os.Stdout, "%v conflicts\n", implicitlyResolvedCount) } return nil @@ -121,20 +132,79 @@ func readGrammar(path string) (grm *grammar.Grammar, retErr error) { return b.Build() } -func writeCompiledGrammar(cgram *spec.CompiledGrammar, path string) error { - out, err := json.Marshal(cgram) +// writeCompiledGrammarAndReport writes a compiled grammar and a report to a files located at a specified path. +// This function selects one of the following output methods depending on how the path is specified. +// +// 1. When the path is a directory path, this function writes the compiled grammar and the report to +// <path>/<grammar-name>.json and <path>/<grammar-name>-report.json files, respectively. +// <grammar-name>-report.json as the output files. +// 2. When the path is a file path or a non-exitent path, this function asumes that the path represents a file +// path for the compiled grammar. Then it also writes the report in the same directory as the compiled grammar. +// The report file is named <grammar-name>.json. +// 3. When the path is an empty string, this function writes the compiled grammar to the stdout and writes +// the report to a file named <current-directory>/<grammar-name>-report.json. +func writeCompiledGrammarAndReport(cgram *spec.CompiledGrammar, report *spec.Report, path string) error { + cgramPath, reportPath, err := makeOutputFilePaths(cgram.Name, path) if err != nil { return err } - w := os.Stdout - if path != "" { - f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + + { + var cgramW io.Writer + if cgramPath != "" { + cgramFile, err := os.OpenFile(cgramPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer cgramFile.Close() + cgramW = cgramFile + } else { + cgramW = os.Stdout + } + + b, err := json.Marshal(cgram) if err != nil { - return fmt.Errorf("Cannot open the output file %s: %w", path, err) + return err } - defer f.Close() - w = f + fmt.Fprintf(cgramW, "%v\n", string(b)) } - fmt.Fprintf(w, "%v\n", string(out)) + + { + reportFile, err := os.OpenFile(reportPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer reportFile.Close() + + b, err := json.Marshal(report) + if err != nil { + return err + } + fmt.Fprintf(reportFile, "%v\n", string(b)) + } + return nil } + +func makeOutputFilePaths(gramName string, path string) (string, string, error) { + reportFileName := gramName + "-report.json" + + if path == "" { + wd, err := os.Getwd() + if err != nil { + return "", "", err + } + return "", filepath.Join(wd, reportFileName), nil + } + + fi, err := os.Stat(path) + if err != nil && !os.IsNotExist(err) { + return "", "", err + } + if os.IsNotExist(err) || !fi.IsDir() { + dir, _ := filepath.Split(path) + return path, filepath.Join(dir, reportFileName), nil + } + + return filepath.Join(path, gramName+".json"), filepath.Join(path, reportFileName), nil +} |