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

View File

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

View File

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

View File

@ -11,9 +11,6 @@ const (
)
fn test_c_files() {
$if windows {
return
}
println('Running V => C tests')
vexe := os.getenv('VEXE')
vroot := filepath.dir(vexe)
@ -21,9 +18,14 @@ fn test_c_files() {
term_fail := term.fail_message('FAIL')
for i in 1 .. nr_tests + 1 {
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)
}
ctext = ctext // unused warn
// normalise line endings on win
$if windows {
ctext = ctext.replace('\r', '')
}
mut b := builder.new_builder(pref.Preferences{})
res := b.gen_c([path])
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) {
match node {
ast.FnDecl {
ti := g.table.refresh_ti(it.ti)
g.write('/** @return { $ti.name } **/\nfunction ${it.name}(')
g.write('/** @return { $it.typ.typ.name } **/\nfunction ${it.name}(')
for arg in it.args {
arg_ti := g.table.refresh_ti(arg.ti)
g.write(' /** @type { $arg_ti.name } **/ $arg.name')
g.write(' /** @type { $arg.typ.typ.name } **/ $arg.name')
}
g.writeln(') { ')
for stmt in it.stmts {
@ -58,8 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
typ := g.table.refresh_ti(it.typ)
g.write('var /* $typ.name */ $it.name = ')
g.write('var /* $it.typ.typ.name */ $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -121,8 +118,7 @@ fn (g mut JsGen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
ti := g.table.refresh_ti(it.ti)
g.writeln('/*$ti.name*/{')
g.writeln('/*$it.typ.typ.name*/{')
for i, field in it.fields {
g.write('\t$field : ')
g.expr(it.exprs[i])

View File

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

View File

@ -5,51 +5,57 @@ int testa();
int testb();
int testa();
int main() {
Bar b = (Bar){
Bar b = (Bar){
.a = 122,
};
Foo a = (Foo){
};
Foo a = (Foo){
.a = tos3("hello"),
.b = b,
};
a.a = tos3("da");
a.b.a = 111;
string a1 = a.a;
int a2 = ;
int c = testa();
c = 1;
string d = testb(1);
d = tos3("hello");
string e = tos3("hello");
e = testb(111);
e = tos3("world");
return 0;
};
a.a = tos3("da");
a.b.a = 111;
string a1 = a.a;
int a2 = ;
int c = testa();
c = 1;
string d = testb(1);
d = tos3("hello");
string e = tos3("hello");
e = testb(111);
e = tos3("world");
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() {
return testc(1);
return testc(1);
}
string testb(int a) {
return tos3("hello");
return tos3("hello");
}
int testc(int a) {
return a;
return a;
}
int testa() {
int a = ;
a = 1;
return 4;
int a = ;
a = 1;
return 4;
}
int testb() {
return 4;
return 4;
}
int testa() {
return 4;
return 4;
}
typedef struct {

View File

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

View File

@ -8,7 +8,7 @@ import (
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
fn_name := p.check_name()
p.check(.lpar)
@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
name: fn_name
args: args
// tok: tok
pos: tok.position()
}
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) {
return node,f.return_type
}
typ := p.add_unresolved(node)
typ := p.add_unresolved('${fn_name}()', node)
return node,typ
}
@ -65,7 +64,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
// Receiver?
mut rec_name := ''
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 {
is_method = true
p.next()
@ -73,10 +72,10 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut {
p.next()
}
rec_ti = p.parse_type()
rec_type = p.parse_type()
p.table.register_var(table.Var{
name: rec_name
typ: rec_ti
typ: rec_type
})
p.check(.rpar)
}
@ -120,19 +119,19 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut {
p.check(.key_mut)
}
ti := p.parse_type()
typ := p.parse_type()
for arg_name in arg_names {
arg := table.Var{
name: arg_name
typ: ti
typ: typ
}
args << arg
p.table.register_var(arg)
ast_args << ast.Arg{
ti: ti
typ: typ
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')
}
}
@ -143,16 +142,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
}
p.check(.rpar)
// 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] {
typ = p.parse_type()
p.return_type = typ
}
else {
p.return_type = table.void_type
// p.return_type = table.void_type
p.return_type = typ
}
if is_method {
ok := p.table.register_method(rec_ti, table.Fn{
ok := p.table.register_method(rec_type.typ, table.Fn{
name: name
args: args
return_type: typ
@ -175,28 +175,13 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
return ast.FnDecl{
name: name
stmts: stmts
ti: typ
typ: typ
args: ast_args
is_pub: is_pub
receiver: ast.Field{
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
)
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)
// fixed array
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()
p.check(.rsbr)
p.check_name()
idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1)
return table.new_type(.array_fixed, name, idx, nr_muls)
idx := p.table.find_or_register_array_fixed(elem_ti, size, 1)
return p.table.type_ref_ptr(idx, nr_muls)
}
// array
p.check(.rsbr)
@ -26,29 +26,30 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
p.check(.rsbr)
nr_dims++
}
idx,name := p.table.find_or_register_array(&elem_ti, nr_dims)
return table.new_type(.array, name, idx, nr_muls)
idx := p.table.find_or_register_array(elem_ti, nr_dims)
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 {
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.check(.lsbr)
key_ti := p.parse_type()
p.check(.rsbr)
value_ti := p.parse_type()
idx,name := p.table.find_or_register_map(&key_ti, &value_ti)
return table.new_type(.map, name, idx, nr_muls)
idx := p.table.find_or_register_map(key_ti, value_ti)
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)
mut mr_tis := []table.Type
mut mr_types := []table.TypeRef
for {
mr_ti := p.parse_type()
mr_tis << mr_ti
mr_type := p.parse_type()
mr_types << mr_type
if p.tok.kind == .comma {
p.check(.comma)
}
@ -57,24 +58,24 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
}
}
p.check(.rpar)
idx,name := p.table.find_or_register_multi_return(mr_tis)
return table.new_type(.multi_return, name, idx, 0)
idx := p.table.find_or_register_multi_return(mr_types)
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)
variadic_ti := p.parse_type()
idx,name := p.table.find_or_register_variadic(&variadic_ti)
return table.new_type(.variadic, name, idx, 0)
variadic_type := p.parse_type()
idx := p.table.find_or_register_variadic(variadic_type)
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.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
for p.tok.kind == .amp {
p.check(.amp)
@ -120,63 +121,64 @@ pub fn (p mut Parser) parse_type() table.Type {
return p.parse_map_type(nr_muls)
}
'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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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' {
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
else {
// struct / enum
mut idx := p.table.find_type_idx(name)
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
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
// vars []string
table &table.Table
return_type table.Type // current function's return type
return_type table.TypeRef // current function's return type
// scope_level int
// var_idx int
is_c bool
@ -44,6 +44,7 @@ mut:
builtin_mod bool
mod string
unresolved []ast.Expr
unresolved_idxs map[string]int
}
// 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] {
return p.var_decl()
}
expr,ti := p.expr(0)
expr,typ := p.expr(0)
return ast.ExprStmt{
expr: expr
ti: ti
typ: typ
}
}
}
@ -298,8 +299,8 @@ fn (p mut Parser) range_expr(low ast.Expr) ast.Expr {
}
p.check(.dotdot)
high,typ := p.expr(0)
if typ.kind != .int {
p.error('non-integer index `$typ.name`')
if typ.typ.kind != .int {
p.error('non-integer index `$typ.typ.name`')
}
node := ast.RangeExpr{
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 typ := table.void_type
mut typ := p.table.type_ref(table.void_type_idx)
// mut typ := table.unresolved_type
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
if is_c {
@ -416,7 +417,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
exprs << expr
}
node = ast.StructInit{
ti: typ
typ: typ
exprs: exprs
fields: field_names
pos: p.tok.position()
@ -431,25 +432,23 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
}
// variable
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
ident.kind = .variable
ident.info = ast.IdentVar{
typ: typ
// name: ident.name
// expr: p.expr(0)// var.expr
}
// ident.ti = ti
node = ident
p.next()
}else{
if is_c {
typ = table.int_type
typ = p.table.type_ref(table.int_type_idx)
ident.info = ast.IdentVar{
typ: typ
// name: ident.name
}
node = ident
p.next()
@ -462,7 +461,6 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
ident.info = ast.IdentVar{
typ: typ
// name: ident.name
}
node = ident
p.next()
@ -479,9 +477,9 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
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()')
mut typ := table.void_type
mut typ := p.table.type_ref(table.void_type_idx)
mut node := ast.Expr{}
// Prefix
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()
}
.chartoken {
typ = table.byte_type
typ = p.table.type_ref(table.byte_type_idx)
node = ast.CharLiteral{
val: p.tok.lit
}
@ -509,7 +507,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
node = ast.BoolLiteral{
val: p.tok.kind == .key_true
}
typ = table.bool_type
typ = p.table.type_ref(table.bool_type_idx)
p.next()
}
.key_match {
@ -537,7 +535,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
p.check(.lpar)
p.next()
p.check(.rpar)
typ = table.int_type
typ = p.table.type_ref(table.int_type_idx)
}
else {
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
}
fn (p mut Parser) prefix_expr() (ast.Expr,table.Type) {
fn (p mut Parser) prefix_expr() (ast.Expr,table.TypeRef) {
op := p.tok.kind
p.next()
right,ti := p.expr(1)
right,typ := p.expr(1)
mut expr := ast.Expr{}
expr = ast.PrefixExpr{
op: op
right: right
}
return expr,ti
return expr,typ
}
// 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 ]')
// /ti := table.int_type
mut node := ast.Expr{}
// println('index expr: $typ.typ.name')
node = ast.IndexExpr{
left: left
index: index_expr
pos: p.tok.position()
// typ: typ
}
return node
// 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()
field_name := p.check_name()
mut ti := table.unresolved_type
// Method call
if p.tok.kind == .lpar {
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{}
node = mcall_expr
ti = p.add_unresolved(mcall_expr)
return node,ti
typ := p.add_unresolved('${left_type.typ.name}.${field_name}()', mcall_expr)
return node,typ
}
sel_expr := ast.SelectorExpr{
expr: left
field: field_name
pos: p.tok.position()
}
typ := p.add_unresolved('${left_type.typ.name}.$field_name', sel_expr)
mut node := ast.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
// mut typ := p.
// println('infix op=$op.str()')
precedence := p.tok.precedence()
p.next()
right,mut ti := p.expr(precedence)
right,mut typ := p.expr(precedence)
if op.is_relational() {
ti = table.bool_type
typ = p.table.type_ref(table.bool_type_idx)
}
mut expr := ast.Expr{}
expr = ast.InfixExpr{
left: left
right: right
right_type: ti
right_type: typ
op: op
pos: p.tok.position()
}
return expr,ti
return expr,typ
}
// Implementation of Pratt Precedence
@ -716,7 +714,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
}
p.check(.semicolon)
if p.tok.kind != .semicolon {
mut typ := table.Type{}
mut typ := table.TypeRef{typ:0}
cond,typ = p.expr(0)
}
p.check(.semicolon)
@ -740,7 +738,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
val_name := p.check_name()
p.table.register_var(table.Var{
name: val_name
typ: table.int_type
typ: p.table.type_ref(table.int_type_idx)
})
}
p.check(.key_in)
@ -752,7 +750,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
}
p.table.register_var(table.Var{
name: var_name
typ: table.int_type
typ: p.table.type_ref(table.int_type_idx)
})
stmts := p.parse_block()
// 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
// defer {
// }
@ -792,14 +790,14 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
else_stmts = p.parse_block()
}
}
mut ti := table.void_type
mut typ := p.table.type_ref(table.void_type_idx)
// mut left := ast.Expr{}
// If the last statement is an expression, return its type
if stmts.len > 0 {
match stmts[stmts.len - 1] {
ast.ExprStmt {
p.warn('if expr ret $it.ti.name')
ti = it.ti
p.warn('if expr ret $it.typ.typ.name')
typ = it.typ
// return node,it.ti
// left =
}
@ -810,22 +808,22 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
cond: cond
stmts: stmts
else_stmts: else_stmts
ti: ti
typ: typ
pos: p.tok.position()
// 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{}
node = ast.StringLiteral{
val: p.tok.lit
}
if p.peek_tok.kind != .str_dollar {
p.next()
return node,table.string_type
return node, p.table.type_ref(table.string_type_idx)
}
// Handle $ interpolation
for p.tok.kind == .str {
@ -839,13 +837,13 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
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{}
p.check(.lsbr)
mut val_type := table.void_type
mut val_type := p.table.type_ref(table.void_type_idx)
mut exprs := []ast.Expr
for i := 0; p.tok.kind != .rsbr; i++ {
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)
// node =
}
type_idx,type_name := p.table.find_or_register_array(val_type, 1)
array_ti := table.new_type(.array, type_name, type_idx, 0)
// array_type := 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{
ti: array_ti
typ: array_type
exprs: exprs
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
mut node := ast.Expr{}
mut ti := table.int_type
mut ti := p.table.type_ref(table.int_type_idx)
if lit.contains('.') {
node = ast.FloatLiteral{
// val: lit.f64()
val: lit
}
// ti = table.new_builtin_ti(.f64, 0)
ti = table.new_type(.f64, 'f64', table.f64_type_idx, 0)
ti = p.table.type_ref(table.f64_type_idx)
}
else {
node = ast.IntegerLiteral{
@ -987,7 +985,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
}
field_name := p.check_name()
// p.warn('field $field_name')
ti := p.parse_type()
typ := p.parse_type()
// Default value
if p.tok.kind == .assign {
p.next()
@ -995,19 +993,19 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
}
ast_fields << ast.Field{
name: field_name
typ: ti
typ: typ
}
fields << table.Field{
name: field_name
// type_idx: ti.idx
ti: ti
typ: typ
}
// println('struct field $ti.name $field_name')
}
p.check(.rcbr)
if name != 'string' {
ret := p.table.register_type(table.Type{
parent: 0
kind: .struct_
name: name
info: table.Struct{
@ -1051,7 +1049,7 @@ fn (p mut Parser) return_stmt() ast.Return {
}
// TODO: consider non deferred
stmt := ast.Return{
expected_ti: p.return_type
expected_type: p.return_type
exprs: exprs
pos: p.tok.position()
}
@ -1082,7 +1080,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
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)
node := ast.VarDecl{
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.expr(0)
p.check(.lcbr)
@ -1156,16 +1154,25 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
p.check(.rcbr)
mut node := ast.Expr{}
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 {
t := table.Type{
idx: p.unresolved.len
kind: .unresolved
name: 'unresolved'
fn (p mut Parser) add_unresolved(key string, expr ast.Expr) table.TypeRef {
mut idx := p.unresolved.len
if key in p.unresolved_idxs {
idx = p.unresolved_idxs[key]
}
else {
p.unresolved << expr
}
t := table.TypeRef{
idx: idx
typ: &table.Type{
parent: 0
kind: .unresolved
name: 'unresolved $p.unresolved.len'
}
}
p.unresolved << expr
return t
}

View File

@ -7,14 +7,19 @@ pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic
pub struct Type {
pub:
idx int
parent_idx int
parent &Type
mut:
info TypeInfo
kind Kind
name string
methods []Fn
nr_muls int
}
pub struct TypeRef {
pub:
idx int
typ &Type
nr_muls int
}
pub const (
@ -35,7 +40,11 @@ pub const (
char_type_idx = 15
byte_type_idx = 16
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 {
@ -68,162 +77,170 @@ pub enum Kind {
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 {
return t.name
}
*/
pub fn (t &Type) str() string {
pub fn (t &TypeRef) str() string {
mut muls := ''
for _ in 0 .. t.nr_muls {
muls += '&'
}
// return '$muls$ti.name'
return '$muls$t.idx'
return '$muls$t.typ.name'
}
pub fn new_type(kind Kind, name string, idx int, nr_muls int) Type {
return Type{
[inline]
pub fn (t &Table) type_ref(idx int) TypeRef {
return TypeRef{
idx: idx
kind: kind
name: name
nr_muls: nr_muls
typ: &t.types[idx]
}
}
[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() {
// reserve index 0 so nothing can go there
// save index check, 0 will mean not found
t.register_type(Type{
parent: 0
kind: .placeholder
name: 'reserved_0'
})
t.register_type(Type{
parent: 0
kind: .void
name: 'void'
})
t.register_type(Type{
parent: 0
kind: .voidptr
name: 'voidptr'
})
t.register_type(Type{
parent: 0
kind: .charptr
name: 'charptr'
})
t.register_type(Type{
parent: 0
kind: .byteptr
name: 'byteptr'
})
t.register_type(Type{
parent: 0
kind: .i8
name: 'i8'
})
t.register_type(Type{
parent: 0
kind: .i16
name: 'i16'
})
t.register_type(Type{
parent: 0
kind: .int
name: 'int'
})
t.register_type(Type{
parent: 0
kind: .i64
name: 'i64'
})
t.register_type(Type{
parent: 0
kind: .u16
name: 'u16'
})
t.register_type(Type{
parent: 0
kind: .u32
name: 'u32'
})
t.register_type(Type{
parent: 0
kind: .u64
name: 'u64'
})
t.register_type(Type{
parent: 0
kind: .f32
name: 'f32'
})
t.register_type(Type{
parent: 0
kind: .f64
name: 'f64'
})
t.register_type(Type{
parent: 0
kind: .string
name: 'string'
})
t.register_type(Type{
parent: 0
kind: .char
name: 'char'
})
t.register_type(Type{
parent: 0
kind: .byte
name: 'byte'
})
t.register_type(Type{
parent: 0
kind: .bool
name: 'bool'
})
t.register_type(Type{
parent: 0
kind: .unresolved
name: 'unresolved'
})
}
[inline]
pub fn (ti &Type) is_ptr() bool {
return ti.nr_muls > 0
pub fn (t &TypeRef) is_ptr() bool {
return t.nr_muls > 0
}
[inline]
pub fn (ti &Type) is_int() bool {
return ti.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64]
pub fn (t &Type) is_int() bool {
return t.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64]
}
[inline]
pub fn (ti &Type) is_float() bool {
return ti.kind in [.f32, .f64]
pub fn (t &Type) is_float() bool {
return t.kind in [.f32, .f64]
}
[inline]
pub fn (ti &Type) is_number() bool {
return ti.is_int() || ti.is_float()
pub fn (t &Type) is_number() bool {
return t.is_int() || t.is_float()
}
pub fn (k Kind) str() string {
@ -271,7 +288,13 @@ pub fn (k Kind) str() string {
'byte'
}
.u16{
'u18'
'u16'
}
.u32{
'u32'
}
.u64{
'u64'
}
.f32{
'f32'
@ -336,7 +359,7 @@ pub mut:
pub struct Field {
pub:
name string
ti Type
typ TypeRef
// type_idx int
}
// pub struct Int {
@ -350,58 +373,40 @@ pub:
// }
pub struct Array {
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:
elem_type_kind Kind
elem_type_idx int
elem_is_ptr bool
nr_dims int
size int
nr_dims int
size int
mut:
elem_type TypeRef
}
pub struct Map {
pub:
key_type_kind Kind
key_type_idx int
value_type_kind Kind
value_type_idx int
pub mut:
key_type TypeRef
value_type TypeRef
}
pub struct MultiReturn {
pub:
name string
tis []Type
name string
types []TypeRef
}
pub struct Variadic {
pub:
ti Type
typ TypeRef
}
pub fn (t &Table) refresh_ti(ti Type) Type {
if ti.idx == 0 {
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 {
[inline]
pub fn (t &Table) get_type(idx int) &Type {
if 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:
name string
args []Var
return_type Type
return_type TypeRef
}
pub struct Var {
@ -37,11 +37,13 @@ pub:
is_global bool
scope_level int
mut:
typ Type
typ TypeRef
}
pub fn new_table() &Table {
mut t := &Table{}
mut t := &Table{
types: make(0, 400, sizeof(Type))
}
t.register_builtin_types()
return t
}
@ -77,7 +79,7 @@ pub fn (t mut Table) register_const(v Var) {
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{
name: name
typ: typ
@ -86,12 +88,11 @@ pub fn (t mut Table) register_global(name string, typ Type) {
// mod: p.mod
// is_mut: true
// idx: -1
}
}
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 := {
v |
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
}
pub fn (t mut Table) register_method(typ &Type, new_fn Fn) bool {
idx := typ.idx
println('register method `$new_fn.name` type=$typ.name idx=$typ.idx')
mut methods := t.types[idx].methods
pub fn (t &Table) register_method(typ &Type, new_fn Fn) bool {
// println('register method `$new_fn.name` type=$typ.name idx=$typ.idx')
println('register method `$new_fn.name` type=$typ.name')
mut t1 := typ
mut methods := typ.methods
methods << new_fn
t.types[idx].methods = methods
t1.methods = methods
return true
}
pub fn (t &Table) has_method(type_idx int, name string) bool {
t.find_method(type_idx, name) or {
pub fn (t &Type) has_method(name string) bool {
t.find_method(name) or {
return false
}
return true
}
pub fn (t &Table) find_method(type_idx int, name string) ?Fn {
for method in t.types[type_idx].methods {
pub fn (t &Type) find_method(name string) ?Fn {
for method in t.methods {
if method.name == name {
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 {
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 {
// println('$typ.idx $typ.name')
// }
@ -229,20 +235,25 @@ pub fn (t &Table) struct_has_field(s &Type, name string) bool {
}
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
for field in info.fields {
if field.name == name {
return field
}
}
if s.parent_idx != 0 {
parent := t.types[s.parent_idx]
parent_info := s.info as Struct
println('got parent $parent.name')
for field in parent_info.fields {
if field.name == name {
return field
if !isnil(s.parent) {
if s.parent.kind == .struct_ {
parent_info := s.parent.info as Struct
println('got parent $s.parent.name')
for field in parent_info.fields {
if field.name == name {
return field
}
}
}
}
@ -282,14 +293,15 @@ pub fn (t mut Table) register_type(typ Type) int {
if ex_type.kind == typ.kind {
return existing_idx
}
// panic('cannot register type `$typ.name`, another type with this name exists')
return -1
}
}
}
}
idx := t.types.len
typ_idx := t.types.len
t.types << typ
t.type_idxs[typ.name] = idx
return idx
t.type_idxs[typ.name] = typ_idx
return typ_idx
}
pub fn (t &Table) known_type(name string) bool {
@ -299,136 +311,127 @@ pub fn (t &Table) known_type(name string) bool {
return true
}
pub fn (t mut Table) find_or_register_map(key_typ &Type, value_typ &Type) (int,string) {
name := 'map_${key_typ.name}_${value_typ.name}'
pub fn (t mut Table) find_or_register_map(key_type TypeRef, value_type TypeRef) int {
name := map_name(&key_type, &value_type)
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
return existing_idx
}
// register
map_type := Type{
parent: &t.types[t.type_idxs['map']]
kind: .map
name: name
info: Map{
key_type_idx: key_typ.idx
value_type_idx: value_typ.idx
key_type: key_type
value_type: value_type
}
}
idx := t.register_type(map_type)
return idx,name
return t.register_type(map_type)
}
pub fn (t mut Table) find_or_register_array(elem_typ &Type, nr_dims int) (int,string) {
name := 'array_${elem_typ.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' }
pub fn (t mut Table) find_or_register_array(elem_type TypeRef, nr_dims int) int {
name := array_name(&elem_type, nr_dims)
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
return existing_idx
}
// register
parent_idx := t.type_idxs['array']
array_type := Type{
parent_idx: parent_idx
parent: &t.types[t.type_idxs['array']]
kind: .array
name: name
info: Array{
elem_type_idx: elem_typ.idx
elem_is_ptr: elem_typ.is_ptr()
elem_type: elem_type
nr_dims: nr_dims
}
}
idx := t.register_type(array_type)
return idx,name
return t.register_type(array_type)
}
pub fn (t mut Table) find_or_register_array_fixed(elem_typ &Type, size int, nr_dims int) (int,string) {
name := 'array_fixed_${elem_typ.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' }
pub fn (t mut Table) find_or_register_array_fixed(elem_type TypeRef, size int, nr_dims int) int {
name := array_fixed_name(&elem_type, size, nr_dims)
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
return existing_idx
}
// register
array_fixed_type := Type{
parent: 0
kind: .array_fixed
name: name
info: ArrayFixed{
elem_type_idx: elem_typ.idx
elem_is_ptr: elem_typ.is_ptr()
elem_type: elem_type
size: size
nr_dims: nr_dims
}
}
idx := t.register_type(array_fixed_type)
return idx,name
return t.register_type(array_fixed_type)
}
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'
for mr_typ in mr_typs {
name += '_$mr_typ.name'
name += '_$mr_typ.typ.name'
}
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
return existing_idx
}
// register
mr_type := Type{
parent: 0
kind: .multi_return
name: name
info: MultiReturn{
tis: mr_typs
types: mr_typs
}
}
idx := t.register_type(mr_type)
return idx,name
return t.register_type(mr_type)
}
pub fn (t mut Table) find_or_register_variadic(variadic_typ &Type) (int,string) {
name := 'variadic_$variadic_typ.name'
pub fn (t mut Table) find_or_register_variadic(variadic_typ TypeRef) int {
name := 'variadic_$variadic_typ.typ.name'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
return existing_idx
}
// register
variadic_type := Type{
parent: 0
kind: .variadic
name: name
info: Variadic{
ti: variadic_typ
typ: variadic_typ
}
}
idx := t.register_type(variadic_type)
return idx,name
return t.register_type(variadic_type)
}
pub fn (t mut Table) add_placeholder_type(name string) int {
ph_type := Type{
parent: 0
kind: .placeholder
name: name
}
idx := t.register_type(ph_type)
println('added placeholder: $name - $idx')
return idx
// println('added placeholder: $name - $ph_type.idx')
return t.register_type(ph_type)
}
// [inline]
// pub fn (t &Table) update_typ(ti &types.Type) types.Type {
// if typ.kind == .unresolved {
// }
// }
pub fn (t &Table) check(got, expected &Type) bool {
println('check: $got.name, $expected.name')
if expected.kind == .voidptr {
pub fn (t &Table) check(got, expected &TypeRef) bool {
println('check: $got.typ.name, $expected.typ.name')
if expected.typ.kind == .voidptr {
return true
}
// if expected.name == 'array' {
// 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 true