diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index bfbca33853..00ac1ff731 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -4,8 +4,9 @@ module compiler fn (p mut Parser) bool_expression() string { + is_ret := p.prev_tok == .key_return start_ph := p.cgen.add_placeholder() - expected := p.expected_type + mut expected := p.expected_type tok := p.tok typ := p.bterm() mut got_and := false // to catch `a && b || c` in one expression without () @@ -46,7 +47,11 @@ fn (p mut Parser) bool_expression() string { println(tok.str()) p.error('expr() returns empty type') } + if p.inside_return_expr { //is_ret { // return a,b hack TODO + expected = p.expected_type + } if expected != typ && expected in p.table.sum_types { // TODO perf + //p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type') p.cgen.set_placeholder(start_ph, //'/*SUM TYPE CAST*/($expected) { .obj = &($typ[]) { ') '/*SUM TYPE CAST*/($expected) { .obj = memdup(& ') diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index a05d2d1323..40498b2b5b 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -272,8 +272,9 @@ fn (p &Parser) gen_fmt() { s3 := s2.replace(') or{', ') or {') s4 := s3.replace(')or{', ') or {') s5 := s4.replace('or{', 'or {') + s6 := s5.replace('}}\n', '}\n\t}\n') - s := s5 + s := s6 if s == '' { return diff --git a/vlib/compiler2/ast/ast.v b/vlib/compiler2/ast/ast.v index 605b56a34f..e79c9290b6 100644 --- a/vlib/compiler2/ast/ast.v +++ b/vlib/compiler2/ast/ast.v @@ -11,8 +11,9 @@ import ( struct Foo {} pub type Expr = Foo | IfExpr | BinaryExpr | UnaryExpr | - StringLiteral | IntegerLiteral -pub type Stmt = Foo | VarDecl + StringLiteral | IntegerLiteral | VarDecl + +pub type Stmt = Foo | Foo //VarDecl pub struct IntegerLiteral { pub: @@ -43,6 +44,7 @@ pub struct VarDecl { pub: name string expr Expr + typ Type } @@ -51,6 +53,18 @@ pub: exprs []Expr } +pub struct Type { +pub: + name string +} + +pub const ( + string_type = Type{'string'} + int_type = Type{'int'} + void_type = Type{'void'} +) + + // A single identifier struct Ident { token token.Token @@ -63,7 +77,9 @@ pub: //op BinaryOp op token.Token left Expr + left_type Type right Expr + right_type Type } pub struct UnaryExpr { @@ -90,13 +106,16 @@ struct ReturnStmt { pub fn (x Expr) str() string { match x { BinaryExpr { - return '(${it.left.str()}$it.op.str()${it.right.str()})' + return '(${it.left.str()} $it.op.str() ${it.right.str()})' } - //ScalarExpr { - //return '${it.left.str()}$it.val' - //} UnaryExpr { - return '${it.left.str()}$it.op.str()' + return it.left.str() + it.op.str() + } + IntegerLiteral { + return it.val.str() + } + IntegerLiteral { + return '"$it.val"' } else { return '' } } diff --git a/vlib/compiler2/cgen/cgen.v b/vlib/compiler2/cgen/cgen.v index a2ca782a39..c952a50930 100644 --- a/vlib/compiler2/cgen/cgen.v +++ b/vlib/compiler2/cgen/cgen.v @@ -41,12 +41,11 @@ const ( void_type = Type{'void'} ) -fn (g mut Gen) expr(node ast.Expr) Type { +fn (g mut Gen) expr(node ast.Expr) { //println('cgen expr()') match node { ast.IntegerLiteral { g.write(it.val.str()) - return int_type } ast.UnaryExpr { g.expr(it.left) @@ -54,10 +53,9 @@ fn (g mut Gen) expr(node ast.Expr) Type { } ast.StringLiteral { g.write('"$it.val"') - return string_type } ast.BinaryExpr { - typ := g.expr(it.left) + g.expr(it.left) match it.op { .plus { g.write(' + ') } .minus { g.write(' - ') } @@ -65,22 +63,24 @@ fn (g mut Gen) expr(node ast.Expr) Type { .div { g.write(' / ') } else {} } - typ2 := g.expr(it.right) - if typ.name != typ2.name { - println('bad types $typ.name $typ2.name') - } - return typ + g.expr(it.right) + // if typ.name != typ2.name { + //verror('bad types $typ.name $typ2.name') + //} } ast.VarDecl { - g.write('var $it.name = ') + g.write('$it.typ.name $it.name = ') g.expr(it.expr) g.writeln(';') - return void_type } else { println('bad node') } } - return void_type +} + +fn verror(s string) { + println(s) + exit(1) } diff --git a/vlib/compiler2/parser/parser.v b/vlib/compiler2/parser/parser.v index 108ad64a74..85fcf20682 100644 --- a/vlib/compiler2/parser/parser.v +++ b/vlib/compiler2/parser/parser.v @@ -7,6 +7,7 @@ import ( compiler2.scanner compiler2.ast compiler2.token + compiler2.table ) struct Parser { @@ -14,20 +15,49 @@ struct Parser { mut: tok token.Token lit string + //vars []string + table &table.Table } -pub fn parse_expr(text string) ast.Expr { +pub fn parse_expr(text string, table &table.Table) ast.Expr { mut s := scanner.new_scanner(text) res := s.scan() mut p := Parser{ scanner: s tok: res.tok lit: res.lit + table: table } - // return p.expr() - return p.expr(token.lowest_prec) + expr,_ := p.expr(token.lowest_prec) + return expr } +pub fn parse_file(text string, table &table.Table) ast.Program { + s := scanner.new_scanner(text) + mut exprs := []ast.Expr + mut p := Parser{ + scanner: s + //tok: res.tok + //lit: res.lit + table: table + } + p.next() + for { + //res := s.scan() + if p.tok == .eof { + break + } + println('expr at ' + p.tok.str()) + expr,_ := p.expr(token.lowest_prec) + exprs << expr + p.next() + } + println('nr exprs = $exprs.len') + println(exprs[0]) + return ast.Program{exprs} +} + +/* pub fn parse_stmt(text string) ast.Stmt { mut s := scanner.new_scanner(text) res := s.scan() @@ -38,6 +68,8 @@ pub fn parse_stmt(text string) ast.Stmt { } return p.stmt() } +*/ + fn (p mut Parser) next() { res := p.scanner.scan() @@ -47,15 +79,40 @@ fn (p mut Parser) next() { } // Implementation of Pratt Precedence -pub fn (p mut Parser) expr(rbp int) ast.Expr { +pub fn (p mut Parser) expr(rbp int) (ast.Expr,ast.Type) { // null denotation (prefix) tok := p.tok lit := p.lit - p.next() + + if p.tok == .name { + name := p.lit + p.next() + if p.tok == .decl_assign { + p.next() + mut node := ast.Expr{} + expr,t :=p.expr(token.lowest_prec) + if name in p.table.names { + verror('redefinition of `$name`') + } + p.table.names << name + println(p.table.names) + println('added $name') + // TODO can't return VarDecl{} + node = ast.VarDecl{ + name: name + expr: expr//p.expr(token.lowest_prec) + typ: t + }//, ast.void_type + return node, ast.void_type + } + } else { + p.next() + } mut node := ast.Expr{} + mut typ := ast.void_type match tok { .lpar { - node = p.expr(0) + node,typ = p.expr(0) if p.tok != .rpar { panic('Parse Error: expected )') } @@ -65,48 +122,70 @@ pub fn (p mut Parser) expr(rbp int) ast.Expr { // TODO: fix bug. note odd conditon instead of else if (same below) if tok.is_scalar() { if tok == .str { - node = ast.StringLiteral { + node = ast.StringLiteral{ val: lit } - } if tok == .number { - node = ast.IntegerLiteral { + typ = ast.string_type + } + if tok == .number { + node = ast.IntegerLiteral{ val: lit.int() } + typ = ast.int_type } - //else { - //verror('bad scalar token') - //} + // else { + // verror('bad scalar token') + // } } if !tok.is_scalar() && tok.is_unary() { + expr,_ := p.expr(token.highest_prec) node = ast.UnaryExpr{ - left: p.expr(token.highest_prec) + // left: p.expr(token.highest_prec) + left: expr op: tok } } - }} + } + } // left binding power for rbp < p.tok.precedence() { tok2 := p.tok p.next() + //mut t1 := ast.Type{} + mut t2 := ast.Type{} + //mut q := false // left denotation (infix) if tok2.is_right_assoc() { + //q = true + mut expr := ast.Expr{} + expr,t2 = p.expr(tok2.precedence() - 1) node = ast.BinaryExpr{ left: node + //left_type: t1 op: tok2 - right: p.expr(tok2.precedence() - 1) + // right: p.expr(tok2.precedence() - 1) + + right: expr + + } + if typ.name != t2.name { + println('bad types $typ.name $t2.name') } } if !tok2.is_right_assoc() && tok2.is_left_assoc() { + mut expr := ast.Expr{} + expr,t2 = p.expr(tok2.precedence()) node = ast.BinaryExpr{ left: node op: tok2 - right: p.expr(tok2.precedence()) + right: expr } } } - return node + return node,typ } +/* fn (p mut Parser) stmt() ast.Stmt { if p.tok == .name { name := p.lit @@ -131,6 +210,8 @@ fn (p mut Parser) stmt() ast.Stmt { return ast.VarDecl{} } +*/ + fn verror(s string) { println(s) diff --git a/vlib/compiler2/parser/parser_test.v b/vlib/compiler2/parser/parser_test.v index a8c028d922..933b3d7523 100644 --- a/vlib/compiler2/parser/parser_test.v +++ b/vlib/compiler2/parser/parser_test.v @@ -3,6 +3,8 @@ module parser import ( compiler2.ast compiler2.cgen + compiler2.table + ) fn test_parser() { @@ -11,8 +13,8 @@ fn test_parser() { //expr := ast.BinaryExpr{} // print using walk - expr := parse_expr('3 + 7') - println('\n') + //expr := parse_expr('3 + 7') + //println('\n') text_expr := [ '1 += 2', @@ -24,29 +26,53 @@ fn test_parser() { '2 ^ 8 * (7 * 6)', '20 + (10 * 15) / 5', // 50 '(2) + (17*2-30) * (5)+2 - (8/2)*4', // 8 - '2 + "hi"' + '2 + "hi"', + 'x := 10' ] + table := &table.Table{} for s in text_expr { // print using str method - x := parse_expr(s) + x := parse_expr(s, table) println('source: $s') println('parsed: $x') println('===================') } } +/* +fn test_cgen2() { + s := '2 + 3 + 5+7 +//x := 100 +' + table := &table.Table{} + prog := parse_file(s, table) + cgen.gen(prog) + println('done') +} +*/ fn test_cgen() { + //if true { return } + s := [ + 'x := 10', + //'x := 10' + ] //expr := parse_expr('3 + 7 * 2') //expr2 := parse_stmt('a := 3 + "f"') - expr2 := parse_expr('2 + "helo"') - program := ast.Program{ - exprs: [ - expr2, + mut e := []ast.Expr + table := &table.Table{} + for ss in s { + //expr2 := parse_expr('x := 10') + //program := ast.Program{ + e << parse_expr(ss, table) + //exprs: [ + //expr2, //parse_expr('2 * 2'), - ] + //] } + program := ast.Program{exprs:e} cgen.gen(program) //cgen.save() } diff --git a/vlib/compiler2/table/table.v b/vlib/compiler2/table/table.v new file mode 100644 index 0000000000..13bc2e1b18 --- /dev/null +++ b/vlib/compiler2/table/table.v @@ -0,0 +1,7 @@ +module table + +pub struct Table { +pub mut: + names []string + +} diff --git a/vlib/compiler2/token/token.v b/vlib/compiler2/token/token.v index 357604bb38..d48e70b25f 100644 --- a/vlib/compiler2/token/token.v +++ b/vlib/compiler2/token/token.v @@ -289,7 +289,7 @@ fn (t []Token) contains(val Token) bool { pub fn (t Token) str() string { lit := 't.lit' if t == .number { - return lit + return 'number' } if t == .chartoken { return '`lit`'