From b815878d60e848d3c75eb3f6a30bbf1b2c231c99 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 6 Jan 2020 16:13:12 +0100 Subject: [PATCH] simplify and improve pratt --- vlib/compiler/tests/type_test.v | 2 +- vlib/v/ast/ast.v | 52 +-- vlib/v/gen/cgen.v | 43 ++- vlib/v/gen/cgen_test.v | 2 +- vlib/v/gen/jsgen.v | 10 +- vlib/v/gen/tests/1.c | 7 +- vlib/v/gen/tests/1.vv | 14 +- vlib/v/gen/tests/3.c | 13 + vlib/v/gen/tests/3.vv | 11 + vlib/v/gen/x64/gen.v | 8 +- vlib/v/parser/a_type.v | 162 ++++++++++ vlib/v/parser/fn.v | 17 +- vlib/v/parser/parser.v | 546 +++++++++++++------------------- vlib/v/parser/parser_test.v | 66 +++- vlib/v/table/table.v | 107 +------ vlib/v/table/type.v | 183 +++++++++++ vlib/v/token/token.v | 66 +++- vlib/v/types/types.v | 70 ++-- 18 files changed, 861 insertions(+), 518 deletions(-) create mode 100644 vlib/v/gen/tests/3.c create mode 100644 vlib/v/gen/tests/3.vv create mode 100644 vlib/v/parser/a_type.v create mode 100644 vlib/v/table/type.v diff --git a/vlib/compiler/tests/type_test.v b/vlib/compiler/tests/type_test.v index cb81dda236..fc14fe6ef7 100644 --- a/vlib/compiler/tests/type_test.v +++ b/vlib/compiler/tests/type_test.v @@ -38,7 +38,7 @@ fn expr1() Expr { //return BinExpr{} } -fn expr2() Expr { +fn expr() Expr { return BinExpr{} } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 8d94262f7a..eab7ae1b45 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -8,11 +8,12 @@ import ( v.types ) -pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | -FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr +pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | +FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr -pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | +pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | ForStmt | StructDecl +// | IncDecStmt k // Stand-alone expression in a statement list. pub struct ExprStmt { pub: @@ -71,8 +72,8 @@ pub: pub struct StructInit { pub: - ti types.TypeIdent - // typ types.Type + // typ types.TypeIdent + ti types.TypeIdent fields []string exprs []Expr } @@ -80,26 +81,23 @@ pub: // import statement pub struct Import { pub: - mods []string + mods map[string]string // alias -> module // expr Expr - // imports map[string]string } pub struct Arg { pub: ti types.TypeIdent - // typ types.Type name string } pub struct FnDecl { pub: - name string - stmts []Stmt - ti types.TypeIdent - // typ types.Type - args []Arg - is_pub bool + name string + stmts []Stmt + ti types.TypeIdent + args []Arg + is_pub bool receiver Field } @@ -137,7 +135,6 @@ pub: name string expr Expr ti types.TypeIdent - // typ types.Type } pub struct File { @@ -159,9 +156,9 @@ pub: // op BinaryOp op token.Kind left Expr - // left_type Type + // left_ti types.TypeIdent right Expr - // right_type Type + // right_ti types.TypeIdent } pub struct UnaryExpr { @@ -172,6 +169,18 @@ pub: left Expr } +pub struct PostfixExpr { +pub: + op token.Kind + expr Expr +} + +pub struct PrefixExpr { +pub: + op token.Kind + right Expr +} + pub struct IfExpr { pub: tok_kind token.Kind @@ -179,7 +188,6 @@ pub: stmts []Stmt else_stmts []Stmt ti types.TypeIdent - // typ types.Type left Expr // `a` in `a := if ...` } @@ -202,11 +210,17 @@ pub: op token.Kind } +pub struct AssignExpr { +pub: + left Expr + val Expr + op token.Kind +} + pub struct ArrayInit { pub: exprs []Expr 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 b78d3a4b63..6a89f76f46 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -14,6 +14,7 @@ struct Gen { } pub fn cgen(files []ast.File, table &table.Table) string { + println('start cgen') mut g := Gen{ out: strings.new_builder(100) definitions: strings.new_builder(100) @@ -39,25 +40,32 @@ pub fn (g mut Gen) writeln(s string) { } fn (g mut Gen) stmt(node ast.Stmt) { + // println('cgen.stmt()') + // g.writeln('//// stmt start') match node { + ast.Import { + + } + /* ast.AssignStmt { g.expr(it.left) g.write(' $it.op.str() ') g.expr(it.right) g.writeln(';') } + */ ast.FnDecl { is_main := it.name == 'main' if is_main { g.write('int ${it.name}(') } else { - g.write('$it.ti.type_name ${it.name}(') - g.definitions.write('$it.ti.type_name ${it.name}(') + g.write('$it.ti.name ${it.name}(') + g.definitions.write('$it.ti.name ${it.name}(') } for arg in it.args { - g.write(arg.ti.type_name + ' ' + arg.name) - g.definitions.write(arg.ti.type_name + ' ' + arg.name) + g.write(arg.ti.name + ' ' + arg.name) + g.definitions.write(arg.ti.name + ' ' + arg.name) } g.writeln(') { ') if !is_main { @@ -77,7 +85,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('$it.ti.type_name $it.name = ') + g.write('$it.ti.name $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -97,7 +105,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.StructDecl { g.writeln('typedef struct {') for field in it.fields { - g.writeln('\t$field.ti.type_name $field.name;') + g.writeln('\t$field.ti.name $field.name;') } g.writeln('} $it.name;') } @@ -120,12 +128,21 @@ fn (g mut Gen) stmt(node ast.Stmt) { fn (g mut Gen) expr(node ast.Expr) { // println('cgen expr()') match node { + ast.AssignExpr { + g.expr(it.left) + g.write(' $it.op.str() ') + g.expr(it.val) + } ast.IntegerLiteral { g.write(it.val.str()) } ast.FloatLiteral { g.write(it.val) } + ast.PostfixExpr { + g.expr(it.expr) + g.write(it.op.str()) + } ast.UnaryExpr { // probably not :D if it.op in [.inc, .dec] { @@ -140,6 +157,10 @@ fn (g mut Gen) expr(node ast.Expr) { ast.StringLiteral { g.write('tos3("$it.val")') } + ast.PrefixExpr { + g.write(it.op.str()) + g.expr(it.right) + } ast.BinaryExpr { g.expr(it.left) if it.op == .dot { @@ -153,7 +174,7 @@ fn (g mut Gen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('($it.ti.type_name){') + g.writeln('($it.ti.name){') for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) @@ -172,7 +193,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.ti.type_name), {\t') + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.name), {\t') for expr in it.exprs { g.expr(expr) g.write(', ') @@ -199,16 +220,16 @@ 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.ti.type_kind != ._void { + if it.ti.kind != ._void { tmp = g.table.new_tmp_var() - // g.writeln('$it.typ.name $tmp;') + // g.writeln('$it.ti.name $tmp;') } g.write('if (') g.expr(it.cond) g.writeln(') {') for i, stmt in it.stmts { // Assign ret value - if i == it.stmts.len - 1 && it.ti.type_kind != ._void { + if i == it.stmts.len - 1 && it.ti.kind != ._void { // g.writeln('$tmp =') println(1) } diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index e9959fcc58..e55842a8a0 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -9,7 +9,7 @@ import ( ) const ( - nr_tests = 2 + nr_tests = 3 ) fn test_c_files() { diff --git a/vlib/v/gen/jsgen.v b/vlib/v/gen/jsgen.v index 4873ac66cd..167cfc25de 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.ti.type_name } **/\nfunction ${it.name}(') + g.write('/** @return { $it.ti.name } **/\nfunction ${it.name}(') for arg in it.args { - g.write(' /** @type { arg.ti.type_name } **/ $arg.name') + g.write(' /** @type { arg.ti.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.ti.type_name */ $it.name = ') + g.write('var /* $it.ti.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.ti.type_name $field.name;') + // g.writeln('\t$field.ti.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.ti.type_name*/{') + g.writeln('/*$it.ti.name*/{') for i, field in it.fields { g.write('\t$field : ') g.expr(it.exprs[i]) diff --git a/vlib/v/gen/tests/1.c b/vlib/v/gen/tests/1.c index 44e94c7a91..0c2a38340c 100644 --- a/vlib/v/gen/tests/1.c +++ b/vlib/v/gen/tests/1.c @@ -10,9 +10,10 @@ typedef struct { int main() { int a = 10; a++; -int c = -a; +int negative = -a; a == 1; foo(3); +int ak = 10; return 0; } @@ -37,4 +38,8 @@ void myuser() { int boo = 2; int boo2 = boo + 1; bool b = age > 0; + bool b2 = user.age > 0; +} + +void variadic(variadic_int a) { } diff --git a/vlib/v/gen/tests/1.vv b/vlib/v/gen/tests/1.vv index d4d2c1a955..4c16cee197 100644 --- a/vlib/v/gen/tests/1.vv +++ b/vlib/v/gen/tests/1.vv @@ -1,13 +1,19 @@ +import moda +import modb as mb + struct User { age int } +// lol fn main() { a := 10 a++ - c := -a + negative := -a a == 1 foo(3) + ak := 10 +} /* user := User{} user.age = 10 @@ -16,7 +22,6 @@ fn main() { } */ -} fn foo(a int) { n := get_int2() @@ -37,5 +42,8 @@ fn myuser() { boo := 2 boo2 := boo+1 b := age > 0 - //b2 := user.age > 0 + b2 := user.age > 0 +} + +fn variadic(a ...int) { } diff --git a/vlib/v/gen/tests/3.c b/vlib/v/gen/tests/3.c new file mode 100644 index 0000000000..0d00389255 --- /dev/null +++ b/vlib/v/gen/tests/3.c @@ -0,0 +1,13 @@ +typedef struct { + int age; + string name; +} User; + +int main() { + User user = (User){ +}; + user.age = 10; + user.age++; + user.name = tos3("bob"); + return 0; +} diff --git a/vlib/v/gen/tests/3.vv b/vlib/v/gen/tests/3.vv new file mode 100644 index 0000000000..ede302921b --- /dev/null +++ b/vlib/v/gen/tests/3.vv @@ -0,0 +1,11 @@ +struct User { + age int + name string +} + +fn main() { + user := User{} + user.age = 10 + user.age++ + user.name = 'bob' +} diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index 569e741ff5..f80b9b9fdd 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.ti.type_name $it.name = ') + g.write('$it.ti.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.ti.type_name $field.name;') + g.writeln('\t$field.ti.name $field.name;') } g.writeln('} $it.name;') } @@ -400,7 +400,7 @@ fn (g mut Gen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('($it.ti.type_name){') + g.writeln('($it.ti.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.ti.type_name), {\t') + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.name), {\t') for expr in it.exprs { g.expr(expr) g.write(', ') diff --git a/vlib/v/parser/a_type.v b/vlib/v/parser/a_type.v new file mode 100644 index 0000000000..d737d6ef40 --- /dev/null +++ b/vlib/v/parser/a_type.v @@ -0,0 +1,162 @@ +module parser + +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +import v.types + +pub fn (p mut Parser) parse_array_ti(nr_muls int) types.TypeIdent { + p.check(.lsbr) + // fixed array + if p.tok.kind == .number { + size := p.tok.lit.int() + p.check(.rsbr) + elem_ti := p.parse_ti() + idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1) + return types.new_ti(._array_fixed, name, idx, nr_muls) + } + // array + elem_ti := p.parse_ti() + mut nr_dims := 1 + for p.tok.kind == .lsbr { + p.check(.lsbr) + p.next() + nr_dims++ + } + p.check(.rsbr) + idx,name := p.table.find_or_register_array(&elem_ti, nr_dims) + return types.new_ti(._array, name, idx, nr_muls) +} + +pub fn (p mut Parser) parse_map_ti(nr_muls int) types.TypeIdent { + p.next() + p.check(.lsbr) + key_ti := p.parse_ti() + p.check(.rsbr) + value_ti := p.parse_ti() + idx,name := p.table.find_or_register_map(&key_ti, &value_ti) + return types.new_ti(._map, name, idx, nr_muls) +} + +pub fn (p mut Parser) parse_multi_return_ti() types.TypeIdent { + p.check(.lpar) + mut mr_tis := []&types.TypeIdent + for { + mr_ti := p.parse_ti() + mr_tis << &mr_ti + if p.tok.kind == .comma { + p.check(.comma) + } + else { + break + } + } + p.check(.rpar) + idx,name := p.table.find_or_register_multi_return(mr_tis) + return types.new_ti(._multi_return, name, idx, 0) +} + +pub fn (p mut Parser) parse_variadic_ti() types.TypeIdent { + p.check(.ellipsis) + variadic_ti := p.parse_ti() + idx,name := p.table.find_or_register_variadic(&variadic_ti) + return types.new_ti(._variadic, name, idx, 0) +} + +pub fn (p mut Parser) parse_ti() types.TypeIdent { + mut nr_muls := 0 + for p.tok.kind == .amp { + p.check(.amp) + nr_muls++ + } + name := p.tok.lit + match p.tok.kind { + // array + .lsbr { + return p.parse_array_ti(nr_muls) + } + // multiple return + .lpar { + if nr_muls > 0 { + p.error('parse_ti: unexpected `&` before multiple returns') + } + return p.parse_multi_return_ti() + } + // variadic + .ellipsis { + if nr_muls > 0 { + p.error('parse_ti: unexpected `&` before variadic') + } + return p.parse_variadic_ti() + } + else { + defer { + p.next() + } + match name { + // map + 'map' { + return p.parse_map_ti(nr_muls) + } + '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) + } + 'i8' { + return types.new_base_ti(._i8, nr_muls) + } + 'i16' { + 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) + } + // struct / enum / placeholder + 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) + } + } + } + } +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index c5ab8164cc..6e492d5a67 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -15,14 +15,15 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) { fn_name := p.check_name() p.check(.lpar) mut is_unknown := false + is_unknown = false mut args := []ast.Expr - mut return_ti := types.new_base_ti(._void, 0) + mut return_ti := types.void_ti if f := p.table.find_fn(fn_name) { return_ti = f.return_ti for i, arg in f.args { 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`') + if !types.check(&arg.ti, &ti) { + p.error('cannot use type `$ti.name` as type `$arg.ti.name` in argument to `$fn_name`') } args << e if i < f.args.len - 1 { @@ -49,7 +50,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) { args: args is_unknown: is_unknown tok: tok - // typ: return_type + // typ: return_ti } if is_unknown { @@ -67,7 +68,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { p.check(.key_fn) // Receiver? mut rec_name := '' - mut rec_ti := types.new_base_ti(._void, 0) + mut rec_ti := types.void_ti if p.tok.kind == .lpar { p.next() rec_name = p.check_name() @@ -113,8 +114,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } p.check(.rpar) // Return type - mut ti := types.new_base_ti(._void, 0) - if p.tok.kind in [.amp, .name] { + mut ti := types.void_ti + if p.tok.kind == .name { ti = p.parse_ti() p.return_ti = ti } @@ -145,7 +146,7 @@ pub fn (p &Parser) check_fn_calls() { return } println(f.name) - // println(f.return_type.name) + // println(f.return_ti.name) // println('IN AST typ=' + call.typ.name) } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 3a63ba39d1..d11b2bb57f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -13,16 +13,24 @@ import ( os ) +type PrefixParseFn fn()ast.Expr + +type InfixParseFn fn(e ast.Expr)ast.Expr + +type PostfixParseFn fn()ast.Expr + struct Parser { - scanner &scanner.Scanner - file_name string + scanner &scanner.Scanner + file_name string mut: - tok token.Token - peek_tok token.Token + tok token.Token + peek_tok token.Token // vars []string - table &table.Table - return_ti types.TypeIdent - is_c bool + table &table.Table + return_ti types.TypeIdent + is_c bool + // + prefix_parse_fns []PrefixParseFn } pub fn parse_stmt(text string, table &table.Table) ast.Stmt { @@ -31,135 +39,13 @@ pub fn parse_stmt(text string, table &table.Table) ast.Stmt { scanner: s table: table } + p.init_parse_fns() p.read_first_token() 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 - elem_is_ptr: elem_ti.is_ptr() - } - 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 - elem_is_ptr: elem_ti.is_ptr() - } - 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.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) - // } - // println('RET Typ $typ.name') - } - } -} - pub fn parse_file(path string, table &table.Table) ast.File { - println('parse file "$path"') + println('parse_file("$path")') text := os.read_file(path) or { panic(err) } @@ -173,12 +59,11 @@ pub fn parse_file(path string, table &table.Table) ast.File { for { // res := s.scan() if p.tok.kind == .eof { + println('EOF, breaking') break } - // println('expr at ' + p.tok.str()) - s := p.stmt() - // println(s) - stmts << s // p.stmt() + // println('stmt at ' + p.tok.str()) + stmts << p.top_stmt() } p.check_fn_calls() // println('nr stmts = $stmts.len') @@ -196,6 +81,11 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File { return files } +pub fn (p mut Parser) init_parse_fns() { + p.prefix_parse_fns = make(100, 100, sizeof(PrefixParseFn)) + // p.prefix_parse_fns[token.Kind.name] = parse_name +} + pub fn (p mut Parser) read_first_token() { // need to call next() twice to get peek token and current token p.next() @@ -205,13 +95,14 @@ pub fn (p mut Parser) read_first_token() { pub fn (p mut Parser) parse_block() []ast.Stmt { p.check(.lcbr) mut stmts := []ast.Stmt - for { - // res := s.scan() - if p.tok.kind in [.eof, .rcbr] { - break + if p.tok.kind != .rcbr { + for { + stmts << p.stmt() + // p.warn('after stmt(): tok=$p.tok.str()') + if p.tok.kind in [.eof, .rcbr] { + break + } } - // println('expr at ' + p.tok.str()) - stmts << p.stmt() } p.check(.rcbr) // println('nr exprs in block = $exprs.len') @@ -238,17 +129,7 @@ fn (p mut Parser) check_name() string { return name } -pub fn (p mut Parser) stmt() ast.Stmt { - // println('stmt at ' + p.tok.str()) - // `x := ...` - if p.tok.kind == .name { - if p.peek_tok.kind == .decl_assign { - return p.var_decl() - } - else if p.peek_tok.is_assign() { - return p.assign_stmt() - } - } +pub fn (p mut Parser) top_stmt() ast.Stmt { match p.tok.kind { .key_module { return p.module_decl() @@ -285,16 +166,30 @@ pub fn (p mut Parser) stmt() ast.Stmt { .key_struct { return p.struct_decl() } - .key_return { - return p.return_stmt() + else { + p.error('bad top level statement') + return ast.Module{} // silence C warning + // exit(0) } + } +} + +pub fn (p mut Parser) stmt() ast.Stmt { + match p.tok.kind { .key_mut { return p.var_decl() } .key_for { return p.for_statement() } + .key_return { + return p.return_stmt() + } else { + // `x := ...` + if p.tok.kind == .name && p.peek_tok.kind == .decl_assign { + return p.var_decl() + } expr,ti := p.expr(0) return ast.ExprStmt{ expr: expr @@ -304,11 +199,24 @@ pub fn (p mut Parser) stmt() ast.Stmt { } } +pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr { + op := p.tok.kind + p.next() + val,_ := p.expr(0) + node := ast.AssignExpr{ + left: left + op: op + val: val + } + return node +} + +/* pub fn (p mut Parser) assign_stmt() ast.AssignStmt { name := p.tok.lit // println('looking for $name') var := p.table.find_var(name) or { - p.error('unknown variable `$name`') + p.error('assign unknown variable `$name`') exit(1) } if !var.is_mut { @@ -328,6 +236,8 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { op: op } } +*/ + pub fn (p &Parser) error(s string) { println(term.bold(term.red('$p.file_name:$p.tok.line_nr: $s'))) @@ -343,138 +253,137 @@ pub fn (p &Parser) warn(s string) { println(term.blue('$p.file_name:$p.tok.line_nr: $s')) } -// Implementation of Pratt Precedence -pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) { - // println('expr at ' + p.tok.str()) - // null denotation (prefix) +pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) { mut node := ast.Expr{} - // mut typ := types.void_type - mut ti := types.new_base_ti(._void, 0) + mut ti := types.void_ti + // fn call + if p.peek_tok.kind == .lpar { + x,ti2 := p.call_expr() // TODO `node,typ :=` should work + node = x + ti = ti2 + } + // struct init + else if p.peek_tok.kind == .lcbr { + ti = p.parse_ti() + // println('sturct init ti=$ti.name') + p.check(.lcbr) + mut field_names := []string + mut exprs := []ast.Expr + for p.tok.kind != .rcbr { + field_name := p.check_name() + field_names << field_name + p.check(.colon) + // expr,field_type := p.expr(0) + expr,_ := p.expr(0) + // if !types.check( ,field_type + exprs << expr + } + node = ast.StructInit{ + ti: ti + exprs: exprs + fields: field_names + } + p.check(.rcbr) + } + else { + // p.warn('name ') + // left := p.parse_ident() + node = ast.Ident{ + name: p.tok.lit + } + var := p.table.find_var(p.tok.lit) or { + p.error('name expr unknown variable `$p.tok.lit`') + exit(0) + } + ti = var.ti + p.next() + } + return node,ti +} + +pub fn (p mut Parser) expr(precedence int) (ast.Expr,types.TypeIdent) { + mut ti := types.void_ti + mut node := ast.Expr{} + // Prefix match p.tok.kind { .name { - /* - sym := p.table.find_symbol(p.tok.lit) - if sym.cat == .function { - return - } - */ - if p.tok.lit == 'C' { - p.is_c = true - println('is c') - p.next() - p.check(.dot) - } - // fn call - if p.peek_tok.kind == .lpar { - x,ti2 := p.call_expr() // TODO `node,typ :=` should work - node = x - ti = ti2 - } - // struct init - else if p.peek_tok.kind == .lcbr { - ti = p.parse_ti() - // println('sturct init typ=$typ.name') - p.check(.lcbr) - mut field_names := []string - mut exprs := []ast.Expr - for p.tok.kind != .rcbr { - field_name := p.check_name() - field_names << field_name - p.check(.colon) - // expr,field_type := p.expr(0) - expr,_ := p.expr(0) - // if !types.check( ,field_type - exprs << expr - } - node = ast.StructInit{ - ti: ti - exprs: exprs - fields: field_names - } - p.check(.rcbr) - } - else { - // name expr - node = ast.Ident{ - name: p.tok.lit - } - var := p.table.find_var(p.tok.lit) or { - p.error('unknown variable `$p.tok.lit`') - exit(0) - } - ti = var.ti - // ///typ = types.int_type - p.next() - } + node,ti = p.name_expr() } - .lsbr { - node,ti = p.array_init() + .str { + node,ti = p.parse_string_literal() + } + // -1, -a etc + .minus { + node,ti = p.prefix_expr() } .key_true, .key_false { node = ast.BoolLiteral{ val: p.tok.kind == .key_true } - ti = types.new_base_ti(._bool, 0) + ti = types.bool_ti p.next() } - .str { - node,ti = p.parse_string_literal() - } .number { node,ti = p.parse_number_literal() } - .key_if { - node,ti = p.if_expr() - } .lpar { p.check(.lpar) p.next() - node,ti = p.expr(token.lowest_prec) + node,ti = p.expr(0) p.check(.rpar) } + .key_if { + node,ti = p.if_expr() + } + .lsbr { + node,ti = p.array_init() + } else { - if p.tok.is_unary() { - pt := p.tok - p.next() - expr,ti2 := p.expr(token.lowest_prec) - node = ast.UnaryExpr{ - left: expr - op: pt.kind - } - ti = ti2 - } - else { - p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind') - } + p.error('expr(): bad token `$p.tok.str()`') } } - // left binding power - for rbp < p.tok.precedence() { - prev_tok := p.tok - p.next() - // 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,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(&ti, &ti2) { - println('tok: $prev_tok.str()') - p.error('cannot convert `$ti2.type_name` to `$ti.type_name`') - } + // Infix + for precedence < p.tok.precedence() { + if p.tok.kind.is_assign() { + node = p.assign_expr(node) } - else if prev_tok.is_left_assoc() { - // postfix `.` - if prev_tok.kind == .dot { - p.warn('dot prev_tok = $prev_tok.str() typ=$ti.type_name') + else if p.tok.kind == .dot { + node,ti = p.dot_expr(node) + } + else if p.tok.kind.is_infix() { + node,ti = p.infix_expr(node) + } + else if p.tok.kind in [.inc, .dec] { + node = ast.PostfixExpr{ + op: p.tok.kind + expr: node + } + p.next() + return node,ti + } + else { + return node,ti + } + } + return node,ti +} + +fn (p mut Parser) prefix_expr() (ast.Expr,types.TypeIdent) { + op := p.tok.kind + p.next() + right,ti := p.expr(1) + mut expr := ast.Expr{} + expr = ast.PrefixExpr{ + op: op + right: right + } + return expr,ti +} + +fn (p mut Parser) dot_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { + p.next() + field_name := p.check_name() + /* // p.next() field := p.check_name() if !ti.type_kind in [._placeholder, ._struct] { @@ -491,41 +400,36 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) { if !ok { p.error('unknown field `${typ.name}.$field`') } - node = ast.SelectorExpr{ - expr: node - field: field - } - // return node,typ - } - // postfix (`++` | `--`) - else if prev_tok.kind in [.inc, .dec] { - node = ast.UnaryExpr{ - left: node - op: prev_tok.kind - } - } - else { - mut expr := ast.Expr{} - expr,ti2 = p.expr(prev_tok.precedence() - 1) - if prev_tok.is_relational() { - // typ = types.bool_type - ti = types.new_base_ti(._bool, 0) - } - else { - ti = ti2 - } - // println(ti2.type_name + '222') - node = ast.BinaryExpr{ - left: node - op: prev_tok.kind - right: expr - } - } - } + */ + + mut node := ast.Expr{} + node = ast.SelectorExpr{ + expr: left + field: field_name } - return node,ti + return node,types.int_ti } +fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { + op := p.tok.kind + // mut typ := p. + // println('infix op=$op.str()') + precedence := p.tok.precedence() + p.next() + right,mut ti := p.expr(precedence) + if op.is_relational() { + ti = types.bool_ti + } + mut expr := ast.Expr{} + expr = ast.BinaryExpr{ + op: op + left: left + right: right + } + return expr,ti +} + +// Implementation of Pratt Precedence [inline] fn (p &Parser) is_addative() bool { return p.tok.kind in [.plus, .minus] && p.peek_tok.kind in [.number, .name] @@ -552,8 +456,7 @@ fn (p mut Parser) for_statement() ast.ForStmt { } // `for cond {` cond,ti := p.expr(0) - // if !types.check(types.bool_type, ti) { - if ti.type_kind != ._bool { + if !types.check(types.bool_ti, ti) { p.error('non-bool used as for condition') } stmts := p.parse_block() @@ -566,27 +469,25 @@ fn (p mut Parser) for_statement() ast.ForStmt { 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 cond_type.type_kind != ._bool { + cond,cond_ti := p.expr(0) + // if !types.check(types.bool_ti, cond_ti) { + if cond_ti.kind != ._bool { p.error('non-bool used as if condition') } stmts := p.parse_block() mut else_stmts := []ast.Stmt if p.tok.kind == .key_else { - // println('GOT ELSE') p.check(.key_else) else_stmts = p.parse_block() } - // mut typ := types.void_type - mut ti := types.new_base_ti(._void, 0) + mut ti := types.void_ti // 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.ti.type_name') + p.warn('if expr ret $it.ti.name') ti = it.ti - // return node,it.typ + // return node,it.ti // left = } else {} @@ -608,14 +509,12 @@ fn (p mut Parser) parse_string_literal() (ast.Expr,types.TypeIdent) { val: p.tok.lit } p.next() - // return node,types.string_type - return node, types.new_base_ti(._string, 0) + return node,types.string_ti } fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) { p.check(.lsbr) - // mut val_type := types.void_type - mut val_ti := types.new_base_ti(._void, 0) + mut val_ti := types.void_ti mut exprs := []ast.Expr mut i := 0 for p.tok.kind != .rsbr { @@ -625,7 +524,7 @@ fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) { val_ti = ti } else if !types.check(val_ti, ti) { - p.error('expected array element with type `$val_ti.type_name`') + p.error('expected array element with type `$val_ti.name`') } exprs << expr i++ @@ -672,8 +571,15 @@ fn (p mut Parser) module_decl() ast.Module { fn (p mut Parser) import_stmt() ast.Import { p.check(.key_import) name := p.check_name() + mut alias := name + if p.tok.kind == .key_as { + p.check(.key_as) + alias = p.check_name() + } + mut mods := map[string]string + mods[alias] = name return ast.Import{ - mods: [name] + mods: mods } } @@ -700,14 +606,10 @@ fn (p mut Parser) struct_decl() ast.StructDecl { } fields << types.Field{ name: field_name - type_idx: ti.type_idx + type_idx: ti.idx } } p.check(.rcbr) - 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 @@ -723,7 +625,7 @@ fn (p mut Parser) return_stmt() ast.Return { p.next() expr,t := p.expr(0) if !types.check(p.return_ti, t) { - p.error('cannot use `$t.type_name` as type `$p.return_ti.type_name` in return argument') + p.error('cannot use `$t.name` as type `$p.return_ti.name` in return argument') } return ast.Return{ expr: expr @@ -743,22 +645,22 @@ fn (p mut Parser) var_decl() ast.VarDecl { } name := p.tok.lit p.read_first_token() - expr,t := p.expr(token.lowest_prec) + expr,ti := p.expr(token.lowest_prec) if _ := p.table.find_var(name) { p.error('redefinition of `$name`') } p.table.register_var(table.Var{ name: name - ti: t + ti: ti is_mut: is_mut }) // println(p.table.names) - // println('added $name') + // println('added var `$name` with type $t.name') return ast.VarDecl{ name: name expr: expr // p.expr(token.lowest_prec) - ti: t + ti: ti } } diff --git a/vlib/v/parser/parser_test.v b/vlib/v/parser/parser_test.v index 20ab4e3031..2a016ce975 100644 --- a/vlib/v/parser/parser_test.v +++ b/vlib/v/parser/parser_test.v @@ -4,6 +4,7 @@ import ( v.ast v.gen v.table + term ) fn test_parse_file() { @@ -27,23 +28,58 @@ x := 10 println(res) } -fn test_parse_expr() { - input := [ +fn test_one() { + println('\n\ntest_one()') + input := ['a := 10', + // 'a = 20', + 'b := -a', + 'c := 20', // + ] + expected := 'int a = 10;int b = -a;int c = 20;' + table := &table.Table{} + mut e := []ast.Stmt + for line in input { + e << parse_stmt(line, table) + } + program := ast.File{ + stmts: e + } + res := gen.cgen([program], table).replace('\n', '').trim_space() + ok := expected == res + println(res) + assert ok + if !ok {} + // exit(0) +} + +fn test_parse_expr() { + input := ['1 == 1', + '2 * 8 + 3', + 'a := 3', + 'a++', + 'b := 4 + 2', + 'neg := -a', + 'a + a', + 'bo := 2 + 3 == 5', + '2 + 1', 'q := 1', 'q + 777', '2 + 3', '2+2*4', // '(2+2)*4', 'x := 10', - 'mut a := 12', + 'mut aa := 12', 'ab := 10 + 3 * 9', 's := "hi"', // '1 += 2', + 'x = 11', 'a += 10', '1.2 + 3.4', '4 + 4', '1 + 2 * 5', + '-a', + /* /* '(2 * 3) / 2', '3 + (7 * 6)', @@ -52,28 +88,39 @@ fn test_parse_expr() { '(2) + (17*2-30) * (5)+2 - (8/2)*4', // 8 //'2 + "hi"', */ + */ ] - expecting := [ - // + expecting := ['1 == 1;', + '2 * 8 + 3;', + 'int a = 3;', + 'a++;', + 'int b = 4 + 2;', + 'int neg = -a;', + 'a + a;', + 'bool bo = 2 + 3 == 5;', + '2 + 1;', 'int q = 1;', 'q + 777;', '2 + 3;', '2 + 2 * 4;', // '(2 + 2) * 4', 'int x = 10;', - 'int a = 12;', + 'int aa = 12;', 'int ab = 10 + 3 * 9;', 'string s = tos3("hi");', // '1 += 2;', + 'x = 11;', 'a += 10;', '1.2 + 3.4;', '4 + 4;', '1 + 2 * 5;', + '-a;', ] mut e := []ast.Stmt table := &table.Table{} for s in input { + // println('\n\nst="$s"') e << parse_stmt(s, table) } program := ast.File{ @@ -89,8 +136,13 @@ fn test_parse_expr() { if line == '' { continue } - println('V:"$line" expecting:"${expecting[i]}"') + if line != expecting[i] { + println('V:"$line" expecting:"${expecting[i]}"') + } assert line == expecting[i] + println(term.green('$i OK')) + println(line) + println('') i++ if i >= expecting.len { break diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 578112757e..27cd171576 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -8,8 +8,8 @@ import ( pub struct Table { // struct_fields map[string][]string pub mut: - // types map[string]types.Type types []types.Type + // type_idxs Hashmap type_idxs map[string]int local_vars []Var // fns Hashmap @@ -30,7 +30,7 @@ pub struct Fn { pub: name string args []Var - return_ti types.TypeIdent + return_ti types.TypeIdent } pub fn new_table() &Table { @@ -46,7 +46,6 @@ pub fn new_table() &Table { // save index check, 0 will mean not found t.types << types.Type{} t.type_idxs['dymmy_type_at_idx_0'] = 0 - return t } @@ -117,108 +116,6 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } -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('overriding type placeholder `$it.name` with struct') - t2 = {typ| idx: existing_idx} - t.types[existing_idx] = t2 - return existing_idx - } - types.Struct { - return existing_idx - } - else { - panic('cannot register type `$typ.name`, another type with this name exists') - } - } - } - // 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 { - idx := t.type_idxs[name] - if idx > 0 { - return t.types[idx] - } - return none -} pub fn (t mut Table) new_tmp_var() string { t.tmp_cnt++ diff --git a/vlib/v/table/type.v b/vlib/v/table/type.v new file mode 100644 index 0000000000..2bcca9d0a5 --- /dev/null +++ b/vlib/v/table/type.v @@ -0,0 +1,183 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module table + +import v.types + +[inline] +pub fn (t &Table) find_type_idx(name string) int { + return t.type_idxs[name] +} + +[inline] +pub fn (t &Table) find_type(name string) ?types.Type { + idx := t.type_idxs[name] + if idx > 0 { + return t.types[idx] + } + return none +} + +pub fn (t mut Table) register_struct(typ types.Struct) int { + mut struct_type := 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('overriding type placeholder `$it.name` with struct') + struct_type = { + typ | + idx:existing_idx + } + t.types[existing_idx] = struct_type + return existing_idx + } + types.Struct { + return existing_idx + } + else { + panic('cannot register type `$typ.name`, another type with this name exists') + } + } + } + // register + println('registering: $typ.name') + idx := t.types.len + t.type_idxs[typ.name] = idx + struct_type = { + typ | + idx:idx + } + t.types << struct_type + return idx +} + +pub fn (t mut Table) find_or_register_map(key_ti &types.TypeIdent, value_ti &types.TypeIdent) (int,string) { + name := 'map_${key_ti.name}_${value_ti.name}' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut map_type := types.Type{} + map_type = types.Map{ + name: name + key_type_idx: key_ti.idx + value_type_idx: value_ti.idx + } + t.type_idxs[name] = idx + t.types << map_type + return idx,name +} + +pub fn (t mut Table) find_or_register_array(elem_ti &types.TypeIdent, nr_dims int) (int,string) { + name := 'array_${elem_ti.name}_${nr_dims}d' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut array_type := types.Type{} + array_type = types.Array{ + idx: idx + name: name + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + nr_dims: nr_dims + } + t.type_idxs[name] = idx + t.types << array_type + return idx,name +} + +pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size int, nr_dims int) (int,string) { + name := 'array_fixed_${elem_ti.name}_${size}_${nr_dims}d' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut array_fixed_type := types.Type{} + array_fixed_type = types.ArrayFixed{ + idx: idx + name: name + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + size: size + nr_dims: nr_dims + } + t.type_idxs[name] = idx + t.types << array_fixed_type + return idx,name +} + +pub fn (t mut Table) find_or_register_multi_return(mr_tis []&types.TypeIdent) (int,string) { + mut name := 'multi_return' + mut mr_type_kinds := []types.Kind + mut mr_type_idxs := []int + for mr_ti in mr_tis { + name += '_$mr_ti.name' + mr_type_kinds << mr_ti.kind + mr_type_idxs << mr_ti.idx + } + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut mr_type := types.Type{} + mr_type = types.MultiReturn{ + idx: idx + name: name + type_kinds: mr_type_kinds + type_idxs: mr_type_idxs + } + t.type_idxs[name] = idx + t.types << mr_type + return idx,name +} + +pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (int,string) { + name := 'variadic_$variadic_ti.name' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut variadic_type := types.Type{} + variadic_type = types.Variadic{ + idx: idx + type_kind: variadic_ti.kind + type_idx: variadic_ti.idx + } + t.type_idxs[name] = idx + t.types << variadic_type + return idx,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 +} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 3b7deb3d1f..66a0f559bd 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -267,8 +267,8 @@ pub fn is_decl(t Kind) bool { return t in [.key_enum, .key_interface, .key_fn, .key_struct, .key_type, .key_const, .key_import_const, .key_pub, .eof] } -pub fn (t Token) is_assign() bool { - return t.kind in assign_tokens +pub fn (t Kind) is_assign() bool { + return t in assign_tokens } fn (t []Kind) contains(val Kind) bool { @@ -308,7 +308,54 @@ pub const ( lowest_prec = 0 highest_prec = 8 ) -// Precedence returns a tokens precedence if defined, otherwise lowest_prec + +pub enum Precedence { + lowest + cond // OR or AND + assign // = + eq // == or != + less_greater // > or < + sum // + or - + product // * or / + mod // % + prefix // -X or !X + call // func(X) or foo.method(X) + index // array[index], map[key] +} + +pub fn build_precedences() []Precedence { + mut p := []Precedence + p = make(100, 100, sizeof(Precedence)) + p[Kind.assign] = .assign + p[Kind.eq] = .eq + p[Kind.ne] = .eq + p[Kind.lt] = .less_greater + p[Kind.gt] = .less_greater + p[Kind.le] = .less_greater + p[Kind.ge] = .less_greater + p[Kind.plus] = .sum + p[Kind.plus_assign] = .sum + p[Kind.minus] = .sum + p[Kind.minus_assign] = .sum + p[Kind.div] = .product + p[Kind.div_assign] = .product + p[Kind.mul] = .product + p[Kind.mult_assign] = .product + p[Kind.mod] = .mod + p[Kind.and] = .cond + p[Kind.logical_or] = .cond + p[Kind.lpar] = .call + p[Kind.dot] = .call + p[Kind.lsbr] = .index + return p +} + +const ( + precedences = build_precedences() + // int(Kind.assign): Precedence.assign + // } +) +// precedence returns a tokens precedence if defined, otherwise lowest_prec pub fn (tok Token) precedence() int { match tok.kind { .dot { @@ -316,6 +363,7 @@ pub fn (tok Token) precedence() int { } // `++` | `--` .inc, .dec { + // return 0 return 7 } // `*` | `/` | `%` | `<<` | `>>` | `&` @@ -335,7 +383,7 @@ pub fn (tok Token) precedence() int { return 3 } // `||` - .logical_or { + .logical_or, .assign, .plus_assign, .minus_assign, .div_assign, .mult_assign { return 2 } // /.plus_assign { @@ -366,7 +414,7 @@ pub fn (tok Token) is_left_assoc() bool { return tok.kind in [ // `.` .dot, - // `+` | `-` + // `+` | `-` .plus, .minus, // additive // .number, // `++` | `--` @@ -396,8 +444,12 @@ pub fn (tok Token) is_right_assoc() bool { .and_assign, .xor_assign, .or_assign] } -pub fn (tok Token) is_relational() bool { - return tok.kind in [ +pub fn (tok Kind) is_relational() bool { + return tok in [ // `<` | `<=` | `>` | `>=` .lt, .le, .gt, .ge, .eq, .ne] } + +pub fn (kind Kind) is_infix() bool { + return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .ge, .le, .logical_or, .and, .dot] +} diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index fc9133b8e3..3905883a4a 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -34,27 +34,27 @@ pub enum Kind { pub struct TypeIdent { pub: - type_idx int - type_kind Kind - type_name string + idx int + kind Kind + name string nr_muls int } [inline] -pub fn new_ti(type_kind Kind, type_name string, type_idx int, nr_muls int) TypeIdent { +pub fn new_ti(kind Kind, name string, idx int, nr_muls int) TypeIdent { return TypeIdent{ - type_idx: type_idx - type_kind: type_kind - type_name: type_name + idx: idx + kind: kind + name: name nr_muls: nr_muls } } [inline] -pub fn new_base_ti(type_kind Kind, nr_muls int) TypeIdent { +pub fn new_base_ti(kind Kind, nr_muls int) TypeIdent { return TypeIdent{ - type_kind: type_kind - type_name: type_kind.str() + kind: kind + name: kind.str() nr_muls: nr_muls } } @@ -66,12 +66,12 @@ pub fn (ti &TypeIdent) is_ptr() bool { [inline] pub fn (ti &TypeIdent) is_int() bool { - return ti.type_kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64] + return ti.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] + return ti.kind in [._f32, ._f64] } [inline] @@ -80,18 +80,18 @@ pub fn (ti &TypeIdent) is_number() bool { } pub fn (ti &TypeIdent) str() string { - return '$ti.type_kind.str() $ti.type_idx: $ti.type_name ($ti.nr_muls)' + return '$ti.kind.str() $ti.idx: $ti.name ($ti.nr_muls)' } pub fn check(got, expected &TypeIdent) bool { - if got.type_idx != expected.type_idx { + if got.idx != expected.idx { return false } return true } -pub fn (t Kind) str() string { - t_str := match t { +pub fn (k Kind) str() string { + k_str := match k { ._placeholder { 'placeholder' } @@ -168,7 +168,18 @@ pub fn (t Kind) str() string { 'unknown' } } - return t_str + return k_str +} + +pub fn (kinds []Kind) str() string { + mut kinds_str := '' + for i, k in kinds { + kinds_str += k.str() + if i < kinds.len-1 { + kinds_str += '_' + } + } + return kinds_str } pub type Type = Placeholder | Void | Voidptr | Charptr | Byteptr | Const | Enum | Struct | @@ -179,7 +190,7 @@ pub struct Placeholder { pub: idx int name string - kind Kind + // kind Kind } pub struct Void {} @@ -250,6 +261,7 @@ pub: elem_type_kind Kind elem_type_idx int elem_is_ptr bool + nr_dims int size int } @@ -265,14 +277,17 @@ pub: pub struct MultiReturn { pub: - elem_type_kinds []Kind - elem_type_idxs []int + idx int + name string + type_kinds []Kind + type_idxs []int } pub struct Variadic { pub: - elem_type_kind Kind - elem_type_idx int + idx int + type_kind Kind + type_idx int } pub fn (t Void) str() string { return 'void' } @@ -290,8 +305,8 @@ 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 fn (t MultiReturn) str() string { return t.name } +pub fn (t Variadic) str() string { return 'variadic_$t.type_kind.str()' } pub const ( void_type = Void{} @@ -312,3 +327,10 @@ pub const ( char_type = Char{} bool_type = Bool{} ) + +pub const ( + void_ti = new_base_ti(._void, 0) + int_ti = new_base_ti(._int, 0) + string_ti = new_base_ti(._string, 0) + bool_ti = new_base_ti(._bool, 0) +)