parser: anonymous functions (part 1)

pull/4473/head
Tim Basel 2020-04-17 21:59:19 +02:00 committed by GitHub
parent fe249ab0c3
commit 73073cd954
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 4 deletions

View File

@ -10,7 +10,7 @@ import (
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl 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 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 alias string
} }
pub struct AnonFn {
pub:
decl FnDecl
mut:
typ table.Type
}
pub struct FnDecl { pub struct FnDecl {
pub: pub:
name string name string
@ -193,11 +200,12 @@ pub:
is_deprecated bool is_deprecated bool
is_pub bool is_pub bool
is_variadic bool is_variadic bool
is_anon bool
receiver Field receiver Field
is_method bool is_method bool
rec_mut bool // is receiver mutable rec_mut bool // is receiver mutable
is_c bool is_c bool
is_js bool is_js bool
no_body bool // just a definition `fn C.malloc()` no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv is_builtin bool // this function is defined in builtin/strconv
pos token.Position pos token.Position

View File

@ -1198,6 +1198,9 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
it.expr_type = c.expr(it.expr) it.expr_type = c.expr(it.expr)
return table.string_type return table.string_type
} }
ast.AnonFn {
return it.typ
}
else { else {
tnode := typeof(node) tnode := typeof(node)
if tnode != 'unknown v.ast.Expr' { if tnode != 'unknown v.ast.Expr' {

View File

@ -248,8 +248,14 @@ pub fn (var g Gen) write_typedef_types() {
.function { .function {
info := typ.info as table.FnType info := typ.info as table.FnType
func := info.func func := info.func
if !info.has_decl && !info.is_anon { if !info.has_decl {
fn_name := if func.is_c { func.name.replace('.', '__') } else { c_name(func.name) } 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)(') g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(')
for i, arg in func.args { for i, arg in func.args {
g.definitions.write(g.typ(arg.typ)) g.definitions.write(g.typ(arg.typ))
@ -1085,6 +1091,33 @@ fn (var g Gen) expr(node ast.Expr) {
ast.TypeOf { ast.TypeOf {
g.typeof_expr(it) 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 { else {
// #printf("node=%d\n", node.typ); // #printf("node=%d\n", node.typ);
println(term.red('cgen.expr(): bad node ' + typeof(node))) println(term.red('cgen.expr(): bad node ' + typeof(node)))

View File

@ -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) { fn (var p Parser) fn_args() ([]table.Arg, bool) {
p.check(.lpar) p.check(.lpar)
var args := []table.Arg var args := []table.Arg