aboutsummaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c88
1 files changed, 85 insertions, 3 deletions
diff --git a/src/eval.c b/src/eval.c
index 34259eb..2bed8a8 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -446,6 +446,64 @@ static int remember_last_eval(ecex_t *ed,
return ECEX_OK;
}
+static char *eval_module_key(const char *filename, int wrap_as_statements) {
+ const char *name = (filename && filename[0]) ? filename : "<eval>";
+ int needed = snprintf(NULL, 0, "%d:%s", wrap_as_statements ? 1 : 0, name);
+ if (needed < 0) return NULL;
+
+ char *key = malloc((size_t)needed + 1);
+ if (!key) return NULL;
+
+ snprintf(key, (size_t)needed + 1, "%d:%s", wrap_as_statements ? 1 : 0, name);
+ return key;
+}
+
+static void eval_remove_kept_module_ref(ecex_t *ed, void *module) {
+ if (!ed || !module) return;
+
+ for (size_t i = 0; i < ed->jit_module_count; i++) {
+ if (ed->jit_modules[i] != module) continue;
+
+ if (i + 1 < ed->jit_module_count) {
+ memmove(&ed->jit_modules[i],
+ &ed->jit_modules[i + 1],
+ (ed->jit_module_count - i - 1) * sizeof(ed->jit_modules[i]));
+ }
+ ed->jit_module_count--;
+ return;
+ }
+}
+
+static int eval_remember_kept_module(ecex_t *ed, char *key, ccdjit_module *module) {
+ if (!ed || !key || !module) return ECEX_ERR;
+
+ for (size_t i = 0; i < ed->eval_module_count; i++) {
+ if (!ed->eval_modules[i].key || strcmp(ed->eval_modules[i].key, key) != 0) continue;
+
+ ccdjit_module *old = (ccdjit_module *)ed->eval_modules[i].module;
+ ed->eval_modules[i].module = module;
+ free(key);
+
+ if (old && old != module) {
+ eval_remove_kept_module_ref(ed, old);
+ ccdjit_module_free(old);
+ }
+ return ECEX_OK;
+ }
+
+ if (ECEX_GROW_ARRAY(ed->eval_modules,
+ ed->eval_module_count,
+ ed->eval_module_cap,
+ 8) != ECEX_OK) {
+ return ECEX_ERR;
+ }
+
+ ed->eval_modules[ed->eval_module_count].key = key;
+ ed->eval_modules[ed->eval_module_count].module = module;
+ ed->eval_module_count++;
+ return ECEX_OK;
+}
+
int ecex_eval_source(ecex_t *ed,
const char *source,
const char *filename,
@@ -573,12 +631,36 @@ int ecex_eval_source(ecex_t *ed,
buffer_append(out, line);
/*
- * Keep successful eval modules alive. This makes eval useful for live
- * customization: code evaluated from a buffer may register commands whose
- * function pointers remain valid after eval returns.
+ * Keep the latest successful eval module for each source key alive. A
+ * rerun of the same buffer replaces the old module after the new one has
+ * run, so normal eval-output `g` loops do not accumulate generated code.
*/
+ char *module_key = eval_module_key(filename, wrap_as_statements);
+ if (!module_key) {
+ buffer_append(out, "failed to allocate eval module key\n");
+ ccdjit_module_free(module);
+ g_eval_editor = NULL;
+ ccdjit_context_free(ctx);
+ free(eval_source);
+ ecex_switch_buffer(ed, "*eval-output*");
+ return ECEX_ERR;
+ }
+
if (ecex_keep_jit_module(ed, module) != ECEX_OK) {
buffer_append(out, "failed to keep eval module alive\n");
+ free(module_key);
+ ccdjit_module_free(module);
+ g_eval_editor = NULL;
+ ccdjit_context_free(ctx);
+ free(eval_source);
+ ecex_switch_buffer(ed, "*eval-output*");
+ return ECEX_ERR;
+ }
+
+ if (eval_remember_kept_module(ed, module_key, module) != ECEX_OK) {
+ buffer_append(out, "failed to track eval module\n");
+ free(module_key);
+ eval_remove_kept_module_ref(ed, module);
ccdjit_module_free(module);
g_eval_editor = NULL;
ccdjit_context_free(ctx);