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:
parent
63b70ddb06
commit
2d2e0307b8
16
tools/gen10k.v
Normal file
16
tools/gen10k.v
Normal 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
20
v2.v
Normal 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()
|
||||
}
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ module cgen
|
||||
import (
|
||||
strings
|
||||
v.ast
|
||||
term
|
||||
)
|
||||
|
||||
struct Gen {
|
||||
@ -61,7 +62,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.expr(it.expr)
|
||||
g.writeln(';')
|
||||
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 {
|
||||
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('cgen.expr(): bad node')
|
||||
println(term.red('cgen.expr(): bad node'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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'))
|
||||
|
@ -16,5 +16,10 @@ void function2() {
|
||||
x += 1;
|
||||
m += 2;
|
||||
function1();
|
||||
if (true) {
|
||||
foo(10);
|
||||
x += 8;
|
||||
}
|
||||
int j = 0;
|
||||
}
|
||||
|
||||
|
@ -20,5 +20,11 @@ fn function2() {
|
||||
function1()
|
||||
//a += 1
|
||||
//c := 0
|
||||
if true {
|
||||
foo(10)
|
||||
x += 8
|
||||
}
|
||||
j := 0
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user