v: fix/gen multi return/assign + merge VarDecl & AssignStmt

pull/3984/head
Joe Conigliaro 2020-03-10 22:01:37 +11:00
parent 876b73f92c
commit f7a93a69f6
13 changed files with 173 additions and 123 deletions

View File

@ -16,7 +16,7 @@ AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr |
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr |
ConcatExpr | Type | AsCast ConcatExpr | Type | AsCast
pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment | AssertStmt | UnsafeStmt LineComment | MultiLineComment | AssertStmt | UnsafeStmt
@ -164,6 +164,7 @@ mut:
is_c bool is_c bool
muts []bool muts []bool
or_block OrExpr or_block OrExpr
typ table.Type
} }
pub struct MethodCallExpr { pub struct MethodCallExpr {
@ -201,10 +202,9 @@ pub struct Stmt {
*/ */
pub struct VarDecl { pub struct Var {
pub: pub:
name string name string
name2 string // TODO
expr Expr expr Expr
is_mut bool is_mut bool
mut: mut:

View File

@ -10,7 +10,7 @@ mut:
start_pos int start_pos int
end_pos int end_pos int
// vars map[string]table.Var // vars map[string]table.Var
vars map[string]VarDecl vars map[string]Var
} }
pub fn new_scope(parent &Scope, start_pos int) &Scope { pub fn new_scope(parent &Scope, start_pos int) &Scope {
@ -20,7 +20,7 @@ pub fn new_scope(parent &Scope, start_pos int) &Scope {
} }
} }
pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) { pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,Var) {
if name in s.vars { if name in s.vars {
return s,s.vars[name] return s,s.vars[name]
} }
@ -32,7 +32,7 @@ pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
return none return none
} }
pub fn (s &Scope) find_var(name string) ?VarDecl { pub fn (s &Scope) find_var(name string) ?Var {
if name in s.vars { if name in s.vars {
return s.vars[name] return s.vars[name]
} }
@ -51,7 +51,7 @@ pub fn (s &Scope) known_var(name string) bool {
return false return false
} }
pub fn (s mut Scope) register_var(var VarDecl) { pub fn (s mut Scope) register_var(var Var) {
if x := s.find_var(var.name) { if x := s.find_var(var.name) {
// println('existing var: $var.name') // println('existing var: $var.name')
return return
@ -59,7 +59,7 @@ pub fn (s mut Scope) register_var(var VarDecl) {
s.vars[var.name] = var s.vars[var.name] = var
} }
pub fn (s mut Scope) override_var(var VarDecl) { pub fn (s mut Scope) override_var(var Var) {
s.vars[var.name] = var s.vars[var.name] = var
} }

View File

@ -78,8 +78,26 @@ pub fn (x Expr) str() string {
pub fn (node Stmt) str() string { pub fn (node Stmt) str() string {
match node { match node {
VarDecl { AssignStmt {
return it.name + ' = ' + it.expr.str() mut out := ''
for i,ident in it.left {
var_info := ident.var_info()
if var_info.is_mut {
out += 'mut '
}
out += ident.name
if i < it.left.len-1 {
out += ','
}
}
out += ' $it.op.str() '
for i,val in it.right {
out += val.str()
if i < it.right.len-1 {
out += ','
}
}
return out
} }
ExprStmt { ExprStmt {
return it.expr.str() return it.expr.str()

View File

@ -206,6 +206,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
if !found { if !found {
c.error('unknown fn: $fn_name', call_expr.pos) c.error('unknown fn: $fn_name', call_expr.pos)
} }
call_expr.typ = f.return_type
if f.is_c || call_expr.is_c { if f.is_c || call_expr.is_c {
for expr in call_expr.args { for expr in call_expr.args {
c.expr(expr) c.expr(expr)
@ -259,12 +260,13 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
mut scope := c.file.scope.innermost(method_call_expr.pos.pos) or { mut scope := c.file.scope.innermost(method_call_expr.pos.pos) or {
c.file.scope c.file.scope
} }
scope.override_var(ast.VarDecl{ scope.override_var(ast.Var{
name: 'it' name: 'it'
typ: array_info.elem_type typ: array_info.elem_type
}) })
} }
if method := typ_sym.find_method(name) { if method := typ_sym.find_method(name) {
method_call_expr.typ = method.return_type
for i, arg_expr in method_call_expr.args { for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ c.expected_type = method.args[i].typ
c.expr(arg_expr) c.expr(arg_expr)
@ -370,27 +372,70 @@ pub fn (c mut Checker) return_stmt(return_stmt ast.Return) {
} }
} }
pub fn (c mut Checker) assign_stmt(assign_stmt ast.AssignStmt) { pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
// multi return // multi return
if assign_stmt.left.len > assign_stmt.right.len { if assign_stmt.left.len > assign_stmt.right.len {
right := c.expr(assign_stmt.right[0]) right := c.expr(assign_stmt.right[0])
right_sym := c.table.get_type_symbol(right) right_sym := c.table.get_type_symbol(right)
info := right_sym.mr_info() mr_info := right_sym.mr_info()
if right_sym.kind != .multi_return { if right_sym.kind != .multi_return {
c.error('wrong number of vars', assign_stmt.pos) c.error('wrong number of vars', assign_stmt.pos)
} }
mut scope := c.file.scope.innermost(assign_stmt.pos.pos) or { mut scope := c.file.scope.innermost(assign_stmt.pos.pos) or {
c.file.scope c.file.scope
} }
for i, ident in assign_stmt.left { for i, _ in assign_stmt.left {
// TODO: check types mut ident := assign_stmt.left[i]
scope.override_var(ast.VarDecl{ mut var_info := ident.var_info()
val_type := mr_info.types[i]
var_info.typ = val_type
ident.info = var_info
assign_stmt.left[i] = ident
if assign_stmt.op == .assign {
if !c.table.check(val_type, var_info.typ) {
val_type_sym := c.table.get_type_symbol(val_type)
var_type_sym := c.table.get_type_symbol(var_info.typ)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
}
}
scope.override_var(ast.Var{
name: ident.name name: ident.name
typ: info.types[i] typ: mr_info.types[i]
})
}
}
// `a := 1` | `a,b := 1,2`
else {
if assign_stmt.left.len != assign_stmt.right.len {
c.error('wrong number of vars', assign_stmt.pos)
}
for i, _ in assign_stmt.left {
mut ident := assign_stmt.left[i]
val := assign_stmt.right[i]
val_type := c.expr(val)
if assign_stmt.op == .assign {
var_info := ident.var_info()
if !c.table.check(val_type, var_info.typ) {
val_type_sym := c.table.get_type_symbol(val_type)
var_type_sym := c.table.get_type_symbol(var_info.typ)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
}
}
else if assign_stmt.op == .decl_assign {
mut var_info := ident.var_info()
var_info.typ = val_type
ident.info = var_info
assign_stmt.left[i] = ident
}
mut scope := c.file.scope.innermost(assign_stmt.pos.pos) or {
c.file.scope
}
scope.override_var(ast.Var{
name: ident.name
typ: val_type
}) })
} }
} }
// TODO: multiple assign
} }
pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type { pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
@ -448,7 +493,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
// c.expected_type = table.void_type // c.expected_type = table.void_type
match mut node { match mut node {
ast.AssignStmt { ast.AssignStmt {
c.assign_stmt(it) c.assign_stmt(mut it)
} }
// ast.Attr {} // ast.Attr {}
// ast.CompIf {} // ast.CompIf {}
@ -507,10 +552,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.stmt(stmt) c.stmt(stmt)
} }
} }
ast.VarDecl {
typ := c.expr(it.expr)
it.typ = typ
}
else {} else {}
// println('checker.stmt(): unhandled node') // println('checker.stmt(): unhandled node')
// println('checker.stmt(): unhandled node (${typeof(node)})') // println('checker.stmt(): unhandled node (${typeof(node)})')
@ -646,7 +687,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
} }
mut found := true mut found := true
mut var_scope := &ast.Scope(0) mut var_scope := &ast.Scope(0)
mut var := ast.VarDecl{} mut var := ast.Var{}
var_scope,var = start_scope.find_scope_and_var(ident.name) or { var_scope,var = start_scope.find_scope_and_var(ident.name) or {
found = false found = false
c.error('not found: $ident.name - POS: $ident.pos.pos', ident.pos) c.error('not found: $ident.name - POS: $ident.pos.pos', ident.pos)

View File

@ -66,11 +66,14 @@ fn (e mut Eval) stmt(node ast.Stmt) string {
// ast.StructDecl { // ast.StructDecl {
// println('s decl') // println('s decl')
// } // }
ast.VarDecl { ast.AssignStmt {
e.vars[it.name] = Var{ // TODO; replaced VarDecl
value: e.expr(it.expr)
}
} }
// ast.VarDecl {
// e.vars[it.name] = Var{
// value: e.expr(it.expr)
// }
// }
else {} else {}
} }
return '>>' return '>>'

View File

@ -100,18 +100,22 @@ fn (f mut Fmt) stmts(stmts []ast.Stmt) {
fn (f mut Fmt) stmt(node ast.Stmt) { fn (f mut Fmt) stmt(node ast.Stmt) {
match node { match node {
ast.AssignStmt { ast.AssignStmt {
for i, left in it.left { for i,ident in it.left {
if left.var_info().is_mut { var_info := ident.var_info()
if var_info.is_mut {
f.write('mut ') f.write('mut ')
} }
f.expr(left) f.write(ident.name)
if i < it.left.len - 1 { if i < it.left.len-1 {
f.write(', ') f.write(', ')
} }
} }
f.write(' $it.op.str() ') f.write(' $it.op.str() ')
for right in it.right { for i,val in it.right {
f.expr(right) f.expr(val)
if i < it.right.len-1 {
f.write(', ')
}
} }
f.writeln('') f.writeln('')
} }
@ -231,20 +235,6 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts) f.stmts(it.stmts)
f.writeln('}') f.writeln('}')
} }
ast.VarDecl {
// type_sym := f.table.get_type_symbol(it.typ)
if it.is_mut {
f.write('mut ')
}
if it.name2 == '' {
f.write('$it.name := ')
}
else {
f.write('/*2*/$it.name, $it.name2 := ')
}
f.expr(it.expr)
f.writeln('')
}
ast.Import { ast.Import {
// already handled in f.imports // already handled in f.imports
} }

View File

@ -135,22 +135,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.writeln('//// stmt start') // g.writeln('//// stmt start')
match node { match node {
ast.AssignStmt { ast.AssignStmt {
// ident0 := it.left[0] g.gen_assign_stmt(it)
// 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(';')
// }
g.write('') // /*assign*/')
} }
ast.AssertStmt { ast.AssertStmt {
g.write('// assert') g.write('// assert')
@ -283,18 +268,51 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.UnsafeStmt { ast.UnsafeStmt {
g.stmts(it.stmts) g.stmts(it.stmts)
} }
ast.VarDecl {
styp := g.typ(it.typ)
g.write('$styp $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
else { else {
verror('cgen.stmt(): unhandled node ' + typeof(node)) verror('cgen.stmt(): unhandled node ' + typeof(node))
} }
} }
} }
fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
// multi return
if assign_stmt.left.len > assign_stmt.right.len {
mut return_type := table.void_type
match assign_stmt.right[0] {
ast.CallExpr {
return_type = it.typ
}
ast.MethodCallExpr {
return_type = it.typ
}
else {
panic('expected call')
}
}
mr_typ_sym := g.table.get_type_symbol(return_type)
mr_var_name := 'mr_$assign_stmt.pos.pos'
g.write('$mr_typ_sym.name $mr_var_name = ')
g.expr(assign_stmt.right[0])
g.writeln(';')
for i, ident in assign_stmt.left {
ident_var_info := ident.var_info()
var_type_sym := g.table.get_type_symbol(ident_var_info.typ)
g.writeln('$var_type_sym.name $ident.name = $mr_var_name->arg[$i];')
}
}
// `a := 1` | `a,b := 1,2`
else {
for i, ident in assign_stmt.left {
val := assign_stmt.right[i]
ident_var_info := ident.var_info()
var_type_sym := g.table.get_type_symbol(ident_var_info.typ)
g.write('$var_type_sym.name $ident.name = ')
g.expr(val)
g.writeln(';')
}
}
}
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if it.is_c || it.name == 'malloc' || it.no_body { if it.is_c || it.name == 'malloc' || it.no_body {
return return

View File

@ -57,12 +57,20 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
} }
g.writeln(';') g.writeln(';')
} }
ast.AssignStmt {} ast.AssignStmt {
ast.VarDecl { if it.left.len > it.right.len {
type_sym := g.table.get_type_symbol(it.typ) // TODO: multi return
g.write('var /* $type_sym.name */ $it.name = ') }
g.expr(it.expr) else {
g.writeln(';') for i,ident in it.left {
var_info := ident.var_info()
var_type_sym := g.table.get_type_symbol(var_info.typ)
val := it.right[i]
g.write('var /* $var_type_sym.name */ $ident.name = ')
g.expr(val)
g.writeln(';')
}
}
} }
ast.ForStmt { ast.ForStmt {
g.write('while (') g.write('while (')

View File

@ -54,7 +54,10 @@ int main() {
string foo_a = af_idx_el.a; string foo_a = af_idx_el.a;
map_string_string m1 = new_map(1, sizeof(string)); map_string_string m1 = new_map(1, sizeof(string));
map_string_int m2 = new_map_init(2, sizeof(int), (string[2]){tos3("v"), tos3("lang"), }, (int[2]){1, 2, }); map_string_int m2 = new_map_init(2, sizeof(int), (string[2]){tos3("v"), tos3("lang"), }, (int[2]){1, 2, });
return 0; multi_return_int_string mr_548 = mr_test();
int mr1 = mr_548->arg[0];
string mr2 = mr_548->arg[1];
return 0;
} }
multi_return_int_string mr_test() { multi_return_int_string mr_test() {

View File

@ -31,8 +31,6 @@ fn main() {
mut f := [testa(),2,3,4] mut f := [testa(),2,3,4]
mut g := [testb(1),'hello'] mut g := [testb(1),'hello']
mr1, mr2 := mr_test()
//mut arr_foo := []Foo //mut arr_foo := []Foo
arr_foo := [a] arr_foo := [a]
//arr_foo << a // TODO //arr_foo << a // TODO
@ -41,6 +39,8 @@ fn main() {
mut m1 := map[string]string mut m1 := map[string]string
mut m2 := {'v': 1, 'lang': 2} mut m2 := {'v': 1, 'lang': 2}
mr1, mr2 := mr_test()
} }
fn mr_test() (int, string) { fn mr_test() (int, string) {

View File

@ -332,7 +332,6 @@ fn (g mut Gen) stmt(node ast.Stmt) {
} }
ast.Return {} ast.Return {}
ast.AssignStmt {} ast.AssignStmt {}
ast.VarDecl {}
ast.ForStmt {} ast.ForStmt {}
ast.StructDecl {} ast.StructDecl {}
ast.ExprStmt { ast.ExprStmt {

View File

@ -88,7 +88,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
// name: rec_name // name: rec_name
// typ: rec_type // typ: rec_type
// }) // })
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: rec_name name: rec_name
typ: rec_type typ: rec_type
}) })
@ -115,7 +115,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
typ: ast_arg.typ typ: ast_arg.typ
} }
args << var args << var
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: ast_arg.name name: ast_arg.name
typ: ast_arg.typ typ: ast_arg.typ
}) })

View File

@ -296,7 +296,7 @@ pub fn (p mut Parser) stmt() ast.Stmt {
} }
} }
.key_mut { .key_mut {
return p.var_decl_and_assign_stmt() return p.assign_stmt()
} }
.key_for { .key_for {
return p.for_statement() return p.for_statement()
@ -341,7 +341,7 @@ pub fn (p mut Parser) stmt() ast.Stmt {
else { else {
// `x := ...` // `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] {
return p.var_decl_and_assign_stmt() return p.assign_stmt()
} }
// `label:` // `label:`
else if p.tok.kind == .name && p.peek_tok.kind == .colon { else if p.tok.kind == .name && p.peek_tok.kind == .colon {
@ -870,7 +870,7 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
fn (p mut Parser) filter() { fn (p mut Parser) filter() {
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: 'it' name: 'it'
}) })
} }
@ -990,7 +990,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
// mut inc := ast.Stmt{} // mut inc := ast.Stmt{}
mut inc := ast.Expr{} mut inc := ast.Expr{}
if p.peek_tok.kind in [.assign, .decl_assign] { if p.peek_tok.kind in [.assign, .decl_assign] {
init = p.var_decl_and_assign_stmt() init = p.assign_stmt()
} }
else if p.tok.kind != .semicolon {} else if p.tok.kind != .semicolon {}
// allow `for ;; i++ {` // allow `for ;; i++ {`
@ -1029,7 +1029,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
if p.tok.kind == .comma { if p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
val_name = p.check_name() val_name = p.check_name()
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: val_name name: val_name
typ: table.int_type typ: table.int_type
}) })
@ -1048,7 +1048,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
high_expr = p.expr(0) high_expr = p.expr(0)
} }
// TODO: update var type in checker // TODO: update var type in checker
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: var_name name: var_name
// expr: cond // expr: cond
@ -1093,7 +1093,7 @@ fn (p mut Parser) if_expr() ast.Expr {
var_name := p.check_name() var_name := p.check_name()
p.check(.decl_assign) p.check(.decl_assign)
expr := p.expr(0) expr := p.expr(0)
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: var_name name: var_name
expr: expr expr: expr
}) })
@ -1508,50 +1508,22 @@ fn (p mut Parser) parse_assign_rhs() []ast.Expr {
return exprs return exprs
} }
fn (p mut Parser) var_decl_and_assign_stmt() ast.Stmt { fn (p mut Parser) assign_stmt() ast.Stmt {
idents := p.parse_assign_lhs() idents := p.parse_assign_lhs()
op := p.tok.kind op := p.tok.kind
p.next() // :=, = p.next() // :=, =
exprs := p.parse_assign_rhs() exprs := p.parse_assign_rhs()
is_decl := op == .decl_assign is_decl := op == .decl_assign
// VarDecl for ident in idents {
if idents.len == 1 {
ident := idents[0]
expr := exprs[0]
info0 := ident.var_info()
known_var := p.scope.known_var(ident.name) known_var := p.scope.known_var(ident.name)
if !is_decl && !known_var { if !is_decl && !known_var {
p.error('unknown variable `$ident.name`') p.error('unknown variable `$ident.name`')
} }
if is_decl && ident.kind != .blank_ident {
if known_var {
p.error('redefinition of `$ident.name`')
}
p.scope.register_var(ast.VarDecl{
name: ident.name
expr: expr
})
}
return ast.VarDecl{
name: ident.name
// name2: name2
expr: expr // p.expr(token.lowest_prec)
is_mut: info0.is_mut
// typ: typ
pos: p.tok.position()
}
// return p.var_decl(ident[0], exprs[0])
}
// AssignStmt
for ident in idents {
if is_decl && ident.kind != .blank_ident { if is_decl && ident.kind != .blank_ident {
if p.scope.known_var(ident.name) { if p.scope.known_var(ident.name) {
p.error('redefinition of `$ident.name`') p.error('redefinition of `$ident.name`')
} }
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: ident.name name: ident.name
}) })
} }
@ -1564,8 +1536,6 @@ fn (p mut Parser) var_decl_and_assign_stmt() ast.Stmt {
} }
} }
// pub fn (p mut Parser) assign_stmt() ast.AssignStmt {}
// fn (p mut Parser) var_decl() ast.VarDecl {}
fn (p mut Parser) hash() ast.HashStmt { fn (p mut Parser) hash() ast.HashStmt {
val := p.tok.lit val := p.tok.lit
p.next() p.next()
@ -1633,7 +1603,7 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
exprs << ast.Type{ exprs << ast.Type{
typ: typ typ: typ
} }
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.Var{
name: 'it' name: 'it'
typ: typ typ: typ
}) })