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
}
// 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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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