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);  |