From 66a07d7fe06a76ac7e4f3ab9085b701c26be5388 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 27 Dec 2019 13:57:49 +0100 Subject: [PATCH] FnDecl, Return, statement block --- vlib/compiler/parser.v | 27 ++++++-- vlib/v/ast/ast.v | 22 +++++- vlib/v/cgen/cgen.v | 22 +++--- vlib/v/parser/parser.v | 130 ++++++++++++++++++++++++++++-------- vlib/v/parser/parser_test.v | 15 +++-- vlib/v/token/token.v | 7 +- vlib/v/types/types.v | 1 + 7 files changed, 170 insertions(+), 54 deletions(-) diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 6c54279682..af6697b3c0 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -793,13 +793,13 @@ fn (p mut Parser) type_decl() { if p.tok == .key_struct { p.error('use `struct $name {` instead of `type $name struct {`') } - if p.tok == .assign { + is_sum := p.tok == .assign + if is_sum { p.next() - } - parent := p.get_type2() + mut parent := Type{} // Sum type - is_sum := p.tok == .pipe + //is_sum := p.tok == .pipe if is_sum { if !p.builtin_mod && p.mod != 'main' { name = p.prepend_mod(name) @@ -815,10 +815,15 @@ fn (p mut Parser) type_decl() { */ // Register the rest of them mut idx := 0 - for p.tok == .pipe { + mut done := false + for {//p.tok == .pipe { idx++ - p.next() + //p.next() child_type_name := p.check_name() + //println('$idx $child_type_name') + if p.tok != .pipe { + done = true + } if p.pass == .main { // Update the type's parent //println('child=$child_type_name parent=$name') @@ -830,13 +835,17 @@ fn (p mut Parser) type_decl() { p.table.rewrite_type(t) p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2' } + if done { + break + } + p.check(.pipe) } if p.pass == .decl { p.table.sum_types << name println(p.table.sum_types) } // Register the actual sum type - //println('registering sum $name') + println('registering sum $name') p.table.register_type(Type{ name: name mod: p.mod @@ -849,6 +858,10 @@ int typ; } $name; ') } + else { + + parent = p.get_type2() + } nt_pair := p.table.cgen_name_type_pair(name, parent.name) // TODO dirty C typedef hacks for DOOM // Unknown type probably means it's a struct, and it's used before the struct is defined, diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 643e24491c..7347d6ce7d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -11,10 +11,12 @@ import ( struct Foo {} -pub type Expr = Foo | IfExpr | BinaryExpr | UnaryExpr | - StringLiteral | IntegerLiteral | FloatLiteral | VarDecl +pub type Expr = BinaryExpr | UnaryExpr | IfExpr | + StringLiteral | IntegerLiteral | FloatLiteral | VarDecl | + FnDecl | Return + +pub type Stmt = Foo//VarDecl -pub type Stmt = Foo | Foo //VarDecl pub struct IntegerLiteral { pub: @@ -32,6 +34,20 @@ pub: val string } +pub struct FnDecl { +pub: + name string + //stmts []Stmt + exprs []Expr + typ types.Type + +} + +pub struct Return { +pub: + expr Expr +} + /* pub enum Expr { Binary(BinaryExpr) diff --git a/vlib/v/cgen/cgen.v b/vlib/v/cgen/cgen.v index 22b2f62331..77d9e5ae96 100644 --- a/vlib/v/cgen/cgen.v +++ b/vlib/v/cgen/cgen.v @@ -31,16 +31,6 @@ 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) { //println('cgen expr()') match node { @@ -57,6 +47,18 @@ fn (g mut Gen) expr(node ast.Expr) { ast.StringLiteral { g.write('tos3("$it.val")') } + ast.FnDecl { + g.writeln('$it.typ.name $it.name () { ') + for expr in it.exprs { + g.expr(expr) + } + g.writeln('}') + } + ast.Return { + g.write('return ') + g.expr(it.expr) + g.writeln(';') + } ast.BinaryExpr { g.expr(it.left) match it.op { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 5cc7238574..5e8cd81993 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -18,6 +18,7 @@ mut: lit string //vars []string table &table.Table + return_type types.Type } pub fn parse_expr(text string, table &table.Table) ast.Expr { @@ -33,6 +34,20 @@ pub fn parse_expr(text string, table &table.Table) ast.Expr { return expr } +pub fn (p mut Parser) get_type() types.Type { + defer { + p.next() + } + if p.lit == 'int' { return types.int_type } + else if p.lit == 'string' { return types.string_type } + else if p.lit == 'f64' { return types.f64_type } + else { + verror('bad type lit') + exit(1) + } + +} + pub fn parse_file(text string, table &table.Table) ast.Program { s := scanner.new_scanner(text) mut exprs := []ast.Expr @@ -57,6 +72,24 @@ pub fn parse_file(text string, table &table.Table) ast.Program { return ast.Program{exprs} } +pub fn (p mut Parser) parse_block() []ast.Expr { + mut exprs := []ast.Expr + + for { + //res := s.scan() + if p.tok == .eof || p.tok == .rcbr { + break + } + //println('expr at ' + p.tok.str()) + expr,_ := p.expr(token.lowest_prec) + exprs << expr + } + p.next() + println('nr exprs in block = $exprs.len') + return exprs + +} + /* pub fn parse_stmt(text string) ast.Stmt { mut s := scanner.new_scanner(text) @@ -78,12 +111,59 @@ fn (p mut Parser) next() { p.lit = res.lit } +fn (p mut Parser) check(expected token.Token) { + if p.tok != expected { + s := 'syntax error: unexpected `${p.tok.str()}`, expecting `${expected.str()}`' + verror(s) + } + p.next() +} + +fn (p mut Parser) check_name() string { + name := p.lit + p.check(.name) + return name +} + // Implementation of Pratt Precedence pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { // null denotation (prefix) tok := p.tok lit := p.lit - if p.tok == .name { + if p.tok == .key_fn { + p.next() + name := p.lit + println('fn decl $name') + p.check(.name) + p.check(.lpar) + p.check(.rpar) + // Return type + mut typ := types.void_type + if p.tok == .name { + typ = p.get_type() + p.return_type = typ + + } + p.check(.lcbr) + //p.check(.rcbr) + println('OK!') + exprs := p.parse_block() + + mut node := ast.Expr{} + node = ast.FnDecl{name: name, exprs: exprs, typ: typ} + return node, types.void_type + } + else if p.tok == .key_return { + p.next() + mut node := ast.Expr{} + expr, typ := p.expr(0) + if !types.check(p.return_type, typ) { + verror('bad ret type') + } + node = ast.Return{expr: expr} + return node, types.void_type + } + else if p.tok == .name { name := p.lit p.next() if p.tok == .decl_assign { @@ -117,34 +197,30 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { } p.next() } + .str { + node = ast.StringLiteral{ + val: lit + } + typ = types.string_type + + } + .number { + if lit.contains('.') { + node = ast.FloatLiteral{ + //val: lit.f64() + val: lit + } + typ = types.int_type + } else { + node = ast.IntegerLiteral{ + val: lit.int() + } + typ = types.int_type + } + } else { // TODO: fix bug. note odd conditon instead of else if (same below) - if tok.is_scalar() { - if tok == .str { - node = ast.StringLiteral{ - val: lit - } - typ = types.string_type - } - if tok == .number { - if lit.contains('.') { - node = ast.FloatLiteral{ - //val: lit.f64() - val: lit - } - typ = types.int_type - } else { - node = ast.IntegerLiteral{ - val: lit.int() - } - typ = types.int_type - } - } - // else { - // verror('bad scalar token') - // } - } - if !tok.is_scalar() && tok.is_unary() { + if tok.is_unary() { expr,_ := p.expr(token.highest_prec) node = ast.UnaryExpr{ // left: p.expr(token.highest_prec) diff --git a/vlib/v/parser/parser_test.v b/vlib/v/parser/parser_test.v index 706d8f4ccc..5ed52a9117 100644 --- a/vlib/v/parser/parser_test.v +++ b/vlib/v/parser/parser_test.v @@ -7,10 +7,16 @@ import ( ) fn test_parse_file() { - s := '12 + 3 - x := 10 - 5+7 - 8+4 + s := ' +fn foo() string { + f := 23 + return 10+4 +} + +12 + 3 +x := 10 +5+7 +8+4 ' table := &table.Table{} prog := parse_file(s, table) @@ -20,6 +26,7 @@ fn test_parse_file() { fn test_parse_expr() { + //if true { return } input := [ '2 + 3', '2+2*4', diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index ee65720593..7161b707b2 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -287,19 +287,20 @@ fn (t []Token) contains(val Token) bool { } pub fn (t Token) str() string { - lit := 't.lit' if t == .number { return 'number' } if t == .chartoken { - return '`lit`' + return 'char'//'`lit`' } if t == .str { - return "'lit'" + return 'str' //"'lit'" } + /* if t < .plus { return lit // string, number etc } + */ return token_str[int(t)] } diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index 15f1d00d32..b5d0b40a93 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -13,6 +13,7 @@ pub const ( void_type = Type{'void', 0} int_type = Type{'int', 1} string_type = Type{'string', 2} + f64_type = Type{'f64', 3} )