From 0dd848de6cc92cc0df41801ee31bdec3eeb47d8a Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Wed, 18 Aug 2021 18:47:13 +0200 Subject: [PATCH] cli: Better filenames in errors --- pkg/interp/funcs.go | 12 +++++++++-- pkg/interp/interp.go | 29 +++++++++++++++------------ pkg/interp/interp.jq | 18 +++++++++-------- pkg/interp/testdata/exitcode.fqtest | 4 ++-- pkg/interp/testdata/incudepath.fqtest | 2 +- pkg/interp/testdata/inputs.fqtest | 4 ++-- pkg/interp/testdata/repl.fqtest | 4 ++-- pkg/interp/testdata/var.fqtest | 2 +- 8 files changed, 44 insertions(+), 31 deletions(-) diff --git a/pkg/interp/funcs.go b/pkg/interp/funcs.go index 2e8575f3..ce29eaca 100644 --- a/pkg/interp/funcs.go +++ b/pkg/interp/funcs.go @@ -38,7 +38,7 @@ func (i *Interp) makeFunctions(registry *registry.Registry) []Function { {[]string{"tty"}, 0, 0, i.tty, nil}, {[]string{"readline"}, 0, 2, i.readline, nil}, - {[]string{"eval"}, 1, 1, nil, i.eval}, + {[]string{"eval"}, 1, 2, nil, i.eval}, {[]string{"stdout"}, 0, 0, nil, i.stdout}, {[]string{"stderr"}, 0, 0, nil, i.stderr}, @@ -246,12 +246,20 @@ func (i *Interp) readline(c interface{}, a []interface{}) interface{} { } func (i *Interp) eval(c interface{}, a []interface{}) gojq.Iter { + var err error src, err := toString(a[0]) if err != nil { return gojq.NewIter(fmt.Errorf("src: %w", err)) } + var filenameHint string + if len(a) >= 2 { + filenameHint, err = toString(a[1]) + if err != nil { + return gojq.NewIter(fmt.Errorf("filename hint: %w", err)) + } + } - iter, err := i.Eval(i.evalContext.ctx, ScriptMode, c, src, i.evalContext.stdout) + iter, err := i.Eval(i.evalContext.ctx, ScriptMode, c, src, filenameHint, i.evalContext.stdout) if err != nil { return gojq.NewIter(err) } diff --git a/pkg/interp/interp.go b/pkg/interp/interp.go index eb6e020d..06a51435 100644 --- a/pkg/interp/interp.go +++ b/pkg/interp/interp.go @@ -54,10 +54,11 @@ type compileError struct { func (ce compileError) Value() interface{} { return map[string]interface{}{ - "error": ce.err.Error(), - "what": ce.what, - "line": ce.pos.Line, - "column": ce.pos.Column, + "error": ce.err.Error(), + "what": ce.what, + "filename": ce.filename, + "line": ce.pos.Line, + "column": ce.pos.Column, } } func (ee compileError) Error() string { @@ -540,7 +541,7 @@ func (i *Interp) Main(ctx context.Context, stdout io.Writer, version string) err return nil } -func (i *Interp) Eval(ctx context.Context, mode RunMode, c interface{}, src string, stdout Output) (gojq.Iter, error) { +func (i *Interp) Eval(ctx context.Context, mode RunMode, c interface{}, src string, filename string, stdout Output) (gojq.Iter, error) { var err error // TODO: did not work // nq := &(*q) @@ -549,9 +550,10 @@ func (i *Interp) Eval(ctx context.Context, mode RunMode, c interface{}, src stri if err != nil { p := queryErrorPosition(err) return nil, compileError{ - err: err, - what: "parse", - pos: p, + err: err, + what: "parse", + filename: filename, + pos: p, } } @@ -692,7 +694,7 @@ func (i *Interp) Eval(ctx context.Context, mode RunMode, c interface{}, src stri return nil, compileError{ err: err, what: "parse", - filename: filename, + filename: filenamePart, pos: p, } } @@ -712,9 +714,10 @@ func (i *Interp) Eval(ctx context.Context, mode RunMode, c interface{}, src stri if err != nil { p := queryErrorPosition(err) return nil, compileError{ - err: err, - what: "compile", - pos: p, + err: err, + what: "compile", + filename: filename, + pos: p, } } @@ -752,7 +755,7 @@ func (i *Interp) EvalFunc(ctx context.Context, mode RunMode, c interface{}, name /// _args to mark variable as internal and hide it from completion // {input: ..., args: [...]} | .args as {args: $_args} | .input | name[($_args[0]; ...)] trampolineExpr := fmt.Sprintf(". as {args: $_args} | .input | %s%s", name, argExpr) - iter, err := i.Eval(ctx, mode, trampolineInput, trampolineExpr, stdout) + iter, err := i.Eval(ctx, mode, trampolineInput, trampolineExpr, "", stdout) if err != nil { return nil, err } diff --git a/pkg/interp/interp.jq b/pkg/interp/interp.jq index c495f035..2c2f19b5 100644 --- a/pkg/interp/interp.jq +++ b/pkg/interp/interp.jq @@ -169,9 +169,9 @@ def _eval_is_compile_error: type == "object" and .error != null and .what != nul def _eval_compile_error_tostring: "\(.filename // "src"):\(.line):\(.column): \(.error)"; -def _eval($e; f; on_error; on_compile_error): +def _eval($e; $filename; f; on_error; on_compile_error): ( _default_options(_build_default_options) as $_ - | try eval($e) | f + | try eval($e; $filename) | f catch if _eval_is_compile_error then on_compile_error else on_error @@ -184,7 +184,7 @@ def _repl_on_error: | (_error_str | println) ); def _repl_on_compile_error: _repl_on_error; -def _repl_eval($e): _eval($e; _repl_display; _repl_on_error; _repl_on_compile_error); +def _repl_eval($e): _eval($e; "repl"; _repl_display; _repl_on_error; _repl_on_compile_error); # run read-eval-print-loop def repl($opts; iter): #:: a|(Opts) => @ @@ -231,8 +231,8 @@ def _cli_expr_on_compile_error: | halt_error(_exit_code_compile_error) ); # _cli_expr_eval halts on compile errors -def _cli_expr_eval($e; f): _eval($e; f; _cli_expr_on_error; _cli_expr_on_compile_error); -def _cli_expr_eval($e): _eval($e; .; _cli_expr_on_error; _cli_expr_on_compile_error); +def _cli_expr_eval($e; $filename; f): _eval($e; $filename; f; _cli_expr_on_error; _cli_expr_on_compile_error); +def _cli_expr_eval($e; $filename): _eval($e; $filename; .; _cli_expr_on_error; _cli_expr_on_compile_error); # next valid input def input: @@ -450,10 +450,12 @@ def _main: ( { null_input: ($parsed_args.null_input == true) } | if $parsed_args.file then ( .expr = ($parsed_args.file | open | string) + | .expr_filename = $parsed_args.file | .filenames = $rest ) else ( .expr = ($rest[0] // ".") + | .expr_filename = "arg" | .filenames = $rest[1:] ) end @@ -462,7 +464,7 @@ def _main: elif .filenames == [] then .filenames = ["-"] end - | . as {$expr, $filenames, $null_input} + | . as {$expr, $expr_filename, $filenames, $null_input} | _include_paths([ $parsed_args.include_path // empty ]) as $_ @@ -472,10 +474,10 @@ def _main: else inputs end # will iterate zero or more inputs - | if $parsed_args.repl then [_cli_expr_eval($expr)] | repl({}; .[]) + | if $parsed_args.repl then [_cli_expr_eval($expr; $expr_filename)] | repl({}; .[]) else ( _cli_last_expr_error(null) as $_ - | _cli_expr_eval($expr; _repl_display) + | _cli_expr_eval($expr; $expr_filename; _repl_display) ) end ) diff --git a/pkg/interp/testdata/exitcode.fqtest b/pkg/interp/testdata/exitcode.fqtest index 6f1f1c4d..daf5b6f5 100644 --- a/pkg/interp/testdata/exitcode.fqtest +++ b/pkg/interp/testdata/exitcode.fqtest @@ -15,11 +15,11 @@ exitcode: 123 $ fq -n invalid exitcode: 3 stderr: -error: src:1:0: function not defined: invalid/0 +error: arg:1:0: function not defined: invalid/0 $ fq -n "(" exitcode: 3 stderr: -error: src:1:2: unexpected token +error: arg:1:2: unexpected token $ fq . non-existing exitcode: 2 stderr: diff --git a/pkg/interp/testdata/incudepath.fqtest b/pkg/interp/testdata/incudepath.fqtest index 9cbfb7ec..7176e2d7 100644 --- a/pkg/interp/testdata/incudepath.fqtest +++ b/pkg/interp/testdata/incudepath.fqtest @@ -5,4 +5,4 @@ $ fq -L /library -n 'include "a"; a' $ fq -L /wrong -n 'include "a"; a' exitcode: 3 stderr: -error: src:1:0: open a.jq: file does not exist +error: arg:1:0: open a.jq: file does not exist diff --git a/pkg/interp/testdata/inputs.fqtest b/pkg/interp/testdata/inputs.fqtest index d4486d76..ae052850 100644 --- a/pkg/interp/testdata/inputs.fqtest +++ b/pkg/interp/testdata/inputs.fqtest @@ -54,11 +54,11 @@ error: /non-existing: file not found $ fq -d raw '(' /a /b /c exitcode: 3 stderr: -error: src:1:2: unexpected token +error: arg:1:2: unexpected token $ fq -d raw bla /a /b /c exitcode: 3 stderr: -error: src:1:0: function not defined: bla/0 +error: arg:1:0: function not defined: bla/0 $ fq -d raw '1+"a"' /a /b /c exitcode: 5 stderr: diff --git a/pkg/interp/testdata/repl.fqtest b/pkg/interp/testdata/repl.fqtest index f1a344b1..84c9059f 100644 --- a/pkg/interp/testdata/repl.fqtest +++ b/pkg/interp/testdata/repl.fqtest @@ -2,9 +2,9 @@ $ fq -i null> 1+1 2 null> ( -error: src:1:2: unexpected token +error: repl:1:2: unexpected token null> abc -error: src:1:0: function not defined: abc/0 +error: repl:1:0: function not defined: abc/0 null> 1+"a" error: cannot add: number (1) and string ("a") null> 1 | repl diff --git a/pkg/interp/testdata/var.fqtest b/pkg/interp/testdata/var.fqtest index 98569711..3665c32d 100644 --- a/pkg/interp/testdata/var.fqtest +++ b/pkg/interp/testdata/var.fqtest @@ -19,7 +19,7 @@ null> $a "aa" null> var("a"; empty) null> $a -error: src:1:0: variable not defined: $a +error: repl:1:0: variable not defined: $a null> var { "bb": "bb"