diff options
-rw-r--r-- | cmd/vartan/compile.go | 84 | ||||
-rw-r--r-- | cmd/vartan/parse.go | 18 | ||||
-rw-r--r-- | cmd/vartan/root.go | 10 | ||||
-rw-r--r-- | error/error.go | 52 |
4 files changed, 139 insertions, 25 deletions
diff --git a/cmd/vartan/compile.go b/cmd/vartan/compile.go index 769f143..3601f00 100644 --- a/cmd/vartan/compile.go +++ b/cmd/vartan/compile.go @@ -3,8 +3,11 @@ package main import ( "encoding/json" "fmt" + "io/ioutil" "os" + "path/filepath" + verr "github.com/nihei9/vartan/error" "github.com/nihei9/vartan/grammar" "github.com/nihei9/vartan/spec" "github.com/spf13/cobra" @@ -28,7 +31,63 @@ func init() { } func runCompile(cmd *cobra.Command, args []string) (retErr error) { - gram, err := readGrammar(*compileFlags.grammar) + var tmpDirPath string + defer func() { + if tmpDirPath == "" { + return + } + os.RemoveAll(tmpDirPath) + }() + + grmPath := *compileFlags.grammar + defer func() { + v := recover() + if v != nil { + err, ok := v.(error) + if !ok { + retErr = fmt.Errorf("an unexpected error occurred: %v\n", v) + fmt.Fprintln(os.Stderr, retErr) + return + } + + retErr = err + } + + if retErr != nil { + specErr, ok := retErr.(*verr.SpecError) + if ok { + if *compileFlags.grammar != "" { + specErr.FilePath = grmPath + specErr.SourceName = grmPath + } else { + specErr.FilePath = grmPath + specErr.SourceName = "stdin" + } + } + fmt.Fprintln(os.Stderr, retErr) + } + }() + + if grmPath == "" { + var err error + tmpDirPath, err = os.MkdirTemp("", "vartan-compile-*") + if err != nil { + return err + } + + src, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + + grmPath = filepath.Join(tmpDirPath, "stdin.vr") + err = ioutil.WriteFile(grmPath, src, 0600) + if err != nil { + return err + } + } + + gram, err := readGrammar(grmPath) if err != nil { return err } @@ -46,17 +105,22 @@ func runCompile(cmd *cobra.Command, args []string) (retErr error) { return nil } -func readGrammar(path string) (*grammar.Grammar, error) { - r := os.Stdin - if path != "" { - f, err := os.Open(path) - if err != nil { - return nil, fmt.Errorf("Cannot open the grammar file %s: %w", path, err) +func readGrammar(path string) (grm *grammar.Grammar, retErr error) { + defer func() { + err := recover() + specErr, ok := err.(*verr.SpecError) + if ok { + specErr.FilePath = path + retErr = specErr } - defer f.Close() - r = f + }() + + f, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("Cannot open the grammar file %s: %w", path, err) } - ast, err := spec.Parse(r) + defer f.Close() + ast, err := spec.Parse(f) if err != nil { return nil, err } diff --git a/cmd/vartan/parse.go b/cmd/vartan/parse.go index 8089c5e..ef22ff3 100644 --- a/cmd/vartan/parse.go +++ b/cmd/vartan/parse.go @@ -28,6 +28,24 @@ func init() { } func runParse(cmd *cobra.Command, args []string) (retErr error) { + defer func() { + v := recover() + if v != nil { + err, ok := v.(error) + if !ok { + retErr = fmt.Errorf("an unexpected error occurred: %v\n", v) + fmt.Fprintln(os.Stderr, retErr) + return + } + + retErr = err + } + + if retErr != nil { + fmt.Fprintln(os.Stderr, retErr) + } + }() + cgram, err := readCompiledGrammar(args[0]) if err != nil { return fmt.Errorf("Cannot read a compiled grammar: %w", err) diff --git a/cmd/vartan/root.go b/cmd/vartan/root.go index ad163a6..a193577 100644 --- a/cmd/vartan/root.go +++ b/cmd/vartan/root.go @@ -1,9 +1,6 @@ package main import ( - "fmt" - "os" - "github.com/spf13/cobra" ) @@ -19,10 +16,5 @@ var rootCmd = &cobra.Command{ } func Execute() error { - err := rootCmd.Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return err - } - return nil + return rootCmd.Execute() } diff --git a/error/error.go b/error/error.go index 1745c52..cc4fed5 100644 --- a/error/error.go +++ b/error/error.go @@ -1,15 +1,55 @@ package error -import "fmt" +import ( + "bufio" + "fmt" + "os" + "strings" +) type SpecError struct { - Cause error - Row int + Cause error + FilePath string + SourceName string + Row int } func (e *SpecError) Error() string { - if e.Row == 0 { - return fmt.Sprintf("error: %v", e.Cause) + var b strings.Builder + if e.SourceName != "" { + fmt.Fprintf(&b, "%v: ", e.SourceName) } - return fmt.Sprintf("%v: error: %v", e.Row, e.Cause) + if e.Row != 0 { + fmt.Fprintf(&b, "%v: ", e.Row) + } + fmt.Fprintf(&b, "error: %v", e.Cause) + + line := readLine(e.FilePath, e.Row) + if line != "" { + fmt.Fprintf(&b, "\n %v", line) + } + + return b.String() +} + +func readLine(filePath string, row int) string { + if filePath == "" || row <= 0 { + return "" + } + + f, err := os.Open(filePath) + if err != nil { + return "" + } + + i := 1 + s := bufio.NewScanner(f) + for s.Scan() { + if i == row { + return s.Text() + } + i++ + } + + return "" } |