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
|
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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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'))
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,5 +20,11 @@ fn function2() {
|
|||||||
function1()
|
function1()
|
||||||
//a += 1
|
//a += 1
|
||||||
//c := 0
|
//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
|
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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user