1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

parser: fix to multi-expr

This commit is contained in:
Tanel Liiv 2020-05-18 19:33:27 +03:00 committed by GitHub
parent 66506673f8
commit 2344c1a435
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 88 deletions

View File

@ -448,7 +448,7 @@ pub fn (mut p Parser) stmt() ast.Stmt {
return p.assign_stmt()
} else if p.peek_tok.kind == .comma {
// `a, b ...`
return p.parse_comma_separated()
return p.parse_multi_expr()
} else if p.peek_tok.kind == .colon {
// `label:`
name := p.check_name()
@ -462,11 +462,7 @@ pub fn (mut p Parser) stmt() ast.Stmt {
[.rcbr, .eof] {
p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
}
epos := p.tok.position()
return ast.ExprStmt{
expr: p.expr(0)
pos: epos
}
return p.parse_multi_expr()
}
.comment {
return p.comment()
@ -527,8 +523,9 @@ pub fn (mut p Parser) stmt() ast.Stmt {
p.error_with_pos('const can only be defined at the top level (outside of functions)',
p.tok.position())
}
// literals, 'if', etc. in here
else {
return p.parse_comma_separated()
return p.parse_multi_expr()
}
}
}
@ -644,39 +641,47 @@ pub fn (mut p Parser) warn_with_pos(s string, pos token.Position) {
}
}
fn (mut p Parser) parse_comma_separated() ast.Stmt {
fn (mut p Parser) parse_multi_expr() ast.Stmt {
// in here might be 1) multi-expr 2) multi-assign
// 1, a, c ... } // multi-expression
// a, mut b ... :=/= // multi-assign
// collect things upto hard boundaries
mut collected := []ast.Expr{}
mut op := p.tok.kind
for op !in [.rcbr, .decl_assign, .assign] {
if op == .name {
collected << p.name_expr()
} else {
collected << p.expr(0)
}
for {
collected << p.expr(0)
if p.tok.kind == .comma {
p.next()
} else {
break
}
op = p.tok.kind
}
is_assignment := p.tok.kind in [.decl_assign, .assign]
if is_assignment {
// TODO: Try to merge assign_expr and assign_stmt
if p.tok.kind == .decl_assign || (p.tok.kind == .assign && collected.len > 1) {
mut idents := []ast.Ident{}
for c in collected {
idents << c as ast.Ident
}
return p.partial_assign_stmt(idents)
} else if p.tok.kind.is_assign() {
epos := p.tok.position()
if collected.len == 1 {
return ast.ExprStmt {
expr: p.assign_expr(collected[0])
pos: epos
}
} else {
return ast.ExprStmt {
expr: p.assign_expr(ast.ConcatExpr{
vals: collected
})
pos: epos
}
}
} else {
if collected.len == 1 {
epos := p.tok.position()
return ast.ExprStmt{
expr: collected[0]
pos: epos
pos: p.tok.position()
}
}
return ast.ExprStmt{

View File

@ -138,7 +138,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
}
// Infix
for precedence < p.tok.precedence() {
if p.tok.kind.is_assign() {
if p.tok.kind.is_assign() && !p.is_stmt_ident {
node = p.assign_expr(node)
} else if p.tok.kind == .dot {
node = p.dot_expr(node)

View File

@ -7,25 +7,7 @@ fn multireturner(n int, s string) (int, string) {
return n + 1, s
}
fn test_assign_multireturn_expression() {
a, b := if true {
multireturner(13, 'awesome')
} else {
multireturner(-1, 'notawesome')
}
assert a == 14
assert b == 'awesome'
c, d := if false {
multireturner(-1, 'notawesome')
} else if true {
multireturner(17, 'awesomer')
} else {
multireturner(-1, 'notawesome')
}
assert c == 18
assert d == 'awesomer'
fn test_assign_multi_expr_func() {
e, f := if false {
multireturner(-1, 'notawesome')
} else if false {
@ -43,63 +25,84 @@ fn test_assign_multireturn_expression() {
}
assert g == 1
assert h == 'good'
}
i, j := match true {
false { multireturner(100, 'bad') }
else { multireturner(0, 'good') }
}
assert i == 1
assert j == 'good'
k, l, m := if true {
1, 'awesome', [13]
} else {
0, 'bad', [0]
}
assert k == 1
assert l == 'awesome'
assert m == [13]
n, o, p := if false {
1, 'awesome', [13]
} else {
0, 'bad', [0]
}
assert n == 0
assert o == 'bad'
assert p == [0]
mut var1 := 17
var2 := 'awesome'
q, r, s := if true {
1 + var1, var2, [13]
} else {
0, 'bad', [0]
}
assert q == 18
assert r == 'awesome'
assert s == [13]
fn test_assign_multi_expr() {
// helpers
val1 := 1
val2 := 0
t, u, v := if true {
val2 := 2
// simple case for match
a,b,c := match false {
true { 1,2,3 }
false { 4,5,6 }
else { 7,8,9 }
}
assert a == 4
assert b == 5
assert c == 6
// test with first value `literal`
d, e, f := if true {
1, 'awesome', [13]
} else {
0, 'bad', [0]
}
assert d == 1
assert e == 'awesome'
assert f == [13]
// test with first value `literal expr` and statement
awesome := 'awesome'
g, h, i := if true {
1 + val1, awesome, [13]
} else {
0, 'bad', [0]
}
assert g == 2
assert h == 'awesome'
assert i == [13]
// test with first value `.name`
j, k, l := if true {
val1, 'awesome', [13]
} else {
val2, 'bad', [0]
}
assert t == val1
assert u == 'awesome'
assert v == [13]
assert j == 1
assert k == 'awesome'
assert l == [13]
val3 := Object { name: 'foo', value: 19 }
x, y, z := if true {
1 + 1, 'awe' + 'some', { val3 | name: 'bar' }
// test with first value name and peek != .comma
m, n, o := if true {
val1 + 1, val1, val1
} else {
val2, val2, val2
}
assert m == val1 + 1
assert n == val1
assert o == val1
// test practical complex expressions
val3 := Object { name: 'initial', value: 19 }
mut q, mut r, mut s := if true {
1 + 1, 'awe' + 'some', { val3 | name: 'ok' }
} else {
0, '0', Object {}
}
assert x == 2
assert y == 'awesome'
assert z.name == 'bar'
assert z.value == 19
assert q == 2
assert r == 'awesome'
assert s.name == 'ok'
assert s.value == 19
// test assign to existing variables
q, r, s = if false {
0, '0', Object {}
} else {
5, '55', { val3 | value: 555 }
}
assert q == 5
assert r == '55'
assert s.value == 555
assert s.name == 'initial'
}