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 |
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 |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment | AssertStmt | UnsafeStmt
@ -164,6 +164,7 @@ mut:
is_c bool
muts []bool
or_block OrExpr
typ table.Type
}
pub struct MethodCallExpr {
@ -201,10 +202,9 @@ pub struct Stmt {
*/
pub struct VarDecl {
pub struct Var {
pub:
name string
name2 string // TODO
expr Expr
is_mut bool
mut:

View File

@ -10,7 +10,7 @@ mut:
start_pos int
end_pos int
// vars map[string]table.Var
vars map[string]VarDecl
vars map[string]Var
}
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 {
return s,s.vars[name]
}
@ -32,7 +32,7 @@ pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
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 {
return s.vars[name]
}
@ -51,7 +51,7 @@ pub fn (s &Scope) known_var(name string) bool {
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) {
// println('existing var: $var.name')
return
@ -59,7 +59,7 @@ pub fn (s mut Scope) register_var(var VarDecl) {
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
}

View File

@ -78,8 +78,26 @@ pub fn (x Expr) str() string {
pub fn (node Stmt) str() string {
match node {
VarDecl {
return it.name + ' = ' + it.expr.str()
AssignStmt {
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 {
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 {
c.error('unknown fn: $fn_name', call_expr.pos)
}
call_expr.typ = f.return_type
if f.is_c || call_expr.is_c {
for expr in call_expr.args {
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 {
c.file.scope
}
scope.override_var(ast.VarDecl{
scope.override_var(ast.Var{
name: 'it'
typ: array_info.elem_type
})
}
if method := typ_sym.find_method(name) {
method_call_expr.typ = method.return_type
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
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
if assign_stmt.left.len > assign_stmt.right.len {
right := c.expr(assign_stmt.right[0])
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 {
c.error('wrong number of vars', assign_stmt.pos)
}
mut scope := c.file.scope.innermost(assign_stmt.pos.pos) or {
c.file.scope
}
for i, ident in assign_stmt.left {
// TODO: check types
scope.override_var(ast.VarDecl{
for i, _ in assign_stmt.left {
mut ident := assign_stmt.left[i]
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
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 {
@ -448,7 +493,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
// c.expected_type = table.void_type
match mut node {
ast.AssignStmt {
c.assign_stmt(it)
c.assign_stmt(mut it)
}
// ast.Attr {}
// ast.CompIf {}
@ -507,10 +552,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.stmt(stmt)
}
}
ast.VarDecl {
typ := c.expr(it.expr)
it.typ = typ
}
else {}
// println('checker.stmt(): unhandled 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 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 {
found = false
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 {
// println('s decl')
// }
ast.VarDecl {
e.vars[it.name] = Var{
value: e.expr(it.expr)
}
ast.AssignStmt {
// TODO; replaced VarDecl
}
// ast.VarDecl {
// e.vars[it.name] = Var{
// value: e.expr(it.expr)
// }
// }
else {}
}
return '>>'

View File

@ -100,18 +100,22 @@ fn (f mut Fmt) stmts(stmts []ast.Stmt) {
fn (f mut Fmt) stmt(node ast.Stmt) {
match node {
ast.AssignStmt {
for i, left in it.left {
if left.var_info().is_mut {
for i,ident in it.left {
var_info := ident.var_info()
if var_info.is_mut {
f.write('mut ')
}
f.expr(left)
if i < it.left.len - 1 {
f.write(ident.name)
if i < it.left.len-1 {
f.write(', ')
}
}
f.write(' $it.op.str() ')
for right in it.right {
f.expr(right)
for i,val in it.right {
f.expr(val)
if i < it.right.len-1 {
f.write(', ')
}
}
f.writeln('')
}
@ -231,20 +235,6 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts)
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 {
// already handled in f.imports
}

View File

@ -135,22 +135,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.writeln('//// stmt start')
match node {
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(';')
// }
g.write('') // /*assign*/')
g.gen_assign_stmt(it)
}
ast.AssertStmt {
g.write('// assert')
@ -283,18 +268,51 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.UnsafeStmt {
g.stmts(it.stmts)
}
ast.VarDecl {
styp := g.typ(it.typ)
g.write('$styp $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
else {
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) {
if it.is_c || it.name == 'malloc' || it.no_body {
return

View File

@ -57,12 +57,20 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
}
g.writeln(';')
}
ast.AssignStmt {}
ast.VarDecl {
type_sym := g.table.get_type_symbol(it.typ)
g.write('var /* $type_sym.name */ $it.name = ')
g.expr(it.expr)
g.writeln(';')
ast.AssignStmt {
if it.left.len > it.right.len {
// TODO: multi return
}
else {
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 {
g.write('while (')

View File

@ -54,7 +54,10 @@ int main() {
string foo_a = af_idx_el.a;
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, });
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() {

View File

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

View File

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

View File

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

View File

@ -296,7 +296,7 @@ pub fn (p mut Parser) stmt() ast.Stmt {
}
}
.key_mut {
return p.var_decl_and_assign_stmt()
return p.assign_stmt()
}
.key_for {
return p.for_statement()
@ -341,7 +341,7 @@ pub fn (p mut Parser) stmt() ast.Stmt {
else {
// `x := ...`
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:`
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() {
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
name: 'it'
})
}
@ -990,7 +990,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
// mut inc := ast.Stmt{}
mut inc := ast.Expr{}
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 {}
// allow `for ;; i++ {`
@ -1029,7 +1029,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
if p.tok.kind == .comma {
p.check(.comma)
val_name = p.check_name()
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
name: val_name
typ: table.int_type
})
@ -1048,7 +1048,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
high_expr = p.expr(0)
}
// TODO: update var type in checker
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
name: var_name
// expr: cond
@ -1093,7 +1093,7 @@ fn (p mut Parser) if_expr() ast.Expr {
var_name := p.check_name()
p.check(.decl_assign)
expr := p.expr(0)
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
name: var_name
expr: expr
})
@ -1508,50 +1508,22 @@ fn (p mut Parser) parse_assign_rhs() []ast.Expr {
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()
op := p.tok.kind
p.next() // :=, =
exprs := p.parse_assign_rhs()
is_decl := op == .decl_assign
// VarDecl
if idents.len == 1 {
ident := idents[0]
expr := exprs[0]
info0 := ident.var_info()
for ident in idents {
known_var := p.scope.known_var(ident.name)
if !is_decl && !known_var {
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 p.scope.known_var(ident.name) {
p.error('redefinition of `$ident.name`')
}
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
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 {
val := p.tok.lit
p.next()
@ -1633,7 +1603,7 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
exprs << ast.Type{
typ: typ
}
p.scope.register_var(ast.VarDecl{
p.scope.register_var(ast.Var{
name: 'it'
typ: typ
})