checker/parser: check & gen stmts for ForIn & fix key, val vars

pull/4057/head
Joe Conigliaro 2020-03-18 23:18:18 +11:00
parent e37fed437d
commit 4262ff76c3
4 changed files with 117 additions and 64 deletions

View File

@ -319,6 +319,11 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
method_call_expr.return_type = method.return_type method_call_expr.return_type = method.return_type
return method.return_type return method.return_type
} }
// TODO: str methods
if typ_sym.kind in [.map] && name == 'str' {
method_call_expr.return_type = table.string_type
return table.string_type
}
c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos) c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos)
return table.void_type return table.void_type
} }
@ -530,9 +535,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
ast.FnDecl { ast.FnDecl {
c.expected_type = table.void_type c.expected_type = table.void_type
c.fn_return_type = it.return_type c.fn_return_type = it.return_type
for stmt in it.stmts { c.stmts(it.stmts)
c.stmt(stmt)
}
} }
ast.ForStmt { ast.ForStmt {
typ := c.expr(it.cond) typ := c.expr(it.cond)
@ -541,22 +544,47 @@ fn (c mut Checker) stmt(node ast.Stmt) {
} }
// TODO: update loop var type // TODO: update loop var type
// how does this work currenly? // how does this work currenly?
for stmt in it.stmts { c.stmts(it.stmts)
c.stmt(stmt)
}
} }
ast.ForCStmt { ast.ForCStmt {
c.stmt(it.init) c.stmt(it.init)
c.expr(it.cond) c.expr(it.cond)
// c.stmt(it.inc) // c.stmt(it.inc)
c.expr(it.inc) c.expr(it.inc)
for stmt in it.stmts { c.stmts(it.stmts)
c.stmt(stmt)
}
} }
ast.ForInStmt { ast.ForInStmt {
c.expr(it.cond) typ := c.expr(it.cond)
c.expr(it.high) if it.is_range {
c.expr(it.high)
}
else {
mut scope := c.file.scope.innermost(it.pos.pos)
if it.key_var.len > 0 {
sym := c.table.get_type_symbol(typ)
key_type := match sym.kind {
.map{
sym.map_info().key_type
}
else {
table.int_type}
}
scope.override_var(ast.Var{
name: it.key_var
typ: key_type
})
}
value_type := c.table.value_type(typ)
if value_type == table.void_type {
typ_sym := c.table.get_type_symbol(typ)
c.error('for in: cannot index $typ_sym.name', it.pos)
}
scope.override_var(ast.Var{
name: it.val_var
typ: c.table.value_type(typ)
})
}
c.stmts(it.stmts)
} }
// ast.GlobalDecl {} // ast.GlobalDecl {}
// ast.HashStmt {} // ast.HashStmt {}
@ -566,9 +594,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
} }
// ast.StructDecl {} // ast.StructDecl {}
ast.UnsafeStmt { ast.UnsafeStmt {
for stmt in it.stmts { c.stmts(it.stmts)
c.stmt(stmt)
}
} }
else {} else {}
// println('checker.stmt(): unhandled node') // println('checker.stmt(): unhandled node')
@ -761,6 +787,15 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) {
name = '${c.file.mod.name}.$ident.name' name = '${c.file.mod.name}.$ident.name'
} }
// hack - const until consts are fixed properly
if ident.name == 'v_modules_path' {
ident.name = name
ident.kind = .constant
ident.info = ast.IdentVar{
typ: table.string_type
}
return table.string_type
}
// constant // constant
if constant := c.table.find_const(name) { if constant := c.table.find_const(name) {
ident.name = name ident.name = name
@ -913,30 +948,10 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx { else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx {
c.error('non-string map index (type `$typ_sym.name`)', node.pos) c.error('non-string map index (type `$typ_sym.name`)', node.pos)
} }
if typ_sym.kind == .array { value_type := c.table.value_type(typ)
// Check index type if value_type != table.void_type {
info := typ_sym.info as table.Array return value_type
return info.elem_type
} }
else if typ_sym.kind == .array_fixed {
info := typ_sym.info as table.ArrayFixed
return info.elem_type
}
else if typ_sym.kind == .map {
info := typ_sym.info as table.Map
return info.value_type
}
else if typ_sym.kind in [.byteptr, .string] {
return table.byte_type
}
else if table.type_is_ptr(typ) {
// byte* => byte
// bytes[0] is a byte, not byte*
return table.type_deref(typ)
}
// else {
// return table.int_type
// }
} }
return typ return typ
} }

View File

