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
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)
return table.void_type
}
@ -530,9 +535,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
ast.FnDecl {
c.expected_type = table.void_type
c.fn_return_type = it.return_type
for stmt in it.stmts {
c.stmt(stmt)
}
c.stmts(it.stmts)
}
ast.ForStmt {
typ := c.expr(it.cond)
@ -541,22 +544,47 @@ fn (c mut Checker) stmt(node ast.Stmt) {
}
// TODO: update loop var type
// how does this work currenly?
for stmt in it.stmts {
c.stmt(stmt)
}
c.stmts(it.stmts)
}
ast.ForCStmt {
c.stmt(it.init)
c.expr(it.cond)
// c.stmt(it.inc)
c.expr(it.inc)
for stmt in it.stmts {
c.stmt(stmt)
}
c.stmts(it.stmts)
}
ast.ForInStmt {
c.expr(it.cond)
c.expr(it.high)
typ := c.expr(it.cond)
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.HashStmt {}
@ -566,9 +594,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
}
// ast.StructDecl {}
ast.UnsafeStmt {
for stmt in it.stmts {
c.stmt(stmt)
}
c.stmts(it.stmts)
}
else {}
// 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']) {
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
if constant := c.table.find_const(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 {
c.error('non-string map index (type `$typ_sym.name`)', node.pos)
}
if typ_sym.kind == .array {
// Check index type
info := typ_sym.info as table.Array
return info.elem_type
value_type := c.table.value_type(typ)
if value_type != table.void_type {
return value_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
}

View File

@ -271,9 +271,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.stmt(it.inc)
g.expr(it.inc)
g.writeln(') {')
for stmt in it.stmts {
g.stmt(stmt)
}
g.stmts(it.stmts)
g.writeln('}')
}
ast.ForInStmt {
@ -284,7 +282,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('; $i < ')
g.expr(it.high)
g.writeln('; $i++) { ')
// g.stmts(it.stmts) TODO
g.stmts(it.stmts)
g.writeln('}')
}
}
@ -297,9 +295,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.expr(it.cond)
}
g.writeln(') {')
for stmt in it.stmts {
g.stmt(stmt)
}
g.stmts(it.stmts)
g.writeln('}')
}
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`
else if p.peek_tok.kind in [.key_in, .comma] {
var_name := p.check_name()
mut val_name := ''
mut key_var_name := ''
mut val_var_name := p.check_name()
if p.tok.kind == .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{
name: val_name
name: key_var_name
typ: table.int_type
})
}
@ -1118,13 +1119,17 @@ fn (p mut Parser) for_statement() ast.Stmt {
is_range = true
p.check(.dotdot)
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()
// println('nr stmts=$stmts.len')
p.close_scope()
@ -1132,8 +1137,8 @@ fn (p mut Parser) for_statement() ast.Stmt {
stmts: stmts
pos: p.tok.position()
cond: cond
key_var: var_name
val_var: val_name
key_var: key_var_name
val_var: val_var_name
high: high_expr
is_range: is_range
}

View File

@ -29,19 +29,19 @@ pub:
pub struct Arg {
pub:
name string
is_mut bool
typ Type
name string
is_mut bool
typ Type
}
pub struct Var {
pub:
name string
is_mut bool
is_const bool
is_global bool
name string
is_mut bool
is_const bool
is_global bool
mut:
typ Type
typ Type
}
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)
}
[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 {
got_type_sym := t.get_type_symbol(got)
exp_type_sym := t.get_type_symbol(expected)