cgen tests

pull/3252/head
Alexander Medvednikov 2019-12-28 11:02:06 +01:00
parent 379c79025b
commit 651c7e8de1
9 changed files with 145 additions and 29 deletions

View File

@ -96,6 +96,20 @@ pub fn eprintln(s string) {
println(s) println(s)
} }
pub fn eprint(s string) {
if isnil(s.str) {
panic('eprint(NIL)')
}
$if !windows {
C.fflush(stdout)
C.fflush(stderr)
C.fprintf(stderr, '%.*s', s.len, s.str)
C.fflush(stderr)
return
}
print(s)
}
pub fn print(s string) { pub fn print(s string) {
$if windows { $if windows {
C.wprintf(s.to_wide()) C.wprintf(s.to_wide())

View File

@ -30,7 +30,7 @@ pub:
val string val string
} }
// module decleration // module declaration
pub struct Module { pub struct Module {
pub: pub:
name string name string

View File

@ -7,11 +7,12 @@ import (
struct Gen { struct Gen {
out strings.Builder out strings.Builder
} }
pub fn gen(program ast.Program) string { pub fn gen(program ast.Program) string {
mut g := Gen{out:strings.new_builder(100)} mut g := Gen{
out: strings.new_builder(100)
}
for expr in program.exprs { for expr in program.exprs {
g.expr(expr) g.expr(expr)
g.writeln('') g.writeln('')
@ -19,9 +20,7 @@ pub fn gen(program ast.Program) string {
return (g.out.str()) return (g.out.str())
} }
pub fn (g &Gen) save() { pub fn (g &Gen) save() {}
}
pub fn (g mut Gen) write(s string) { pub fn (g mut Gen) write(s string) {
g.out.write(s) g.out.write(s)
@ -32,7 +31,7 @@ pub fn (g mut Gen) writeln(s string) {
} }
fn (g mut Gen) expr(node ast.Expr) { fn (g mut Gen) expr(node ast.Expr) {
//println('cgen expr()') // println('cgen expr()')
match node { match node {
ast.IntegerLiteral { ast.IntegerLiteral {
g.write(it.val.str()) g.write(it.val.str())
@ -48,7 +47,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write('tos3("$it.val")') g.write('tos3("$it.val")')
} }
ast.FnDecl { ast.FnDecl {
g.writeln('$it.typ.name $it.name () { ') g.writeln('$it.typ.name ${it.name}() { ')
for expr in it.exprs { for expr in it.exprs {
g.expr(expr) g.expr(expr)
} }
@ -62,17 +61,27 @@ fn (g mut Gen) expr(node ast.Expr) {
ast.BinaryExpr { ast.BinaryExpr {
g.expr(it.left) g.expr(it.left)
match it.op { match it.op {
.plus { g.write(' + ') } .plus {
.minus { g.write(' - ') } g.write(' + ')
.mul { g.write(' * ') } }
.div { g.write(' / ') } .minus {
.plus_assign { g.write(' += ') } g.write(' - ')
}
.mul {
g.write(' * ')
}
.div {
g.write(' / ')
}
.plus_assign {
g.write(' += ')
}
else {} else {}
} }
g.expr(it.right) g.expr(it.right)
// if typ.name != typ2.name { // if typ.name != typ2.name {
//verror('bad types $typ.name $typ2.name') // verror('bad types $typ.name $typ2.name')
//} // }
} }
ast.VarDecl { ast.VarDecl {
g.write('$it.typ.name $it.name = ') g.write('$it.typ.name $it.name = ')
@ -89,4 +98,3 @@ fn verror(s string) {
println(s) println(s)
exit(1) exit(1)
} }

View File

@ -0,0 +1,50 @@
import (
os
v.parser
v.ast
v.cgen
v.table
)
const (
nr_tests = 2
)
fn test_c_files() {
println('Running V => C tests')
for i in 1 .. nr_tests + 1 {
text := os.read_file('tests/${i}.v') or {
panic(err)
}
ctext := os.read_file('tests/${i}.c') or {
panic(err)
}
table := &table.Table{}
program := parser.parse_file(text, table)
res := cgen.gen(program)
if compare_texts(res, ctext) {
eprintln('${i}... OK')
}
else {
eprintln('${i}... FAIL')
eprintln('expected:\n$ctext\ngot:\n$res')
}
}
}
fn compare_texts(a, b string) bool {
lines_a := a.trim_space().split_into_lines()
lines_b := b.trim_space().split_into_lines()
if lines_a.len != lines_b.len {
println('different len')
return false
}
for i, line_a in lines_a {
line_b := lines_b[i]
if line_a.trim_space() != line_b.trim_space() {
println('!' + line_a)
return false
}
}
return true
}

View File

@ -0,0 +1,4 @@
int main() {
int a = 10;
return 0;
}

View File

@ -0,0 +1,4 @@
fn main() int {
a := 10
return 0
}

View File

@ -0,0 +1,11 @@
int function1() {
int a = 10 + 1;
return 0;
}
void function2() {
int x = 0;
f64 f = 10.1;
string s = tos3("hi");
int m = 10;
}

View File

@ -0,0 +1,12 @@
fn function1() int {
a := 10 + 1
return 0
}
// comment
fn function2() {
x := 0
f := 10.1
s := 'hi'
mut m := 10
}

View File

@ -72,7 +72,7 @@ pub fn parse_file(text string, table &table.Table) ast.Program {
expr,_ := p.expr(token.lowest_prec) expr,_ := p.expr(token.lowest_prec)
exprs << expr exprs << expr
} }
println('nr exprs = $exprs.len') // println('nr exprs = $exprs.len')
println(exprs[0]) println(exprs[0])
return ast.Program{ return ast.Program{
exprs} exprs}
@ -90,7 +90,7 @@ pub fn (p mut Parser) parse_block() []ast.Expr {
exprs << expr exprs << expr
} }
p.next() p.next()
println('nr exprs in block = $exprs.len') // println('nr exprs in block = $exprs.len')
return exprs return exprs
} }
@ -146,6 +146,9 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
.key_return { .key_return {
return p.return_stmt() return p.return_stmt()
} }
.key_mut {
return p.var_decl()
}
.name { .name {
if p.peek_tok.kind == .decl_assign { if p.peek_tok.kind == .decl_assign {
return p.var_decl() return p.var_decl()
@ -159,9 +162,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
} }
.lpar { .lpar {
node,typ = p.expr(0) node,typ = p.expr(0)
if p.tok.kind != .rpar { p.check(.rpar)
panic('Parse Error: expected )')
}
} }
else { else {
p.next() p.next()
@ -173,6 +174,9 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
op: p.tok.kind op: p.tok.kind
} }
} }
else {
verror('!unknown token ' + p.tok.str())
}
} }
} }
// left binding power // left binding power
@ -256,7 +260,7 @@ fn (p mut Parser) parse_number_literal() (ast.Expr,types.Type) {
// val: lit.f64() // val: lit.f64()
val: lit val: lit
} }
typ = types.int_type typ = types.f64_type
} }
else { else {
node = ast.IntegerLiteral{ node = ast.IntegerLiteral{
@ -283,7 +287,7 @@ fn (p mut Parser) import_stmt() (ast.Expr,types.Type) {
fn (p mut Parser) fn_decl() (ast.Expr,types.Type) { fn (p mut Parser) fn_decl() (ast.Expr,types.Type) {
p.check(.key_fn) p.check(.key_fn)
name := p.tok.lit name := p.tok.lit
println('fn decl $name') // println('fn decl $name')
p.check(.name) p.check(.name)
p.check(.lpar) p.check(.lpar)
p.check(.rpar) p.check(.rpar)
@ -295,7 +299,6 @@ fn (p mut Parser) fn_decl() (ast.Expr,types.Type) {
} }
p.check(.lcbr) p.check(.lcbr)
// p.check(.rcbr) // p.check(.rcbr)
println('OK!')
exprs := p.parse_block() exprs := p.parse_block()
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.FnDecl{ node = ast.FnDecl{
@ -307,7 +310,7 @@ fn (p mut Parser) fn_decl() (ast.Expr,types.Type) {
} }
fn (p mut Parser) return_stmt() (ast.Expr,types.Type) { fn (p mut Parser) return_stmt() (ast.Expr,types.Type) {
println('return st') // println('return st')
p.next() p.next()
expr,t := p.expr(0) expr,t := p.expr(0)
if !types.check(p.return_type, t) { if !types.check(p.return_type, t) {
@ -321,6 +324,16 @@ fn (p mut Parser) return_stmt() (ast.Expr,types.Type) {
} }
fn (p mut Parser) var_decl() (ast.Expr,types.Type) { fn (p mut Parser) var_decl() (ast.Expr,types.Type) {
is_mut := p.tok.kind == .key_mut // || p.prev_tok == .key_for
is_static := p.tok.kind == .key_static
if p.tok.kind == .key_mut {
p.check(.key_mut)
// p.fspace()
}
if p.tok.kind == .key_static {
p.check(.key_static)
// p.fspace()
}
name := p.tok.lit name := p.tok.lit
p.next() p.next()
p.next() p.next()
@ -329,8 +342,8 @@ fn (p mut Parser) var_decl() (ast.Expr,types.Type) {
verror('redefinition of `$name`') verror('redefinition of `$name`')
} }
p.table.names << name p.table.names << name
println(p.table.names) // println(p.table.names)
println('added $name') // println('added $name')
mut node := ast.Expr{} mut node := ast.Expr{}
// TODO can't return VarDecl{} // TODO can't return VarDecl{}
node = ast.VarDecl{ node = ast.VarDecl{