1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker/gen/table: impl fn types & sum/other fixes & tidy

This commit is contained in:
Joe Conigliaro 2020-03-12 02:10:46 +11:00
parent 1cea85df0c
commit a1314bd199
10 changed files with 151 additions and 53 deletions

View File

@ -8,7 +8,7 @@ import (
v.table
)
pub type TypeDecl = AliasTypeDecl | SumTypeDecl
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
@ -128,15 +128,17 @@ pub:
pub struct Arg {
pub:
typ table.Type
name string
name string
is_mut bool
typ table.Type
}
pub struct FnDecl {
pub:
name string
stmts []Stmt
typ table.Type
return_type table.Type
args []Arg
is_deprecated bool
is_pub bool
@ -232,9 +234,9 @@ pub:
scope &Scope
}
pub struct IdentFunc {
pub struct IdentFn {
pub mut:
return_type table.Type
typ table.Type
}
pub struct IdentVar {
@ -244,7 +246,7 @@ pub mut:
is_static bool
}
pub type IdentInfo = IdentFunc | IdentVar
pub type IdentInfo = IdentFn | IdentVar
pub enum IdentKind {
unresolved
@ -459,6 +461,13 @@ pub:
sub_types []table.Type
}
pub struct FnTypeDecl {
pub:
name string
is_pub bool
typ table.Type
}
pub struct DeferStmt {
pub:
stmts []Stmt

View File

@ -48,10 +48,10 @@ pub fn (node &FnDecl) str(t &table.Table) string {
}
}
f.write(')')
if node.typ != table.void_type {
if node.return_type != table.void_type {
// typ := t.type_to_str(node.typ)
// if typ.starts_with('
f.write(' ' + t.type_to_str(node.typ))
f.write(' ' + t.type_to_str(node.return_type))
}
return f.str()
}

View File

@ -204,6 +204,19 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
f = f1
}
}
// check for arg (var) of fn type
if !found {
scope := c.file.scope.innermost(call_expr.pos.pos)
if var := scope.find_var(fn_name) {
if var.typ != 0 {
vts := c.table.get_type_symbol(var.typ)
if vts.kind == .function {
f = vts.info as table.Fn
found = true
}
}
}
}
if !found {
c.error('unknown fn: $fn_name', call_expr.pos)
}
@ -277,11 +290,17 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
return info.elem_type
}
if method := c.table.type_find_method(typ_sym, name) {
if method_call_expr.args.len < method.args.len-1 {
c.error('too few arguments in call to `${typ_sym.name}.$name`', method_call_expr.pos)
}
else if !method.is_variadic && method_call_expr.args.len > method.args.len+1 {
c.error('too many arguments in call to `${typ_sym.name}.$name` ($method_call_expr.args.len instead of $method.args.len)', method_call_expr.pos)
}
// if name == 'clone' {
// println('CLONE nr args=$method.args.len')
// }
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
c.expected_type = method.args[i+1].typ
c.expr(arg_expr)
}
method_call_expr.receiver_type = method.args[0].typ
@ -492,7 +511,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.expr(it.expr)
}
ast.FnDecl {
c.fn_return_type = it.typ
c.fn_return_type = it.return_type
for stmt in it.stmts {
c.stmt(stmt)
}
@ -697,8 +716,8 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
}
// second use, already resovled in unresovled branch
else if ident.kind == .function {
info := ident.info as ast.IdentFunc
return info.return_type
info := ident.info as ast.IdentFn
return info.typ
}
// Handle indents with unresolved types during the parsing step
// (declared after first usage)
@ -719,12 +738,13 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
}
// Function object (not a call), e.g. `onclick(my_click)`
if func := c.table.find_fn(name) {
ident.name = name
fn_type := c.table.find_or_register_fn_type(func)
ident.name = name
ident.kind = .function
ident.info = ast.IdentFunc{
return_type: func.return_type
ident.info = ast.IdentFn{
typ: fn_type
}
return func.return_type
return fn_type
}
}
// TODO
@ -889,6 +909,7 @@ pub fn (c mut Checker) enum_val(node ast.EnumVal) table.Type {
typ := c.table.get_type_symbol(table.Type(typ_idx))
// println('tname=$typ.name')
if typ.kind != .enum_ {
println('# $typ.kind.str()')
c.error('not an enum', node.pos)
}
// info := typ.info as table.Enum

View File

@ -245,7 +245,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('return')
// multiple returns
if it.exprs.len > 1 {
styp := g.typ(g.fn_decl.typ)
styp := g.typ(g.fn_decl.return_type)
g.write(' ($styp){')
for i, expr in it.exprs {
g.write('.arg$i=')
@ -375,8 +375,8 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if name.starts_with('_op_') {
name = op_to_fn_name(name)
}
// type_name := g.table.type_to_str(it.typ)
type_name := g.typ(it.typ)
// type_name := g.table.type_to_str(it.return_type)
type_name := g.typ(it.return_type)
g.write('$type_name ${name}(')
g.definitions.write('$type_name ${name}(')
}

View File

@ -37,7 +37,7 @@ pub fn (g mut JsGen) writeln(s string) {
fn (g mut JsGen) stmt(node ast.Stmt) {
match node {
ast.FnDecl {
type_sym := g.table.get_type_symbol(it.typ)
type_sym := g.table.get_type_symbol(it.return_type)
g.write('/** @return { $type_sym.name } **/\nfunction ${it.name}(')
for arg in it.args {
arg_type_sym := g.table.get_type_symbol(arg.typ)

View File

@ -81,27 +81,18 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
is_method = true
p.next()
rec_name = p.check_name()
if p.tok.kind == .key_mut {
rec_mut = true
}
rec_mut = p.tok.kind == .key_mut
// if rec_mut {
// p.check(.key_mut)
// }
// TODO: talk to alex, should mut be parsed with the type like this?
// or should it be a property of the arg, like this ptr/mut becomes indistinguishable
rec_type = p.parse_type()
args << table.Var{
// Receiver is the first arg
typ: rec_type
name: rec_name
}
ast_args << ast.Arg{
name: rec_name
is_mut: rec_mut
typ: rec_type
}
// p.table.register_var(table.Var{
// name: rec_name
// typ: rec_type
// })
p.scope.register_var(ast.Var{
name: rec_name
typ: rec_type
})
p.check(.rpar)
}
mut name := ''
@ -126,6 +117,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
for ast_arg in ast_args {
var := table.Var{
name: ast_arg.name
is_mut: ast_arg.is_mut
typ: ast_arg.typ
}
args << var
@ -136,9 +128,9 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
// p.table.register_var(var)
}
// Return type
mut typ := table.void_type
mut return_type := table.void_type
if p.tok.kind.is_start_of_type() {
typ = p.parse_type()
return_type = p.parse_type()
}
// Register
if is_method {
@ -147,7 +139,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
type_sym.register_method(table.Fn{
name: name
args: args
return_type: typ
return_type: return_type
})
}
else {
@ -160,7 +152,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.table.register_fn(table.Fn{
name: name
args: args
return_type: typ
return_type: return_type
is_variadic: is_variadic
is_c: is_c
})
@ -175,7 +167,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
return ast.FnDecl{
name: name
stmts: stmts
typ: typ
return_type: return_type
args: ast_args
is_deprecated: is_deprecated
is_pub: is_pub
@ -202,6 +194,10 @@ fn (p mut Parser) fn_args() ([]ast.Arg,bool) {
mut arg_no := 1
for p.tok.kind != .rpar {
arg_name := 'arg_$arg_no'
is_mut := p.tok.kind == .key_mut
if is_mut {
p.check(.key_mut)
}
if p.tok.kind == .ellipsis {
p.check(.ellipsis)
is_variadic = true
@ -218,6 +214,7 @@ fn (p mut Parser) fn_args() ([]ast.Arg,bool) {
}
args << ast.Arg{
name: arg_name
is_mut: is_mut
typ: arg_type
}
}
@ -231,7 +228,8 @@ fn (p mut Parser) fn_args() ([]ast.Arg,bool) {
p.check(.comma)
arg_names << p.check_name()
}
if p.tok.kind == .key_mut {
is_mut := p.tok.kind == .key_mut
if is_mut {
p.check(.key_mut)
}
if p.tok.kind == .ellipsis {
@ -245,6 +243,7 @@ fn (p mut Parser) fn_args() ([]ast.Arg,bool) {
for arg_name in arg_names {
args << ast.Arg{
name: arg_name
is_mut: is_mut
typ: typ
}
// if typ.typ.kind == .variadic && p.tok.kind == .comma {

View File

@ -66,15 +66,32 @@ pub fn (p mut Parser) parse_multi_return_type() table.Type {
return table.new_type(idx)
}
pub fn (p mut Parser) parse_fn_type() table.Type {
// p.warn('parrse fn')
// given anon name based off signature when `name` is blank
pub fn (p mut Parser) parse_fn_type(name string) table.Type {
// p.warn('parse fn')
p.check(.key_fn)
// p.fn_decl()
p.fn_args()
if p.tok.kind.is_start_of_type() {
p.parse_type()
ast_args, is_variadic := p.fn_args()
mut args := []table.Var
for ast_arg in ast_args {
arg := table.Var{
name: ast_arg.name
is_mut: ast_arg.is_mut
typ: ast_arg.typ
}
args << arg
}
return table.int_type
mut return_type := table.void_type
if p.tok.kind.is_start_of_type() {
return_type = p.parse_type()
}
func := table.Fn{
name: name
args: args
is_variadic: is_variadic
return_type: return_type
}
idx := p.table.find_or_register_fn_type(func)
return table.new_type(idx)
}
pub fn (p mut Parser) parse_type() table.Type {
@ -137,7 +154,7 @@ pub fn (p mut Parser) parse_any_type(is_c, is_ptr bool) table.Type {
match p.tok.kind {
// func
.key_fn {
return p.parse_fn_type()
return p.parse_fn_type('')
}
// array
.lsbr {

View File

@ -1727,6 +1727,16 @@ fn (p mut Parser) type_decl() ast.TypeDecl {
sub_types: sum_variants
}
}
// function type: `type mycallback fn(string, int)`
if p.tok.kind == .key_fn {
fn_name := p.prepend_mod(name)
fn_type := p.parse_fn_type(fn_name)
return ast.FnTypeDecl{
name: fn_name
is_pub: is_pub
typ: fn_type
}
}
// type MyType int
parent_type := p.parse_type()
pid := table.type_idx(parent_type)

View File

@ -8,7 +8,7 @@ import (
)
pub type TypeInfo = Array | ArrayFixed | Map | Struct |
MultiReturn | Alias | Enum | SumType
MultiReturn | Alias | Enum | SumType | Fn
pub struct TypeSymbol {
pub:
@ -87,6 +87,7 @@ pub enum Kind {
sum_type
alias
enum_
function
}
pub fn (t &TypeSymbol) str() string {

View File

@ -60,6 +60,25 @@ pub fn (t mut Table) register_global(name string, typ Type) {
}
}
// used to compare fn's & for naming anon fn's
pub fn (f &Fn) signature() string {
mut sig := ''
for i, arg in f.args {
// TODO: for now ignore mut/pts in sig for now
typ := type_set_nr_muls(arg.typ, 0)
// if arg.is_mut {
// sig += 'mut_'
// }
// sig += '$arg.typ'
sig += '$typ'
if i < f.args.len-1 {
sig += '_'
}
}
sig += '_$f.return_type'
return sig
}
pub fn (t &Table) find_fn(name string) ?Fn {
f := t.fns[name]
if f.name.str != 0 {
@ -360,6 +379,20 @@ pub fn (t mut Table) find_or_register_multi_return(mr_typs []Type) int {
return t.register_type_symbol(mr_type)
}
pub fn (t mut Table) find_or_register_fn_type(f Fn) int {
name := if f.name.len > 0 {
f.name
}
else {
'anon_$f.signature()'
}
return t.register_type_symbol(TypeSymbol{
kind: .function
name: name
info: f
})
}
pub fn (t mut Table) add_placeholder_type(name string) int {
ph_type := TypeSymbol{
kind: .placeholder
@ -440,12 +473,20 @@ pub fn (t &Table) check(got, expected Type) bool {
return true
}
}
else if exp_type_sym.kind == .sum_type {
if exp_type_sym.kind == .sum_type {
sum_info := exp_type_sym.info as SumType
if got in sum_info.variants {
return true
}
}
// fn type
if got_type_sym.kind == .function && exp_type_sym.kind == .function {
got_fn := got_type_sym.info as Fn
exp_fn := exp_type_sym.info as Fn
if got_fn.signature() == exp_fn.signature() {
return true
}
}
if got_idx != exp_idx {
// && got.typ.name != expected.typ.name*/
return false