From 2061394ad7d35ec1c8af32d1be58065ca9d3490c Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Sun, 5 Jan 2020 03:57:25 +1100 Subject: [PATCH] v: initial impl of new type sys w/ pointer & placeholder support (#3323) --- vlib/v/ast/ast.v | 22 ++- vlib/v/gen/cgen.v | 20 +-- vlib/v/gen/jsgen.v | 10 +- vlib/v/gen/x64/gen.v | 12 +- vlib/v/parser/fn.v | 40 ++--- vlib/v/parser/parser.v | 279 +++++++++++++++++++++++--------- vlib/v/table/table.v | 125 +++++++++++++-- vlib/v/types/types.v | 327 +++++++++++++++++++++++++++++++++----- vlib/v/types/types_test.v | 5 + 9 files changed, 667 insertions(+), 173 deletions(-) create mode 100644 vlib/v/types/types_test.v diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ed4e047cc3..8d94262f7a 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -17,7 +17,7 @@ ForStmt | StructDecl pub struct ExprStmt { pub: expr Expr - typ types.Type + ti types.TypeIdent } pub struct IntegerLiteral { @@ -59,7 +59,7 @@ pub: pub struct Field { pub: name string - typ types.Type + ti types.TypeIdent } pub struct StructDecl { @@ -71,7 +71,8 @@ pub: pub struct StructInit { pub: - typ types.Type + ti types.TypeIdent + // typ types.Type fields []string exprs []Expr } @@ -86,7 +87,8 @@ pub: pub struct Arg { pub: - typ types.Type + ti types.TypeIdent + // typ types.Type name string } @@ -94,7 +96,8 @@ pub struct FnDecl { pub: name string stmts []Stmt - typ types.Type + ti types.TypeIdent + // typ types.Type args []Arg is_pub bool receiver Field @@ -133,7 +136,8 @@ pub struct VarDecl { pub: name string expr Expr - typ types.Type + ti types.TypeIdent + // typ types.Type } pub struct File { @@ -174,7 +178,8 @@ pub: cond Expr stmts []Stmt else_stmts []Stmt - typ types.Type + ti types.TypeIdent + // typ types.Type left Expr // `a` in `a := if ...` } @@ -200,7 +205,8 @@ pub: pub struct ArrayInit { pub: exprs []Expr - typ types.Type + ti types.TypeIdent + // typ types.Type } // string representaiton of expr diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 924390474e..ea8c9c8e2d 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -53,12 +53,12 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('int ${it.name}(') } else { - g.write('$it.typ.name ${it.name}(') - g.definitions.write('$it.typ.name ${it.name}(') + g.write('$it.ti.type_name ${it.name}(') + g.definitions.write('$it.ti.type_name ${it.name}(') } for arg in it.args { - g.write(arg.typ.name + ' ' + arg.name) - g.definitions.write(arg.typ.name + ' ' + arg.name) + g.write(arg.ti.type_name + ' ' + arg.name) + g.definitions.write(arg.ti.type_name + ' ' + arg.name) } g.writeln(') { ') if !is_main { @@ -78,7 +78,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('$it.typ.name $it.name = ') + g.write('$it.ti.type_name $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -98,7 +98,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.StructDecl { g.writeln('typedef struct {') for field in it.fields { - g.writeln('\t$field.typ.name $field.name;') + g.writeln('\t$field.ti.type_name $field.name;') } g.writeln('} $it.name;') } @@ -154,7 +154,7 @@ fn (g mut Gen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('($it.typ.name){') + g.writeln('($it.ti.type_name){') for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) @@ -173,7 +173,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(')') } ast.ArrayInit { - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t') for expr in it.exprs { g.expr(expr) g.write(', ') @@ -200,7 +200,7 @@ fn (g mut Gen) expr(node ast.Expr) { // If expression? Assign the value to a temp var. // Previously ?: was used, but it's too unreliable. mut tmp := '' - if it.typ.idx != types.void_type.idx { + if it.ti.type_kind != ._void { tmp = g.table.new_tmp_var() // g.writeln('$it.typ.name $tmp;') } @@ -209,7 +209,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 && it.typ.idx != types.void_type.idx { + if i == it.stmts.len - 1 && it.ti.type_kind != ._void { // g.writeln('$tmp =') println(1) } diff --git a/vlib/v/gen/jsgen.v b/vlib/v/gen/jsgen.v index dd816e290f..4873ac66cd 100644 --- a/vlib/v/gen/jsgen.v +++ b/vlib/v/gen/jsgen.v @@ -40,9 +40,9 @@ fn (g mut JsGen) stmt(node ast.Stmt) { g.writeln(';') } ast.FnDecl { - g.write('/** @return { $it.typ.name } **/\nfunction ${it.name}(') + g.write('/** @return { $it.ti.type_name } **/\nfunction ${it.name}(') for arg in it.args { - g.write(' /** @type { arg.typ.name } **/ $arg.name') + g.write(' /** @type { arg.ti.type_name } **/ $arg.name') } g.writeln(') { ') for stmt in it.stmts { @@ -56,7 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('var /* $it.typ.name */ $it.name = ') + g.write('var /* $it.ti.type_name */ $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -72,7 +72,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) { ast.StructDecl { // g.writeln('typedef struct {') // for field in it.fields { - // g.writeln('\t$field.typ.name $field.name;') + // g.writeln('\t$field.ti.type_name $field.name;') // } g.writeln('var $it.name = function() {};') } @@ -115,7 +115,7 @@ fn (g mut JsGen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('/*$it.typ.name*/{') + g.writeln('/*$it.ti.type_name*/{') for i, field in it.fields { g.write('\t$field : ') g.expr(it.exprs[i]) diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index fa4280c29e..569e741ff5 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -337,7 +337,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('$it.typ.name $it.name = ') + g.write('$it.ti.type_name $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -354,7 +354,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.StructDecl { g.writeln('typedef struct {') for field in it.fields { - g.writeln('\t$field.typ.name $field.name;') + g.writeln('\t$field.ti.type_name $field.name;') } g.writeln('} $it.name;') } @@ -394,13 +394,13 @@ fn (g mut Gen) expr(node ast.Expr) { g.expr(it.left) g.write(' $it.op.str() ') g.expr(it.right) - // if typ.name != typ2.name { - // verror('bad types $typ.name $typ2.name') + // if ti.type_name != typ2.name { + // verror('bad types $ti.type_name $typ2.name') // } } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('($it.typ.name){') + g.writeln('($it.ti.type_name){') for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) @@ -426,7 +426,7 @@ fn (g mut Gen) expr(node ast.Expr) { } ast.ArrayInit { - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t') for expr in it.exprs { g.expr(expr) g.write(', ') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index f935c360b2..12da266008 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -13,20 +13,20 @@ import ( os ) -pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) { +pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) { // println('got fn call') tok := p.tok fn_name := p.check_name() p.check(.lpar) mut is_unknown := false mut args := []ast.Expr - mut return_type := types.void_type + mut return_ti := types.new_base_ti(._void, 0) if f := p.table.find_fn(fn_name) { - return_type = f.return_type + return_ti = f.return_ti for i, arg in f.args { - e,typ := p.expr(0) - if !types.check(arg.typ, typ) { - p.error('cannot use type `$typ.name` as type `$arg.typ.name` in argument to `$fn_name`') + e,ti := p.expr(0) + if !types.check(arg.ti, ti) { + p.error('cannot use type `$ti.type_name` as type `$arg.ti.type_name` in argument to `$fn_name`') } args << e if i < f.args.len - 1 { @@ -59,7 +59,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) { if is_unknown { p.table.unknown_calls << node } - return node,return_type + return node,return_ti } fn (p mut Parser) fn_decl() ast.FnDecl { @@ -71,17 +71,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl { p.check(.key_fn) // Receiver? mut rec_name := '' - mut rec_type := types.void_type + mut rec_ti := types.new_base_ti(._void, 0) if p.tok.kind == .lpar { p.next() rec_name = p.check_name() if p.tok.kind == .key_mut { p.next() } - rec_type = p.parse_type() + rec_ti = p.parse_ti() p.table.register_var(table.Var{ name: rec_name - typ: rec_type + ti: rec_ti }) p.check(.rpar) } @@ -98,16 +98,16 @@ fn (p mut Parser) fn_decl() ast.FnDecl { p.check(.comma) arg_names << p.check_name() } - typ := p.parse_type() + ti := p.parse_ti() for arg_name in arg_names { arg := table.Var{ name: arg_name - typ: typ + ti: ti } args << arg p.table.register_var(arg) ast_args << ast.Arg{ - typ: typ + ti: ti name: arg_name } } @@ -117,26 +117,26 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } p.check(.rpar) // Return type - mut typ := types.void_type - if p.tok.kind == .name { - typ = p.parse_type() - p.return_type = typ + mut ti := types.new_base_ti(._void, 0) + if p.tok.kind in [.amp, .name] { + ti = p.parse_ti() + p.return_ti = ti } p.table.register_fn(table.Fn{ name: name args: args - return_type: typ + return_ti: ti }) stmts := p.parse_block() return ast.FnDecl{ name: name stmts: stmts - typ: typ + ti: ti args: ast_args is_pub: is_pub receiver: ast.Field{ name: rec_name - typ: rec_type + ti: rec_ti } } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index e06c2cd1eb..471ddec3d2 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -21,7 +21,7 @@ mut: peek_tok token.Token // vars []string table &table.Table - return_type types.Type + return_ti types.TypeIdent is_c bool } @@ -35,6 +35,126 @@ pub fn parse_stmt(text string, table &table.Table) ast.Stmt { return p.stmt() } +pub fn (p mut Parser) parse_ti() types.TypeIdent { + defer { + p.next() + } + mut nr_muls := 0 + if p.tok.kind == .amp { + p.check(.amp) + nr_muls = 1 + } + name := p.tok.lit + if nr_muls > 0 { + println('## POINTER: $name') + } + match name { + 'voidptr' { + return types.new_base_ti(._voidptr, nr_muls) + } + 'byteptr' { + return types.new_base_ti(._byteptr, nr_muls) + } + 'charptr' { + return types.new_base_ti(._charptr, nr_muls) + } + '164' { + return types.new_base_ti(._i16, nr_muls) + } + 'int' { + return types.new_base_ti(._int, nr_muls) + } + 'i64' { + return types.new_base_ti(._i64, nr_muls) + } + 'byte' { + return types.new_base_ti(._byte, nr_muls) + } + 'u16' { + return types.new_base_ti(._u16, nr_muls) + } + 'u32' { + return types.new_base_ti(._u32, nr_muls) + } + 'u64' { + return types.new_base_ti(._u64, nr_muls) + } + 'f32' { + return types.new_base_ti(._f32, nr_muls) + } + 'f64' { + return types.new_base_ti(._f64, nr_muls) + } + 'string' { + return types.new_base_ti(._string, nr_muls) + } + 'char' { + return types.new_base_ti(._char, nr_muls) + } + 'bool' { + return types.new_base_ti(._bool, nr_muls) + } + else { + // array + if p.tok.kind == .lsbr { + p.check(.lsbr) + // fixed array + if p.tok.kind == .number { + fixed_size := p.tok.lit.int() + p.check(.rsbr) + elem_ti := p.parse_ti() + array_fixed_type := types.ArrayFixed{ + name: 'array_fixed_$elem_ti.type_name' + size: fixed_size + elem_type_idx: elem_ti.type_idx + } + idx := p.table.find_or_register_array_fixed(array_fixed_type) + return types.new_ti(._array_fixed, array_fixed_type.name, idx, nr_muls) + } + p.check(.rsbr) + // array + elem_ti := p.parse_ti() + array_type := types.Array{ + name: 'array_$elem_ti.type_name' + elem_type_idx: elem_ti.type_idx + } + idx := p.table.find_or_register_array(array_type) + return types.new_ti(._array, array_type.name, idx, nr_muls) + } + // map + else if name == 'map' { + p.next() + p.check(.lsbr) + key_ti := p.parse_ti() + p.check(.rsbr) + value_ti := p.parse_ti() + map_type := types.Map{ + name: 'map_${key_ti.type_name}_${value_ti.type_name}' + key_type_idx: key_ti.type_idx, + value_type_idx: value_ti.type_idx + } + idx := p.table.find_or_register_map(map_type) + return types.new_ti(._map, map_type.name, idx, nr_muls) + } else { + // struct / enum + mut idx := p.table.find_type_idx(name) + // add placeholder + if idx == 0 { + idx = p.table.add_placeholder_type(name) + } + return types.new_ti(._placeholder, name, idx, nr_muls) + } + + // typ := p.table.types[p.tok.lit] + // if isnil(typ.name.str) || typ.name == '' { + // p.error('undefined type `$p.tok.lit`') + // } + // println('RET Typ $typ.name') + // typ + } + } +} + pub fn parse_file(path string, table &table.Table) ast.File { println('parse file "$path"') text := os.read_file(path) or { @@ -74,16 +194,16 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File { } // former get_type() -pub fn (p mut Parser) parse_type() types.Type { - typ := p.table.find_type(p.tok.lit) or { - // typ := p.table.types[p.tok.lit] - // if isnil(typ.name.str) || typ.name == '' { - p.error('undefined type `$p.tok.lit`') - exit(0) - } - p.next() - return typ -} +// pub fn (p mut Parser) parse_ti() types.Type { +// typ := p.table.find_type(p.tok.lit) or { +// // typ := p.table.types[p.tok.lit] +// // if isnil(typ.name.str) || typ.name == '' { +// p.error('undefined type `$p.tok.lit`') +// exit(0) +// } +// p.next() +// return typ +// } pub fn (p mut Parser) read_first_token() { // need to call next() twice to get peek token and current token @@ -157,7 +277,7 @@ pub fn (p mut Parser) stmt() ast.Stmt { p.error('wrong pub keyword usage') return ast.Stmt{} } - } + } // .key_const { // return p.const_decl() // } @@ -184,10 +304,10 @@ pub fn (p mut Parser) stmt() ast.Stmt { return p.for_statement() } else { - expr,typ := p.expr(0) + expr,ti := p.expr(0) return ast.ExprStmt{ expr: expr - typ: typ + ti: ti } } } @@ -233,11 +353,12 @@ pub fn (p &Parser) warn(s string) { } // Implementation of Pratt Precedence -pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { +pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) { // println('expr at ' + p.tok.str()) // null denotation (prefix) mut node := ast.Expr{} - mut typ := types.void_type + // mut typ := types.void_type + mut ti := types.new_base_ti(._void, 0) match p.tok.kind { .name { /* @@ -254,13 +375,13 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { } // fn call if p.peek_tok.kind == .lpar { - x,typ2 := p.call_expr() // TODO `node,typ :=` should work + x,ti2 := p.call_expr() // TODO `node,typ :=` should work node = x - typ = typ2 + ti = ti2 } // struct init else if p.peek_tok.kind == .lcbr { - typ = p.parse_type() + ti = p.parse_ti() // println('sturct init typ=$typ.name') p.check(.lcbr) mut field_names := []string @@ -275,7 +396,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { exprs << expr } node = ast.StructInit{ - typ: typ + ti: ti exprs: exprs fields: field_names } @@ -290,46 +411,46 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { p.error('unknown variable `$p.tok.lit`') exit(0) } - typ = var.typ + ti = var.ti // ///typ = types.int_type p.next() } } .lsbr { - node,typ = p.array_init() + node,ti = p.array_init() } .key_true, .key_false { node = ast.BoolLiteral{ val: p.tok.kind == .key_true } - typ = types.bool_type + ti = types.new_base_ti(._bool, 0) p.next() } .str { - node,typ = p.parse_string_literal() + node,ti = p.parse_string_literal() } .number { - node,typ = p.parse_number_literal() + node,ti = p.parse_number_literal() } .key_if { - node,typ = p.if_expr() + node,ti = p.if_expr() } .lpar { p.check(.lpar) p.next() - node,typ = p.expr(token.lowest_prec) + node,ti = p.expr(token.lowest_prec) p.check(.rpar) } else { if p.tok.is_unary() { pt := p.tok p.next() - expr,t2 := p.expr(token.lowest_prec) + expr,ti2 := p.expr(token.lowest_prec) node = ast.UnaryExpr{ left: expr op: pt.kind } - typ = t2 + ti = ti2 } else { p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind') @@ -340,30 +461,36 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { for rbp < p.tok.precedence() { prev_tok := p.tok p.next() - mut t2 := types.Type{} + // mut t2 := types.Type{} + mut ti2 := types.new_base_ti(._void, 0) // left denotation (infix / postfix) if prev_tok.is_right_assoc() && !p.tok.kind in [.plus, .minus] && // think of better way to handle this !p.peek_tok.kind in [.number, .name] { // supposed to be only unary, additive handled in left asssoc mut expr := ast.Expr{} - expr,t2 = p.expr(prev_tok.precedence() - 1) + expr,ti2 = p.expr(prev_tok.precedence() - 1) node = ast.BinaryExpr{ left: node op: prev_tok.kind right: expr } // println(t2.name + 'OOO') - if !types.check(&typ, &t2) { + if !types.check(&ti, &ti2) { println('tok: $prev_tok.str()') - p.error('cannot convert `$t2.name` to `$typ.name`') + p.error('cannot convert `$ti2.type_name` to `$ti.type_name`') } } else if prev_tok.is_left_assoc() { // postfix `.` if prev_tok.kind == .dot { - p.warn('dot prev_tok = $prev_tok.str() typ=$typ.name') + p.warn('dot prev_tok = $prev_tok.str() typ=$ti.type_name') // p.next() field := p.check_name() + if !ti.type_kind in [._placeholder, ._struct] { + println('kind: $ti.str()') + p.error('cannot access field, `$ti.type_name` is not a struct') + } + typ := p.table.types[ti.type_idx] as types.Struct mut ok := false for f in typ.fields { if f.name == field { @@ -388,14 +515,15 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { } else { mut expr := ast.Expr{} - expr,t2 = p.expr(prev_tok.precedence() - 1) + expr,ti2 = p.expr(prev_tok.precedence() - 1) if prev_tok.is_relational() { - typ = types.bool_type + // typ = types.bool_type + ti = types.new_base_ti(._bool, 0) } else { - typ = t2 + ti = ti2 } - // println(t2.name + '222') + // println(ti2.type_name + '222') node = ast.BinaryExpr{ left: node op: prev_tok.kind @@ -404,7 +532,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { } } } - return node,typ + return node,ti } [inline] @@ -432,8 +560,9 @@ fn (p mut Parser) for_statement() ast.ForStmt { } } // `for cond {` - cond,typ := p.expr(0) - if !types.check(types.bool_type, typ) { + cond,ti := p.expr(0) + // if !types.check(types.bool_type, ti) { + if ti.type_kind != ._bool { p.error('non-bool used as for condition') } stmts := p.parse_block() @@ -443,11 +572,12 @@ fn (p mut Parser) for_statement() ast.ForStmt { } } -fn (p mut Parser) if_expr() (ast.Expr,types.Type) { +fn (p mut Parser) if_expr() (ast.Expr,types.TypeIdent) { mut node := ast.Expr{} p.check(.key_if) cond,cond_type := p.expr(0) - if !types.check(types.bool_type, cond_type) { + // if !types.check(types.bool_type, cond_type) { + if cond_type.type_kind != ._bool { p.error('non-bool used as if condition') } stmts := p.parse_block() @@ -457,13 +587,14 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) { p.check(.key_else) else_stmts = p.parse_block() } - mut typ := types.void_type + // mut typ := types.void_type + mut ti := types.new_base_ti(._void, 0) // mut left := ast.Expr{} // If the last statement is an expression, return its type match stmts[stmts.len - 1] { ast.ExprStmt { - p.warn('if expr ret $it.typ.name') - typ = it.typ + p.warn('if expr ret $it.ti.type_name') + ti = it.ti // return node,it.typ // left = } @@ -473,35 +604,37 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) { cond: cond stmts: stmts else_stmts: else_stmts - typ: typ + ti: ti // left: left } - return node,typ + return node,ti } -fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) { +fn (p mut Parser) parse_string_literal() (ast.Expr,types.TypeIdent) { mut node := ast.Expr{} node = ast.StringLiteral{ val: p.tok.lit } p.next() - return node,types.string_type + // return node,types.string_type + return node, types.new_base_ti(._string, 0) } -fn (p mut Parser) array_init() (ast.Expr,types.Type) { +fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) { p.check(.lsbr) - mut val_type := types.void_type + // mut val_type := types.void_type + mut val_ti := types.new_base_ti(._void, 0) mut exprs := []ast.Expr mut i := 0 for p.tok.kind != .rsbr { - expr,typ := p.expr(0) + expr,ti := p.expr(0) // The first element's type if i == 0 { - val_type = typ + val_ti = ti } - else if !types.check(val_type, typ) { - p.error('expected array element with type `$val_type.name`') + else if !types.check(val_ti, ti) { + p.error('expected array element with type `$val_ti.type_name`') } exprs << expr i++ @@ -511,32 +644,32 @@ fn (p mut Parser) array_init() (ast.Expr,types.Type) { } mut node := ast.Expr{} node = ast.ArrayInit{ - typ: val_type + ti: val_ti exprs: exprs } p.check(.rsbr) - return node,val_type + return node,val_ti } -fn (p mut Parser) parse_number_literal() (ast.Expr,types.Type) { +fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) { lit := p.tok.lit mut node := ast.Expr{} - mut typ := types.int_type + mut ti := types.new_base_ti(._int, 0) if lit.contains('.') { node = ast.FloatLiteral{ // val: lit.f64() val: lit } - typ = types.f64_type + ti = types.new_base_ti(._f64, 0) } else { node = ast.IntegerLiteral{ val: lit.int() } - typ = types.int_type + // ti = types.new_base_ti(._int, 0) } p.next() - return node,typ + return node,ti } fn (p mut Parser) module_decl() ast.Module { @@ -569,18 +702,22 @@ fn (p mut Parser) struct_decl() ast.StructDecl { p.check(.colon) } field_name := p.check_name() - typ := p.parse_type() + ti := p.parse_ti() ast_fields << ast.Field{ name: field_name - typ: typ + ti: ti } fields << types.Field{ name: field_name - type_idx: typ.idx + type_idx: ti.type_idx } } p.check(.rcbr) - p.table.register_type(types.Type{ + if name in p.table.type_idxs { + println('placeholder exists: $name') + } + println('about to register: $name') + p.table.register_struct(types.Struct{ name: name fields: fields }) @@ -594,8 +731,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl { fn (p mut Parser) return_stmt() ast.Return { p.next() expr,t := p.expr(0) - if !types.check(p.return_type, t) { - p.error('cannot use `$t.name` as type `$p.return_type.name` in return argument') + if !types.check(p.return_ti, t) { + p.error('cannot use `$t.type_name` as type `$p.return_ti.type_name` in return argument') } return ast.Return{ expr: expr @@ -621,7 +758,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { } p.table.register_var(table.Var{ name: name - typ: t + ti: t is_mut: is_mut }) // println(p.table.names) @@ -630,7 +767,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { name: name expr: expr // p.expr(token.lowest_prec) - typ: t + ti: t } } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index fcdfd72e56..f901eae5b5 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -8,7 +8,9 @@ import ( pub struct Table { // struct_fields map[string][]string pub mut: - types map[string]types.Type + // types map[string]types.Type + types []types.Type + type_idxs map[string]int local_vars []Var // fns Hashmap fns map[string]Fn @@ -20,7 +22,7 @@ pub mut: pub struct Var { pub: name string - typ types.Type + ti types.TypeIdent is_mut bool } @@ -28,17 +30,23 @@ pub struct Fn { pub: name string args []Var - return_type types.Type + return_ti types.TypeIdent } pub fn new_table() &Table { + // mut t := &Table{} + // t.register_type(types.void_type) + // t.register_type(types.int_type) + // t.register_type(types.string_type) + // t.register_type(types.f64_type) + // t.register_type(types.bool_type) + // t.register_type(types.voidptr_type) mut t := &Table{} - t.register_type(types.void_type) - t.register_type(types.int_type) - t.register_type(types.string_type) - t.register_type(types.f64_type) - t.register_type(types.bool_type) - t.register_type(types.voidptr_type) + // add dummy type at 0 so nothing can go there + // save index check, 0 will mean not found + t.types << types.Type{} + t.type_idxs['dymmy_type_at_idx_0'] = 0 + return t } @@ -109,19 +117,106 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } -pub fn (t mut Table) register_type(typ types.Type) { - t.types[typ.name] = typ +pub fn (t mut Table) register_struct(typ types.Struct) int { + mut t2 := types.Type{} + // existing + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + ex_type := t.types[existing_idx] + match ex_type { + types.Placeholder { + // override placeholder + println('placeholder exists: $it.name overidding') + t2 = {typ| idx: existing_idx} + t.types[existing_idx] = t2 + return existing_idx + } + else {} + } + } + // register + println('registering: $typ.name') + idx := t.types.len + t.type_idxs[typ.name] = idx + t2 = {typ| idx: idx} + t.types << t2 + + return idx +} + +pub fn (t mut Table) find_or_register_map(typ types.Map) int { + // existing + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + return existing_idx + } + // register + idx := t.types.len + mut t2 := types.Type{} + t2 = {typ| idx: idx} + t.type_idxs[typ.name] = idx + t.types << t2 + return idx +} + +pub fn (t mut Table) find_or_register_array(typ types.Array) int { + // existing + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + return existing_idx + } + // register + idx := t.types.len + mut t2 := types.Type{} + t2 = {typ| idx: idx} + t.type_idxs[typ.name] = idx + t.types << t2 + return idx +} + +pub fn (t mut Table) find_or_register_array_fixed(typ types.ArrayFixed) int { + // existing + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + return existing_idx + } + // register + idx := t.types.len + mut t2 := types.Type{} + t2 = {typ| idx: idx} + t.type_idxs[typ.name] = idx + t.types << t2 + return idx +} + +[inline] +pub fn (t &Table) find_type_idx(name string) int { + return t.type_idxs[name] +} + +pub fn (t mut Table) add_placeholder_type(name string) int { + idx := t.types.len + t.type_idxs[name] = t.types.len + mut pt := types.Type{} + pt = types.Placeholder{ + idx: idx + name: name + } + println('added placeholder: $name - $idx ') + t.types << pt + return idx } pub fn (t &Table) find_type(name string) ?types.Type { - typ := t.types[name] - if isnil(typ.name.str) || typ.name == '' { - return none + idx := t.type_idxs[name] + if idx > 0 { + return t.types[idx] } - return typ + return none } pub fn (t mut Table) new_tmp_var() string { t.tmp_cnt++ return 'tmp$t.tmp_cnt' } + diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index 508179fb7f..29a0fef2c4 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -4,16 +4,208 @@ module types pub enum Kind { - struct_ - builtin - enum_ + _placeholder, + _void, + _voidptr, + _charptr, + _byteptr, + _const, + _enum, + _struct, + _int, + _i8, + _i16, + _i64, + _byte, + _u16, + _u32, + _u64, + _f32, + _f64, + _string, + _char, + _bool, + _array, + _array_fixed, + _map, + _multi_return, + _variadic } -pub struct Type { +pub struct TypeIdent { +pub: + type_idx int + type_kind Kind + type_name string + nr_muls int +} + +[inline] +pub fn new_ti(type_kind Kind, type_name string, type_idx int, nr_muls int) TypeIdent { + return TypeIdent{ + type_idx: type_idx + type_kind: type_kind + type_name: type_name + nr_muls: nr_muls + } +} + +[inline] +pub fn new_base_ti(type_kind Kind, nr_muls int) TypeIdent { + return TypeIdent{ + type_kind: type_kind + type_name: type_kind.str() + nr_muls: nr_muls + } +} + +[inline] +pub fn (ti &TypeIdent) is_ptr() bool { + return ti.nr_muls > 0 +} + +[inline] +pub fn (ti &TypeIdent) is_int() bool { + return ti.type_kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64] +} + +[inline] +pub fn (ti &TypeIdent) is_float() bool { + return ti.type_kind in [._f32, ._f64] +} + +[inline] +pub fn (ti &TypeIdent) is_number() bool { + return ti.is_int() || ti.is_float() +} + +pub fn (ti &TypeIdent) str() string { + return '$ti.type_kind.str() $ti.type_idx: $ti.type_name ($ti.nr_muls)' +} + +pub fn check(got, expected &TypeIdent) bool { + if got.type_idx != expected.type_idx { + return false + } + return true +} + +pub fn (t Kind) str() string { + t_str := match t { + ._placeholder { + 'placeholder' + } + ._void { + 'void' + } + ._voidptr { + 'voidptr' + } + ._charptr { + 'charptr' + } + ._byteptr { + 'byteptr' + } + ._const { + 'const' + } + ._enum { + 'enum' + } + ._struct { + 'struct' + } + ._int { + 'int' + } + ._i8 { + 'i8' + } + ._i16 { + 'i16' + } + ._i64 { + 'i64' + } + ._byte { + 'byte' + } + ._u16 { + 'u18' + } + ._f32 { + 'f32' + } + ._f64 { + 'f64' + } + ._string { + 'string' + } + ._char { + 'char' + } + ._bool { + 'bool' + } + ._array { + 'array' + } + ._array_fixed { + 'array_fixed' + } + ._map { + 'map' + } + ._multi_return { + 'multi_return' + } + ._variadic { + 'variadic' + } + else { + 'unknown' + } + } + return t_str +} + +pub type Type = Placeholder | Void | Voidptr | Charptr | Byteptr | Const | Enum | Struct | + Int | Float | String | Char | Byte | Bool | Array | ArrayFixed | Map | MultiReturn | Variadic + + +pub struct Placeholder { +pub: + idx int + name string + kind Kind +} + +pub struct Void {} + +pub struct Voidptr {} + +pub struct Charptr {} + +pub struct Byteptr {} + +pub struct Const { +pub: + idx int + name string +} + +pub struct Enum { +pub: + idx int + name string +} + +pub struct Struct { pub: - name string idx int - // kind Kind + name string fields []Field } @@ -23,36 +215,95 @@ pub: type_idx int } -pub const ( - void_type = Type{ - name: 'void' - idx: 0 - } - int_type = Type{ - name: 'int' - idx: 1 - } - string_type = Type{ - name: 'string' - idx: 2 - } - f64_type = Type{ - name: 'f64' - idx: 3 - } - bool_type = Type{ - name: 'bool' - idx: 4 - } - voidptr_type = Type{ - name: 'voidptr' - idx: 5 - } -) - -pub fn check(got, expected &Type) bool { - if got.idx != expected.idx { - return false - } - return true +pub struct Int { +pub: + bit_size u32 + is_unsigned bool } + +pub struct Float { + bit_size u32 +} + +pub struct String {} + +pub struct Char {} + +pub struct Byte {} + +pub struct Bool {} + +pub struct Array { +pub: + idx int + name string + elem_type_kind Kind + elem_type_idx int + nr_dims int +} + +pub struct ArrayFixed { +pub: + idx int + name string + elem_type_kind Kind + elem_type_idx int + size int +} + +pub struct Map { +pub: + idx int + name string + key_type_kind Kind + key_type_idx int + value_type_kind Kind + value_type_idx int +} + +pub struct MultiReturn { +pub: + elem_type_kinds []Kind + elem_type_idxs []int +} + +pub struct Variadic { +pub: + elem_type_kind Kind + elem_type_idx int +} + +pub fn (t Void) str() string { return 'void' } +pub fn (t Voidptr) str() string { return 'voidptr' } +pub fn (t Charptr) str() string { return 'charptr' } +pub fn (t Byteptr) str() string { return 'Byteptr' } +pub fn (t Const) str() string { return t.name } +pub fn (t Enum) str() string { return t.name } +pub fn (t Struct) str() string { return t.name } +pub fn (t Int) str() string { return if t.is_unsigned {'u$t.bit_size' } else { 'i$t.bit_size' } } +pub fn (t Float) str() string { return 'f$t.bit_size' } +pub fn (t String) str() string { return 'string' } +pub fn (t Char) str() string { return 'char' } +pub fn (t Byte) str() string { return 'byte' } +pub fn (t Array) str() string { return t.name } +pub fn (t ArrayFixed) str() string { return t.name } +pub fn (t Map) str() string { return t.name } +pub fn (t MultiReturn) str() string { return 'multi_return_$t.elem_type_kinds.str()' } +pub fn (t Variadic) str() string { return 'variadic_$t.elem_type_kind.str()' } + +pub const ( + void_type = Void{} + voidptr_type = Voidptr{} + charptr_type = Charptr{} + byteptr_type = Byteptr{} + int_type = Int{32, false} + i64_type = Int{64, false} + byte_type = Int{8, true} + u32_type = Int{32, true} + u64_type = Int{64, true} + f32_type = Float{32} + f64_type = Float{64} + string_type = String{} + char_type = Char{} + bool_type = Bool{} +) diff --git a/vlib/v/types/types_test.v b/vlib/v/types/types_test.v new file mode 100644 index 0000000000..93a62492b4 --- /dev/null +++ b/vlib/v/types/types_test.v @@ -0,0 +1,5 @@ +module types + +fn test_types() { + +}