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:
parent
1cea85df0c
commit
a1314bd199
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}(')
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user