diff options
author | Thomas Voss <mail@thomasvoss.com> | 2024-06-24 05:36:48 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2024-06-24 05:39:22 +0200 |
commit | 28270d80af2fa090694359f84ec2b9cadee77995 (patch) | |
tree | dd0232b891e68be6e8f53cf43f22f657f424e208 | |
parent | 578a597b942eaf3c79854b09062001f6fc169abb (diff) |
Support nested functions
-rw-r--r-- | README | 14 | ||||
-rw-r--r-- | src/codegen.c | 50 |
2 files changed, 51 insertions, 13 deletions
@@ -61,3 +61,17 @@ Portuguese or ‘Όρυξ’ in Greek) as opposed to using the English name. x: int = 69; y: i64 = x; /* Compile-time error */ } + +7. Nested functions are supported, but not closures. Closures will + never be supported in the language. + + /* Recall that constants (including functions!) can be declared + in any order. This lets us define Inner *after* it gets + called by the assignment to ‘x’. */ + Outer :: () { + x := Inner(5); + + Inner :: (x: int) int { + return x; + } + } diff --git a/src/codegen.c b/src/codegen.c index 9ba4c2d..f31bcf4 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -200,28 +200,52 @@ codegenalloca(struct cgctx ctx, idx_t i) } idx_t -codegenfunc(struct cgctx ctx, idx_t i, const char *name) +codegenfunc(struct cgctx ctx, idx_t i, strview_t sv) { + size_t namesz = ctx.namespace.len + sv.len + 1; + char *name = arena_new(ctx.a, char, namesz + 1); + if (ctx.namespace.len == 0) { + svtocstr(name, sv); + namesz--; + } else + sprintf(name, "%.*s.%.*s", SV_PRI_ARGS(ctx.namespace), SV_PRI_ARGS(sv)); + + ctx.namespace.p = name; + ctx.namespace.len = namesz; + + idx_t proto = ctx.ast.kids[i].lhs; + idx_t blk = ctx.ast.kids[i].rhs; + + snapshot_t snap = arena_snapshot_create(*ctx.a); + for (idx_t i = ctx.ast.kids[blk].lhs; i <= ctx.ast.kids[blk].rhs; + i = fwdnode(ctx.ast, i)) + { + if (ctx.ast.kinds[i] == ASTCDECL && ctx.ast.kids[i].rhs != AST_EMPTY + && ctx.ast.kinds[ctx.ast.kids[i].rhs] == ASTFN) + { + (void)codegendecl(ctx, i); + } + } + arena_snapshot_restore(ctx.a, snap); + LLVMTypeRef ret = ctx.types[i].ret == NULL ? LLVMVoidTypeInContext(ctx.ctx) : type2llvm(ctx, *ctx.types[i].ret); LLVMTypeRef ft = LLVMFunctionType(ret, NULL, 0, false); ctx.func = LLVMAddFunction(ctx.mod, name, ft); - LLVMBasicBlockRef entry = - LLVMAppendBasicBlockInContext(ctx.ctx, ctx.func, "entry"); + LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(ctx.ctx, ctx.func, + "entry"); LLVMPositionBuilderAtEnd(ctx.bob, entry); - idx_t proto = ctx.ast.kids[i].lhs; - idx_t blk = ctx.ast.kids[i].rhs; - - snapshot_t snap = arena_snapshot_create(*ctx.a); + snap = arena_snapshot_create(*ctx.a); (void)codegenalloca(ctx, blk); arena_snapshot_restore(ctx.a, snap); i = codegenblk(ctx, blk); if (ctx.ast.kids[proto].rhs == AST_EMPTY) LLVMBuildRetVoid(ctx.bob); + return i; } @@ -232,14 +256,14 @@ codegendecl(struct cgctx ctx, idx_t i) if (ctx.ast.kinds[i] == ASTCDECL) { /* Constants are purely a compiler concept; they aren’t generated - into anything */ - if (ctx.ast.kinds[p.rhs] != ASTFN) + into anything unless they’re functions… but functions + shouldn’t be generated if we’re inside a function already, + because codegenfunc() will have already generated its child + functions before codegendecl() gets called. */ + if (ctx.ast.kinds[p.rhs] != ASTFN || ctx.func != NULL) return fwdnode(ctx.ast, i); - /* TODO: Namespace the name */ - strview_t sv = ctx.toks.strs[ctx.ast.lexemes[i]]; - char *name = tmpalloc(ctx.s, sv.len + 1, 1); - return codegenfunc(ctx, p.rhs, svtocstr(name, sv)); + return codegenfunc(ctx, p.rhs, ctx.toks.strs[ctx.ast.lexemes[i]]); } assert(ctx.ast.kinds[i] == ASTDECL); |