parser: fix to multi-expr
parent
66506673f8
commit
2344c1a435
|
@ -448,7 +448,7 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||||
return p.assign_stmt()
|
return p.assign_stmt()
|
||||||
} else if p.peek_tok.kind == .comma {
|
} else if p.peek_tok.kind == .comma {
|
||||||
// `a, b ...`
|
// `a, b ...`
|
||||||
return p.parse_comma_separated()
|
return p.parse_multi_expr()
|
||||||
} else if p.peek_tok.kind == .colon {
|
} else if p.peek_tok.kind == .colon {
|
||||||
// `label:`
|
// `label:`
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
|
@ -462,11 +462,7 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||||
[.rcbr, .eof] {
|
[.rcbr, .eof] {
|
||||||
p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
|
p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
|
||||||
}
|
}
|
||||||
epos := p.tok.position()
|
return p.parse_multi_expr()
|
||||||
return ast.ExprStmt{
|
|
||||||
expr: p.expr(0)
|
|
||||||
pos: epos
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.comment {
|
.comment {
|
||||||
return p.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.error_with_pos('const can only be defined at the top level (outside of functions)',
|
||||||
p.tok.position())
|
p.tok.position())
|
||||||
}
|
}
|
||||||
|
// literals, 'if', etc. in here
|
||||||
else {
|
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
|
// in here might be 1) multi-expr 2) multi-assign
|
||||||
// 1, a, c ... } // multi-expression
|
// 1, a, c ... } // multi-expression
|
||||||
// a, mut b ... :=/= // multi-assign
|
// a, mut b ... :=/= // multi-assign
|
||||||
// collect things upto hard boundaries
|
// collect things upto hard boundaries
|
||||||
mut collected := []ast.Expr{}
|
mut collected := []ast.Expr{}
|
||||||
mut op := p.tok.kind
|
for {
|
||||||
for op !in [.rcbr, .decl_assign, .assign] {
|
|
||||||
if op == .name {
|
|
||||||
collected << p.name_expr()
|
|
||||||
} else {
|
|
||||||
collected << p.expr(0)
|
collected << p.expr(0)
|
||||||
}
|
|
||||||
if p.tok.kind == .comma {
|
if p.tok.kind == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
op = p.tok.kind
|
|
||||||
}
|
}
|
||||||
is_assignment := p.tok.kind in [.decl_assign, .assign]
|
// TODO: Try to merge assign_expr and assign_stmt
|
||||||
if is_assignment {
|
if p.tok.kind == .decl_assign || (p.tok.kind == .assign && collected.len > 1) {
|
||||||
mut idents := []ast.Ident{}
|
mut idents := []ast.Ident{}
|
||||||
for c in collected {
|
for c in collected {
|
||||||
idents << c as ast.Ident
|
idents << c as ast.Ident
|
||||||
}
|
}
|
||||||
return p.partial_assign_stmt(idents)
|
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 {
|
} else {
|
||||||
if collected.len == 1 {
|
if collected.len == 1 {
|
||||||
epos := p.tok.position()
|
|
||||||
return ast.ExprStmt{
|
return ast.ExprStmt{
|
||||||
expr: collected[0]
|
expr: collected[0]
|
||||||
pos: epos
|
pos: p.tok.position()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast.ExprStmt{
|
return ast.ExprStmt{
|
||||||
|
|
|
@ -138,7 +138,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
}
|
}
|
||||||
// Infix
|
// Infix
|
||||||
for precedence < p.tok.precedence() {
|
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)
|
node = p.assign_expr(node)
|
||||||
} else if p.tok.kind == .dot {
|
} else if p.tok.kind == .dot {
|
||||||
node = p.dot_expr(node)
|
node = p.dot_expr(node)
|
||||||
|
|
|
@ -7,25 +7,7 @@ fn multireturner(n int, s string) (int, string) {
|
||||||
return n + 1, s
|
return n + 1, s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_assign_multireturn_expression() {
|
fn test_assign_multi_expr_func() {
|
||||||
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'
|
|
||||||
|
|
||||||
e, f := if false {
|
e, f := if false {
|
||||||
multireturner(-1, 'notawesome')
|
multireturner(-1, 'notawesome')
|
||||||
} else if false {
|
} else if false {
|
||||||
|
@ -43,63 +25,84 @@ fn test_assign_multireturn_expression() {
|
||||||
}
|
}
|
||||||
assert g == 1
|
assert g == 1
|
||||||
assert h == 'good'
|
assert h == 'good'
|
||||||
|
}
|
||||||
|
|
||||||
i, j := match true {
|
fn test_assign_multi_expr() {
|
||||||
false { multireturner(100, 'bad') }
|
// helpers
|
||||||
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]
|
|
||||||
|
|
||||||
val1 := 1
|
val1 := 1
|
||||||
val2 := 0
|
val2 := 2
|
||||||
t, u, v := if true {
|
|
||||||
|
// 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]
|
val1, 'awesome', [13]
|
||||||
} else {
|
} else {
|
||||||
val2, 'bad', [0]
|
val2, 'bad', [0]
|
||||||
}
|
}
|
||||||
assert t == val1
|
assert j == 1
|
||||||
assert u == 'awesome'
|
assert k == 'awesome'
|
||||||
assert v == [13]
|
assert l == [13]
|
||||||
|
|
||||||
val3 := Object { name: 'foo', value: 19 }
|
// test with first value name and peek != .comma
|
||||||
x, y, z := if true {
|
m, n, o := if true {
|
||||||
1 + 1, 'awe' + 'some', { val3 | name: 'bar' }
|
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 {
|
} else {
|
||||||
0, '0', Object {}
|
0, '0', Object {}
|
||||||
}
|
}
|
||||||
assert x == 2
|
assert q == 2
|
||||||
assert y == 'awesome'
|
assert r == 'awesome'
|
||||||
assert z.name == 'bar'
|
assert s.name == 'ok'
|
||||||
assert z.value == 19
|
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'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue