handle unknown fns; fn.v; type fixes
parent
c949e9e636
commit
460b35137a
5
v2.v
5
v2.v
|
@ -20,9 +20,8 @@ string tos3(char* s) { return (string){ .str = s }; }
|
||||||
fn main() {
|
fn main() {
|
||||||
path := os.args[1]
|
path := os.args[1]
|
||||||
println('V2 $path')
|
println('V2 $path')
|
||||||
text := os.read_file(path)?
|
table := table.new_table()
|
||||||
table := &table.Table{}
|
program := parser.parse_file(path, table)
|
||||||
program := parser.parse_file(text, table)
|
|
||||||
res := gen.cgen([program])
|
res := gen.cgen([program])
|
||||||
mut out := os.create('out.c')?
|
mut out := os.create('out.c')?
|
||||||
out.writeln(cdefs)
|
out.writeln(cdefs)
|
||||||
|
|
|
@ -395,7 +395,7 @@ pub fn (v mut V) compile2() {
|
||||||
println('all .v files:')
|
println('all .v files:')
|
||||||
println(v.files)
|
println(v.files)
|
||||||
}
|
}
|
||||||
table := &table.Table{}
|
table := table.new_table()
|
||||||
files := parser.parse_files(v.files, table)
|
files := parser.parse_files(v.files, table)
|
||||||
c := gen.cgen(files)
|
c := gen.cgen(files)
|
||||||
println('out: $v.out_name_c')
|
println('out: $v.out_name_c')
|
||||||
|
|
|
@ -95,6 +95,7 @@ pub:
|
||||||
name string
|
name string
|
||||||
args []Expr
|
args []Expr
|
||||||
is_unknown bool
|
is_unknown bool
|
||||||
|
tok token.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Return {
|
pub struct Return {
|
||||||
|
|
|
@ -8,11 +8,13 @@ import (
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
|
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cgen(files []ast.File) string {
|
pub fn cgen(files []ast.File) string {
|
||||||
mut g := Gen{
|
mut g := Gen{
|
||||||
out: strings.new_builder(100)
|
out: strings.new_builder(100)
|
||||||
|
definitions: strings.new_builder(100)
|
||||||
}
|
}
|
||||||
for file in files {
|
for file in files {
|
||||||
for stmt in file.stmts {
|
for stmt in file.stmts {
|
||||||
|
@ -20,7 +22,7 @@ pub fn cgen(files []ast.File) string {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return g.out.str()
|
return g.definitions.str() + g.out.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (g &Gen) save() {}
|
pub fn (g &Gen) save() {}
|
||||||
|
@ -42,20 +44,26 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
if it.name == 'main' {
|
is_main := it.name == 'main'
|
||||||
|
if is_main {
|
||||||
g.write('int ${it.name}(')
|
g.write('int ${it.name}(')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.write('$it.typ.name ${it.name}(')
|
g.write('$it.typ.name ${it.name}(')
|
||||||
|
g.definitions.write('$it.typ.name ${it.name}(')
|
||||||
}
|
}
|
||||||
for arg in it.args {
|
for arg in it.args {
|
||||||
g.write(arg.typ.name + ' ' + arg.name)
|
g.write(arg.typ.name + ' ' + arg.name)
|
||||||
|
g.definitions.write(arg.typ.name + ' ' + arg.name)
|
||||||
}
|
}
|
||||||
g.writeln(') { ')
|
g.writeln(') { ')
|
||||||
|
if !is_main {
|
||||||
|
g.definitions.writeln(');')
|
||||||
|
}
|
||||||
for stmt in it.stmts {
|
for stmt in it.stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
}
|
}
|
||||||
if it.name == 'main' {
|
if is_main {
|
||||||
g.writeln('return 0;')
|
g.writeln('return 0;')
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
|
|
|
@ -21,7 +21,7 @@ fn test_c_files() {
|
||||||
ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or {
|
ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
table := &table.Table{}
|
table := &table.new_table()
|
||||||
program := parser.parse_file(path, table)
|
program := parser.parse_file(path, table)
|
||||||
res := gen.cgen([program])
|
res := gen.cgen([program])
|
||||||
if compare_texts(res, ctext) {
|
if compare_texts(res, ctext) {
|
||||||
|
@ -46,7 +46,7 @@ fn compare_texts(a, b string) bool {
|
||||||
for i, line_a in lines_a {
|
for i, line_a in lines_a {
|
||||||
line_b := lines_b[i]
|
line_b := lines_b[i]
|
||||||
if line_a.trim_space() != line_b.trim_space() {
|
if line_a.trim_space() != line_b.trim_space() {
|
||||||
println(term.red('i=$i a="$line_a" b="$line_b"'))
|
println(term.red('i=$i V="$line_a" C="$line_b"'))
|
||||||
// exit(1)
|
// exit(1)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
void foo(int a);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int a = 10;
|
int a = 10;
|
||||||
a++;
|
a++;
|
||||||
int c = -a;
|
int c = -a;
|
||||||
a == 1;
|
a == 1;
|
||||||
|
foo(3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void foo(int a) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -3,4 +3,9 @@ fn main() {
|
||||||
a++
|
a++
|
||||||
c := -a
|
c := -a
|
||||||
a == 1
|
a == 1
|
||||||
|
foo(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(a int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
int function1();
|
||||||
|
void foo(int a);
|
||||||
|
void init_user();
|
||||||
|
User get_user();
|
||||||
|
void puts(string s);
|
||||||
|
void function2();
|
||||||
|
void init_array();
|
||||||
|
void end();
|
||||||
|
|
||||||
|
|
||||||
int function1() {
|
int function1() {
|
||||||
int a = 10 + 1;
|
int a = 10 + 1;
|
||||||
int b = a + 1;
|
int b = a + 1;
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
v.scanner
|
||||||
|
v.ast
|
||||||
|
v.token
|
||||||
|
v.table
|
||||||
|
v.types
|
||||||
|
term
|
||||||
|
os
|
||||||
|
)
|
||||||
|
|
||||||
|
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
|
||||||
|
// println('got fn call')
|
||||||
|
tok := p.tok
|
||||||
|
fn_name := p.check_name()
|
||||||
|
p.check(.lpar)
|
||||||
|
mut is_unknown := false
|
||||||
|
mut args := []ast.Expr
|
||||||
|
if f := p.table.find_fn(fn_name) {
|
||||||
|
for i, arg in f.args {
|
||||||
|
e,typ := p.expr(0)
|
||||||
|
if !types.check(arg.typ, typ) {
|
||||||
|
p.error('cannot use 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`')
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
is_unknown = true
|
||||||
|
p.warn('unknown function `$fn_name`')
|
||||||
|
for p.tok.kind != .rpar {
|
||||||
|
e,_ := p.expr(0)
|
||||||
|
args << e
|
||||||
|
if p.tok.kind != .rpar {
|
||||||
|
p.check(.comma)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.check(.rpar)
|
||||||
|
node := ast.CallExpr{
|
||||||
|
name: fn_name
|
||||||
|
args: args
|
||||||
|
is_unknown: is_unknown
|
||||||
|
tok: tok
|
||||||
|
}
|
||||||
|
if is_unknown {
|
||||||
|
p.table.unknown_calls << node
|
||||||
|
}
|
||||||
|
return node,types.int_type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
|
p.table.clear_vars()
|
||||||
|
p.check(.key_fn)
|
||||||
|
name := p.check_name()
|
||||||
|
// println('fn decl $name')
|
||||||
|
p.check(.lpar)
|
||||||
|
// Args
|
||||||
|
mut args := []table.Var
|
||||||
|
mut ast_args := []ast.Arg
|
||||||
|
for p.tok.kind != .rpar {
|
||||||
|
arg_name := p.check_name()
|
||||||
|
typ := p.parse_type()
|
||||||
|
args << table.Var{
|
||||||
|
name: arg_name
|
||||||
|
typ: typ
|
||||||
|
}
|
||||||
|
ast_args << ast.Arg{
|
||||||
|
typ: typ
|
||||||
|
name: arg_name
|
||||||
|
}
|
||||||
|
if p.tok.kind != .rpar {
|
||||||
|
p.check(.comma)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.check(.rpar)
|
||||||
|
// Return type
|
||||||
|
mut typ := types.void_type
|
||||||
|
if p.tok.kind == .name {
|
||||||
|
typ = p.parse_type()
|
||||||
|
p.return_type = typ
|
||||||
|
}
|
||||||
|
p.table.register_fn(table.Fn{
|
||||||
|
name: name
|
||||||
|
args: args
|
||||||
|
})
|
||||||
|
stmts := p.parse_block()
|
||||||
|
return ast.FnDecl{
|
||||||
|
name: name
|
||||||
|
stmts: stmts
|
||||||
|
typ: typ
|
||||||
|
args: ast_args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (p &Parser) check_fn_calls() {
|
||||||
|
println('CHEKC FN CALLS')
|
||||||
|
for call in p.table.unknown_calls {
|
||||||
|
f := p.table.find_fn(call.name) or {
|
||||||
|
p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println(call.name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,7 @@ pub fn parse_file(path string, table &table.Table) ast.File {
|
||||||
// println(s)
|
// println(s)
|
||||||
stmts << s // p.stmt()
|
stmts << s // p.stmt()
|
||||||
}
|
}
|
||||||
|
p.check_fn_calls()
|
||||||
// println('nr stmts = $stmts.len')
|
// println('nr stmts = $stmts.len')
|
||||||
// println(stmts[0])
|
// println(stmts[0])
|
||||||
return ast.File{
|
return ast.File{
|
||||||
|
@ -86,6 +87,7 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
||||||
// println(s)
|
// println(s)
|
||||||
stmts << s // p.stmt()
|
stmts << s // p.stmt()
|
||||||
}
|
}
|
||||||
|
p.check_fn_calls()
|
||||||
// println('nr stmts = $stmts.len')
|
// println('nr stmts = $stmts.len')
|
||||||
// println(stmts[0])
|
// println(stmts[0])
|
||||||
files << ast.File{
|
files << ast.File{
|
||||||
|
@ -95,32 +97,15 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// former get_type()
|
||||||
pub fn (p mut Parser) parse_type() types.Type {
|
pub fn (p mut Parser) parse_type() types.Type {
|
||||||
defer {
|
|
||||||
p.next()
|
|
||||||
}
|
|
||||||
match p.tok.lit {
|
|
||||||
'int' {
|
|
||||||
return types.int_type
|
|
||||||
}
|
|
||||||
'f64' {
|
|
||||||
return types.f64_type
|
|
||||||
}
|
|
||||||
'string' {
|
|
||||||
return types.string_type
|
|
||||||
}
|
|
||||||
'voidptr' {
|
|
||||||
return types.voidptr_type
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
typ := p.table.types[p.tok.lit]
|
typ := p.table.types[p.tok.lit]
|
||||||
if isnil(typ.name.str) || typ.name == '' {
|
if isnil(typ.name.str) || typ.name == '' {
|
||||||
p.error('undefined type `$p.tok.lit`')
|
p.error('undefined type `$p.tok.lit`')
|
||||||
}
|
}
|
||||||
|
p.next()
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (p mut Parser) read_first_token() {
|
pub fn (p mut Parser) read_first_token() {
|
||||||
// need to call next() twice to get peek token and current token
|
// need to call next() twice to get peek token and current token
|
||||||
|
@ -259,50 +244,13 @@ pub fn (p &Parser) error(s string) {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (p &Parser) warn(s string) {
|
pub fn (p &Parser) error_at_line(s string, line_nr int) {
|
||||||
println(term.blue('x.v:$p.tok.line_nr: $s'))
|
println(term.bold(term.red('$p.file_name:$line_nr: $s')))
|
||||||
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
|
pub fn (p &Parser) warn(s string) {
|
||||||
// println('got fn call')
|
println(term.blue('x.v:$p.tok.line_nr: $s'))
|
||||||
fn_name := p.check_name()
|
|
||||||
p.check(.lpar)
|
|
||||||
mut is_unknown := false
|
|
||||||
mut args := []ast.Expr
|
|
||||||
if f := p.table.find_fn(fn_name) {
|
|
||||||
for i, arg in f.args {
|
|
||||||
e,typ := p.expr(0)
|
|
||||||
if !types.check(arg.typ, typ) {
|
|
||||||
p.error('cannot use 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`')
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
is_unknown = true
|
|
||||||
p.warn('unknown function `$fn_name`')
|
|
||||||
for p.tok.kind != .rpar {
|
|
||||||
p.expr(0)
|
|
||||||
if p.tok.kind != .rpar {
|
|
||||||
p.check(.comma)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.check(.rpar)
|
|
||||||
node := ast.CallExpr{
|
|
||||||
name: fn_name
|
|
||||||
args: args
|
|
||||||
is_unknown: is_unknown
|
|
||||||
}
|
|
||||||
if is_unknown {
|
|
||||||
p.table.unknown_calls << node
|
|
||||||
}
|
|
||||||
return node,types.int_type
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of Pratt Precedence
|
// Implementation of Pratt Precedence
|
||||||
|
@ -611,50 +559,6 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) fn_decl() ast.FnDecl {
|
|
||||||
p.table.clear_vars()
|
|
||||||
p.check(.key_fn)
|
|
||||||
name := p.check_name()
|
|
||||||
// println('fn decl $name')
|
|
||||||
p.check(.lpar)
|
|
||||||
// Args
|
|
||||||
mut args := []table.Var
|
|
||||||
mut ast_args := []ast.Arg
|
|
||||||
for p.tok.kind != .rpar {
|
|
||||||
arg_name := p.check_name()
|
|
||||||
typ := p.parse_type()
|
|
||||||
args << table.Var{
|
|
||||||
name: arg_name
|
|
||||||
typ: typ
|
|
||||||
}
|
|
||||||
ast_args << ast.Arg{
|
|
||||||
typ: typ
|
|
||||||
name: arg_name
|
|
||||||
}
|
|
||||||
if p.tok.kind != .rpar {
|
|
||||||
p.check(.comma)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.check(.rpar)
|
|
||||||
// Return type
|
|
||||||
mut typ := types.void_type
|
|
||||||
if p.tok.kind == .name {
|
|
||||||
typ = p.parse_type()
|
|
||||||
p.return_type = typ
|
|
||||||
}
|
|
||||||
p.table.register_fn(table.Fn{
|
|
||||||
name: name
|
|
||||||
args: args
|
|
||||||
})
|
|
||||||
stmts := p.parse_block()
|
|
||||||
return ast.FnDecl{
|
|
||||||
name: name
|
|
||||||
stmts: stmts
|
|
||||||
typ: typ
|
|
||||||
args: ast_args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (p mut Parser) return_stmt() ast.Return {
|
fn (p mut Parser) return_stmt() ast.Return {
|
||||||
p.next()
|
p.next()
|
||||||
expr,t := p.expr(0)
|
expr,t := p.expr(0)
|
||||||
|
|
|
@ -28,6 +28,17 @@ pub:
|
||||||
args []Var
|
args []Var
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_table() &Table {
|
||||||
|
mut t := &Table{}
|
||||||
|
t.register_type(types.void_type)
|
||||||
|
t.register_type(types.int_type)
|
||||||
|
t.register_type(types.string_type)
|
||||||
|
t.register_type(types.f64_type)
|
||||||
|
t.register_type(types.bool_type)
|
||||||
|
t.register_type(types.voidptr_type)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (t &Table) find_var(name string) ?Var {
|
pub fn (t &Table) find_var(name string) ?Var {
|
||||||
/*
|
/*
|
||||||
for i in 0 .. p.var_idx {
|
for i in 0 .. p.var_idx {
|
||||||
|
|
Loading…
Reference in New Issue