1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

fn call; if expression; bool literals; 100k line program gen

fix

yay

lovely
This commit is contained in:
Alexander Medvednikov 2019-12-29 08:51:55 +01:00
parent 63b70ddb06
commit 2d2e0307b8
10 changed files with 171 additions and 38 deletions

16
tools/gen10k.v Normal file
View File

@ -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()} ')
}

20
v2.v Normal file
View File

@ -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()
}

View File

@ -3094,7 +3094,8 @@ fn (p mut Parser) check_unused_imports() {
return return
} }
// the imports are usually at the start of the file // 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) { fn (p &Parser) is_expr_fn_call(start_tok_idx int) (bool,string) {

View File

@ -9,7 +9,7 @@ import (
) )
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | 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 pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt
// Stand-alone expression in a statement list. // Stand-alone expression in a statement list.
@ -34,6 +34,11 @@ pub:
val string val string
} }
pub struct BoolLiteral {
pub:
val bool
}
// module declaration // module declaration
pub struct Module { pub struct Module {
pub: pub:
@ -131,9 +136,10 @@ pub:
} }
pub struct IfExpr { pub struct IfExpr {
pub:
tok_kind token.TokenKind tok_kind token.TokenKind
cond Expr cond Expr
body []Stmt stmts []Stmt
else_ []Stmt else_ []Stmt
} }

View File

@ -3,6 +3,7 @@ module cgen
import ( import (
strings strings
v.ast v.ast
term
) )
struct Gen { struct Gen {
@ -61,7 +62,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
} }
ast.ExprStmt { ast.ExprStmt {
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') match it.expr {
// no ; after an if expression
ast.IfExpr {}
else {
g.writeln(';')
}
}
} }
else { else {
verror('stmt bad node') verror('stmt bad node')
@ -114,13 +121,37 @@ fn (g mut Gen) expr(node ast.Expr) {
// } // }
} }
ast.CallExpr { 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 { ast.Ident {
g.write('$it.name') 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 { else {
println('cgen.expr(): bad node') println(term.red('cgen.expr(): bad node'))
} }
} }
} }

View File

@ -27,7 +27,7 @@ fn test_c_files() {
program := parser.parse_file(text, table) program := parser.parse_file(text, table)
res := cgen.gen(program) res := cgen.gen(program)
if compare_texts(res, ctext) { if compare_texts(res, ctext) {
eprintln('${i}... OK') eprintln('${i}... ' + term.green('OK'))
} }
else { else {
eprintln('${i}... ' + term.red('FAIL')) eprintln('${i}... ' + term.red('FAIL'))

View File

@ -16,5 +16,10 @@ void function2() {
x += 1; x += 1;
m += 2; m += 2;
function1(); function1();
if (true) {
foo(10);
x += 8;
}
int j = 0;
} }

View File

@ -20,5 +20,11 @@ fn function2() {
function1() function1()
//a += 1 //a += 1
//c := 0 //c := 0
if true {
foo(10)
x += 8
}
j := 0
} }

View File

@ -48,8 +48,8 @@ pub fn (p mut Parser) get_type() types.Type {
return types.string_type return types.string_type
} }
else { else {
verror('bad type lit') p.error('bad type lit')
exit(1) exit(0)
} }
} }
} }
@ -68,10 +68,10 @@ pub fn parse_file(text string, table &table.Table) ast.Program {
} }
// println('expr at ' + p.tok.str()) // println('expr at ' + p.tok.str())
s := p.stmt() s := p.stmt()
println(s) // println(s)
stmts << s // p.stmt() stmts << s // p.stmt()
} }
println('nr stmts = $stmts.len') // println('nr stmts = $stmts.len')
// println(stmts[0]) // println(stmts[0])
return ast.Program{ return ast.Program{
stmts: stmts stmts: stmts
@ -184,6 +184,9 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
// println('assignn_stmt() ' + op.str()) // println('assignn_stmt() ' + op.str())
p.next() p.next()
right_expr,right_type := p.expr(0) right_expr,right_type := p.expr(0)
if !types.check(left_type, right_type) {
p.error('oops')
}
return ast.AssignStmt{ return ast.AssignStmt{
left: left_expr left: left_expr
right: right_expr right: right_expr
@ -196,6 +199,37 @@ pub fn (p &Parser) error(s string) {
exit(1) 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 // Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
// println('expr at ' + p.tok.str()) // println('expr at ' + p.tok.str())
@ -213,26 +247,9 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
// fn call // fn call
if p.peek_tok.kind == .lpar { if p.peek_tok.kind == .lpar {
println('got fn call') x,typ2 := p.call_expr() // TODO `node,typ :=` should work
fn_name := p.tok.lit node = x
f := p.table.find_fn(fn_name) or { typ = typ2
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
} }
else { else {
// name expr // name expr
@ -243,12 +260,22 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
p.next() p.next()
} }
} }
.key_true {
node = ast.BoolLiteral{
val: true
}
typ = types.bool_type
p.next()
}
.str { .str {
node,typ = p.parse_string_literal() node,typ = p.parse_string_literal()
} }
.number { .number {
node,typ = p.parse_number_literal() node,typ = p.parse_number_literal()
} }
.key_if {
node,typ = p.if_expr()
}
.lpar { .lpar {
node,typ = p.expr(0) node,typ = p.expr(0)
p.check(.rpar) p.check(.rpar)
@ -299,6 +326,22 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
return node,typ 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) { fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.StringLiteral{ node = ast.StringLiteral{
@ -399,7 +442,7 @@ fn (p mut Parser) return_stmt() ast.Return {
fn (p mut Parser) var_decl() ast.VarDecl { fn (p mut Parser) var_decl() ast.VarDecl {
is_mut := p.tok.kind == .key_mut // || p.prev_tok == .key_for 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 { if p.tok.kind == .key_mut {
p.check(.key_mut) p.check(.key_mut)
// p.fspace() // p.fspace()
@ -412,7 +455,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
p.read_first_token() p.read_first_token()
expr,t := p.expr(token.lowest_prec) expr,t := p.expr(token.lowest_prec)
if _ := p.table.find_var(name) { if _ := p.table.find_var(name) {
verror('redefinition of `$name`') p.error('redefinition of `$name`')
} }
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: name name: name

View File

@ -10,13 +10,18 @@ pub:
} }
pub const ( pub const (
void_type = Type{'void', 0} void_type = Type{
int_type = Type{'int', 1} 'void',0}
string_type = Type{'string', 2} int_type = Type{
f64_type = Type{'f64', 3} 'int',1}
string_type = Type{
'string',2}
f64_type = Type{
'f64',3}
bool_type = Type{
'bool',4}
) )
pub fn check(got, expected &Type) bool { pub fn check(got, expected &Type) bool {
if got.idx != expected.idx { if got.idx != expected.idx {
return false return false