parser: warn about ambiguous infix/prefix op token (#6491)

pull/6507/head
Nick Treleaven 2020-09-29 02:13:10 +01:00 committed by GitHub
parent 9e31335744
commit 9f33b33803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 5 deletions

View File

@ -422,6 +422,8 @@ pub fn (i &Ident) var_info() IdentVar {
} }
} }
// left op right
// See: token.Kind.is_infix
pub struct InfixExpr { pub struct InfixExpr {
pub: pub:
op token.Kind op token.Kind
@ -434,6 +436,7 @@ pub mut:
auto_locked string auto_locked string
} }
// ++, --
pub struct PostfixExpr { pub struct PostfixExpr {
pub: pub:
op token.Kind op token.Kind
@ -443,6 +446,7 @@ pub mut:
auto_locked string auto_locked string
} }
// See: token.Kind.is_prefix
pub struct PrefixExpr { pub struct PrefixExpr {
pub: pub:
op token.Kind op token.Kind

View File

@ -269,12 +269,14 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
pos: pos pos: pos
} }
} else if p.tok.kind.is_infix() { } else if p.tok.kind.is_infix() {
if p.tok.kind.is_prefix() && p.tok.line_nr != p.prev_tok.line_nr {
// return early for deref assign `*x = 2` goes to prefix expr // return early for deref assign `*x = 2` goes to prefix expr
if p.tok.kind == .mul && if p.tok.kind == .mul && p.peek_tok2.kind == .assign {
p.tok.line_nr != p.prev_tok.line_nr &&
p.peek_tok2.kind == .assign {
return node return node
} }
// added 10/2020: LATER this will be parsed as PrefixExpr instead
p.warn_with_pos('move infix `$p.tok.kind` operator before new line (if infix intended) or use brackets for a prefix expression', p.tok.position())
}
// continue on infix expr // continue on infix expr
node = p.infix_expr(node) node = p.infix_expr(node)
// return early `if bar is SumType as b {` // return early `if bar is SumType as b {`

View File

@ -0,0 +1,28 @@
vlib/v/parser/tests/prefix_first.vv:15:3: warning: move infix `-` operator before new line (if infix intended) or use brackets for a prefix expression
13 | _ = if true {
14 | v = 1
15 | -1
| ^
16 | } else {1}
17 | }
vlib/v/parser/tests/prefix_first.vv:26:3: warning: move infix `&` operator before new line (if infix intended) or use brackets for a prefix expression
24 | _ = opt() or {
25 | _ = 1
26 | &v
| ^
27 | }
28 | }
vlib/v/parser/tests/prefix_first.vv:13:6: error: `if` expression requires an expression as the last statement of every branch
11 |
12 | // later this should compile correctly
13 | _ = if true {
| ~~~~~~~
14 | v = 1
15 | -1
vlib/v/parser/tests/prefix_first.vv:24:6: error: last statement in the `or {}` block should be an expression of type `&int` or exit parent scope
22 | // later this should compile correctly
23 | v := 3
24 | _ = opt() or {
| ~~~~~
25 | _ = 1
26 | &v

View File

@ -0,0 +1,28 @@
// a prefix op can be parsed as an infix op if there's an expression on the line before
// https://github.com/vlang/v/pull/6491
fn test_prefix() {
mut v := 1
mut p := &v
// OK, special workaround
unsafe {
v = 1
*p = 2
}
// later this should compile correctly
_ = if true {
v = 1
-1
} else {1}
}
fn opt() ?&int {return none}
fn test_prefix_or() {
// later this should compile correctly
v := 3
_ = opt() or {
_ = 1
&v
}
}

View File

@ -409,6 +409,10 @@ pub fn (k Kind) is_start_of_type() bool {
return k in [.name, .lpar, .amp, .lsbr, .question] return k in [.name, .lpar, .amp, .lsbr, .question]
} }
pub fn (kind Kind) is_prefix() bool {
return kind in [.minus, .amp, .mul, .not, .bit_not]
}
pub fn (kind Kind) is_infix() bool { pub fn (kind Kind) is_infix() bool {
return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .key_in, return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .key_in,
// //