v2: lots of small fixes parent method/field resolution

pull/3687/head
joe-conigliaro 2020-02-08 19:50:12 +11:00 committed by GitHub
parent ea9961a8fb
commit 9e9bdc32ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 123 additions and 88 deletions

View File

@ -116,6 +116,7 @@ pub:
typ table.TypeRef typ table.TypeRef
args []Arg args []Arg
is_pub bool is_pub bool
is_variadic bool
receiver Field receiver Field
} }

View File

@ -28,7 +28,7 @@ pub fn (c mut Checker) check(ast_file ast.File) {
// if ast_file.unresolved.len != c.resolved.len { // if ast_file.unresolved.len != c.resolved.len {
// c.resolve_exprs(file) // c.resolve_exprs(file)
// } // }
c.complete_types(ast_file) c.complete_types()
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) c.stmt(stmt)
} }
@ -39,7 +39,7 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) {
// files this muse be done first. TODO: optimize // files this muse be done first. TODO: optimize
for file in ast_files { for file in ast_files {
c.file_name = file.path c.file_name = file.path
c.resolve_expr_types(file) c.resolve_expr_types(file.unresolved)
} }
for file in ast_files { for file in ast_files {
c.check(file) c.check(file)
@ -47,14 +47,14 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) {
} }
// resolve type of unresolved expressions // resolve type of unresolved expressions
fn (c mut Checker) resolve_expr_types(f ast.File) { fn (c mut Checker) resolve_expr_types(exprs []ast.Expr) {
for x in f.unresolved { for x in exprs {
c.resolved << c.expr(x) c.resolved << c.expr(x)
} }
} }
// update any types chich contain unresolved sub types // update any types chich contain unresolved sub types
fn (c &Checker) complete_types(f ast.File) { fn (c &Checker) complete_types() {
for idx, t in c.table.types { for idx, t in c.table.types {
// println('Resolve type: $t.name') // println('Resolve type: $t.name')
if t.kind == .array { if t.kind == .array {
@ -160,6 +160,16 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef {
c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos) c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos)
} }
} }
// for debugging
if f.name == 'backtrace_symbols_fd' {
println('ARGS FOR: backtrace_symbols_fd:')
for i, arg_expr in call_expr.args {
typ := c.expr(arg_expr)
println(' -- $i - $typ.typ.name')
}
}
// TODO: variadic
if fn_name != 'printf' && f.args.len > 0 {
for i, arg in f.args { for i, arg in f.args {
arg_expr := call_expr.args[i] arg_expr := call_expr.args[i]
typ := c.expr(arg_expr) typ := c.expr(arg_expr)
@ -167,6 +177,7 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef {
c.error('!cannot use type `$typ.typ.name` as type `$arg.typ.typ.name` in argument to `$fn_name`', call_expr.pos) c.error('!cannot use type `$typ.typ.name` as type `$arg.typ.typ.name` in argument to `$fn_name`', call_expr.pos)
} }
} }
}
return f.return_type return f.return_type
} }
c.error('unknown fn: $fn_name', call_expr.pos) c.error('unknown fn: $fn_name', call_expr.pos)
@ -178,11 +189,9 @@ pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr)
if method := typ.typ.find_method(method_call_expr.name) { if method := typ.typ.find_method(method_call_expr.name) {
return method.return_type return method.return_type
} }
if typ.typ.kind == .array { // check parent
a := c.table.find_type('array') or { if !isnil(typ.typ.parent) {
exit(1) if method := typ.typ.parent.find_method(method_call_expr.name) {
}
if method := a.find_method(method_call_expr.name) {
return method.return_type return method.return_type
} }
} }
@ -201,13 +210,17 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.TypeRef
} }
return field.typ return field.typ
} }
.array {
if field_name == 'len' {
return c.table.type_ref(table.int_type_idx)
}
}
.string {}
else { else {
// types with parent struct (array/maps) handled here
if !isnil(typ.typ.parent) && typ.typ.parent.kind == .struct_ {
parent := typ.typ.parent
if field := c.table.struct_find_field(parent, field_name) {
if field.typ.typ.kind == .unresolved {
return c.resolved[field.typ.idx]
}
return field.typ
}
}
c.error('`$typ.typ.name` is not a struct', selector_expr.pos) c.error('`$typ.typ.name` is not a struct', selector_expr.pos)
} }
} }
@ -439,6 +452,8 @@ pub fn (c &Checker) error(s string, pos token.Position) {
path = path.replace(workdir, '') path = path.replace(workdir, '')
} }
final_msg_line := '$path:$pos.line_nr: checker error: $s' final_msg_line := '$path:$pos.line_nr: checker error: $s'
// sometimes eprintln wasnt working?
println(final_msg_line)
eprintln(final_msg_line) eprintln(final_msg_line)
/* /*
if colored_output { if colored_output {

View File

@ -72,8 +72,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.definitions.write('$it.typ.typ.name ${it.name}(') g.definitions.write('$it.typ.typ.name ${it.name}(')
} }
for i, arg in it.args { for i, arg in it.args {
g.write(arg.typ.typ.name + ' ' + arg.name) mut arg_type := arg.typ.typ.name
g.definitions.write(arg.typ.typ.name + ' ' + arg.name) if i == it.args.len-1 && it.is_variadic {
arg_type = 'variadic_$arg.typ.typ.name'
}
g.write(arg_type + ' ' + arg.name)
g.definitions.write(arg_type + ' ' + arg.name)
if i < it.args.len - 1 { if i < it.args.len - 1 {
g.write(', ') g.write(', ')
g.definitions.write(', ') g.definitions.write(', ')

View File

@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.TypeRef) {
name: fn_name name: fn_name
args: args args: args
// tok: tok // tok: tok
pos: tok.position() pos: tok.position()
} }
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
@ -93,6 +92,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
} }
// println('fn decl $name') // println('fn decl $name')
p.check(.lpar) p.check(.lpar)
mut is_variadic := false
// Args // Args
mut args := []table.Var mut args := []table.Var
mut ast_args := []ast.Arg mut ast_args := []ast.Arg
@ -102,12 +102,32 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.peek_tok.kind == .rpar p.peek_tok.kind == .rpar
if types_only { if types_only {
p.warn('types only') p.warn('types only')
mut arg_no := 1
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
p.parse_type() arg_name := 'arg_$arg_no'
if p.tok.kind == .ellipsis {
p.check(.ellipsis)
is_variadic = true
}
arg_type := p.parse_type()
if p.tok.kind == .comma { if p.tok.kind == .comma {
if is_variadic {
p.error('cannot use ...(variadic) with non-final parameter no $arg_no')
}
p.next() p.next()
} }
arg := table.Var{
name: arg_name
typ: arg_type
} }
args << arg
//p.table.register_var(arg)
ast_args << ast.Arg{
name: arg_name
typ: arg_type
}
}
arg_no++
} }
else { else {
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
@ -120,6 +140,10 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.check(.key_mut) p.check(.key_mut)
} }
if p.tok.kind == .ellipsis {
p.check(.ellipsis)
is_variadic = true
}
typ := p.parse_type() typ := p.parse_type()
for arg_name in arg_names { for arg_name in arg_names {
arg := table.Var{ arg := table.Var{
@ -129,10 +153,11 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
args << arg args << arg
p.table.register_var(arg) p.table.register_var(arg)
ast_args << ast.Arg{ ast_args << ast.Arg{
typ: typ
name: arg_name name: arg_name
typ: typ
} }
if typ.typ.kind == .variadic && p.tok.kind == .comma { //if typ.typ.kind == .variadic && p.tok.kind == .comma {
if is_variadic && p.tok.kind == .comma {
p.error('cannot use ...(variadic) with non-final parameter $arg_name') p.error('cannot use ...(variadic) with non-final parameter $arg_name')
} }
} }
@ -167,6 +192,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
name: name name: name
args: args args: args
return_type: typ return_type: typ
is_variadic: is_variadic
is_c: is_c is_c: is_c
}) })
} }
@ -180,6 +206,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
typ: typ typ: typ
args: ast_args args: ast_args
is_pub: is_pub is_pub: is_pub
is_variadic: is_variadic
receiver: ast.Field{ receiver: ast.Field{
name: rec_name name: rec_name
typ: rec_type typ: rec_type

View File

@ -62,13 +62,6 @@ pub fn (p mut Parser) parse_multi_return_ti() table.TypeRef {
return p.table.type_ref(idx) return p.table.type_ref(idx)
} }
pub fn (p mut Parser) parse_variadic_ti() table.TypeRef {
p.check(.ellipsis)
variadic_type := p.parse_type()
idx := p.table.find_or_register_variadic(variadic_type)
return p.table.type_ref(idx)
}
pub fn (p mut Parser) parse_fn_type() table.TypeRef { pub fn (p mut Parser) parse_fn_type() table.TypeRef {
// p.check(.key_fn) // p.check(.key_fn)
p.fn_decl() p.fn_decl()
@ -105,13 +98,6 @@ pub fn (p mut Parser) parse_type() table.TypeRef {
} }
return p.parse_multi_return_ti() return p.parse_multi_return_ti()
} }
// variadic
.ellipsis {
if nr_muls > 0 {
p.error('parse_ti: unexpected `&` before variadic')
}
return p.parse_variadic_ti()
}
else { else {
defer { defer {
p.next() p.next()

View File

@ -71,12 +71,13 @@ pub fn parse_file(path string, table &table.Table) ast.File {
table: table table: table
file_name: path file_name: path
pref: &pref.Preferences{} pref: &pref.Preferences{}
builtin_mod: true
} }
p.read_first_token() p.read_first_token()
// module decl // module decl
module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main' module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main'
} } } }
p.mod = module_decl.name
p.builtin_mod = p.mod == 'builtin'
// imports // imports
mut imports := []ast.Import mut imports := []ast.Import
for p.tok.kind == .key_import { for p.tok.kind == .key_import {
@ -471,7 +472,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) {
if p.peek_tok.kind == .lpar { if p.peek_tok.kind == .lpar {
name := p.tok.lit name := p.tok.lit
// type cast. TODO: finish // type cast. TODO: finish
if name in p.table.type_idxs { if name in table.builtin_type_names {
// ['byte', 'string', 'int'] // ['byte', 'string', 'int']
// SKIP FOR NOW // SKIP FOR NOW
mut par_d := 0 mut par_d := 0
@ -1054,26 +1055,30 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
} }
fields << table.Field{ fields << table.Field{
name: field_name name: field_name
// type_idx: ti.idx
typ: typ typ: typ
} }
// println('struct field $ti.name $field_name') // println('struct field $ti.name $field_name')
} }
p.check(.rcbr) p.check(.rcbr)
if name != 'string' { t := table.Type{
ret := p.table.register_type(table.Type{
parent: 0 parent: 0
kind: .struct_ kind: .struct_
name: name name: name
info: table.Struct{ info: table.Struct{
fields: fields fields: fields
} }
}) }
mut ret := 0
if p.builtin_mod && t.name in table.builtin_type_names {
// this allows overiding the builtins type
// with the real struct type info parsed from builtin
ret = p.table.register_builtin_type(t)
} else {
ret = p.table.register_type(t)
}
if ret == -1 { if ret == -1 {
p.error('cannot register type `$name`, another type with this name exists') p.error('cannot register type `$name`, another type with this name exists')
} }
}
return ast.StructDecl{ return ast.StructDecl{
name: name name: name
is_pub: is_pub is_pub: is_pub

View File

@ -3,7 +3,7 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module table module table
pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn
pub struct Type { pub struct Type {
pub: pub:
@ -47,6 +47,13 @@ pub const (
// map_type_idx = 18 // map_type_idx = 18
) )
pub const (
builtin_type_names = [
'void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64',
'f32' ,'f64', 'string', 'char', 'byte' ,'bool', 'struct', 'array', 'array_fixed', 'map'
]
)
pub enum Kind { pub enum Kind {
placeholder placeholder
void void
@ -66,14 +73,13 @@ pub enum Kind {
char char
byte byte
bool bool
const_ //const_
enum_ //enum_
struct_ struct_
array array
array_fixed array_fixed
map map
multi_return multi_return
variadic
unresolved unresolved
} }
@ -371,9 +377,6 @@ pub fn (k Kind) str() string {
.multi_return{ .multi_return{
'multi_return' 'multi_return'
} }
.variadic{
'variadic'
}
else { else {
'unknown'} 'unknown'}
} }
@ -407,6 +410,7 @@ pub mut:
pub struct Field { pub struct Field {
pub: pub:
name string name string
mut:
typ TypeRef typ TypeRef
// type_idx int // type_idx int
} }
@ -447,11 +451,6 @@ mut:
types []TypeRef types []TypeRef
} }
pub struct Variadic {
pub:
typ TypeRef
}
[inline] [inline]
pub fn (t &Table) get_type(idx int) &Type { pub fn (t &Table) get_type(idx int) &Type {
if idx == 0 { if idx == 0 {

View File

@ -27,6 +27,7 @@ pub:
name string name string
args []Var args []Var
return_type TypeRef return_type TypeRef
is_variadic bool
is_c bool is_c bool
} }
@ -279,6 +280,19 @@ pub fn (t &Table) find_type(name string) ?Type {
return none return none
} }
// this will override or register builtin type
// allows prexisitng types added in register_builtins
// to be overriden with their real type info
[inline]
pub fn (t mut Table) register_builtin_type(typ Type) int {
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
t.types[existing_idx] = typ
return existing_idx
}
return t.register_type(typ)
}
[inline] [inline]
pub fn (t mut Table) register_type(typ Type) int { pub fn (t mut Table) register_type(typ Type) int {
existing_idx := t.type_idxs[typ.name] existing_idx := t.type_idxs[typ.name]
@ -399,25 +413,6 @@ pub fn (t mut Table) find_or_register_multi_return(mr_typs []TypeRef) int {
return t.register_type(mr_type) return t.register_type(mr_type)
} }
pub fn (t mut Table) find_or_register_variadic(variadic_typ TypeRef) int {
name := 'variadic_$variadic_typ.typ.name'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx
}
// register
variadic_type := Type{
parent: 0
kind: .variadic
name: name
info: Variadic{
typ: variadic_typ
}
}
return t.register_type(variadic_type)
}
pub fn (t mut Table) add_placeholder_type(name string) int { pub fn (t mut Table) add_placeholder_type(name string) int {
ph_type := Type{ ph_type := Type{
parent: 0 parent: 0
@ -433,6 +428,9 @@ pub fn (t &Table) check(got, expected &TypeRef) bool {
if expected.typ.kind == .voidptr { if expected.typ.kind == .voidptr {
return true return true
} }
if expected.typ.kind in [.voidptr, .byteptr, .charptr] && got.typ.kind == .int {
return true
}
if expected.typ.kind == .byteptr && got.typ.kind == .voidptr { if expected.typ.kind == .byteptr && got.typ.kind == .voidptr {
return true return true
} }