commit 169777f038533a9820dc94dfcb664a2ab53068df
parent 82b27b67550b5b5d715db6f17b24cfca4cead61b
Author: m21c <ho*******@gmail.com>
Date: Fri, 27 Jun 2025 21:20:25 +0200
worked on extract nested
functions
Diffstat:
| M | compiler.c | | | 169 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
1 file changed, 168 insertions(+), 1 deletion(-)
diff --git a/compiler.c b/compiler.c
@@ -591,6 +591,12 @@ struct Source {
Env *implicitenv;
+ bool haspendingenv;
+
+ /* pending nodes */
+ Node *pendingnodes[512];
+ int pendingcount;
+
/* parser state */
Node *lastis;
@@ -2179,6 +2185,8 @@ deferfuncenv(Source *source, int keydeclinfunc)
if (funcenv) {
if (!funcenv->pending) {
funcenv->pending = true;
+ /* @todo handle nested functions properly */
+ source->haspendingenv = true;
listappendex(source, funcenv,
pendingenvhead, pendingenvtail,
@@ -5525,7 +5533,166 @@ dataflow2(Analysis *analysis, Node *expr)
// }}}
-// @section intermediate code generation {{{
+
+// @section extract nested functions {{{
+
+Node *extracted[1024 * 4];
+int extractedtop = 0;
+
+static bool
+isnestedfunction(Env *startenv)
+{
+ Env *env;
+ int n = 0;
+
+ for (env = startenv; env; env = env->below) {
+ if (env->kind == SFUNCTION)
+ ++n;
+ }
+
+ return n > 1;
+}
+
+static void
+extractnfs(Env *env, Node *expr);
+
+static void
+substituenfs(Env *env, Node *expr)
+{
+ Decl *decl = expr->u.declref;
+ Node *enlist = NULL;
+
+ assert(decl);
+
+ if (decl->u.content) {
+ env = decl->contentenv ? decl->contentenv : env;
+ extractnfs(env, decl->u.content);
+ }
+
+ if (decl->kind == DFUNCTION && isnestedfunction(decl->contentenv)) {
+ enlist = makenode(expr, NULL);
+ expr->kind = ADECLREF;
+
+ assert(extractedtop < lengthof(extracted));
+ extracted[extractedtop++] = enlist;
+ }
+}
+
+static void
+extractnfs(Env *env, Node *expr)
+{
+advance:
+ assert(expr);
+
+ if (isoperator(expr->kind)) {
+ switch (getnumops(expr->kind)) {
+ case 3:
+ assert(expr->u.payload);
+ extractnfs(env, expr->u.payload);
+ /* FALLTHROUGH */
+ case 2:
+ assert(expr->rhs);
+ extractnfs(env, expr->rhs);
+ /* FALLTHROUGH */
+ case 1:
+ assert(expr->lhs);
+ extractnfs(env, expr->lhs);
+ }
+ return;
+ }
+
+ switch (expr->kind) {
+ case KRETURN:
+ case KIF:
+ case KCASE:
+ case KOF:
+ case KDO:
+ case KFOR:
+ case KLOOP:
+ case KWHILE:
+ case KUNTIL:
+ case AFORSTEP:
+ case AFOREACH:
+ if (expr->u.payload)
+ extractnfs(env, expr->u.payload);
+ if (expr->lhs)
+ extractnfs(env, expr->lhs);
+ if (expr->rhs)
+ extractnfs(env, expr->rhs);
+ break;
+ case ADEREF:
+ case ACONV:
+ case ASELFDISP:
+ assert(expr->lhs);
+ extractnfs(env, expr->lhs);
+ break;
+ case ACOMMA:
+ assert(expr->lhs);
+ assert(expr->rhs);
+ extractnfs(env, expr->lhs);
+ extractnfs(env, expr->rhs);
+ break;
+ case ASTMT:
+ assert(expr->lhs);
+ extractnfs(env, expr->lhs);
+ if (expr->rhs) {
+ expr = expr->rhs;
+ goto advance;
+ }
+ break;
+ case ADECL:
+ substituenfs(env, expr);
+ break;
+ case AENV:
+ case ASCOPE:
+ assert(expr->lhs);
+ assert(expr->u.env);
+ extractnfs(expr->u.env, expr->lhs);
+ break;
+ case TYPE: /* @note is this correct? */
+ case CHAR:
+ case NUMBER:
+ case STRING:
+ case ADECLREF:
+ case IDENT: /* @note is this correct? */
+ break;
+
+ case ACOMPOUND:
+ /* @todo extract within type (lhs)? */
+ assert(expr->rhs);
+ extractnfs(env, expr->lhs);
+ break;
+
+ case AFIELDINIT:
+ assert(expr->rhs);
+ extractnfs(env, expr->rhs);
+ break;
+
+ case KSTRUCT:
+ assert(expr->rhs);
+ extractnfs(env, expr->rhs);
+ break;
+
+ default:
+ error(&expr->loc, "internal error: unknown expression kind"
+ " (%s).", nodestrings[expr->kind]);
+ break;
+ }
+}
+
+static Node *
+extractnestedfunctions(Env *env, Node *expr)
+{
+ extractedtop = 0;
+
+ extractnfs(env, expr);
+
+ assert(extractedtop < lengthof(extracted));
+ extracted[extractedtop++] = expr;
+ return expr;
+}
+
+// }}}