From 8d9f89e72872bdc996817974a8398f03c2edd68e Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 24 Dec 2019 20:54:43 +0300 Subject: [PATCH] compiler2: proof of concept cgen --- vlib/compiler/fn.v | 3 ++ vlib/compiler2/ast/ast.v | 26 +++++++-- vlib/compiler2/cgen/cgen.v | 82 +++++++++++++++++++++++++++++ vlib/compiler2/parser/parser.v | 78 ++++++++++++++++++++++----- vlib/compiler2/parser/parser_test.v | 22 ++++++-- vlib/strings/builder_c.v | 3 ++ 6 files changed, 193 insertions(+), 21 deletions(-) create mode 100644 vlib/compiler2/cgen/cgen.v diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 8be88b659e..3cea04d9b4 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -980,6 +980,9 @@ fn (p mut Parser) fn_args(f mut Fn) { p.next() } } + //if types_only && p.peek() == .lcbr { + //println('wtf') + //} } // foo *(1, 2, 3, mut bar)* diff --git a/vlib/compiler2/ast/ast.v b/vlib/compiler2/ast/ast.v index 2201d7ba9a..c932ae44f2 100644 --- a/vlib/compiler2/ast/ast.v +++ b/vlib/compiler2/ast/ast.v @@ -10,15 +10,19 @@ import ( struct Foo {} -// pub type Expr = Foo | IfExpr | BinaryExpr | IntegerExpr -pub type Expr = Foo | IfExpr | BinaryExpr | ScalarExpr | UnaryExpr +pub type Expr = Foo | IfExpr | BinaryExpr | ScalarExpr | UnaryExpr | + StringLiteral | IntegerExpr +pub type Stmt = Foo | VarDecl -/* pub struct IntegerExpr { pub: val int } -*/ + +pub struct StringLiteral { +pub: + val string +} /* pub enum Expr { @@ -28,10 +32,24 @@ pub enum Expr { } */ +/* pub struct Stmt { pos int //end int } +*/ + +pub struct VarDecl { +pub: + name string + expr Expr + +} + +pub struct Program { +pub: + exprs []Expr +} // A single identifier struct Ident { diff --git a/vlib/compiler2/cgen/cgen.v b/vlib/compiler2/cgen/cgen.v new file mode 100644 index 0000000000..0afbb9e855 --- /dev/null +++ b/vlib/compiler2/cgen/cgen.v @@ -0,0 +1,82 @@ +module cgen + +import ( + strings + compiler2.ast +) + +struct Gen { + out strings.Builder + +} + +pub fn gen(program ast.Program) { + mut g := Gen{out:strings.new_builder(100)} + for expr in program.exprs { + g.expr(expr) + g.writeln('') + } + println(g.out.str()) +} + +pub fn (g &Gen) save() { + +} + +pub fn (g mut Gen) write(s string) { + g.out.write(s) +} + +pub fn (g mut Gen) writeln(s string) { + g.out.writeln(s) +} + +struct Type { + name string +} + +const ( + string_type = Type{'string'} + int_type = Type{'int'} + void_type = Type{'void'} +) + +fn (g mut Gen) expr(node ast.Expr) Type { + //println('cgen expr()') + match node { + ast.IntegerExpr { + g.write(it.val.str()) + return int_type + } + ast.StringLiteral { + g.write('"$it.val"') + return string_type + } + ast.BinaryExpr { + typ := g.expr(it.left) + match it.op { + .plus { g.write(' + ') } + .minus { g.write(' - ') } + .mul { g.write(' * ') } + .div { g.write(' / ') } + else {} + } + typ2 := g.expr(it.right) + if typ.name != typ2.name { + println('bad types $typ.name $typ2.name') + } + return typ + } + ast.VarDecl { + g.write('var $it.name = ') + g.expr(it.expr) + g.writeln(';') + return void_type + } + else { + println('bad node') + } + } + return void_type +} + diff --git a/vlib/compiler2/parser/parser.v b/vlib/compiler2/parser/parser.v index fe69dc54c3..b5386db509 100644 --- a/vlib/compiler2/parser/parser.v +++ b/vlib/compiler2/parser/parser.v @@ -12,8 +12,8 @@ import ( struct Parser { scanner &scanner.Scanner mut: - tok token.Token - lit string + tok token.Token + lit string } pub fn parse_expr(text string) ast.Expr { @@ -28,10 +28,21 @@ pub fn parse_expr(text string) ast.Expr { return p.expr(token.lowest_prec) } +pub fn parse_stmt(text string) ast.Stmt { + mut s := scanner.new_scanner(text) + res := s.scan() + mut p := Parser{ + scanner: s + tok: res.tok + lit: res.lit + } + return p.stmt() +} + fn (p mut Parser) next() { res := p.scanner.scan() p.tok = res.tok - //println(p.tok.str()) + // println(p.tok.str()) p.lit = res.lit } @@ -41,37 +52,76 @@ pub fn (p mut Parser) expr(rbp int) ast.Expr { tok := p.tok lit := p.lit p.next() - mut left := ast.Expr{} + mut node := ast.Expr{ + } match tok { .lpar { - left = p.expr(0) + node = p.expr(0) if p.tok != .rpar { - panic("Parse Error: expected )") + panic('Parse Error: expected )') } p.next() } else { // TODO: fix bug. note odd conditon instead of else if (same below) if tok.is_scalar() { - left = ast.ScalarExpr{val: lit, typ: tok} + node = ast.ScalarExpr{ + val: lit + typ: tok + } } if !tok.is_scalar() && tok.is_unary() { - left = ast.UnaryExpr{left: p.expr(token.highest_prec), op: tok} + node = ast.UnaryExpr{ + left: p.expr(token.highest_prec) + op: tok + } } - } - } - + }} // left binding power for rbp < p.tok.precedence() { tok2 := p.tok p.next() // left denotation (infix) if tok2.is_right_assoc() { - left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence() - 1)} + node = ast.BinaryExpr{ + left: node + op: tok2 + right: p.expr(tok2.precedence() - 1) + } } if !tok2.is_right_assoc() && tok2.is_left_assoc() { - left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence())} + node = ast.BinaryExpr{ + left: node + op: tok2 + right: p.expr(tok2.precedence()) + } } } - return left + return node +} + +fn (p mut Parser) stmt() ast.Stmt { + if p.tok == .name { + name := p.lit + p.next() + if p.tok == .decl_assign { + p.next() + return ast.VarDecl{ + name: name + expr: p.expr(token.lowest_prec) + } + } + } + /* + match node { + Ident { + + + } + + } + */ + + return ast.VarDecl{ + } } diff --git a/vlib/compiler2/parser/parser_test.v b/vlib/compiler2/parser/parser_test.v index 3597ed6667..5be0e21313 100644 --- a/vlib/compiler2/parser/parser_test.v +++ b/vlib/compiler2/parser/parser_test.v @@ -1,6 +1,9 @@ module parser -import compiler2.ast +import ( + compiler2.ast + compiler2.cgen +) fn test_parser() { //expr := ast.IntegerExpr {val:10} @@ -10,7 +13,7 @@ fn test_parser() { expr := parse_expr('3 + 7') walk(expr) println('\n') - + text_expr := [ '1 += 2', '1.2 + 3.4', @@ -62,4 +65,17 @@ fn walk(node ast.Expr) { } else { } } -} \ No newline at end of file +/* + //expr := parse_expr('3 + 7 * 2') + expr := parse_stmt('a := 3 + "f"') + program := ast.Program{ + exprs: [ + expr, + //parse_expr('2 * 2'), + ] + } + cgen.gen(program) + //cgen.save() + */ +} + diff --git a/vlib/strings/builder_c.v b/vlib/strings/builder_c.v index 9c7fad81c7..c19d852008 100644 --- a/vlib/strings/builder_c.v +++ b/vlib/strings/builder_c.v @@ -29,6 +29,9 @@ pub fn (b mut Builder) write_b(data byte) { } pub fn (b mut Builder) write(s string) { + if s == '' { + return + } b.buf.push_many(s.str, s.len) // for c in s { // b.buf << c