mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser: anonymous functions (part 1)
This commit is contained in:
parent
fe249ab0c3
commit
73073cd954
@ -10,7 +10,7 @@ import (
|
||||
|
||||
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
|
||||
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral | AnonFn
|
||||
|
||||
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | Comment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl
|
||||
|
||||
@ -184,6 +184,13 @@ pub:
|
||||
alias string
|
||||
}
|
||||
|
||||
pub struct AnonFn {
|
||||
pub:
|
||||
decl FnDecl
|
||||
mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct FnDecl {
|
||||
pub:
|
||||
name string
|
||||
@ -193,11 +200,12 @@ pub:
|
||||
is_deprecated bool
|
||||
is_pub bool
|
||||
is_variadic bool
|
||||
is_anon bool
|
||||
receiver Field
|
||||
is_method bool
|
||||
rec_mut bool // is receiver mutable
|
||||
is_c bool
|
||||
is_js bool
|
||||
is_js bool
|
||||
no_body bool // just a definition `fn C.malloc()`
|
||||
is_builtin bool // this function is defined in builtin/strconv
|
||||
pos token.Position
|
||||
|
@ -1198,6 +1198,9 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
||||
it.expr_type = c.expr(it.expr)
|
||||
return table.string_type
|
||||
}
|
||||
ast.AnonFn {
|
||||
return it.typ
|
||||
}
|
||||
else {
|
||||
tnode := typeof(node)
|
||||
if tnode != 'unknown v.ast.Expr' {
|
||||
|
@ -248,8 +248,14 @@ pub fn (var g Gen) write_typedef_types() {
|
||||
.function {
|
||||
info := typ.info as table.FnType
|
||||
func := info.func
|
||||
if !info.has_decl && !info.is_anon {
|
||||
fn_name := if func.is_c { func.name.replace('.', '__') } else { c_name(func.name) }
|
||||
if !info.has_decl {
|
||||
fn_name := if func.is_c {
|
||||
func.name.replace('.', '__')
|
||||
} else if info.is_anon {
|
||||
typ.name
|
||||
} else {
|
||||
c_name(func.name)
|
||||
}
|
||||
g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(')
|
||||
for i, arg in func.args {
|
||||
g.definitions.write(g.typ(arg.typ))
|
||||
@ -1085,6 +1091,33 @@ fn (var g Gen) expr(node ast.Expr) {
|
||||
ast.TypeOf {
|
||||
g.typeof_expr(it)
|
||||
}
|
||||
ast.AnonFn {
|
||||
sym := g.table.get_type_symbol(it.typ)
|
||||
func := it.decl
|
||||
|
||||
// TODO: Fix hack and write function implementation directly to definitions
|
||||
pos := g.out.len
|
||||
type_name := g.typ(func.return_type)
|
||||
g.write('$type_name ${sym.name}_impl(')
|
||||
g.fn_args(func.args, func.is_variadic)
|
||||
g.writeln(') {')
|
||||
g.stmts(func.stmts)
|
||||
if g.autofree {
|
||||
g.free_scope_vars(func.pos.pos - 1)
|
||||
}
|
||||
if g.defer_stmts.len > 0 {
|
||||
g.write_defer_stmts()
|
||||
}
|
||||
g.out.writeln('}')
|
||||
g.defer_stmts = []
|
||||
g.fn_decl = 0
|
||||
|
||||
fn_body := g.out.after(pos)
|
||||
g.definitions.write(fn_body)
|
||||
g.out.go_back(fn_body.len)
|
||||
|
||||
g.out.write('&${sym.name}_impl')
|
||||
}
|
||||
else {
|
||||
// #printf("node=%d\n", node.typ);
|
||||
println(term.red('cgen.expr(): bad node ' + typeof(node)))
|
||||
|
@ -234,6 +234,58 @@ fn (var p Parser) fn_decl() ast.FnDecl {
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) anon_fn() ast.AnonFn {
|
||||
pos := p.tok.position()
|
||||
p.open_scope()
|
||||
p.check(.key_fn)
|
||||
|
||||
// TODO generics
|
||||
|
||||
args, is_variadic := p.fn_args()
|
||||
for arg in args {
|
||||
p.scope.register(arg.name, ast.Var{
|
||||
name: arg.name
|
||||
typ: arg.typ
|
||||
})
|
||||
}
|
||||
|
||||
var return_type := table.void_type
|
||||
if p.tok.kind.is_start_of_type() {
|
||||
return_type = p.parse_type()
|
||||
}
|
||||
|
||||
var stmts := []ast.Stmt
|
||||
no_body := p.tok.kind != .lcbr
|
||||
if p.tok.kind == .lcbr {
|
||||
stmts = p.parse_block()
|
||||
}
|
||||
p.close_scope()
|
||||
|
||||
func := table.Fn{
|
||||
args: args
|
||||
is_variadic: is_variadic
|
||||
return_type: return_type
|
||||
}
|
||||
idx := p.table.find_or_register_fn_type(func, false)
|
||||
typ := table.new_type(idx)
|
||||
name := p.table.get_type_name(typ)
|
||||
|
||||
return ast.AnonFn{
|
||||
decl: ast.FnDecl{
|
||||
name: name
|
||||
stmts: stmts
|
||||
return_type: return_type
|
||||
args: args
|
||||
is_variadic: is_variadic
|
||||
is_method: false
|
||||
is_anon: true
|
||||
no_body: no_body
|
||||
pos: pos
|
||||
}
|
||||
typ: typ
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) fn_args() ([]table.Arg, bool) {
|
||||
p.check(.lpar)
|
||||
var args := []table.Arg
|
||||
|
Loading…
Reference in New Issue
Block a user