From 2d2e0307b80b1c48430dcf9758a70059288a7077 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 29 Dec 2019 08:51:55 +0100 Subject: [PATCH] fn call; if expression; bool literals; 100k line program gen fix yay lovely --- tools/gen10k.v | 16 +++++++ v2.v | 20 +++++++++ vlib/compiler/aparser.v | 3 +- vlib/v/ast/ast.v | 10 ++++- vlib/v/cgen/cgen.v | 37 ++++++++++++++-- vlib/v/cgen/cgen_test.v | 2 +- vlib/v/cgen/tests/2.c | 5 +++ vlib/v/cgen/tests/2.v | 6 +++ vlib/v/parser/parser.v | 95 ++++++++++++++++++++++++++++++----------- vlib/v/types/types.v | 15 ++++--- 10 files changed, 171 insertions(+), 38 deletions(-) create mode 100644 tools/gen10k.v create mode 100644 v2.v diff --git a/tools/gen10k.v b/tools/gen10k.v new file mode 100644 index 0000000000..8aea9bcbd7 --- /dev/null +++ b/tools/gen10k.v @@ -0,0 +1,16 @@ +fn main() { + for i in 0..10000 { + println(' +fn foo${i}() { + x := $i + mut a := x + a += 2 + println(a) + a = 0 + a = 1 +} +') + } + println('fn main() {foo1()} ') + +} diff --git a/v2.v b/v2.v new file mode 100644 index 0000000000..8fdc8d1712 --- /dev/null +++ b/v2.v @@ -0,0 +1,20 @@ +module main + +import ( + v.parser + v.table + v.cgen + os +) + +fn main() { + path := os.args[1] + println('V2 $path') + text := os.read_file(path)? + table := &table.Table{} + program := parser.parse_file(text, table) + res := cgen.gen(program) + mut out := os.create('out.c')? + out.writeln(res) + out.close() +} diff --git a/vlib/compiler/aparser.v b/vlib/compiler/aparser.v index 640d9a0b53..416a07ca0c 100644 --- a/vlib/compiler/aparser.v +++ b/vlib/compiler/aparser.v @@ -3094,7 +3094,8 @@ fn (p mut Parser) check_unused_imports() { return } // the imports are usually at the start of the file - p.production_error_with_token_index('the following imports were never used: $output', 0) + //p.production_error_with_token_index('the following imports were never used: $output', 0) + p.warn('the following imports were never used: $output') } fn (p &Parser) is_expr_fn_call(start_tok_idx int) (bool,string) { diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index d5066623d3..41624bb141 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -9,7 +9,7 @@ import ( ) pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | -FloatLiteral | Ident | CallExpr +FloatLiteral | Ident | CallExpr | BoolLiteral pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt // Stand-alone expression in a statement list. @@ -34,6 +34,11 @@ pub: val string } +pub struct BoolLiteral { +pub: + val bool +} + // module declaration pub struct Module { pub: @@ -131,9 +136,10 @@ pub: } pub struct IfExpr { +pub: tok_kind token.TokenKind cond Expr - body []Stmt + stmts []Stmt else_ []Stmt } diff --git a/vlib/v/cgen/cgen.v b/vlib/v/cgen/cgen.v index 6dc7081b3d..d912380a42 100644 --- a/vlib/v/cgen/cgen.v +++ b/vlib/v/cgen/cgen.v @@ -3,6 +3,7 @@ module cgen import ( strings v.ast + term ) struct Gen { @@ -61,7 +62,13 @@ fn (g mut Gen) stmt(node ast.Stmt) { } ast.ExprStmt { g.expr(it.expr) - g.writeln(';') + match it.expr { + // no ; after an if expression + ast.IfExpr {} + else { + g.writeln(';') + } + } } else { verror('stmt bad node') @@ -114,13 +121,37 @@ fn (g mut Gen) expr(node ast.Expr) { // } } ast.CallExpr { - g.write('${it.name}()') + g.write('${it.name}(') + for i, expr in it.args { + g.expr(expr) + if i != it.args.len - 1 { + g.write(', ') + } + } + g.write(')') } ast.Ident { g.write('$it.name') } + ast.BoolLiteral { + if it.val == true { + g.write('true') + } + else { + g.write('false') + } + } + ast.IfExpr { + g.write('if (') + g.expr(it.cond) + g.writeln(') {') + for stmt in it.stmts { + g.stmt(stmt) + } + g.writeln('}') + } else { - println('cgen.expr(): bad node') + println(term.red('cgen.expr(): bad node')) } } } diff --git a/vlib/v/cgen/cgen_test.v b/vlib/v/cgen/cgen_test.v index acca534c98..befc34696c 100644 --- a/vlib/v/cgen/cgen_test.v +++ b/vlib/v/cgen/cgen_test.v @@ -27,7 +27,7 @@ fn test_c_files() { program := parser.parse_file(text, table) res := cgen.gen(program) if compare_texts(res, ctext) { - eprintln('${i}... OK') + eprintln('${i}... ' + term.green('OK')) } else { eprintln('${i}... ' + term.red('FAIL')) diff --git a/vlib/v/cgen/tests/2.c b/vlib/v/cgen/tests/2.c index 3f948dfad3..b0d09bf463 100644 --- a/vlib/v/cgen/tests/2.c +++ b/vlib/v/cgen/tests/2.c @@ -16,5 +16,10 @@ void function2() { x += 1; m += 2; function1(); + if (true) { + foo(10); + x += 8; + } + int j = 0; } diff --git a/vlib/v/cgen/tests/2.v b/vlib/v/cgen/tests/2.v index a8ca700d56..3bdc28c830 100644 --- a/vlib/v/cgen/tests/2.v +++ b/vlib/v/cgen/tests/2.v @@ -20,5 +20,11 @@ fn function2() { function1() //a += 1 //c := 0 + if true { + foo(10) + x += 8 + } + j := 0 } + diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1731787839..3f1ac3d438 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -48,8 +48,8 @@ pub fn (p mut Parser) get_type() types.Type { return types.string_type } else { - verror('bad type lit') - exit(1) + p.error('bad type lit') + exit(0) } } } @@ -68,10 +68,10 @@ pub fn parse_file(text string, table &table.Table) ast.Program { } // println('expr at ' + p.tok.str()) s := p.stmt() - println(s) + // println(s) stmts << s // p.stmt() } - println('nr stmts = $stmts.len') + // println('nr stmts = $stmts.len') // println(stmts[0]) return ast.Program{ stmts: stmts @@ -184,6 +184,9 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { // println('assignn_stmt() ' + op.str()) p.next() right_expr,right_type := p.expr(0) + if !types.check(left_type, right_type) { + p.error('oops') + } return ast.AssignStmt{ left: left_expr right: right_expr @@ -196,6 +199,37 @@ pub fn (p &Parser) error(s string) { exit(1) } +pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) { + // println('got fn call') + fn_name := p.tok.lit + f := p.table.find_fn(fn_name) or { + p.error('unknown function `$p.tok.lit`') + exit(0) + } + p.check(.name) + p.check(.lpar) + mut args := []ast.Expr + for i, arg in f.args { + e,typ := p.expr(0) + if !types.check(arg.typ, typ) { + p.error('cannot used type `$typ.name` as type `$arg.typ.name` in argument to `$fn_name`') + } + args << e + if i < f.args.len - 1 { + p.check(.comma) + } + } + if p.tok.kind == .comma { + p.error('too many arguments in call to `$fn_name`') + } + p.check(.rpar) + node := ast.CallExpr{ + name: fn_name + args: args + } + return node,types.int_type +} + // Implementation of Pratt Precedence pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { // println('expr at ' + p.tok.str()) @@ -213,26 +247,9 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { // fn call if p.peek_tok.kind == .lpar { - println('got fn call') - fn_name := p.tok.lit - f := p.table.find_fn(fn_name) or { - p.error('unknown fucntion `$p.tok.lit`') - exit(0) - } - p.check(.name) - p.check(.lpar) - mut args := []ast.Expr - for _ in 0 .. f.args.len { - e,_ := p.expr(0) - args << e - p.check(.comma) - } - p.check(.rpar) - node = ast.CallExpr{ - name: fn_name - args: args - } - typ = types.int_type + x,typ2 := p.call_expr() // TODO `node,typ :=` should work + node = x + typ = typ2 } else { // name expr @@ -243,12 +260,22 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { p.next() } } + .key_true { + node = ast.BoolLiteral{ + val: true + } + typ = types.bool_type + p.next() + } .str { node,typ = p.parse_string_literal() } .number { node,typ = p.parse_number_literal() } + .key_if { + node,typ = p.if_expr() + } .lpar { node,typ = p.expr(0) p.check(.rpar) @@ -299,6 +326,22 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { return node,typ } +fn (p mut Parser) if_expr() (ast.Expr,types.Type) { + mut node := ast.Expr{} + p.check(.key_if) + cond,typ := p.expr(0) + if !types.check(types.bool_type, typ) { + p.error('non-bool used as if condition') + } + p.check(.lcbr) + stmts := p.parse_block() + node = ast.IfExpr{ + cond: cond + stmts: stmts + } + return node,types.void_type +} + fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) { mut node := ast.Expr{} node = ast.StringLiteral{ @@ -399,7 +442,7 @@ fn (p mut Parser) return_stmt() ast.Return { fn (p mut Parser) var_decl() ast.VarDecl { is_mut := p.tok.kind == .key_mut // || p.prev_tok == .key_for - is_static := p.tok.kind == .key_static + // is_static := p.tok.kind == .key_static if p.tok.kind == .key_mut { p.check(.key_mut) // p.fspace() @@ -412,7 +455,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { p.read_first_token() expr,t := p.expr(token.lowest_prec) if _ := p.table.find_var(name) { - verror('redefinition of `$name`') + p.error('redefinition of `$name`') } p.table.register_var(table.Var{ name: name diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index b5d0b40a93..34e5cc5283 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -10,13 +10,18 @@ pub: } pub const ( - void_type = Type{'void', 0} - int_type = Type{'int', 1} - string_type = Type{'string', 2} - f64_type = Type{'f64', 3} + void_type = Type{ + 'void',0} + int_type = Type{ + 'int',1} + string_type = Type{ + 'string',2} + f64_type = Type{ + 'f64',3} + bool_type = Type{ + 'bool',4} ) - pub fn check(got, expected &Type) bool { if got.idx != expected.idx { return false