checker/parser: check & gen stmts for ForIn & fix key, val vars
parent
e37fed437d
commit
4262ff76c3
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue