v2: use pointer to table.type, fix unresolved array/map sub-types

pull/3668/head
joe-conigliaro 2020-02-06 23:57:35 +11:00 committed by GitHub
parent 6c3613407d
commit d9e92a08cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 495 additions and 492 deletions

View File

@ -20,7 +20,7 @@ HashStmt
pub struct ExprStmt { pub struct ExprStmt {
pub: pub:
expr Expr expr Expr
ti table.Type typ table.TypeRef
} }
pub struct IntegerLiteral { pub struct IntegerLiteral {
@ -69,7 +69,7 @@ pub struct Field {
pub: pub:
name string name string
// type_idx int // type_idx int
typ table.Type typ table.TypeRef
} }
pub struct ConstDecl { pub struct ConstDecl {
@ -89,7 +89,7 @@ pub:
pub struct StructInit { pub struct StructInit {
pub: pub:
pos token.Position pos token.Position
ti table.Type typ table.TypeRef
fields []string fields []string
exprs []Expr exprs []Expr
} }
@ -105,7 +105,7 @@ pub:
pub struct Arg { pub struct Arg {
pub: pub:
ti table.Type typ table.TypeRef
name string name string
} }
@ -113,7 +113,7 @@ pub struct FnDecl {
pub: pub:
name string name string
stmts []Stmt stmts []Stmt
ti table.Type typ table.TypeRef
args []Arg args []Arg
is_pub bool is_pub bool
receiver Field receiver Field
@ -146,7 +146,7 @@ pub:
pub struct Return { pub struct Return {
pub: pub:
pos token.Position pos token.Position
expected_ti table.Type // TODO: remove once checker updated expected_type table.TypeRef // TODO: remove once checker updated
exprs []Expr exprs []Expr
} }
@ -172,7 +172,7 @@ pub:
expr Expr expr Expr
is_mut bool is_mut bool
mut: mut:
typ table.Type typ table.TypeRef
pos token.Position pos token.Position
} }
@ -181,7 +181,7 @@ pub:
name string name string
expr Expr expr Expr
mut: mut:
typ table.Type typ table.TypeRef
} }
pub struct File { pub struct File {
@ -194,9 +194,9 @@ pub:
} }
pub struct IdentVar { pub struct IdentVar {
pub: pub mut:
typ table.Type typ table.TypeRef
// name string //name string
} }
type IdentInfo = IdentVar type IdentInfo = IdentVar
@ -225,9 +225,9 @@ pub:
op token.Kind op token.Kind
pos token.Position pos token.Position
left Expr left Expr
left_type table.Type left_type table.TypeRef
right Expr right Expr
right_type table.Type right_type table.TypeRef
} }
/* /*
@ -241,7 +241,6 @@ pub:
} }
*/ */
pub struct PostfixExpr { pub struct PostfixExpr {
pub: pub:
op token.Kind op token.Kind
@ -270,7 +269,7 @@ pub:
cond Expr cond Expr
stmts []Stmt stmts []Stmt
else_stmts []Stmt else_stmts []Stmt
ti table.Type typ table.TypeRef
left Expr // `a` in `a := if ...` left Expr // `a` in `a := if ...`
pos token.Position pos token.Position
} }
@ -354,7 +353,8 @@ pub struct ArrayInit {
pub: pub:
pos token.Position pos token.Position
exprs []Expr exprs []Expr
ti table.Type mut:
typ table.TypeRef
} }
// s[10..20] // s[10..20]

View File