@ -271,9 +271,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.stmt(it.inc) // g.stmt(it.inc)
g.expr(it.inc) g.expr(it.inc)
g.writeln(') {') g.writeln(') {')
for stmt in it.stmts { g.stmts(it.stmts)
g.stmt(stmt)
}
g.writeln('}') g.writeln('}')
} }
ast.ForInStmt { ast.ForInStmt {
@ -284,7 +282,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('; $i < ') g.write('; $i < ')
g.expr(it.high) g.expr(it.high)
g.writeln('; $i++) { ') g.writeln('; $i++) { ')
// g.stmts(it.stmts) TODO g.stmts(it.stmts)
g.writeln('}') g.writeln('}')
} }
} }
@ -297,9 +295,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.expr(it.cond) g.expr(it.cond)
} }
g.writeln(') {') g.writeln(') {')
for stmt in it.stmts { g.stmts(it.stmts)
g.stmt(stmt)
}
g.writeln('}') g.writeln('}')
} }
ast.GlobalDecl { ast.GlobalDecl {

View File

@ -1096,13 +1096,14 @@ fn (p mut Parser) for_statement() ast.Stmt {
} }
// `for i in vals`, `for i in start .. end` // `for i in vals`, `for i in start .. end`
else if p.peek_tok.kind in [.key_in, .comma] { else if p.peek_tok.kind in [.key_in, .comma] {
var_name := p.check_name() mut key_var_name := ''
mut val_name := '' mut val_var_name := p.check_name()
if p.tok.kind == .comma { if p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
val_name = p.check_name() key_var_name = val_var_name
val_var_name = p.check_name()
p.scope.register_var(ast.Var{ p.scope.register_var(ast.Var{
name: val_name name: key_var_name
typ: table.int_type typ: table.int_type
}) })
} }
@ -1118,13 +1119,17 @@ fn (p mut Parser) for_statement() ast.Stmt {
is_range = true is_range = true
p.check(.dotdot) p.check(.dotdot)
high_expr = p.expr(0) high_expr = p.expr(0)
p.scope.register_var(ast.Var{
name: val_var_name
typ: table.int_type
})
}
else {
// this type will be set in checker
p.scope.register_var(ast.Var{
name: val_var_name
})
} }
// TODO: update var type in checker
p.scope.register_var(ast.Var{
name: var_name
// expr: cond
})
stmts := p.parse_block() stmts := p.parse_block()
// println('nr stmts=$stmts.len') // println('nr stmts=$stmts.len')
p.close_scope() p.close_scope()
@ -1132,8 +1137,8 @@ fn (p mut Parser) for_statement() ast.Stmt {
stmts: stmts stmts: stmts
pos: p.tok.position() pos: p.tok.position()
cond: cond cond: cond
key_var: var_name key_var: key_var_name
val_var: val_name val_var: val_var_name
high: high_expr high: high_expr
is_range: is_range is_range: is_range
} }

View File

@ -29,19 +29,19 @@ pub:
pub struct Arg { pub struct Arg {
pub: pub:
name string name string
is_mut bool is_mut bool
typ Type typ Type
} }
pub struct Var { pub struct Var {
pub: pub:
name string name string
is_mut bool is_mut bool
is_const bool is_const bool
is_global bool is_global bool
mut: mut:
typ Type typ Type
} }
pub fn new_table() &Table { pub fn new_table() &Table {
@ -411,6 +411,43 @@ pub fn (t mut Table) add_placeholder_type(name string) int {
return t.register_type_symbol(ph_type) return t.register_type_symbol(ph_type)
} }
[inline]
pub fn (t &Table) value_type(typ Type) Type {
typ_sym := t.get_type_symbol(typ)
if typ_sym.kind == .array {
// Check index type
info := typ_sym.info as Array
return info.elem_type
}
else if typ_sym.kind == .array_fixed {
info := typ_sym.info as ArrayFixed
return info.elem_type
}
else if typ_sym.kind == .map {
info := typ_sym.info as Map
return info.value_type
}
else if typ_sym.kind in [.byteptr, .string] {
return byte_type
}
else if type_is_ptr(typ) {
// byte* => byte
// bytes[0] is a byte, not byte*
return type_deref(typ)
}
else if type_is_variadic(typ) {
// ...string => string
return type_clear_extra(typ)
}
else {
// TODO: remove when map_string is removed
if typ_sym.name == 'map_string' {
return string_type
}
return void_type
}
}
pub fn (t &Table) check(got, expected Type) bool { pub fn (t &Table) check(got, expected Type) bool {
got_type_sym := t.get_type_symbol(got) got_type_sym := t.get_type_symbol(got)
exp_type_sym := t.get_type_symbol(expected) exp_type_sym := t.get_type_symbol(expected)