diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index bc4f6e0b11..6d4b7bdd9a 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -14,7 +14,7 @@ AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | -HashStmt +HashStmt | AssignStmt // | IncDecStmt k // Stand-alone expression in a statement list. pub struct ExprStmt { @@ -195,7 +195,8 @@ pub: pub struct IdentVar { pub mut: - typ table.TypeRef + typ table.TypeRef + is_mut bool //name string } @@ -205,6 +206,7 @@ pub enum IdentKind { blank_ident variable constant + func } // A single identifier @@ -219,6 +221,18 @@ mut: info IdentInfo } +pub fn(i &Ident) var_info() IdentVar { + match i.info { + IdentVar { + return it + } + else { + // return IdentVar{} + panic('Ident.var_info(): info is not IdentVar variant') + } + } +} + pub struct InfixExpr { pub: // op BinaryOp @@ -326,14 +340,14 @@ pub: name string } -/* + pub struct AssignStmt { pub: - left Expr - right Expr + left []Ident + right []Expr op token.Kind } -*/ + // e.g. `[unsafe_fn]` pub struct Attr { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 6de8cf0863..9ac83aac10 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -46,7 +46,7 @@ fn (c mut Checker) resolve_types() { // update any types with unresolved sub types for idx, t in c.table.types { if t.kind == .array { - mut info := t.info as table.Array + mut info := t.array_info() if info.elem_type.typ.kind == .unresolved { info.elem_type = c.resolved[info.elem_type.idx] mut t1 := &c.table.types[idx] @@ -55,7 +55,7 @@ fn (c mut Checker) resolve_types() { } } else if t.kind == .map { - mut info := t.info as table.Map + mut info := t.map_info() mut updated := false if info.key_type.typ.kind == .unresolved { info.key_type = c.resolved[info.key_type.idx] @@ -71,6 +71,22 @@ fn (c mut Checker) resolve_types() { t1.info = info } } + else if t.kind == .multi_return { + mut info := t.mr_info() + mut types := info.types + mut updated := false + for i, ut in types { + if ut.typ.kind == .unresolved { + types[i] = c.resolved[ut.idx] + updated = true + } + } + if updated { + mut t1 := &c.table.types[idx] + info.types = types + t1.info = info + } + } } } @@ -197,6 +213,8 @@ pub fn (c &Checker) return_stmt(return_stmt ast.Return) { } } +pub fn (c &Checker) assign_stmt(assign_stmt ast.AssignStmt) {} + pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.TypeRef { mut elem_type := c.table.type_ref(table.void_type_idx) for i, expr in array_init.exprs { @@ -224,6 +242,9 @@ fn (c &Checker) stmt(node ast.Stmt) { ast.Return { c.return_stmt(it) } + ast.AssignStmt { + c.assign_stmt(it) + } ast.VarDecl { typ := c.expr(it.expr) // println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr') diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0479bf3bb6..0193b9b7f4 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -106,6 +106,23 @@ fn (g mut Gen) stmt(node ast.Stmt) { } g.writeln(';') } + ast.AssignStmt { + // ident0 := it.left[0] + // info0 := ident0.var_info() + // for i, ident in it.left { + // info := ident.var_info() + // if info0.typ.typ.kind == .multi_return { + // if i == 0 { + // g.write('$info.typ.typ.name $ident.name = ') + // g.expr(it.right[0]) + // } else { + // arg_no := i-1 + // g.write('$info.typ.typ.name $ident.name = $ident0.name->arg[$arg_no]') + // } + // } + // g.writeln(';') + // } + } ast.VarDecl { g.write('$it.typ.typ.name $it.name = ') g.expr(it.expr) diff --git a/vlib/v/gen/jsgen.v b/vlib/v/gen/jsgen.v index 4363d79b1d..714dcfb436 100644 --- a/vlib/v/gen/jsgen.v +++ b/vlib/v/gen/jsgen.v @@ -55,6 +55,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) { } g.writeln(';') } + ast.AssignStmt {} ast.VarDecl { g.write('var /* $it.typ.typ.name */ $it.name = ') g.expr(it.expr) diff --git a/vlib/v/gen/tests/4.c b/vlib/v/gen/tests/4.c index 06a6d233cc..f24c64e5b9 100644 --- a/vlib/v/gen/tests/4.c +++ b/vlib/v/gen/tests/4.c @@ -1,9 +1,11 @@ +multi_return_int_string mr_test(); int testa(); string testb(int a); int testc(int a); int testa(); int testb(); int testa(); + int main() { Bar b = (Bar){ .a = 122, @@ -29,7 +31,11 @@ int main() { array_string g = new_array_from_c_array(2, 2, sizeof(array_string), { testb(1), tos3("hello"), }); - return 0; + return 0; +} + +multi_return_int_string mr_test() { + return (multi_return_int_string){.arg0=1,.arg1=tos3("v")}; } int testa() { diff --git a/vlib/v/gen/tests/4.vv b/vlib/v/gen/tests/4.vv index 2145892da0..c5aaca3ea0 100644 --- a/vlib/v/gen/tests/4.vv +++ b/vlib/v/gen/tests/4.vv @@ -30,8 +30,13 @@ fn main() { mut f := [testa(),2,3,4] mut g := [testb(1),'hello'] + + m1, m2 := mr_test() } +fn mr_test() (int, string) { + return 1,'v' +} fn testa() int { return testc(1) diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index b141f79ab2..58617b9991 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -326,6 +326,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.ret() } ast.Return {} + ast.AssignStmt {} ast.VarDecl {} ast.ForStmt {} ast.StructDecl {} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 2e907c6fde..978751e58d 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -242,9 +242,13 @@ pub fn (p mut Parser) stmt() ast.Stmt { } else { // `x := ...` - if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { + // if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { + if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign] { return p.var_decl() } + if p.tok.kind == .name && p.peek_tok.kind in [.comma] { + return p.assign_stmt() + } expr,typ := p.expr(0) return ast.ExprStmt{ expr: expr @@ -370,6 +374,60 @@ pub fn (p &Parser) warn(s string) { } } +pub fn(p mut Parser) parse_ident(is_c bool) (ast.Ident, table.TypeRef) { + mut node := ast.Ident{} + mut typ := p.table.type_ref(table.void_type_idx) + // p.warn('name ') + // left := p.parse_ident() + name := p.check_name() + mut ident := ast.Ident{ + name: name + } + mut known_var := false + if var := p.table.find_var(name) { + known_var = true + typ = var.typ + } + // variable + if known_var || p.tok.kind in [.comma, .decl_assign, .assign] { + // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx') + ident.kind = .variable + ident.info = ast.IdentVar{ + typ: typ + // name: ident.name + // expr: p.expr(0)// var.expr + } + return ident, typ + }else{ + if is_c { + typ = p.table.type_ref(table.int_type_idx) + ident.info = ast.IdentVar{ + typ: typ + // name: ident.name + } + return ident,typ + } + // const + if c := p.table.find_const(name) { + typ = c.typ + ident.kind = .constant + ident.info = ast.IdentVar{ + typ: typ + // name: ident.name + } + node = ident + }else{ + // Function object (not a call), e.g. `onclick(my_click)` + p.table.find_fn(name) or { + p.error('parse_ident: unknown identifier `$name`') + exit(0) + } + // p.next() + } + } + return node, typ +} + pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) { mut node := ast.Expr{} mut typ := p.table.type_ref(table.void_type_idx) @@ -425,54 +483,9 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) { p.check(.rcbr) } else { - // p.warn('name ') - // left := p.parse_ident() - mut ident := ast.Ident{ - name: p.tok.lit - } - // variable - if var := p.table.find_var(p.tok.lit) { - // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx') - typ = var.typ - ident.kind = .variable - ident.info = ast.IdentVar{ - typ: typ - // name: ident.name - // expr: p.expr(0)// var.expr - } - // ident.ti = ti - node = ident - p.next() - }else{ - if is_c { - typ = p.table.type_ref(table.int_type_idx) - ident.info = ast.IdentVar{ - typ: typ - // name: ident.name - } - node = ident - p.next() - return node,typ - } - // const - if c := p.table.find_const(p.tok.lit) { - typ = c.typ - ident.kind = .constant - ident.info = ast.IdentVar{ - typ: typ - // name: ident.name - } - node = ident - p.next() - }else{ - // Function object (not a call), e.g. `onclick(my_click)` - p.table.find_fn(p.tok.lit) or { - p.error('name expr unknown identifier `$p.tok.lit`') - exit(0) - } - p.next() - } - } + mut ident := ast.Ident{} + ident, typ = p.parse_ident(is_c) + node = ident } return node,typ } @@ -1047,7 +1060,6 @@ fn (p mut Parser) return_stmt() ast.Return { break } } - // TODO: consider non deferred stmt := ast.Return{ expected_type: p.return_type exprs: exprs @@ -1056,6 +1068,26 @@ fn (p mut Parser) return_stmt() ast.Return { return stmt } +pub fn (p mut Parser) assign_stmt() ast.AssignStmt { + // TODO: multiple return & multiple assign + mut idents := []ast.Ident + for { + ident, _ := p.parse_ident(false) + idents << ident + if p.tok.kind == .comma { + p.check(.comma) + } else { + break + } + } + p.next() // :=, = + expr, _ := p.expr(0) + return ast.AssignStmt{ + left: idents + right: [expr] + } +} + fn (p mut Parser) var_decl() ast.VarDecl { is_mut := p.tok.kind == .key_mut // || p.prev_tok == .key_for // is_static := p.tok.kind == .key_static @@ -1076,8 +1108,6 @@ fn (p mut Parser) var_decl() ast.VarDecl { p.table.register_var(table.Var{ name: name is_mut: is_mut - // expr: expr - typ: typ }) p.warn('var decl name=$name typ=$typ.typ.name') @@ -1170,7 +1200,7 @@ fn (p mut Parser) add_unresolved(key string, expr ast.Expr) table.TypeRef { typ: &table.Type{ parent: 0 kind: .unresolved - name: 'unresolved $p.unresolved.len' + name: 'unresolved $idx' } } return t diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index c85eb756ba..9664fae3f9 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -77,6 +77,54 @@ pub enum Kind { unresolved } +[inline] +pub fn(t &Type) mr_info() MultiReturn { + match t.info { + MultiReturn { + return it + } + else { + panic('Type.mr_info(): no multi return info') + } + } +} + +[inline] +pub fn(t &Type) array_info() Array { + match t.info { + Array { + return it + } + else { + panic('Type.mr_info(): no array info') + } + } +} + +[inline] +pub fn(t &Type) array_fixed_info() ArrayFixed { + match t.info { + ArrayFixed { + return it + } + else { + panic('Type.mr_info(): no array fixed info') + } + } +} + +[inline] +pub fn(t &Type) map_info() Map { + match t.info { + Map { + return it + } + else { + panic('Type.mr_info(): no map info') + } + } +} + /* pub fn (t Type) str() string { return t.name @@ -395,6 +443,7 @@ pub mut: pub struct MultiReturn { pub: name string +mut: types []TypeRef }