aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-24 05:36:48 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-24 05:39:22 +0200
commit28270d80af2fa090694359f84ec2b9cadee77995 (patch)
treedd0232b891e68be6e8f53cf43f22f657f424e208
parent578a597b942eaf3c79854b09062001f6fc169abb (diff)
Support nested functions
-rw-r--r--README14
-rw-r--r--src/codegen.c50
2 files changed, 51 insertions, 13 deletions
diff --git a/README b/README
index 91b3fb6..473146c 100644
--- a/README
+++ b/README
@@ -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);