@ -14,7 +14,7 @@ pub struct Checker {
mut: mut:
file_name string file_name string
unresolved []ast.Expr unresolved []ast.Expr
resolved []table.Type resolved []table.TypeRef
} }
pub fn new_checker(table &table.Table) Checker { pub fn new_checker(table &table.Table) Checker {
@ -39,59 +39,88 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) {
} }
fn (c mut Checker) resolve_types() { fn (c mut Checker) resolve_types() {
// resolve type of unresolved expressions
for x in c.unresolved { for x in c.unresolved {
c.resolved << c.expr(x) c.resolved << c.expr(x)
} }
// update any types with unresolved sub types
for idx, t in c.table.types {
if t.kind == .array {
mut info := t.info as table.Array
if info.elem_type.typ.kind == .unresolved {
info.elem_type = c.resolved[info.elem_type.idx]
mut t1 := &c.table.types[idx]
t1.name = table.array_name(&info.elem_type, info.nr_dims)
t1.info = info
}
}
else if t.kind == .map {
mut info := t.info as table.Map
mut updated := false
if info.key_type.typ.kind == .unresolved {
info.key_type = c.resolved[info.key_type.idx]
updated = true
}
if info.value_type.typ.kind == .unresolved {
info.value_type = c.resolved[info.value_type.idx]
updated = true
}
if updated {
mut t1 := &c.table.types[idx]
t1.name = table.map_name(&info.key_type, &info.value_type)
t1.info = info
}
}
}
} }
pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.Type { pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.TypeRef {
typ := c.table.find_type(struct_init.ti.name) or { typ := c.table.find_type(struct_init.typ.typ.name) or {
c.error('unknown struct: $struct_init.ti.name', struct_init.pos) c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
panic('') panic('')
} }
match typ.kind { match typ.kind {
.placeholder { .placeholder {
c.error('unknown struct: $struct_init.ti.name', struct_init.pos) c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
} }
.struct_ { .struct_ {
info := typ.info as table.Struct info := typ.info as table.Struct
for i, expr in struct_init.exprs { for i, expr in struct_init.exprs {
field := info.fields[i] field := info.fields[i]
// expr_ti := c.expr(expr)
field_type := c.expr(expr) field_type := c.expr(expr)
if !c.table.check(field_type, field.ti) { if !c.table.check(field_type, field.typ) {
c.error('cannot assign $field_type.name as $field.ti.name for field $field.name', struct_init.pos) c.error('cannot assign $field_type.typ.name as $field.typ.typ.name for field $field.name', struct_init.pos)
} }
} }
} }
else {} else {}
} }
return struct_init.ti return struct_init.typ
} }
pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type { pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.TypeRef {
left_ti := c.expr(infix_expr.left) left_type := c.expr(infix_expr.left)
right_ti := c.expr(infix_expr.right) right_type := c.expr(infix_expr.right)
if !c.table.check(&right_ti, &left_ti) { if !c.table.check(&right_type, &left_type) {
// if !c.table.check(&infix_expr.right_type, &infix_expr.right_type) { // if !c.table.check(&infix_expr.right_type, &infix_expr.right_type) {
// c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos) // c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos)
c.error('infix expr: cannot use `$left_ti.name` as `$right_ti.name`', infix_expr.pos) c.error('infix expr: cannot use `$left_type.typ.name` as `$right_type.typ.name`', infix_expr.pos)
} }
if infix_expr.op.is_relational() { if infix_expr.op.is_relational() {
return table.bool_type return c.table.type_ref(table.bool_type_idx)
} }
return left_ti return left_type
} }
fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) { fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) {
left_ti := c.expr(assign_expr.left) left_type := c.expr(assign_expr.left)
right_ti := c.expr(assign_expr.val) right_type := c.expr(assign_expr.val)
if !c.table.check(right_ti, left_ti) { if !c.table.check(right_type, left_type) {
c.error('cannot assign $right_ti.name to $left_ti.name', assign_expr.pos) c.error('cannot assign $right_type.typ.name to $left_type.typ.name', assign_expr.pos)
} }
} }
pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type { pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef {
fn_name := call_expr.name fn_name := call_expr.name
if f := c.table.find_fn(fn_name) { if f := c.table.find_fn(fn_name) {
// return_ti := f.return_ti // return_ti := f.return_ti
@ -103,9 +132,9 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type {
} }
for i, arg in f.args { for i, arg in f.args {
arg_expr := call_expr.args[i] arg_expr := call_expr.args[i]
ti := c.expr(arg_expr) typ := c.expr(arg_expr)
if !c.table.check(&ti, &arg.typ) { if !c.table.check(&typ, &arg.typ) {
c.error('!cannot use type `$ti.name` as type `$arg.typ.name` in argument to `$fn_name`', call_expr.pos) c.error('!cannot use type `$typ.typ.name` as type `$arg.typ.typ.name` in argument to `$fn_name`', call_expr.pos)
} }
} }
return f.return_type return f.return_type
@ -114,83 +143,75 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type {
exit(1) exit(1)
} }
pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type { pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.TypeRef {
ti := c.expr(method_call_expr.expr) typ := c.expr(method_call_expr.expr)
if method := c.table.find_method(ti.idx, method_call_expr.name) { if method := typ.typ.find_method(method_call_expr.name) {
return method.return_type return method.return_type
} }
c.error('type `$ti.name` has no method `$method_call_expr.name`', method_call_expr.pos) c.error('type `$typ.typ.name` has no method `$method_call_expr.name`', method_call_expr.pos)
exit(1) exit(1)
} }
pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type { pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.TypeRef {
ti := c.expr(selector_expr.expr) typ := c.expr(selector_expr.expr)
field_name := selector_expr.field field_name := selector_expr.field
// struct_ := c.table.types[ti.idx] match typ.typ.kind {
// struct_info := struct_.info as table.Struct
typ := c.table.types[ti.idx]
match typ.kind {
.struct_ { .struct_ {
// if !c.table.struct_has_field(it, field) { field := c.table.struct_find_field(typ.typ, field_name) or {
// c.error('AAA unknown field `${it.name}.$field`') c.error('unknown field `${typ.typ.name}.$field_name`', selector_expr.pos)
// }
// TODO: fix bug
field := c.table.struct_find_field(typ, field_name) or {
c.error('unknown field `${typ.name}.$field_name`', selector_expr.pos)
exit(0) exit(0)
} }
return field.ti return field.typ
} }
else { else {
c.error('`$typ.name` is not a struct', selector_expr.pos) c.error('`$typ.typ.name` is not a struct', selector_expr.pos)
} }
} }
return table.void_type return c.table.type_ref(table.void_type_idx)
} }
// TODO: non deferred // TODO: non deferred
pub fn (c &Checker) return_stmt(return_stmt ast.Return) { pub fn (c &Checker) return_stmt(return_stmt ast.Return) {
mut got_tis := []table.Type mut got_types := []table.TypeRef
if return_stmt.exprs.len == 0 { if return_stmt.exprs.len == 0 {
return return
} }
for expr in return_stmt.exprs { for expr in return_stmt.exprs {
ti := c.expr(expr) typ := c.expr(expr)
got_tis << ti got_types << typ
} }
expected_ti := return_stmt.expected_ti expected_type := return_stmt.expected_type
mut expected_tis := [expected_ti] mut expected_types := [expected_type]
if expected_ti.kind == .multi_return { if expected_type.typ.kind == .multi_return {
mr_type := c.table.types[expected_ti.idx] mr_info := expected_type.typ.info as table.MultiReturn
mr_info := mr_type.info as table.MultiReturn expected_types = mr_info.types
expected_tis = mr_info.tis
} }
if expected_tis.len > 0 && expected_tis.len != got_tis.len { if expected_types.len > 0 && expected_types.len != got_types.len {
c.error('wrong number of return arguments:\n\texpected: $expected_tis.str()\n\tgot: $got_tis.str()', return_stmt.pos) c.error('wrong number of return arguments:\n\texpected: $expected_types.str()\n\tgot: $got_types.str()', return_stmt.pos)
} }
for i, exp_ti in expected_tis { for i, exp_typ in expected_types {
got_ti := got_tis[i] got_typ := got_types[i]
if !c.table.check(got_ti, exp_ti) { if !c.table.check(got_typ, exp_typ) {
c.error('cannot use `$got_ti.name` as type `$exp_ti.name` in return argument', return_stmt.pos) c.error('cannot use `$got_typ.typ.name` as type `$exp_typ.typ.name` in return argument', return_stmt.pos)
} }
} }
} }
pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.Type { pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.TypeRef {
mut val_ti := table.void_type mut elem_type := c.table.type_ref(table.void_type_idx)
for i, expr in array_init.exprs { for i, expr in array_init.exprs {
c.expr(expr) c.expr(expr)
ti := c.expr(expr) typ := c.expr(expr)
// The first element's type // The first element's type
if i == 0 { if i == 0 {
val_ti = ti elem_type = typ
continue continue
} }
if !c.table.check(val_ti, ti) { if !c.table.check(elem_type, typ) {
c.error('expected array element with type `$val_ti.name`', array_init.pos) c.error('expected array element with type `$elem_type.typ.name`', array_init.pos)
} }
} }
return array_init.ti return array_init.typ
} }
fn (c &Checker) stmt(node ast.Stmt) { fn (c &Checker) stmt(node ast.Stmt) {
@ -205,19 +226,14 @@ fn (c &Checker) stmt(node ast.Stmt) {
} }
ast.VarDecl { ast.VarDecl {
typ := c.expr(it.expr) typ := c.expr(it.expr)
// it.typ = typ
// println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr') // println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr')
if typ.kind != .void { if typ.typ.kind != .void {
it.typ = typ it.typ = typ
} }
// if it.typ.kind == .unresolved {
// it.ti = typ
// println('unresolved var')
// }
} }
ast.ForStmt { ast.ForStmt {
typ := c.expr(it.cond) typ := c.expr(it.cond)
if typ.kind != .bool { if typ.typ.kind != .bool {
c.error('non-bool used as for condition', it.pos) c.error('non-bool used as for condition', it.pos)
} }
for stmt in it.stmts { for stmt in it.stmts {
@ -240,13 +256,13 @@ fn (c &Checker) stmt(node ast.Stmt) {
} }
} }
pub fn (c &Checker) expr(node ast.Expr) table.Type { pub fn (c &Checker) expr(node ast.Expr) table.TypeRef {
match node { match mut node {
ast.AssignExpr { ast.AssignExpr {
c.check_assign_expr(it) c.check_assign_expr(it)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
return table.int_type return c.table.type_ref(table.int_type_idx)
} }
// ast.FloatLiteral {} // ast.FloatLiteral {}
ast.PostfixExpr { ast.PostfixExpr {
@ -259,7 +275,7 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
*/ */
ast.StringLiteral { ast.StringLiteral {
return table.string_type return c.table.type_ref(table.string_type_idx)
} }
ast.PrefixExpr { ast.PrefixExpr {
return c.expr(it.right) return c.expr(it.right)
@ -281,16 +297,19 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
} }
ast.Ident { ast.Ident {
if it.kind == .variable { if it.kind == .variable {
info := it.info as ast.IdentVar mut info := it.info as ast.IdentVar
if info.typ.kind == .unresolved { if info.typ.typ.kind == .unresolved {
return c.resolved[info.typ.idx] typ := c.resolved[info.typ.idx]
info.typ = typ
it.info = info
return typ
} }
return info.typ return info.typ
} }
return table.void_type return c.table.type_ref(table.void_type_idx)
} }
ast.BoolLiteral { ast.BoolLiteral {
return table.bool_type return c.table.type_ref(table.bool_type_idx)
} }
ast.SelectorExpr { ast.SelectorExpr {
return c.selector_expr(it) return c.selector_expr(it)
@ -300,8 +319,8 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
} }
ast.IfExpr { ast.IfExpr {
typ := c.expr(it.cond) typ := c.expr(it.cond)
if typ.kind != .bool { if typ.typ.kind != .bool {
c.error('non-bool (`$typ.name`) used as if condition', it.pos) c.error('non-bool (`$typ.typ.name`) used as if condition', it.pos)
} }
for i, stmt in it.stmts { for i, stmt in it.stmts {
c.stmt(stmt) c.stmt(stmt)
@ -314,10 +333,10 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
} }
else {} else {}
} }
return table.void_type return c.table.type_ref(table.void_type_idx)
} }
pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type { pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.TypeRef {
/* /*
match node.expr { match node.expr {
ast.IdentVar { ast.IdentVar {
@ -327,13 +346,13 @@ pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type {
} }
*/ */
typ := c.expr(node.expr) typ := c.expr(node.expr)
if typ.kind != .int { if typ.typ.kind != .int {
c.error('invalid operation: $node.op.str() (non-numeric type `$typ.name`)', node.pos) c.error('invalid operation: $node.op.str() (non-numeric type `$typ.typ.name`)', node.pos)
} }
return typ return typ
} }
pub fn (c &Checker) index_expr(node ast.IndexExpr) table.Type { pub fn (c &Checker) index_expr(node ast.IndexExpr) table.TypeRef {
mut typ := c.expr(node.left) mut typ := c.expr(node.left)
mut is_range := false // TODO is_range := node.index is ast.RangeExpr mut is_range := false // TODO is_range := node.index is ast.RangeExpr
match node.index { match node.index {
@ -342,28 +361,20 @@ pub fn (c &Checker) index_expr(node ast.IndexExpr) table.Type {
} }
else {} else {}
} }
// TODO if typ.typ.kind == .array {
// info := ti.info as table.Array
// ti = p.table.types[info.elem_type_idx]
if typ.name.starts_with('array_') {
if is_range {} // `x[start..end]` has the same type as `x` if is_range {} // `x[start..end]` has the same type as `x`
else { else {
elm_typ := typ.name[6..]
// TODO `typ = ... or ...`
x := c.table.find_type(elm_typ) or {
c.error(elm_typ, node.pos)
exit(0)
}
typ = x
// Check index type // Check index type
index_type := c.expr(node.index) index_type := c.expr(node.index)
if index_type.kind != .int { if index_type.typ.kind != .int {
c.error('non-integer index (type `$index_type.name`)', node.pos) c.error('non-integer index (type `$index_type.typ.name`)', node.pos)
} }
info := typ.typ.info as table.Array
return info.elem_type
} }
} }
else { else {
typ = table.int_type typ = c.table.type_ref(table.int_type_idx)
} }
return typ return typ
// c.expr(it.index) // c.expr(it.index)

View File

@ -49,7 +49,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.Import {} ast.Import {}
ast.ConstDecl { ast.ConstDecl {
for i, field in it.fields { for i, field in it.fields {
g.write('$field.typ.name $field.name = ') g.write('$field.typ.typ.name $field.name = ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])
g.writeln(';') g.writeln(';')
} }
@ -61,15 +61,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('int ${it.name}(') g.write('int ${it.name}(')
} }
else { else {
ti := g.table.refresh_ti(it.ti) g.write('$it.typ.typ.name ${it.name}(')
g.write('$ti.name ${it.name}(') g.definitions.write('$it.typ.typ.name ${it.name}(')
g.definitions.write('$ti.name ${it.name}(')
} }
for i, arg in it.args { for i, arg in it.args {
// t := g.table.get_type(arg.ti.idx) g.write(arg.typ.typ.name + ' ' + arg.name)
ti := g.table.refresh_ti(arg.ti) g.definitions.write(arg.typ.typ.name + ' ' + arg.name)
g.write(ti.name + ' ' + arg.name)
g.definitions.write(ti.name + ' ' + arg.name)
if i < it.args.len - 1 { if i < it.args.len - 1 {
g.write(', ') g.write(', ')
g.definitions.write(', ') g.definitions.write(', ')
@ -92,9 +89,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('return') g.write('return')
// multiple returns // multiple returns
if it.exprs.len > 1 { if it.exprs.len > 1 {
// ttln( := g.table.get_type(g.fn_decl.ti.idx) g.write(' ($g.fn_decl.typ.typ.name){')
ti := g.table.refresh_ti(g.fn_decl.ti)
g.write(' ($ti.name){')
for i, expr in it.exprs { for i, expr in it.exprs {
g.write('.arg$i=') g.write('.arg$i=')
g.expr(expr) g.expr(expr)
@ -112,7 +107,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {
g.write('$it.typ.name $it.name = ') g.write('$it.typ.typ.name $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
} }
@ -141,9 +136,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl { ast.StructDecl {
g.writeln('typedef struct {') g.writeln('typedef struct {')
for field in it.fields { for field in it.fields {
// t := g.table.get_type(field.ti.idx) g.writeln('\t$field.typ.typ.name $field.name;')
ti := g.table.refresh_ti(field.typ)
g.writeln('\t$ti.name $field.name;')
} }
g.writeln('} $it.name;') g.writeln('} $it.name;')
} }
@ -215,9 +208,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
// t := g.table.get_type(it.ti.idx) g.writeln('($it.typ.typ.name){')
ti := g.table.refresh_ti(it.ti)
g.writeln('($ti.name){')
for i, field in it.fields { for i, field in it.fields {
g.write('\t.$field = ') g.write('\t.$field = ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])
@ -237,9 +228,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
ast.MethodCallExpr {} ast.MethodCallExpr {}
ast.ArrayInit { ast.ArrayInit {
// t := g.table.get_type(it.ti.idx) g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.typ.name), {\t')
ti := g.table.refresh_ti(it.ti)
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($ti.name), {\t')
for expr in it.exprs { for expr in it.exprs {
g.expr(expr) g.expr(expr)
g.write(', ') g.write(', ')
@ -268,9 +257,9 @@ fn (g mut Gen) expr(node ast.Expr) {
ast.IfExpr { ast.IfExpr {
// If expression? Assign the value to a temp var. // If expression? Assign the value to a temp var.
// Previously ?: was used, but it's too unreliable. // Previously ?: was used, but it's too unreliable.
ti := g.table.refresh_ti(it.ti) // ti := g.table.refresh_ti(it.ti)
mut tmp := '' mut tmp := ''
if ti.kind != .void { if it.typ.typ.kind != .void {
tmp = g.table.new_tmp_var() tmp = g.table.new_tmp_var()
// g.writeln('$ti.name $tmp;') // g.writeln('$ti.name $tmp;')
} }
@ -279,7 +268,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.writeln(') {') g.writeln(') {')
for i, stmt in it.stmts { for i, stmt in it.stmts {
// Assign ret value // Assign ret value
if i == it.stmts.len - 1 && ti.kind != .void { if i == it.stmts.len - 1 && it.typ.typ.kind != .void {
// g.writeln('$tmp =') // g.writeln('$tmp =')
println(1) println(1)
} }

View File

@ -11,9 +11,6 @@ const (
) )
fn test_c_files() { fn test_c_files() {
$if windows {
return
}
println('Running V => C tests') println('Running V => C tests')
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := filepath.dir(vexe) vroot := filepath.dir(vexe)
@ -21,9 +18,14 @@ fn test_c_files() {
term_fail := term.fail_message('FAIL') term_fail := term.fail_message('FAIL')
for i in 1 .. nr_tests + 1 { for i in 1 .. nr_tests + 1 {
path := '$vroot/vlib/v/gen/tests/${i}.vv' path := '$vroot/vlib/v/gen/tests/${i}.vv'
ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { mut ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or {
panic(err) panic(err)
} }
ctext = ctext // unused warn
// normalise line endings on win
$if windows {
ctext = ctext.replace('\r', '')
}
mut b := builder.new_builder(pref.Preferences{}) mut b := builder.new_builder(pref.Preferences{})
res := b.gen_c([path]) res := b.gen_c([path])
if compare_texts(res, ctext) { if compare_texts(res, ctext) {

View File

@ -37,11 +37,9 @@ pub fn (g mut JsGen) writeln(s string) {
fn (g mut JsGen) stmt(node ast.Stmt) { fn (g mut JsGen) stmt(node ast.Stmt) {
match node { match node {
ast.FnDecl { ast.FnDecl {
ti := g.table.refresh_ti(it.ti) g.write('/** @return { $it.typ.typ.name } **/\nfunction ${it.name}(')
g.write('/** @return { $ti.name } **/\nfunction ${it.name}(')
for arg in it.args { for arg in it.args {
arg_ti := g.table.refresh_ti(arg.ti) g.write(' /** @type { $arg.typ.typ.name } **/ $arg.name')
g.write(' /** @type { $arg_ti.name } **/ $arg.name')
} }
g.writeln(') { ') g.writeln(') { ')
for stmt in it.stmts { for stmt in it.stmts {
@ -58,8 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {
typ := g.table.refresh_ti(it.typ) g.write('var /* $it.typ.typ.name */ $it.name = ')
g.write('var /* $typ.name */ $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
} }
@ -121,8 +118,7 @@ fn (g mut JsGen) expr(node ast.Expr) {
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
ti := g.table.refresh_ti(it.ti) g.writeln('/*$it.typ.typ.name*/{')
g.writeln('/*$ti.name*/{')
for i, field in it.fields { for i, field in it.fields {
g.write('\t$field : ') g.write('\t$field : ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])

View File

@ -85,7 +85,7 @@ fn myuser() {
x := 1 x := 1
q := x | 0x1004 q := x | 0x1004
user := User{age:10} user := User{age:10}
age := user.age + 1 age := user.age + 1 // crash here
boo := 2 boo := 2
boo2 := boo+1 boo2 := boo+1
b := age > 0 b := age > 0

View File

@ -5,51 +5,57 @@ int testa();
int testb(); int testb();
int testa(); int testa();
int main() { int main() {
Bar b = (Bar){ Bar b = (Bar){
.a = 122, .a = 122,
}; };
Foo a = (Foo){ Foo a = (Foo){
.a = tos3("hello"), .a = tos3("hello"),
.b = b, .b = b,
}; };
a.a = tos3("da"); a.a = tos3("da");
a.b.a = 111; a.b.a = 111;
string a1 = a.a; string a1 = a.a;
int a2 = ; int a2 = ;
int c = testa(); int c = testa();
c = 1; c = 1;
string d = testb(1); string d = testb(1);
d = tos3("hello"); d = tos3("hello");
string e = tos3("hello"); string e = tos3("hello");
e = testb(111); e = testb(111);
e = tos3("world"); e = tos3("world");
return 0; array_int f = new_array_from_c_array(4, 4, sizeof(array_int), {
testa(), 2, 3, 4,
});
array_string g = new_array_from_c_array(2, 2, sizeof(array_string), {
testb(1), tos3("hello"),
});
return 0;
} }
int testa() { int testa() {
return testc(1); return testc(1);
} }
string testb(int a) { string testb(int a) {
return tos3("hello"); return tos3("hello");
} }
int testc(int a) { int testc(int a) {
return a; return a;
} }
int testa() { int testa() {
int a = ; int a = ;
a = 1; a = 1;
return 4; return 4;
} }
int testb() { int testb() {
return 4; return 4;
} }
int testa() { int testa() {
return 4; return 4;
} }
typedef struct { typedef struct {

View File

@ -13,7 +13,6 @@ fn main() {
a: 'hello' a: 'hello'
b: b b: b
} }
// a.c = 'sa'
a.a = 'da' a.a = 'da'
a.b.a = 111 a.b.a = 111
@ -29,10 +28,8 @@ fn main() {
e = testb(111) e = testb(111)
e = 'world' e = 'world'
//mut f := [testa(),2,3,4] mut f := [testa(),2,3,4]
// f = testa() mut g := [testb(1),'hello']
// c := 1 + 'string'
// zz := hi + 1
} }

View File

@ -8,7 +8,7 @@ import (
v.table v.table
) )
pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) { pub fn (p mut Parser) call_expr() (ast.CallExpr,table.TypeRef) {
tok := p.tok tok := p.tok
fn_name := p.check_name() fn_name := p.check_name()
p.check(.lpar) p.check(.lpar)
@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
name: fn_name name: fn_name
args: args args: args
// tok: tok // tok: tok
pos: tok.position() pos: tok.position()
} }
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
@ -28,7 +27,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
if f := p.table.find_fn(fn_name) { if f := p.table.find_fn(fn_name) {
return node,f.return_type return node,f.return_type
} }
typ := p.add_unresolved(node) typ := p.add_unresolved('${fn_name}()', node)
return node,typ return node,typ
} }
@ -65,7 +64,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
// Receiver? // Receiver?
mut rec_name := '' mut rec_name := ''
mut is_method := false mut is_method := false
mut rec_ti := table.void_type mut rec_type := p.table.type_ref(table.void_type_idx)
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
is_method = true is_method = true
p.next() p.next()
@ -73,10 +72,10 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.next() p.next()
} }
rec_ti = p.parse_type() rec_type = p.parse_type()
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: rec_name name: rec_name
typ: rec_ti typ: rec_type
}) })
p.check(.rpar) p.check(.rpar)
} }
@ -120,19 +119,19 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.check(.key_mut) p.check(.key_mut)
} }
ti := p.parse_type() typ := p.parse_type()
for arg_name in arg_names { for arg_name in arg_names {
arg := table.Var{ arg := table.Var{
name: arg_name name: arg_name
typ: ti typ: typ
} }
args << arg args << arg
p.table.register_var(arg) p.table.register_var(arg)
ast_args << ast.Arg{ ast_args << ast.Arg{
ti: ti typ: typ
name: arg_name name: arg_name
} }
if ti.kind == .variadic && p.tok.kind == .comma { if typ.typ.kind == .variadic && p.tok.kind == .comma {
p.error('cannot use ...(variadic) with non-final parameter $arg_name') p.error('cannot use ...(variadic) with non-final parameter $arg_name')
} }
} }
@ -143,16 +142,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
} }
p.check(.rpar) p.check(.rpar)
// Return type // Return type
mut typ := table.void_type mut typ := p.table.type_ref(table.void_type_idx)
if p.tok.kind in [.name, .lpar, .amp, .lsbr, .question] { if p.tok.kind in [.name, .lpar, .amp, .lsbr, .question] {
typ = p.parse_type() typ = p.parse_type()
p.return_type = typ p.return_type = typ
} }
else { else {
p.return_type = table.void_type // p.return_type = table.void_type
p.return_type = typ
} }
if is_method { if is_method {
ok := p.table.register_method(rec_ti, table.Fn{ ok := p.table.register_method(rec_type.typ, table.Fn{
name: name name: name
args: args args: args
return_type: typ return_type: typ
@ -175,28 +175,13 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
return ast.FnDecl{ return ast.FnDecl{
name: name name: name
stmts: stmts stmts: stmts
ti: typ typ: typ
args: ast_args args: ast_args
is_pub: is_pub is_pub: is_pub
receiver: ast.Field{ receiver: ast.Field{
name: rec_name name: rec_name
typ: rec_ti typ: rec_type
} }
} }
} }
pub fn (p &Parser) check_fn_calls() {
println('check fn calls2')
/*
for call in p.table.unknown_calls {
f := p.table.find_fn(call.name) or {
p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
return
}
println(f.name)
// println(f.return_ti.name)
// println('IN AST typ=' + call.typ.name)
}
*/
}

View File

@ -6,7 +6,7 @@ import (
v.table v.table
) )
pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { pub fn (p mut Parser) parse_array_ti(nr_muls int) table.TypeRef {
p.check(.lsbr) p.check(.lsbr)
// fixed array // fixed array
if p.tok.kind == .number { if p.tok.kind == .number {
@ -14,8 +14,8 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
elem_ti := p.parse_type() elem_ti := p.parse_type()
p.check(.rsbr) p.check(.rsbr)
p.check_name() p.check_name()
idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1) idx := p.table.find_or_register_array_fixed(elem_ti, size, 1)
return table.new_type(.array_fixed, name, idx, nr_muls) return p.table.type_ref_ptr(idx, nr_muls)
} }
// array // array
p.check(.rsbr) p.check(.rsbr)
@ -26,29 +26,30 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
p.check(.rsbr) p.check(.rsbr)
nr_dims++ nr_dims++
} }
idx,name := p.table.find_or_register_array(&elem_ti, nr_dims) idx := p.table.find_or_register_array(elem_ti, nr_dims)
return table.new_type(.array, name, idx, nr_muls) return p.table.type_ref_ptr(idx, nr_muls)
} }
pub fn (p mut Parser) parse_map_type(nr_muls int) table.Type { pub fn (p mut Parser) parse_map_type(nr_muls int) table.TypeRef {
if p.tok.kind != .lsbr { if p.tok.kind != .lsbr {
return table.map_type // check notes in table/atypes.v near map_type_idx
return p.table.type_ref(p.table.type_idxs['map'])
} }
p.next() p.next()
p.check(.lsbr) p.check(.lsbr)
key_ti := p.parse_type() key_ti := p.parse_type()
p.check(.rsbr) p.check(.rsbr)
value_ti := p.parse_type() value_ti := p.parse_type()
idx,name := p.table.find_or_register_map(&key_ti, &value_ti) idx := p.table.find_or_register_map(key_ti, value_ti)
return table.new_type(.map, name, idx, nr_muls) return p.table.type_ref_ptr(idx, nr_muls)
} }
pub fn (p mut Parser) parse_multi_return_ti() table.Type { pub fn (p mut Parser) parse_multi_return_ti() table.TypeRef {
p.check(.lpar) p.check(.lpar)
mut mr_tis := []table.Type mut mr_types := []table.TypeRef
for { for {
mr_ti := p.parse_type() mr_type := p.parse_type()
mr_tis << mr_ti mr_types << mr_type
if p.tok.kind == .comma { if p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
} }
@ -57,24 +58,24 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
} }
} }
p.check(.rpar) p.check(.rpar)
idx,name := p.table.find_or_register_multi_return(mr_tis) idx := p.table.find_or_register_multi_return(mr_types)
return table.new_type(.multi_return, name, idx, 0) return p.table.type_ref(idx)
} }
pub fn (p mut Parser) parse_variadic_ti() table.Type { pub fn (p mut Parser) parse_variadic_ti() table.TypeRef {
p.check(.ellipsis) p.check(.ellipsis)
variadic_ti := p.parse_type() variadic_type := p.parse_type()
idx,name := p.table.find_or_register_variadic(&variadic_ti) idx := p.table.find_or_register_variadic(variadic_type)
return table.new_type(.variadic, name, idx, 0) return p.table.type_ref(idx)
} }
pub fn (p mut Parser) parse_fn_type() table.Type { pub fn (p mut Parser) parse_fn_type() table.TypeRef {
// p.check(.key_fn) // p.check(.key_fn)
p.fn_decl() p.fn_decl()
return table.int_type return p.table.type_ref(table.int_type_idx)
} }
pub fn (p mut Parser) parse_type() table.Type { pub fn (p mut Parser) parse_type() table.TypeRef {
mut nr_muls := 0 mut nr_muls := 0
for p.tok.kind == .amp { for p.tok.kind == .amp {
p.check(.amp) p.check(.amp)
@ -120,63 +121,64 @@ pub fn (p mut Parser) parse_type() table.Type {
return p.parse_map_type(nr_muls) return p.parse_map_type(nr_muls)
} }
'voidptr' { 'voidptr' {
return table.new_type(.voidptr, 'voidptr', table.voidptr_type_idx, nr_muls) return p.table.type_ref_ptr(table.voidptr_type_idx, nr_muls)
} }
'byteptr' { 'byteptr' {
return table.new_type(.byteptr, 'byteptr', table.byteptr_type_idx, nr_muls) return p.table.type_ref_ptr(table.byteptr_type_idx, nr_muls)
} }
'charptr' { 'charptr' {
return table.new_type(.charptr, 'charptr', table.charptr_type_idx, nr_muls) return p.table.type_ref_ptr(table.charptr_type_idx, nr_muls)
} }
'i8' { 'i8' {
return table.new_type(.i8, 'i8', table.i8_type_idx, nr_muls) return p.table.type_ref_ptr(table.i8_type_idx, nr_muls)
} }
'i16' { 'i16' {
return table.new_type(.i16, 'i16', table.i16_type_idx, nr_muls) return p.table.type_ref_ptr(table.i16_type_idx, nr_muls)
} }
'int' { 'int' {
return table.new_type(.int, 'int', table.int_type_idx, nr_muls) return p.table.type_ref_ptr(table.int_type_idx, nr_muls)
} }
'i64' { 'i64' {
return table.new_type(.i64, 'i64', table.i64_type_idx, nr_muls) return p.table.type_ref_ptr(table.i64_type_idx, nr_muls)
} }
'byte' { 'byte' {
return table.new_type(.byte, 'byte', table.byte_type_idx, nr_muls) return p.table.type_ref_ptr(table.byte_type_idx, nr_muls)
} }
'u16' { 'u16' {
return table.new_type(.u16, 'u16', table.u16_type_idx, nr_muls) return p.table.type_ref_ptr(table.u16_type_idx, nr_muls)
} }
'u32' { 'u32' {
return table.new_type(.u32, 'u32', table.u32_type_idx, nr_muls) return p.table.type_ref_ptr(table.u32_type_idx, nr_muls)
} }
'u64' { 'u64' {
return table.new_type(.u64, 'u64', table.u64_type_idx, nr_muls) return p.table.type_ref_ptr(table.u64_type_idx, nr_muls)
} }
'f32' { 'f32' {
return table.new_type(.f32, 'f32', table.f32_type_idx, nr_muls) return p.table.type_ref_ptr(table.f32_type_idx, nr_muls)
} }
'f64' { 'f64' {
return table.new_type(.f64, 'f64', table.f64_type_idx, nr_muls) return p.table.type_ref_ptr(table.f64_type_idx, nr_muls)
} }
'string' { 'string' {
return table.new_type(.string, 'string', table.string_type_idx, nr_muls) return p.table.type_ref_ptr(table.string_type_idx, nr_muls)
} }
'char' { 'char' {
return table.new_type(.char, 'char', table.charptr_type_idx, nr_muls) return p.table.type_ref_ptr(table.charptr_type_idx, nr_muls)
} }
'bool' { 'bool' {
return table.new_type(.bool, 'bool', table.bool_type_idx, nr_muls) return p.table.type_ref_ptr(table.bool_type_idx, nr_muls)
} }
// struct / enum / placeholder // struct / enum / placeholder
else { else {
// struct / enum // struct / enum
mut idx := p.table.find_type_idx(name) mut idx := p.table.find_type_idx(name)
if idx > 0 { if idx > 0 {
return table.new_type(p.table.types[idx].kind, name, idx, nr_muls) return p.table.type_ref_ptr(idx, nr_muls)
} }
// not found - add placeholder // not found - add placeholder
idx = p.table.add_placeholder_type(name) idx = p.table.add_placeholder_type(name)
return table.new_type(.placeholder, name, idx, nr_muls) println('NOT FOUND: $name - adding placeholder - $idx')
return p.table.type_ref_ptr(idx, nr_muls)
} }
} }
} }

View File

@ -33,7 +33,7 @@ mut:
peek_tok token.Token peek_tok token.Token
// vars []string // vars []string
table &table.Table table &table.Table
return_type table.Type // current function's return type return_type table.TypeRef // current function's return type
// scope_level int // scope_level int
// var_idx int // var_idx int
is_c bool is_c bool
@ -44,6 +44,7 @@ mut:
builtin_mod bool builtin_mod bool
mod string mod string
unresolved []ast.Expr unresolved []ast.Expr
unresolved_idxs map[string]int
} }
// for tests // for tests
@ -244,10 +245,10 @@ pub fn (p mut Parser) stmt() ast.Stmt {
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() return p.var_decl()
} }
expr,ti := p.expr(0) expr,typ := p.expr(0)
return ast.ExprStmt{ return ast.ExprStmt{
expr: expr expr: expr
ti: ti typ: typ
} }
} }
} }
@ -298,8 +299,8 @@ fn (p mut Parser) range_expr(low ast.Expr) ast.Expr {
} }
p.check(.dotdot) p.check(.dotdot)
high,typ := p.expr(0) high,typ := p.expr(0)
if typ.kind != .int { if typ.typ.kind != .int {
p.error('non-integer index `$typ.name`') p.error('non-integer index `$typ.typ.name`')
} }
node := ast.RangeExpr{ node := ast.RangeExpr{
low: low low: low
@ -369,9 +370,9 @@ pub fn (p &Parser) warn(s string) {
} }
} }
pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) {
mut node := ast.Expr{} mut node := ast.Expr{}
mut typ := table.void_type mut typ := p.table.type_ref(table.void_type_idx)
// mut typ := table.unresolved_type // mut typ := table.unresolved_type
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
if is_c { if is_c {
@ -416,7 +417,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
exprs << expr exprs << expr
} }
node = ast.StructInit{ node = ast.StructInit{
ti: typ typ: typ
exprs: exprs exprs: exprs
fields: field_names fields: field_names
pos: p.tok.position() pos: p.tok.position()
@ -431,25 +432,23 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
} }
// variable // variable
if var := p.table.find_var(p.tok.lit) { if var := p.table.find_var(p.tok.lit) {
// println('#### IDENT: $var.name: $var.typ.name - $var.typ.idx') // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx')
typ = var.typ typ = var.typ
ident.kind = .variable ident.kind = .variable
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
// name: ident.name // name: ident.name
// expr: p.expr(0)// var.expr // expr: p.expr(0)// var.expr
} }
// ident.ti = ti // ident.ti = ti
node = ident node = ident
p.next() p.next()
}else{ }else{
if is_c { if is_c {
typ = table.int_type typ = p.table.type_ref(table.int_type_idx)
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
// name: ident.name // name: ident.name
} }
node = ident node = ident
p.next() p.next()
@ -462,7 +461,6 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
// name: ident.name // name: ident.name
} }
node = ident node = ident
p.next() p.next()
@ -479,9 +477,9 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
return node,typ return node,typ
} }
pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.TypeRef) {
// println('\n\nparser.expr()') // println('\n\nparser.expr()')
mut typ := table.void_type mut typ := p.table.type_ref(table.void_type_idx)
mut node := ast.Expr{} mut node := ast.Expr{}
// Prefix // Prefix
match p.tok.kind { match p.tok.kind {
@ -492,7 +490,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
node,typ = p.string_expr() node,typ = p.string_expr()
} }
.chartoken { .chartoken {
typ = table.byte_type typ = p.table.type_ref(table.byte_type_idx)
node = ast.CharLiteral{ node = ast.CharLiteral{
val: p.tok.lit val: p.tok.lit
} }
@ -509,7 +507,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
node = ast.BoolLiteral{ node = ast.BoolLiteral{
val: p.tok.kind == .key_true val: p.tok.kind == .key_true
} }
typ = table.bool_type typ = p.table.type_ref(table.bool_type_idx)
p.next() p.next()
} }
.key_match { .key_match {
@ -537,7 +535,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
p.check(.lpar) p.check(.lpar)
p.next() p.next()
p.check(.rpar) p.check(.rpar)
typ = table.int_type typ = p.table.type_ref(table.int_type_idx)
} }
else { else {
p.error('pexpr(): bad token `$p.tok.str()`') p.error('pexpr(): bad token `$p.tok.str()`')
@ -573,16 +571,16 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
return node,typ return node,typ
} }
fn (p mut Parser) prefix_expr() (ast.Expr,table.Type) { fn (p mut Parser) prefix_expr() (ast.Expr,table.TypeRef) {
op := p.tok.kind op := p.tok.kind
p.next() p.next()
right,ti := p.expr(1) right,typ := p.expr(1)
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr = ast.PrefixExpr{ expr = ast.PrefixExpr{
op: op op: op
right: right right: right
} }
return expr,ti return expr,typ
} }
// fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Type) { // fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Type) {
@ -605,21 +603,20 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.Expr {
// println('got ]') // println('got ]')
// /ti := table.int_type // /ti := table.int_type
mut node := ast.Expr{} mut node := ast.Expr{}
// println('index expr: $typ.typ.name')
node = ast.IndexExpr{ node = ast.IndexExpr{
left: left left: left
index: index_expr index: index_expr
pos: p.tok.position() pos: p.tok.position()
// typ: typ // typ: typ
} }
return node return node
// return node,typ // return node,typ
} }
fn (p mut Parser) dot_expr(left ast.Expr, left_ti &table.Type) (ast.Expr,table.Type) { fn (p mut Parser) dot_expr(left ast.Expr, left_type &table.TypeRef) (ast.Expr,table.TypeRef) {
p.next() p.next()
field_name := p.check_name() field_name := p.check_name()
mut ti := table.unresolved_type
// Method call // Method call
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.next() p.next()
@ -636,38 +633,39 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_ti &table.Type) (ast.Expr,table.T
} }
mut node := ast.Expr{} mut node := ast.Expr{}
node = mcall_expr node = mcall_expr
ti = p.add_unresolved(mcall_expr) typ := p.add_unresolved('${left_type.typ.name}.${field_name}()', mcall_expr)
return node,ti return node,typ
} }
sel_expr := ast.SelectorExpr{ sel_expr := ast.SelectorExpr{
expr: left expr: left
field: field_name field: field_name
pos: p.tok.position() pos: p.tok.position()
} }
typ := p.add_unresolved('${left_type.typ.name}.$field_name', sel_expr)
mut node := ast.Expr{} mut node := ast.Expr{}
node = sel_expr node = sel_expr
return node,ti return node,typ
} }
fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.Type) { fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.TypeRef) {
op := p.tok.kind op := p.tok.kind
// mut typ := p. // mut typ := p.
// println('infix op=$op.str()') // println('infix op=$op.str()')
precedence := p.tok.precedence() precedence := p.tok.precedence()
p.next() p.next()
right,mut ti := p.expr(precedence) right,mut typ := p.expr(precedence)
if op.is_relational() { if op.is_relational() {
ti = table.bool_type typ = p.table.type_ref(table.bool_type_idx)
} }
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr = ast.InfixExpr{ expr = ast.InfixExpr{
left: left left: left
right: right right: right
right_type: ti right_type: typ
op: op op: op
pos: p.tok.position() pos: p.tok.position()
} }
return expr,ti return expr,typ
} }
// Implementation of Pratt Precedence // Implementation of Pratt Precedence
@ -716,7 +714,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
} }
p.check(.semicolon) p.check(.semicolon)
if p.tok.kind != .semicolon { if p.tok.kind != .semicolon {
mut typ := table.Type{} mut typ := table.TypeRef{typ:0}
cond,typ = p.expr(0) cond,typ = p.expr(0)
} }
p.check(.semicolon) p.check(.semicolon)
@ -740,7 +738,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
val_name := p.check_name() val_name := p.check_name()
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: val_name name: val_name
typ: table.int_type typ: p.table.type_ref(table.int_type_idx)
}) })
} }
p.check(.key_in) p.check(.key_in)
@ -752,7 +750,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
} }
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: var_name name: var_name
typ: table.int_type typ: p.table.type_ref(table.int_type_idx)
}) })
stmts := p.parse_block() stmts := p.parse_block()
// println('nr stmts=$stmts.len') // println('nr stmts=$stmts.len')
@ -773,7 +771,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
} }
} }
fn (p mut Parser) if_expr() (ast.Expr,table.Type) { fn (p mut Parser) if_expr() (ast.Expr,table.TypeRef) {
p.inside_if = true p.inside_if = true
// defer { // defer {
// } // }
@ -792,14 +790,14 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
else_stmts = p.parse_block() else_stmts = p.parse_block()
} }
} }
mut ti := table.void_type mut typ := p.table.type_ref(table.void_type_idx)
// mut left := ast.Expr{} // mut left := ast.Expr{}
// If the last statement is an expression, return its type // If the last statement is an expression, return its type
if stmts.len > 0 { if stmts.len > 0 {
match stmts[stmts.len - 1] { match stmts[stmts.len - 1] {
ast.ExprStmt { ast.ExprStmt {
p.warn('if expr ret $it.ti.name') p.warn('if expr ret $it.typ.typ.name')
ti = it.ti typ = it.typ
// return node,it.ti // return node,it.ti
// left = // left =
} }
@ -810,22 +808,22 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
cond: cond cond: cond
stmts: stmts stmts: stmts
else_stmts: else_stmts else_stmts: else_stmts
ti: ti typ: typ
pos: p.tok.position() pos: p.tok.position()
// left: left // left: left
} }
return node,ti return node,typ
} }
fn (p mut Parser) string_expr() (ast.Expr,table.Type) { fn (p mut Parser) string_expr() (ast.Expr,table.TypeRef) {
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.StringLiteral{ node = ast.StringLiteral{
val: p.tok.lit val: p.tok.lit
} }
if p.peek_tok.kind != .str_dollar { if p.peek_tok.kind != .str_dollar {
p.next() p.next()
return node,table.string_type return node, p.table.type_ref(table.string_type_idx)
} }
// Handle $ interpolation // Handle $ interpolation
for p.tok.kind == .str { for p.tok.kind == .str {
@ -839,13 +837,13 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
p.next() p.next()
} }
} }
return node,table.string_type return node, p.table.type_ref(table.string_type_idx)
} }
fn (p mut Parser) array_init() (ast.Expr,table.Type) { fn (p mut Parser) array_init() (ast.Expr,table.TypeRef) {
mut node := ast.Expr{} mut node := ast.Expr{}
p.check(.lsbr) p.check(.lsbr)
mut val_type := table.void_type mut val_type := p.table.type_ref(table.void_type_idx)
mut exprs := []ast.Expr mut exprs := []ast.Expr
for i := 0; p.tok.kind != .rsbr; i++ { for i := 0; p.tok.kind != .rsbr; i++ {
expr,typ := p.expr(0) expr,typ := p.expr(0)
@ -866,27 +864,27 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
// type_idx,type_name := p.table.find_or_register_array_fixed(val_type, 1) // type_idx,type_name := p.table.find_or_register_array_fixed(val_type, 1)
// node = // node =
} }
type_idx,type_name := p.table.find_or_register_array(val_type, 1) // array_type := table.new_type(.array, type_name, type_idx, 0)
array_ti := table.new_type(.array, type_name, type_idx, 0) idx := p.table.find_or_register_array(val_type, 1)
array_type := p.table.type_ref_ptr(idx, 0)
node = ast.ArrayInit{ node = ast.ArrayInit{
ti: array_ti typ: array_type
exprs: exprs exprs: exprs
pos: p.tok.position() pos: p.tok.position()
} }
return node,array_ti return node,array_type
} }
fn (p mut Parser) parse_number_literal() (ast.Expr,table.Type) { fn (p mut Parser) parse_number_literal() (ast.Expr,table.TypeRef) {
lit := p.tok.lit lit := p.tok.lit
mut node := ast.Expr{} mut node := ast.Expr{}
mut ti := table.int_type mut ti := p.table.type_ref(table.int_type_idx)
if lit.contains('.') { if lit.contains('.') {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
// val: lit.f64() // val: lit.f64()
val: lit val: lit
} }
// ti = table.new_builtin_ti(.f64, 0) ti = p.table.type_ref(table.f64_type_idx)
ti = table.new_type(.f64, 'f64', table.f64_type_idx, 0)
} }
else { else {
node = ast.IntegerLiteral{ node = ast.IntegerLiteral{
@ -987,7 +985,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
} }
field_name := p.check_name() field_name := p.check_name()
// p.warn('field $field_name') // p.warn('field $field_name')
ti := p.parse_type() typ := p.parse_type()
// Default value // Default value
if p.tok.kind == .assign { if p.tok.kind == .assign {
p.next() p.next()
@ -995,19 +993,19 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
} }
ast_fields << ast.Field{ ast_fields << ast.Field{
name: field_name name: field_name
typ: ti typ: typ
} }
fields << table.Field{ fields << table.Field{
name: field_name name: field_name
// type_idx: ti.idx // type_idx: ti.idx
typ: typ
ti: ti
} }
// println('struct field $ti.name $field_name') // println('struct field $ti.name $field_name')
} }
p.check(.rcbr) p.check(.rcbr)
if name != 'string' { if name != 'string' {
ret := p.table.register_type(table.Type{ ret := p.table.register_type(table.Type{
parent: 0
kind: .struct_ kind: .struct_
name: name name: name
info: table.Struct{ info: table.Struct{
@ -1051,7 +1049,7 @@ fn (p mut Parser) return_stmt() ast.Return {
} }
// TODO: consider non deferred // TODO: consider non deferred
stmt := ast.Return{ stmt := ast.Return{
expected_ti: p.return_type expected_type: p.return_type
exprs: exprs exprs: exprs
pos: p.tok.position() pos: p.tok.position()
} }
@ -1082,7 +1080,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
typ: typ typ: typ
}) })
p.warn('var decl name=$name typ=$typ.name') p.warn('var decl name=$name typ=$typ.typ.name')
// println(p.table.names) // println(p.table.names)
node := ast.VarDecl{ node := ast.VarDecl{
name: name name: name
@ -1136,7 +1134,7 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
} }
} }
fn (p mut Parser) match_expr() (ast.Expr,table.Type) { fn (p mut Parser) match_expr() (ast.Expr,table.TypeRef) {
p.check(.key_match) p.check(.key_match)
p.expr(0) p.expr(0)
p.check(.lcbr) p.check(.lcbr)
@ -1156,16 +1154,25 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
p.check(.rcbr) p.check(.rcbr)
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.MatchExpr{} node = ast.MatchExpr{}
return node,table.void_type return node,p.table.type_ref(table.void_type_idx)
} }
fn (p mut Parser) add_unresolved(expr ast.Expr) table.Type { fn (p mut Parser) add_unresolved(key string, expr ast.Expr) table.TypeRef {
t := table.Type{ mut idx := p.unresolved.len
idx: p.unresolved.len if key in p.unresolved_idxs {
kind: .unresolved idx = p.unresolved_idxs[key]
name: 'unresolved'
} }
else {
p.unresolved << expr p.unresolved << expr
}
t := table.TypeRef{
idx: idx
typ: &table.Type{
parent: 0
kind: .unresolved
name: 'unresolved $p.unresolved.len'
}
}
return t return t
} }

View File

@ -7,13 +7,18 @@ pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic
pub struct Type { pub struct Type {
pub: pub:
idx int parent &Type
parent_idx int
mut: mut:
info TypeInfo info TypeInfo
kind Kind kind Kind
name string name string
methods []Fn methods []Fn
}
pub struct TypeRef {
pub:
idx int
typ &Type
nr_muls int nr_muls int
} }
@ -35,7 +40,11 @@ pub const (
char_type_idx = 15 char_type_idx = 15
byte_type_idx = 16 byte_type_idx = 16
bool_type_idx = 17 bool_type_idx = 17
map_type_idx = 18 // currently map is parsed from builtin as a normal struct named `map`
// any maps after that are of type map with parent being the struct named `map`
// same goes for array. this works since builtin is parsed first.
// will probably go back to registering these types manually and add idx here
// map_type_idx = 18
) )
pub enum Kind { pub enum Kind {
@ -68,162 +77,170 @@ pub enum Kind {
unresolved unresolved
} }
pub const (
unresolved_type = Type{
kind: .unresolved
name: 'unresolved'
}
void_type = Type{
kind: .void
name: 'void'
idx: void_type_idx
}
int_type = Type{
kind: .int
name: 'int'
idx: int_type_idx
}
string_type = Type{
kind: .string
name: 'string'
idx: string_type_idx
}
bool_type = Type{
kind: .bool
name: 'bool'
idx: bool_type_idx
}
byte_type = Type{
kind: .byte
name: 'byte'
idx: byte_type_idx
}
map_type = Type{
kind: .map
name: 'map'
idx: map_type_idx
}
)
/* /*
pub fn (t Type) str() string { pub fn (t Type) str() string {
return t.name return t.name
} }
*/ */
pub fn (t &TypeRef) str() string {
pub fn (t &Type) str() string {
mut muls := '' mut muls := ''
for _ in 0 .. t.nr_muls { for _ in 0 .. t.nr_muls {
muls += '&' muls += '&'
} }
// return '$muls$ti.name' return '$muls$t.typ.name'
return '$muls$t.idx'
} }
pub fn new_type(kind Kind, name string, idx int, nr_muls int) Type { [inline]
return Type{ pub fn (t &Table) type_ref(idx int) TypeRef {
return TypeRef{
idx: idx idx: idx
kind: kind typ: &t.types[idx]
name: name
nr_muls: nr_muls
} }
} }
[inline]
pub fn (t &Table) type_ref_ptr(idx int, nr_muls int) TypeRef {
return TypeRef{
idx: idx
nr_muls: nr_muls
typ: &t.types[idx]
}
}
[inline]
pub fn array_name(elem_type &TypeRef, nr_dims int) string {
return 'array_${elem_type.typ.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' }
}
[inline]
pub fn array_fixed_name(elem_type &TypeRef, size int, nr_dims int) string {
return 'array_fixed_${elem_type.typ.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' }
}
[inline]
pub fn map_name(key_type &TypeRef, value_type &TypeRef) string {
return 'map_${key_type.typ.name}_${value_type.typ.name}'
}
pub fn (t mut Table) register_builtin_types() { pub fn (t mut Table) register_builtin_types() {
// reserve index 0 so nothing can go there // reserve index 0 so nothing can go there
// save index check, 0 will mean not found // save index check, 0 will mean not found
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .placeholder kind: .placeholder
name: 'reserved_0' name: 'reserved_0'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .void kind: .void
name: 'void' name: 'void'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .voidptr kind: .voidptr
name: 'voidptr' name: 'voidptr'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .charptr kind: .charptr
name: 'charptr' name: 'charptr'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .byteptr kind: .byteptr
name: 'byteptr' name: 'byteptr'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .i8 kind: .i8
name: 'i8' name: 'i8'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .i16 kind: .i16
name: 'i16' name: 'i16'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .int kind: .int
name: 'int' name: 'int'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .i64 kind: .i64
name: 'i64' name: 'i64'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .u16 kind: .u16
name: 'u16' name: 'u16'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .u32 kind: .u32
name: 'u32' name: 'u32'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .u64 kind: .u64
name: 'u64' name: 'u64'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .f32 kind: .f32
name: 'f32' name: 'f32'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .f64 kind: .f64
name: 'f64' name: 'f64'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .string kind: .string
name: 'string' name: 'string'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .char kind: .char
name: 'char' name: 'char'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .byte kind: .byte
name: 'byte' name: 'byte'
}) })
t.register_type(Type{ t.register_type(Type{
parent: 0
kind: .bool kind: .bool
name: 'bool' name: 'bool'
}) })
t.register_type(Type{
parent: 0
kind: .unresolved
name: 'unresolved'
})
} }
[inline] [inline]
pub fn (ti &Type) is_ptr() bool { pub fn (t &TypeRef) is_ptr() bool {
return ti.nr_muls > 0 return t.nr_muls > 0
} }
[inline] [inline]
pub fn (ti &Type) is_int() bool { pub fn (t &Type) is_int() bool {
return ti.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64] return t.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64]
} }
[inline] [inline]
pub fn (ti &Type) is_float() bool { pub fn (t &Type) is_float() bool {
return ti.kind in [.f32, .f64] return t.kind in [.f32, .f64]
} }
[inline] [inline]
pub fn (ti &Type) is_number() bool { pub fn (t &Type) is_number() bool {
return ti.is_int() || ti.is_float() return t.is_int() || t.is_float()
} }
pub fn (k Kind) str() string { pub fn (k Kind) str() string {
@ -271,7 +288,13 @@ pub fn (k Kind) str() string {
'byte' 'byte'
} }
.u16{ .u16{
'u18' 'u16'
}
.u32{
'u32'
}
.u64{
'u64'
} }
.f32{ .f32{
'f32' 'f32'
@ -336,7 +359,7 @@ pub mut:
pub struct Field { pub struct Field {
pub: pub:
name string name string
ti Type typ TypeRef
// type_idx int // type_idx int
} }
// pub struct Int { // pub struct Int {
@ -350,58 +373,40 @@ pub:
// } // }
pub struct Array { pub struct Array {
pub: pub:
elem_type_kind Kind
elem_type_idx int
elem_is_ptr bool
nr_dims int nr_dims int
mut:
elem_type TypeRef
} }
pub struct ArrayFixed { pub struct ArrayFixed {
pub: pub:
elem_type_kind Kind
elem_type_idx int
elem_is_ptr bool
nr_dims int nr_dims int
size int size int
mut:
elem_type TypeRef
} }
pub struct Map { pub struct Map {
pub: pub mut:
key_type_kind Kind key_type TypeRef
key_type_idx int value_type TypeRef
value_type_kind Kind
value_type_idx int
} }
pub struct MultiReturn { pub struct MultiReturn {
pub: pub:
name string name string
tis []Type types []TypeRef
} }
pub struct Variadic { pub struct Variadic {
pub: pub:
ti Type typ TypeRef
} }
pub fn (t &Table) refresh_ti(ti Type) Type { [inline]
if ti.idx == 0 { pub fn (t &Table) get_type(idx int) &Type {
return ti
}
if ti.kind in [.placeholder, .unresolved] {
typ := t.types[ti.idx]
return {
ti |
kind:typ.kind,
name:typ.name
}
}
return ti
}
pub fn (t &Table) get_type(idx int) Type {
if idx == 0 { if idx == 0 {
panic('get_type: idx 0') panic('get_type: idx 0')
} }
return t.types[idx] return &t.types[idx]
} }

View File

@ -25,7 +25,7 @@ pub struct Fn {
pub: pub:
name string name string
args []Var args []Var
return_type Type return_type TypeRef
} }
pub struct Var { pub struct Var {
@ -37,11 +37,13 @@ pub:
is_global bool is_global bool
scope_level int scope_level int
mut: mut:
typ Type typ TypeRef
} }
pub fn new_table() &Table { pub fn new_table() &Table {
mut t := &Table{} mut t := &Table{
types: make(0, 400, sizeof(Type))
}
t.register_builtin_types() t.register_builtin_types()
return t return t
} }
@ -77,7 +79,7 @@ pub fn (t mut Table) register_const(v Var) {
t.consts[v.name] = v t.consts[v.name] = v
} }
pub fn (t mut Table) register_global(name string, typ Type) { pub fn (t mut Table) register_global(name string, typ TypeRef) {
t.consts[name] = Var{ t.consts[name] = Var{
name: name name: name
typ: typ typ: typ
@ -86,12 +88,11 @@ pub fn (t mut Table) register_global(name string, typ Type) {
// mod: p.mod // mod: p.mod
// is_mut: true // is_mut: true
// idx: -1 // idx: -1
} }
} }
pub fn (t mut Table) register_var(v Var) { pub fn (t mut Table) register_var(v Var) {
println('register_var: $v.name - $v.typ.name') println('register_var: $v.name - $v.typ.typ.name')
new_var := { new_var := {
v | v |
idx:t.var_idx, idx:t.var_idx,
@ -187,24 +188,25 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
pub fn (t mut Table) register_method(typ &Type, new_fn Fn) bool { pub fn (t &Table) register_method(typ &Type, new_fn Fn) bool {
idx := typ.idx // println('register method `$new_fn.name` type=$typ.name idx=$typ.idx')
println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') println('register method `$new_fn.name` type=$typ.name')
mut methods := t.types[idx].methods mut t1 := typ
mut methods := typ.methods
methods << new_fn methods << new_fn
t.types[idx].methods = methods t1.methods = methods
return true return true
} }
pub fn (t &Table) has_method(type_idx int, name string) bool { pub fn (t &Type) has_method(name string) bool {
t.find_method(type_idx, name) or { t.find_method(name) or {
return false return false
} }
return true return true
} }
pub fn (t &Table) find_method(type_idx int, name string) ?Fn { pub fn (t &Type) find_method(name string) ?Fn {
for method in t.types[type_idx].methods { for method in t.methods {
if method.name == name { if method.name == name {
return method return method
} }
@ -218,7 +220,11 @@ pub fn (t mut Table) new_tmp_var() string {
} }
pub fn (t &Table) struct_has_field(s &Type, name string) bool { pub fn (t &Table) struct_has_field(s &Type, name string) bool {
println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') if !isnil(s.parent) {
println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=$s.parent.name')
} else {
println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=none')
}
// for typ in t.types { // for typ in t.types {
// println('$typ.idx $typ.name') // println('$typ.idx $typ.name')
// } // }
@ -229,23 +235,28 @@ pub fn (t &Table) struct_has_field(s &Type, name string) bool {
} }
pub fn (t &Table) struct_find_field(s &Type, name string) ?Field { pub fn (t &Table) struct_find_field(s &Type, name string) ?Field {
println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') if !isnil(s.parent) {
println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=$s.parent.name')
} else {
println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=none')
}
info := s.info as Struct info := s.info as Struct
for field in info.fields { for field in info.fields {
if field.name == name { if field.name == name {
return field return field
} }
} }
if s.parent_idx != 0 { if !isnil(s.parent) {
parent := t.types[s.parent_idx] if s.parent.kind == .struct_ {
parent_info := s.info as Struct parent_info := s.parent.info as Struct
println('got parent $parent.name') println('got parent $s.parent.name')
for field in parent_info.fields { for field in parent_info.fields {
if field.name == name { if field.name == name {
return field return field
} }
} }
} }
}
return none return none
} }
@ -282,14 +293,15 @@ pub fn (t mut Table) register_type(typ Type) int {
if ex_type.kind == typ.kind { if ex_type.kind == typ.kind {
return existing_idx return existing_idx
} }
// panic('cannot register type `$typ.name`, another type with this name exists')
return -1 return -1
} }
} }
} }
idx := t.types.len typ_idx := t.types.len
t.types << typ t.types << typ
t.type_idxs[typ.name] = idx t.type_idxs[typ.name] = typ_idx
return idx return typ_idx
} }
pub fn (t &Table) known_type(name string) bool { pub fn (t &Table) known_type(name string) bool {
@ -299,136 +311,127 @@ pub fn (t &Table) known_type(name string) bool {
return true return true
} }
pub fn (t mut Table) find_or_register_map(key_typ &Type, value_typ &Type) (int,string) { pub fn (t mut Table) find_or_register_map(key_type TypeRef, value_type TypeRef) int {
name := 'map_${key_typ.name}_${value_typ.name}' name := map_name(&key_type, &value_type)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
if existing_idx > 0 { if existing_idx > 0 {
return existing_idx,name return existing_idx
} }
// register // register
map_type := Type{ map_type := Type{
parent: &t.types[t.type_idxs['map']]
kind: .map kind: .map
name: name name: name
info: Map{ info: Map{
key_type_idx: key_typ.idx key_type: key_type
value_type_idx: value_typ.idx value_type: value_type
} }
} }
idx := t.register_type(map_type) return t.register_type(map_type)
return idx,name
} }
pub fn (t mut Table) find_or_register_array(elem_typ &Type, nr_dims int) (int,string) { pub fn (t mut Table) find_or_register_array(elem_type TypeRef, nr_dims int) int {
name := 'array_${elem_typ.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } name := array_name(&elem_type, nr_dims)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
if existing_idx > 0 { if existing_idx > 0 {
return existing_idx,name return existing_idx
} }
// register // register
parent_idx := t.type_idxs['array']
array_type := Type{ array_type := Type{
parent_idx: parent_idx parent: &t.types[t.type_idxs['array']]
kind: .array kind: .array
name: name name: name
info: Array{ info: Array{
elem_type_idx: elem_typ.idx elem_type: elem_type
elem_is_ptr: elem_typ.is_ptr()
nr_dims: nr_dims nr_dims: nr_dims
} }
} }
idx := t.register_type(array_type) return t.register_type(array_type)
return idx,name
} }
pub fn (t mut Table) find_or_register_array_fixed(elem_typ &Type, size int, nr_dims int) (int,string) { pub fn (t mut Table) find_or_register_array_fixed(elem_type TypeRef, size int, nr_dims int) int {
name := 'array_fixed_${elem_typ.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } name := array_fixed_name(&elem_type, size, nr_dims)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
if existing_idx > 0 { if existing_idx > 0 {
return existing_idx,name return existing_idx
} }
// register // register
array_fixed_type := Type{ array_fixed_type := Type{
parent: 0
kind: .array_fixed kind: .array_fixed
name: name name: name
info: ArrayFixed{ info: ArrayFixed{
elem_type_idx: elem_typ.idx elem_type: elem_type
elem_is_ptr: elem_typ.is_ptr()
size: size size: size
nr_dims: nr_dims nr_dims: nr_dims
} }
} }
idx := t.register_type(array_fixed_type) return t.register_type(array_fixed_type)
return idx,name
} }
pub fn (t mut Table) find_or_register_multi_return(mr_typs []Type) (int,string) { pub fn (t mut Table) find_or_register_multi_return(mr_typs []TypeRef) int {
mut name := 'multi_return' mut name := 'multi_return'
for mr_typ in mr_typs { for mr_typ in mr_typs {
name += '_$mr_typ.name' name += '_$mr_typ.typ.name'
} }
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
if existing_idx > 0 { if existing_idx > 0 {
return existing_idx,name return existing_idx
} }
// register // register
mr_type := Type{ mr_type := Type{
parent: 0
kind: .multi_return kind: .multi_return
name: name name: name
info: MultiReturn{ info: MultiReturn{
tis: mr_typs types: mr_typs
} }
} }
idx := t.register_type(mr_type) return t.register_type(mr_type)
return idx,name
} }
pub fn (t mut Table) find_or_register_variadic(variadic_typ &Type) (int,string) { pub fn (t mut Table) find_or_register_variadic(variadic_typ TypeRef) int {
name := 'variadic_$variadic_typ.name' name := 'variadic_$variadic_typ.typ.name'
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
if existing_idx > 0 { if existing_idx > 0 {
return existing_idx,name return existing_idx
} }
// register // register
variadic_type := Type{ variadic_type := Type{
parent: 0
kind: .variadic kind: .variadic
name: name name: name
info: Variadic{ info: Variadic{
ti: variadic_typ typ: variadic_typ
} }
} }
idx := t.register_type(variadic_type) return t.register_type(variadic_type)
return idx,name
} }
pub fn (t mut Table) add_placeholder_type(name string) int { pub fn (t mut Table) add_placeholder_type(name string) int {
ph_type := Type{ ph_type := Type{
parent: 0
kind: .placeholder kind: .placeholder
name: name name: name
} }
idx := t.register_type(ph_type) // println('added placeholder: $name - $ph_type.idx')
println('added placeholder: $name - $idx') return t.register_type(ph_type)
return idx
} }
// [inline] pub fn (t &Table) check(got, expected &TypeRef) bool {
// pub fn (t &Table) update_typ(ti &types.Type) types.Type { println('check: $got.typ.name, $expected.typ.name')
// if typ.kind == .unresolved { if expected.typ.kind == .voidptr {
// }
// }
pub fn (t &Table) check(got, expected &Type) bool {
println('check: $got.name, $expected.name')
if expected.kind == .voidptr {
return true return true
} }
// if expected.name == 'array' { // if expected.name == 'array' {
// return true // return true
// } // }
if got.idx != expected.idx && got.name != expected.name { if got.idx != expected.idx && got.typ.name != expected.typ.name {
return false return false
} }
return true return true