From 8997c515c5c052af313aa4348b0a237353a5fdf5 Mon Sep 17 00:00:00 2001 From: Turiiya <34311583+ttytm@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:02:11 +0100 Subject: [PATCH] parser: improve token detection and error messages for unexpected EOFs, add tests (#21110) --- .../tests/like_operator_outside_orm_error.out | 2 +- vlib/v/parser/fn.v | 29 ++++++++++++++----- ...all_unexpected_eof_comma_multi_arg_err.out | 6 ++++ ...call_unexpected_eof_comma_multi_arg_err.vv | 6 ++++ ...l_unexpected_eof_rpar_after_fn_arg_err.out | 6 ++++ ...ll_unexpected_eof_rpar_after_fn_arg_err.vv | 4 +++ .../tests/fn_call_unexpected_eof_rpar_err.out | 4 +++ .../tests/fn_call_unexpected_eof_rpar_err.vv | 2 ++ ...pected_eof_rpar_multi_arg_too_many_err.out | 6 ++++ ...xpected_eof_rpar_multi_arg_too_many_err.vv | 6 ++++ ...all_unexpected_eof_rpar_multi_line_err.out | 5 ++++ ...call_unexpected_eof_rpar_multi_line_err.vv | 3 ++ ..._call_unexpected_eof_rpar_too_many_err.out | 4 +++ ...n_call_unexpected_eof_rpar_too_many_err.vv | 2 ++ 14 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.vv create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.vv create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.vv create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.vv create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.vv create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.out create mode 100644 vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.vv diff --git a/vlib/v/checker/tests/like_operator_outside_orm_error.out b/vlib/v/checker/tests/like_operator_outside_orm_error.out index 253352ab2..8e0ea9080 100644 --- a/vlib/v/checker/tests/like_operator_outside_orm_error.out +++ b/vlib/v/checker/tests/like_operator_outside_orm_error.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/like_operator_outside_orm_error.vv:4:15: error: unexpected name `like`, expecting `,` +vlib/v/checker/tests/like_operator_outside_orm_error.vv:4:15: error: only `c`, `r`, `js` are recognized string prefixes, but you tried to use `like` 2 | name := 'Luke' 3 | 4 | println(name like 'L%') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 680383b70..b83075eb6 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -23,7 +23,7 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr { 'JS.${name}' } else if language == .wasm { 'WASM.${name}' - } else if mod.len > 0 { + } else if mod != '' { '${mod}.${name}' } else { name @@ -52,8 +52,23 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr { } p.check(.lpar) args := p.call_args() + if p.tok.kind != .rpar { + params := p.table.fns[fn_name] or { unsafe { p.table.fns['${p.mod}.${fn_name}'] } }.params + if args.len < params.len && p.prev_tok.kind != .comma { + p.unexpected_with_pos(p.prev_tok.pos(), expecting: '`,`') + } else if args.len > params.len { + ok_arg_pos := (args[params.len - 1] or { args[0] }).pos + pos := token.Pos{ + ...ok_arg_pos + col: ok_arg_pos.col + ok_arg_pos.len + } + p.unexpected_with_pos(pos.extend(p.tok.pos()), expecting: '`)`') + } else { + p.unexpected_with_pos(p.prev_tok.pos(), expecting: '`)`') + } + } last_pos := p.tok.pos() - p.check(.rpar) + p.next() mut pos := first_pos.extend(last_pos) mut or_stmts := []ast.Stmt{} // TODO: remove unnecessary allocations by just using .absent mut or_pos := p.tok.pos() @@ -104,11 +119,9 @@ fn (mut p Parser) call_args() []ast.CallArg { p.inside_call_args = prev_inside_call_args } mut args := []ast.CallArg{} - start_pos := p.tok.pos() - for p.tok.kind != .rpar { + for p.tok.kind != .rpar && p.tok.kind != .comma { if p.tok.kind == .eof { - p.error_with_pos('unexpected eof reached, while parsing call argument', start_pos) - return [] + return args } is_shared := p.tok.kind == .key_shared is_atomic := p.tok.kind == .key_atomic @@ -149,8 +162,8 @@ fn (mut p Parser) call_args() []ast.CallArg { comments: comments pos: pos } - if p.tok.kind != .rpar { - p.check(.comma) + if p.tok.kind == .comma { + p.next() } } return args diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.out new file mode 100644 index 000000000..7f346b779 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.out @@ -0,0 +1,6 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.vv:5:14: error: unexpected eof, expecting `,` + 3 | fn foo(i i64, s string) {} + 4 | + 5 | foo(time.now() + | ^ + 6 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.vv new file mode 100644 index 000000000..7ff3b0fc6 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_comma_multi_arg_err.vv @@ -0,0 +1,6 @@ +import time + +fn foo(i i64, s string) {} + +foo(time.now() + diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.out new file mode 100644 index 000000000..038039852 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.out @@ -0,0 +1,6 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.vv:3:36: error: unexpected eof, expecting `)` + 1 | import os + 2 | + 3 | println(os.file_last_mod_unix('x.v') + | ^ + 4 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.vv new file mode 100644 index 000000000..6041cd84f --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_after_fn_arg_err.vv @@ -0,0 +1,4 @@ +import os + +println(os.file_last_mod_unix('x.v') + diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.out new file mode 100644 index 000000000..9e61ed837 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.out @@ -0,0 +1,4 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.vv:1:12: error: unexpected eof, expecting `)` + 1 | println('a', + | ^ + 2 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.vv new file mode 100644 index 000000000..38a9c361c --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_err.vv @@ -0,0 +1,2 @@ +println('a', + diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.out new file mode 100644 index 000000000..b85e4ce93 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.out @@ -0,0 +1,6 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.vv:5:22: error: unexpected eof, expecting `)` + 3 | fn foo(i i64, s string) {} + 4 | + 5 | foo(time.now(), 'foo', + | ^ + 6 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.vv new file mode 100644 index 000000000..946027b4c --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_arg_too_many_err.vv @@ -0,0 +1,6 @@ +import time + +fn foo(i i64, s string) {} + +foo(time.now(), 'foo', + diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.out new file mode 100644 index 000000000..9a8ba166c --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.out @@ -0,0 +1,5 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.vv:1:14: error: unexpected eof, expecting `)` + 1 | println('foo' bar + | ~~~~ + 2 | println('baz') + 3 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.vv new file mode 100644 index 000000000..ffeb2dd6d --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_multi_line_err.vv @@ -0,0 +1,3 @@ +println('foo' bar +println('baz') + diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.out b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.out new file mode 100644 index 000000000..93444f009 --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.out @@ -0,0 +1,4 @@ +vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.vv:1:12: error: unexpected eof, expecting `)` + 1 | println('a', 'b' + | ~~~~~ + 2 | diff --git a/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.vv b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.vv new file mode 100644 index 000000000..77f3512cc --- /dev/null +++ b/vlib/v/parser/tests/fn_call_unexpected_eof_rpar_too_many_err.vv @@ -0,0 +1,2 @@ +println('a', 'b' + -- 2.39.5