mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser: return multi expr
This commit is contained in:
parent
7caebc5781
commit
44502a3fb2
@ -755,6 +755,8 @@ pub:
|
||||
pub struct ConcatExpr {
|
||||
pub:
|
||||
vals []Expr
|
||||
pub mut:
|
||||
return_type table.Type
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
return c.array_init(mut it)
|
||||
}
|
||||
@ -1645,6 +1652,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||
ast.CharLiteral {
|
||||
return table.byte_type
|
||||
}
|
||||
ast.ConcatExpr {
|
||||
return c.concat_expr(mut it)
|
||||
}
|
||||
ast.EnumVal {
|
||||
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)
|
||||
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 {
|
||||
tnode := typeof(node)
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
node.is_expr = c.expected_type != table.void_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) {
|
||||
// println('cgen expr() line_nr=$node.pos.line_nr')
|
||||
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 {
|
||||
g.array_init(it)
|
||||
}
|
||||
@ -1226,6 +1238,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
ast.CharLiteral {
|
||||
g.write("'$it.val'")
|
||||
}
|
||||
ast.ConcatExpr {
|
||||
g.concat_expr(it)
|
||||
}
|
||||
ast.EnumVal {
|
||||
// g.write('${it.mod}${it.enum_name}_$it.val')
|
||||
styp := g.typ(it.typ)
|
||||
@ -1375,18 +1390,6 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
ast.TypeOf {
|
||||
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 {
|
||||
// #printf("node=%d\n", node.typ);
|
||||
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)
|
||||
unwrapped_type_str := g.typ(return_type.set_flag(.unset))
|
||||
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
|
||||
if ident_var.is_optional {
|
||||
// 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))
|
||||
}
|
||||
|
||||
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) {
|
||||
if node.is_expr || g.inside_ternary != 0 {
|
||||
g.inside_ternary++
|
||||
|
@ -6,13 +6,21 @@ module parser
|
||||
import v.ast
|
||||
|
||||
fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.next()
|
||||
return p.partial_assign_stmt([])
|
||||
}
|
||||
|
||||
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()
|
||||
op := p.tok.kind
|
||||
p.next() // :=, =
|
||||
p.next()
|
||||
pos := p.tok.position()
|
||||
exprs := p.parse_assign_rhs()
|
||||
is_decl := op == .decl_assign
|
||||
@ -46,7 +54,7 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||
right: exprs
|
||||
op: op
|
||||
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
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_assign_lhs() []ast.Ident {
|
||||
mut idents := []ast.Ident{}
|
||||
for {
|
||||
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
|
||||
fn (mut p Parser) parse_assign_ident() ast.Ident {
|
||||
/// returns a single parsed ident
|
||||
return p.parse_ident(false, false)
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
.name {
|
||||
if p.peek_tok.kind in [.decl_assign, .comma] {
|
||||
if p.peek_tok.kind == .decl_assign {
|
||||
// `x := ...`
|
||||
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 {
|
||||
// `label:`
|
||||
name := p.check_name()
|
||||
@ -524,15 +527,11 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
||||
name: name
|
||||
}
|
||||
}
|
||||
.key_const {
|
||||
p.error_with_pos('const can only be defined at the top level (outside of functions)', p.tok.position())
|
||||
}
|
||||
else {
|
||||
if p.tok.kind == .key_const {
|
||||
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
|
||||
}
|
||||
return p.parse_comma_separated()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
// p.warn('name ')
|
||||
pos := p.tok.position()
|
||||
mut name := p.check_name()
|
||||
if name == '_' {
|
||||
return ast.Ident{
|
||||
name: '_'
|
||||
kind: .blank_ident
|
||||
pos: pos
|
||||
fn (mut p Parser) parse_comma_separated() 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)
|
||||
}
|
||||
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{
|
||||
kind: .unresolved
|
||||
name: name
|
||||
is_c: is_c
|
||||
is_js: is_js
|
||||
mod: p.mod
|
||||
pos: pos
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .name {
|
||||
pos := p.tok.position()
|
||||
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
|
||||
// Prefix
|
||||
match p.tok.kind {
|
||||
.key_mut, .key_static {
|
||||
node = p.parse_assign_ident()
|
||||
}
|
||||
.name {
|
||||
node = p.name_expr()
|
||||
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) {
|
||||
return n + 1, s
|
||||
@ -47,12 +51,55 @@ fn test_assign_multireturn_expression() {
|
||||
assert i == 1
|
||||
assert j == 'good'
|
||||
|
||||
// TODO: returning non-function calls does not work yet due to parsing issues
|
||||
/*
|
||||
e, f := if true {
|
||||
1, 'awesome'
|
||||
k, l, m := if true {
|
||||
1, 'awesome', [13]
|
||||
} 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
Block a user