parser: return multi expr
parent
7caebc5781
commit
44502a3fb2
|
@ -755,6 +755,8 @@ pub:
|
||||||
pub struct ConcatExpr {
|
pub struct ConcatExpr {
|
||||||
pub:
|
pub:
|
||||||
vals []Expr
|
vals []Expr
|
||||||
|
pub mut:
|
||||||
|
return_type table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct None {
|
pub struct None {
|
||||||
|
|
|
@ -1588,6 +1588,13 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
|
||||||
|
|
||||||
pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
match mut node {
|
match mut node {
|
||||||
|
ast.AnonFn {
|
||||||
|
keep_ret_type := c.fn_return_type
|
||||||
|
c.fn_return_type = it.decl.return_type
|
||||||
|
c.stmts(it.decl.stmts)
|
||||||
|
c.fn_return_type = keep_ret_type
|
||||||
|
return it.typ
|
||||||
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
return c.array_init(mut it)
|
return c.array_init(mut it)
|
||||||
}
|
}
|
||||||
|
@ -1645,6 +1652,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
return table.byte_type
|
return table.byte_type
|
||||||
}
|
}
|
||||||
|
ast.ConcatExpr {
|
||||||
|
return c.concat_expr(mut it)
|
||||||
|
}
|
||||||
ast.EnumVal {
|
ast.EnumVal {
|
||||||
return c.enum_val(mut it)
|
return c.enum_val(mut it)
|
||||||
}
|
}
|
||||||
|
@ -1730,13 +1740,6 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
it.expr_type = c.expr(it.expr)
|
it.expr_type = c.expr(it.expr)
|
||||||
return table.string_type
|
return table.string_type
|
||||||
}
|
}
|
||||||
ast.AnonFn {
|
|
||||||
keep_ret_type := c.fn_return_type
|
|
||||||
c.fn_return_type = it.decl.return_type
|
|
||||||
c.stmts(it.decl.stmts)
|
|
||||||
c.fn_return_type = keep_ret_type
|
|
||||||
return it.typ
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
tnode := typeof(node)
|
tnode := typeof(node)
|
||||||
if tnode != 'unknown v.ast.Expr' {
|
if tnode != 'unknown v.ast.Expr' {
|
||||||
|
@ -1858,6 +1861,23 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) concat_expr(concat_expr mut ast.ConcatExpr) table.Type {
|
||||||
|
mut mr_types := []table.Type{}
|
||||||
|
for expr in concat_expr.vals {
|
||||||
|
mr_types << c.expr(expr)
|
||||||
|
}
|
||||||
|
if concat_expr.vals.len == 1 {
|
||||||
|
typ := mr_types[0]
|
||||||
|
concat_expr.return_type = typ
|
||||||
|
return typ
|
||||||
|
} else {
|
||||||
|
typ := c.table.find_or_register_multi_return(mr_types)
|
||||||
|
table.new_type(typ)
|
||||||
|
concat_expr.return_type = typ
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
||||||
node.is_expr = c.expected_type != table.void_type
|
node.is_expr = c.expected_type != table.void_type
|
||||||
node.expected_type = c.expected_type
|
node.expected_type = c.expected_type
|
||||||
|
|
|
@ -1163,6 +1163,18 @@ fn (g &Gen) autofree_var_call(free_fn_name string, v ast.Var) string {
|
||||||
fn (mut g Gen) expr(node ast.Expr) {
|
fn (mut g Gen) expr(node ast.Expr) {
|
||||||
// println('cgen expr() line_nr=$node.pos.line_nr')
|
// println('cgen expr() line_nr=$node.pos.line_nr')
|
||||||
match node {
|
match node {
|
||||||
|
ast.AnonFn {
|
||||||
|
// TODO: dont fiddle with buffers
|
||||||
|
pos := g.out.len
|
||||||
|
def_pos := g.definitions.len
|
||||||
|
g.stmt(it.decl)
|
||||||
|
fn_body := g.out.after(pos)
|
||||||
|
g.out.go_back(fn_body.len)
|
||||||
|
g.definitions.go_back(g.definitions.len - def_pos)
|
||||||
|
g.definitions.write(fn_body)
|
||||||
|
fsym := g.table.get_type_symbol(it.typ)
|
||||||
|
g.write('&${fsym.name}')
|
||||||
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
g.array_init(it)
|
g.array_init(it)
|
||||||
}
|
}
|
||||||
|
@ -1226,6 +1238,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
g.write("'$it.val'")
|
g.write("'$it.val'")
|
||||||
}
|
}
|
||||||
|
ast.ConcatExpr {
|
||||||
|
g.concat_expr(it)
|
||||||
|
}
|
||||||
ast.EnumVal {
|
ast.EnumVal {
|
||||||
// g.write('${it.mod}${it.enum_name}_$it.val')
|
// g.write('${it.mod}${it.enum_name}_$it.val')
|
||||||
styp := g.typ(it.typ)
|
styp := g.typ(it.typ)
|
||||||
|
@ -1375,18 +1390,6 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
ast.TypeOf {
|
ast.TypeOf {
|
||||||
g.typeof_expr(it)
|
g.typeof_expr(it)
|
||||||
}
|
}
|
||||||
ast.AnonFn {
|
|
||||||
// TODO: dont fiddle with buffers
|
|
||||||
pos := g.out.len
|
|
||||||
def_pos := g.definitions.len
|
|
||||||
g.stmt(it.decl)
|
|
||||||
fn_body := g.out.after(pos)
|
|
||||||
g.out.go_back(fn_body.len)
|
|
||||||
g.definitions.go_back(g.definitions.len - def_pos)
|
|
||||||
g.definitions.write(fn_body)
|
|
||||||
fsym := g.table.get_type_symbol(it.typ)
|
|
||||||
g.write('&${fsym.name}')
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// #printf("node=%d\n", node.typ);
|
// #printf("node=%d\n", node.typ);
|
||||||
println(term.red('cgen.expr(): bad node ' + typeof(node)))
|
println(term.red('cgen.expr(): bad node ' + typeof(node)))
|
||||||
|
@ -1524,7 +1527,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
|
||||||
g.or_block(tmp_opt, or_stmts, return_type)
|
g.or_block(tmp_opt, or_stmts, return_type)
|
||||||
unwrapped_type_str := g.typ(return_type.set_flag(.unset))
|
unwrapped_type_str := g.typ(return_type.set_flag(.unset))
|
||||||
ident := node.left as ast.Ident
|
ident := node.left as ast.Ident
|
||||||
if ident.info is ast.IdentVar {
|
if ident.kind != .blank_ident && ident.info is ast.IdentVar {
|
||||||
ident_var := ident.info as ast.IdentVar
|
ident_var := ident.info as ast.IdentVar
|
||||||
if ident_var.is_optional {
|
if ident_var.is_optional {
|
||||||
// var is already an optional, just copy the value
|
// var is already an optional, just copy the value
|
||||||
|
@ -1847,6 +1850,26 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
g.write(g.get_ternary_name(name))
|
g.write(g.get_ternary_name(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
|
||||||
|
styp := g.typ(node.return_type)
|
||||||
|
sym := g.table.get_type_symbol(node.return_type)
|
||||||
|
is_multi := sym.kind == .multi_return
|
||||||
|
|
||||||
|
if !is_multi {
|
||||||
|
g.expr(node.vals[0])
|
||||||
|
} else {
|
||||||
|
g.write('($styp){')
|
||||||
|
for i, expr in node.vals {
|
||||||
|
g.write('.arg$i=')
|
||||||
|
g.expr(expr)
|
||||||
|
if i < node.vals.len - 1 {
|
||||||
|
g.write(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
if node.is_expr || g.inside_ternary != 0 {
|
if node.is_expr || g.inside_ternary != 0 {
|
||||||
g.inside_ternary++
|
g.inside_ternary++
|
||||||
|
|
|
@ -6,13 +6,21 @@ module parser
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
fn (mut p Parser) assign_stmt() ast.Stmt {
|
fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||||
is_static := p.tok.kind == .key_static
|
return p.partial_assign_stmt([])
|
||||||
if is_static {
|
}
|
||||||
p.next()
|
|
||||||
|
fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt {
|
||||||
|
mut idents := known_lhs
|
||||||
|
mut op := p.tok.kind
|
||||||
|
// read (more) idents until assignment sign
|
||||||
|
for op !in [.decl_assign, .assign] {
|
||||||
|
idents << p.parse_assign_ident()
|
||||||
|
if p.tok.kind == .comma {
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
op = p.tok.kind
|
||||||
}
|
}
|
||||||
idents := p.parse_assign_lhs()
|
p.next()
|
||||||
op := p.tok.kind
|
|
||||||
p.next() // :=, =
|
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
exprs := p.parse_assign_rhs()
|
exprs := p.parse_assign_rhs()
|
||||||
is_decl := op == .decl_assign
|
is_decl := op == .decl_assign
|
||||||
|
@ -46,7 +54,7 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||||
right: exprs
|
right: exprs
|
||||||
op: op
|
op: op
|
||||||
pos: pos
|
pos: pos
|
||||||
is_static: is_static
|
is_static: false // individual idents may be static
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,31 +80,9 @@ pub fn (mut p Parser) assign_expr(left ast.Expr) ast.AssignExpr {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_assign_lhs() []ast.Ident {
|
fn (mut p Parser) parse_assign_ident() ast.Ident {
|
||||||
mut idents := []ast.Ident{}
|
/// returns a single parsed ident
|
||||||
for {
|
return p.parse_ident(false, false)
|
||||||
is_mut := p.tok.kind == .key_mut
|
|
||||||
if is_mut {
|
|
||||||
p.next()
|
|
||||||
}
|
|
||||||
is_static := p.tok.kind == .key_static
|
|
||||||
if is_static {
|
|
||||||
p.next()
|
|
||||||
}
|
|
||||||
mut ident := p.parse_ident(false, false)
|
|
||||||
ident.is_mut = is_mut
|
|
||||||
ident.info = ast.IdentVar{
|
|
||||||
is_mut: is_mut
|
|
||||||
is_static: is_static
|
|
||||||
}
|
|
||||||
idents << ident
|
|
||||||
if p.tok.kind == .comma {
|
|
||||||
p.next()
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idents
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// right hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
// right hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
||||||
|
|
|
@ -447,9 +447,12 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||||
return p.for_stmt()
|
return p.for_stmt()
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
if p.peek_tok.kind in [.decl_assign, .comma] {
|
if p.peek_tok.kind == .decl_assign {
|
||||||
// `x := ...`
|
// `x := ...`
|
||||||
return p.assign_stmt()
|
return p.assign_stmt()
|
||||||
|
} else if p.peek_tok.kind == .comma {
|
||||||
|
// `a, b ...`
|
||||||
|
return p.parse_comma_separated()
|
||||||
} else if p.peek_tok.kind == .colon {
|
} else if p.peek_tok.kind == .colon {
|
||||||
// `label:`
|
// `label:`
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
|
@ -524,15 +527,11 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||||
name: name
|
name: name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.key_const {
|
||||||
|
p.error_with_pos('const can only be defined at the top level (outside of functions)', p.tok.position())
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if p.tok.kind == .key_const {
|
return p.parse_comma_separated()
|
||||||
p.error_with_pos('const can only be defined at the top level (outside of functions)', p.tok.position())
|
|
||||||
}
|
|
||||||
epos := p.tok.position()
|
|
||||||
return ast.ExprStmt{
|
|
||||||
expr: p.expr(0)
|
|
||||||
pos: epos
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,27 +644,93 @@ pub fn (mut p Parser) warn_with_pos(s string, pos token.Position) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
|
fn (mut p Parser) parse_comma_separated() ast.Stmt {
|
||||||
// p.warn('name ')
|
// in here might be 1) multi-expr 2) multi-assign
|
||||||
pos := p.tok.position()
|
// 1, a, c ... } // multi-expression
|
||||||
mut name := p.check_name()
|
// a, mut b ... :=/= // multi-assign
|
||||||
if name == '_' {
|
// collect things upto hard boundaries
|
||||||
return ast.Ident{
|
mut collected := []ast.Expr{}
|
||||||
name: '_'
|
mut op := p.tok.kind
|
||||||
kind: .blank_ident
|
for op !in [.rcbr, .decl_assign, .assign] {
|
||||||
pos: pos
|
if op == .name {
|
||||||
|
collected << p.name_expr()
|
||||||
|
} else {
|
||||||
|
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 {
|
||||||
|
mut idents := []ast.Ident{}
|
||||||
|
for c in collected {
|
||||||
|
idents << c as ast.Ident
|
||||||
|
}
|
||||||
|
return p.partial_assign_stmt(idents)
|
||||||
|
} else {
|
||||||
|
if collected.len == 1 {
|
||||||
|
epos := p.tok.position()
|
||||||
|
return ast.ExprStmt{
|
||||||
|
expr: collected[0]
|
||||||
|
pos: epos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ast.ExprStmt{
|
||||||
|
expr: ast.ConcatExpr {
|
||||||
|
vals: collected
|
||||||
|
}
|
||||||
|
pos: p.tok.position()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.expr_mod.len > 0 {
|
}
|
||||||
name = '${p.expr_mod}.$name'
|
|
||||||
|
pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
|
||||||
|
// p.warn('name ')
|
||||||
|
is_mut := p.tok.kind == .key_mut
|
||||||
|
if is_mut {
|
||||||
|
p.next()
|
||||||
}
|
}
|
||||||
return ast.Ident{
|
is_static := p.tok.kind == .key_static
|
||||||
kind: .unresolved
|
if is_static {
|
||||||
name: name
|
p.next()
|
||||||
is_c: is_c
|
}
|
||||||
is_js: is_js
|
if p.tok.kind == .name {
|
||||||
mod: p.mod
|
pos := p.tok.position()
|
||||||
pos: pos
|
mut name := p.check_name()
|
||||||
|
if name == '_' {
|
||||||
|
return ast.Ident{
|
||||||
|
name: '_'
|
||||||
|
kind: .blank_ident
|
||||||
|
pos: pos
|
||||||
|
info: ast.IdentVar {
|
||||||
|
is_mut: false
|
||||||
|
is_static: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.expr_mod.len > 0 {
|
||||||
|
name = '${p.expr_mod}.$name'
|
||||||
|
}
|
||||||
|
mut ident := ast.Ident{
|
||||||
|
kind: .unresolved
|
||||||
|
name: name
|
||||||
|
is_c: is_c
|
||||||
|
is_js: is_js
|
||||||
|
mod: p.mod
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
ident.is_mut = is_mut
|
||||||
|
ident.info = ast.IdentVar{
|
||||||
|
is_mut: is_mut
|
||||||
|
is_static: is_static
|
||||||
|
}
|
||||||
|
return ident
|
||||||
|
} else {
|
||||||
|
p.error('unexpected token `$p.tok.lit`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
p.is_stmt_ident = false
|
p.is_stmt_ident = false
|
||||||
// Prefix
|
// Prefix
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
|
.key_mut, .key_static {
|
||||||
|
node = p.parse_assign_ident()
|
||||||
|
}
|
||||||
.name {
|
.name {
|
||||||
node = p.name_expr()
|
node = p.name_expr()
|
||||||
p.is_stmt_ident = is_stmt_ident
|
p.is_stmt_ident = is_stmt_ident
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
struct Object {
|
||||||
|
name string
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
|
||||||
fn multireturner(n int, s string) (int, string) {
|
fn multireturner(n int, s string) (int, string) {
|
||||||
return n + 1, s
|
return n + 1, s
|
||||||
|
@ -47,12 +51,55 @@ fn test_assign_multireturn_expression() {
|
||||||
assert i == 1
|
assert i == 1
|
||||||
assert j == 'good'
|
assert j == 'good'
|
||||||
|
|
||||||
// TODO: returning non-function calls does not work yet due to parsing issues
|
k, l, m := if true {
|
||||||
/*
|
1, 'awesome', [13]
|
||||||
e, f := if true {
|
|
||||||
1, 'awesome'
|
|
||||||
} else {
|
} else {
|
||||||
0, 'bad'
|
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
|
||||||
|
val2 := 0
|
||||||
|
t, u, v := if true {
|
||||||
|
val1, 'awesome', [13]
|
||||||
|
} else {
|
||||||
|
val2, 'bad', [0]
|
||||||
|
}
|
||||||
|
assert t == val1
|
||||||
|
assert u == 'awesome'
|
||||||
|
assert v == [13]
|
||||||
|
|
||||||
|
val3 := Object { name: 'foo', value: 19 }
|
||||||
|
x, y, z := if true {
|
||||||
|
1 + 1, 'awe' + 'some', { val3 | name: 'bar' }
|
||||||
|
} else {
|
||||||
|
0, '0', Object {}
|
||||||
|
}
|
||||||
|
assert x == 2
|
||||||
|
assert y == 'awesome'
|
||||||
|
assert z.name == 'bar'
|
||||||
|
assert z.value == 19
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue