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() {
|
||||
path := os.args[1]
|
||||
println('V2 $path')
|
||||
text := os.read_file(path)?
|
||||
table := &table.Table{}
|
||||
program := parser.parse_file(text, table)
|
||||
table := table.new_table()
|
||||
program := parser.parse_file(path, table)
|
||||
res := gen.cgen([program])
|
||||
mut out := os.create('out.c')?
|
||||
out.writeln(cdefs)
|
||||
|
|
|
@ -395,7 +395,7 @@ pub fn (v mut V) compile2() {
|
|||
println('all .v files:')
|
||||
println(v.files)
|
||||
}
|
||||
table := &table.Table{}
|
||||
table := table.new_table()
|
||||
files := parser.parse_files(v.files, table)
|
||||
c := gen.cgen(files)
|
||||
println('out: $v.out_name_c')
|
||||
|
|
|
@ -95,6 +95,7 @@ pub:
|
|||
name string
|
||||
args []Expr
|
||||
is_unknown bool
|
||||
tok token.Token
|
||||
}
|
||||
|
||||
pub struct Return {
|
||||
|
|
|
@ -7,12 +7,14 @@ import (
|
|||
)
|
||||
|
||||
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 {
|
||||
mut g := Gen{
|
||||
out: strings.new_builder(100)
|
||||
definitions: strings.new_builder(100)
|
||||
}
|
||||
for file in files {
|
||||
for stmt in file.stmts {
|
||||
|
@ -20,7 +22,7 @@ pub fn cgen(files []ast.File) string {
|
|||
g.writeln('')
|
||||
}
|
||||
}
|
||||
return g.out.str()
|
||||
return g.definitions.str() + g.out.str()
|
||||
}
|
||||
|
||||
pub fn (g &Gen) save() {}
|
||||
|
@ -42,20 +44,26 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
|||
g.writeln(';')
|
||||
}
|
||||
ast.FnDecl {
|
||||
if it.name == 'main' {
|
||||
is_main := it.name == 'main'
|
||||
if is_main {
|
||||
g.write('int ${it.name}(')
|
||||
}
|
||||
else {
|
||||
g.write('$it.typ.name ${it.name}(')
|
||||
g.definitions.write('$it.typ.name ${it.name}(')
|
||||
}
|
||||
for arg in it.args {
|
||||
g.write(arg.typ.name + ' ' + arg.name)
|
||||
g.definitions.write(arg.typ.name + ' ' + arg.name)
|
||||
}
|
||||
g.writeln(') { ')
|
||||
if !is_main {
|
||||
g.definitions.writeln(');')
|
||||
}
|
||||
for stmt in it.stmts {
|
||||
g.stmt(stmt)
|
||||
}
|
||||
if it.name == 'main' {
|
||||
if is_main {
|
||||
g.writeln('return 0;')
|
||||
}
|
||||
g.writeln('}')
|
||||
|
|
|
@ -21,7 +21,7 @@ fn test_c_files() {
|
|||
ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or {
|
||||
panic(err)
|
||||
}
|
||||
table := &table.Table{}
|
||||
table := &table.new_table()
|
||||
program := parser.parse_file(path, table)
|
||||
res := gen.cgen([program])
|
||||
if compare_texts(res, ctext) {
|
||||
|
@ -46,7 +46,7 @@ fn compare_texts(a, b string) bool {
|
|||
for i, line_a in lines_a {
|
||||
line_b := lines_b[i]
|
||||
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)
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
void foo(int a);
|
||||
|
||||
int main() {
|
||||
int a = 10;
|
||||
a++;
|
||||
int c = -a;
|
||||
a == 1;
|
||||
foo(3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo(int a) {
|
||||
|
||||
}
|
||||
|
|
|
@ -3,4 +3,9 @@ fn main() {
|
|||
a++
|
||||
c := -a
|
||||
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 a = 10 + 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)
|
||||
stmts << s // p.stmt()
|
||||
}
|
||||
p.check_fn_calls()
|
||||
// println('nr stmts = $stmts.len')
|
||||
// println(stmts[0])
|
||||
return ast.File{
|
||||
|
@ -86,6 +87,7 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
|||
// println(s)
|
||||
stmts << s // p.stmt()
|
||||
}
|
||||
p.check_fn_calls()
|
||||
// println('nr stmts = $stmts.len')
|
||||
// println(stmts[0])
|
||||
files << ast.File{
|
||||
|
@ -95,31 +97,14 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
|||
return files
|
||||
}
|
||||
|
||||
// former get_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]
|
||||
if isnil(typ.name.str) || typ.name == '' {
|
||||
p.error('undefined type `$p.tok.lit`')
|
||||
}
|
||||
return typ
|
||||
}
|
||||
typ := p.table.types[p.tok.lit]
|
||||
if isnil(typ.name.str) || typ.name == '' {
|
||||
p.error('undefined type `$p.tok.lit`')
|
||||
}
|
||||
p.next()
|
||||
return typ
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) read_first_token() {
|
||||
|
@ -259,50 +244,13 @@ pub fn (p &Parser) error(s string) {
|
|||
exit(1)
|
||||
}
|
||||
|
||||
pub fn (p &Parser) warn(s string) {
|
||||
println(term.blue('x.v:$p.tok.line_nr: $s'))
|
||||
pub fn (p &Parser) error_at_line(s string, line_nr int) {
|
||||
println(term.bold(term.red('$p.file_name:$line_nr: $s')))
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
|
||||
// println('got fn call')
|
||||
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
|
||||
pub fn (p &Parser) warn(s string) {
|
||||
println(term.blue('x.v:$p.tok.line_nr: $s'))
|
||||
}
|
||||
|
||||
// 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 {
|
||||
p.next()
|
||||
expr,t := p.expr(0)
|
||||
|
|
|
@ -28,6 +28,17 @@ pub:
|
|||
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 {
|
||||
/*
|
||||
for i in 0 .. p.var_idx {
|
||||
|
|
Loading…
Reference in New Issue