diff --git a/v2.v b/v2.v index 8fdc8d1712..6f3906cb03 100644 --- a/v2.v +++ b/v2.v @@ -7,6 +7,15 @@ import ( os ) +const ( +cdefs = ' +#define true 1 +#define false 0 +typedef struct { char* str; } string; +typedef double f64; +string tos3(char* s) { return (string){ .str = s }; } +') + fn main() { path := os.args[1] println('V2 $path') @@ -15,6 +24,9 @@ fn main() { program := parser.parse_file(text, table) res := cgen.gen(program) mut out := os.create('out.c')? + out.writeln(cdefs) out.writeln(res) out.close() + println('out.c generated') + os.system('cc out.c') } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 41624bb141..fe0096c6aa 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -9,9 +9,10 @@ import ( ) pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | -FloatLiteral | Ident | CallExpr | BoolLiteral +FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit -pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt +pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | +ForStmt | StructDecl // Stand-alone expression in a statement list. pub struct ExprStmt { pub: @@ -47,6 +48,25 @@ pub: expr Expr } +pub struct Field { +pub: + name string + typ types.Type +} + +pub struct StructDecl { +pub: + name string + fields []Field +} + +pub struct StructInit { +pub: + typ types.Type + fields []string + exprs []Expr +} + // import statement pub struct Import { pub: @@ -143,6 +163,12 @@ pub: else_ []Stmt } +pub struct ForStmt { +pub: + cond Expr + stmts []Stmt +} + pub struct ReturnStmt { tok_kind token.TokenKind // or pos results []Expr diff --git a/vlib/v/cgen/cgen.v b/vlib/v/cgen/cgen.v index d912380a42..196d0bbbb8 100644 --- a/vlib/v/cgen/cgen.v +++ b/vlib/v/cgen/cgen.v @@ -60,6 +60,22 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.expr(it.expr) g.writeln(';') } + ast.ForStmt { + g.write('while (') + g.expr(it.cond) + g.writeln(') {') + for stmt in it.stmts { + g.stmt(stmt) + } + g.writeln('}') + } + ast.StructDecl { + g.writeln('typedef struct {') + for field in it.fields { + g.writeln('\t$field.typ.name $field.name;') + } + g.writeln('} $it.name;') + } ast.ExprStmt { g.expr(it.expr) match it.expr { @@ -71,7 +87,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { } } else { - verror('stmt bad node') + verror('cgen.stmt(): bad node') } } } @@ -94,32 +110,22 @@ fn (g mut Gen) expr(node ast.Expr) { } ast.BinaryExpr { g.expr(it.left) - match it.op { - .plus { - g.write(' + ') - } - .minus { - g.write(' - ') - } - .mul { - g.write(' * ') - } - .div { - g.write(' / ') - } - .plus_assign { - g.write(' += ') - } - else {} - } + g.write(' $it.op.str() ') g.expr(it.right) - // if it.op in [.plus_assign] { - // g.writeln(';') - // } // if typ.name != typ2.name { // verror('bad types $typ.name $typ2.name') // } } + // `user := User{name: 'Bob'}` + ast.StructInit { + g.writeln('($it.typ.name){') + for i, field in it.fields { + g.write('\t.$field = ') + g.expr(it.exprs[i]) + g.writeln(', ') + } + g.write('}') + } ast.CallExpr { g.write('${it.name}(') for i, expr in it.args { diff --git a/vlib/v/cgen/tests/2.c b/vlib/v/cgen/tests/2.c index b0d09bf463..558bd70a91 100644 --- a/vlib/v/cgen/tests/2.c +++ b/vlib/v/cgen/tests/2.c @@ -7,6 +7,10 @@ int function1() { void foo(int a) { } +typedef struct { + string name; +} User; + void function2() { int x = 0; f64 f = 10.1; @@ -20,6 +24,25 @@ void function2() { foo(10); x += 8; } + if (false) { + foo(1); + } + while (true) { + foo(0); + } + int e = 1 + 2 > 0; + int e2 = 1 + 2 < 0; int j = 0; } +void init_user() { + User user = (User){ + .name = tos3("Bob"), + }; +} + +int main() { + return 0; +} + + diff --git a/vlib/v/cgen/tests/2.v b/vlib/v/cgen/tests/2.v index 3bdc28c830..7b50a3aa12 100644 --- a/vlib/v/cgen/tests/2.v +++ b/vlib/v/cgen/tests/2.v @@ -8,6 +8,10 @@ fn foo(a int) { } +struct User { + name string +} + // comment fn function2() { mut x := 0 @@ -24,7 +28,28 @@ fn function2() { foo(10) x += 8 } + if false { + foo(1) + } + for true { + foo(0) + } + e := 1 + 2 > 0 + e2 := 1 + 2 < 0 + + ////x += 1 + //} j := 0 } +fn init_user() { + user := User{ + name: 'Bob' + } +} + +fn main() int { + return 0 +} + diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 3f1ac3d438..66fea51427 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -48,8 +48,12 @@ pub fn (p mut Parser) get_type() types.Type { return types.string_type } else { - p.error('bad type lit') - exit(0) + 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') + return typ } } } @@ -99,20 +103,6 @@ pub fn (p mut Parser) parse_block() []ast.Stmt { return stmts } -/* -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() { p.tok = p.peek_tok p.peek_tok = p.scanner.scan() @@ -154,12 +144,18 @@ pub fn (p mut Parser) stmt() ast.Stmt { .key_fn { return p.fn_decl() } + .key_struct { + return p.struct_decl() + } .key_return { return p.return_stmt() } .key_mut { return p.var_decl() } + .key_for { + return p.for_statement() + } else { expr,_ := p.expr(0) return ast.ExprStmt{ @@ -251,6 +247,26 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { node = x typ = typ2 } + // struct init + else if p.peek_tok.kind == .lcbr { + typ = p.get_type() + 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) + exprs << expr + } + node = ast.StructInit{ + typ: typ + exprs: exprs + fields: field_names + } + p.check(.rcbr) + } else { // name expr node = ast.Ident{ @@ -260,9 +276,9 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { p.next() } } - .key_true { + .key_true, .key_false { node = ast.BoolLiteral{ - val: true + val: p.tok.kind == .key_true } typ = types.bool_type p.next() @@ -309,6 +325,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { op: prev_tok.kind right: expr } + // println(t2.name + 'OOO') if !types.check(&typ, &t2) { p.error('cannot convert `$t2.name` to `$typ.name`') } @@ -316,6 +333,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { else if prev_tok.is_left_assoc() { mut expr := ast.Expr{} expr,t2 = p.expr(prev_tok.precedence()) + // println(t2.name + '222') node = ast.BinaryExpr{ left: node op: prev_tok.kind @@ -326,6 +344,20 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { return node,typ } +fn (p mut Parser) for_statement() ast.ForStmt { + p.check(.key_for) + cond,typ := p.expr(0) + if !types.check(types.bool_type, typ) { + p.error('non-bool used as for condition') + } + p.check(.lcbr) + stmts := p.parse_block() + return ast.ForStmt{ + cond: cond + stmts: stmts + } +} + fn (p mut Parser) if_expr() (ast.Expr,types.Type) { mut node := ast.Expr{} p.check(.key_if) @@ -384,12 +416,34 @@ fn (p mut Parser) import_stmt() ast.Import { return ast.Import{} } +fn (p mut Parser) struct_decl() ast.StructDecl { + p.check(.key_struct) + name := p.check_name() + p.check(.lcbr) + mut fields := []ast.Field + for p.tok.kind != .rcbr { + field_name := p.check_name() + typ := p.get_type() + fields << ast.Field{ + name: field_name + typ: typ + } + } + p.check(.rcbr) + p.table.register_type(types.Type{ + name: name + }) + return ast.StructDecl{ + name: name + fields: fields + } +} + fn (p mut Parser) fn_decl() ast.FnDecl { p.table.clear_vars() p.check(.key_fn) - name := p.tok.lit + name := p.check_name() // println('fn decl $name') - p.check(.name) p.check(.lpar) // Args mut args := []table.Var diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index d03423d4de..b0e19d0558 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -9,6 +9,7 @@ pub mut: local_vars []Var // fns Hashmap fns map[string]Fn + types map[string]types.Type } pub struct Var { @@ -90,3 +91,7 @@ pub fn (t mut Table) register_fn(new_fn Fn) { // println('reg fn $new_fn.name nr_args=$new_fn.args.len') t.fns[new_fn.name] = new_fn } + +pub fn (t mut Table) register_type(typ types.Type) { + t.types[typ.name] = typ +} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 7c42d8574d..440b12ddc2 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -360,8 +360,8 @@ pub fn (tok Token) is_left_assoc() bool { // .number, // `*` | `/` | `%` .mul, .div, .mod, - // `^` | `||` | `&` - .xor, .logical_or, .and, + // `^` | `||` | `&` < > <= >= + .xor, .logical_or, .and, .gt, .lt, .le, .ge, // `,` .comma] }