diff --git a/docs/commands.md b/docs/commands.md index 2c7af964..4899b2fc 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -32,6 +32,10 @@ Erase the specified variable name. Not a system function because it only clears the variables value (previous code `↩`ing it will still be able to), and to allow it to be executed even when the VM is completely out of memory such that it can't even parse REPL input BQN. +## `)escaped "escaped expr"` + +Parse `\`-escapes and execute as REPL input. Primarily for external tools to be able to execute multiline input. + ## `)mem` Get statistics on memory usage. diff --git a/src/load.c b/src/load.c index 69f35fb4..f43e761a 100644 --- a/src/load.c +++ b/src/load.c @@ -506,7 +506,7 @@ static void freed_visit(Value* x) { static void empty_free(Value* x) { err("FREEING EMPTY\n"); } static void builtin_free(Value* x) { err("FREEING BUILTIN\n"); } DEF_FREE(def) { } -static void def_visit(Value* x) { printf("(no visit for %d=%s)\n", x->type, type_repr(x->type)); } +static void def_visit(Value* x) { err("undefined visit for object\n"); } static void def_print(FILE* f, B x) { fprintf(f, "(%d=%s)", v(x)->type, type_repr(v(x)->type)); } static bool def_canStore(B x) { return false; } static B def_identity(B f) { return bi_N; } @@ -646,6 +646,7 @@ void base_init() { // very first init function TIi(t_empty,getU) = empty_getU; #endif TIi(t_shape,visit) = noop_visit; + TIi(t_temp,visit) = noop_visit; TIi(t_funBI,visit) = TIi(t_md1BI,visit) = TIi(t_md2BI,visit) = noop_visit; TIi(t_funBI,freeO) = TIi(t_md1BI,freeO) = TIi(t_md2BI,freeO) = builtin_free; TIi(t_funBI,freeF) = TIi(t_md1BI,freeF) = TIi(t_md2BI,freeF) = builtin_free; diff --git a/src/main.c b/src/main.c index 1505be5d..564372a2 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "vm.h" #include "ns.h" #include "utils/utf.h" +#include "utils/talloc.h" #include "utils/file.h" #include "utils/time.h" #include "utils/interrupt.h" @@ -46,6 +47,15 @@ void profiler_free(void); void profiler_displayResults(void); void clearImportCache(void); +static B escape_parser; +B simple_unescape(B x) { + if (RARE(escape_parser.u==0)) { + escape_parser = bqn_exec(utf8Decode0("{m←\"Expected surrounding quotes\" ⋄ m!2≤≠𝕩 ⋄ m!\"\"\"\"\"\"≡0‿¯1⊏𝕩 ⋄ s←¬e←<`'\\'=𝕩 ⋄ i‿o←\"\\\"\"nr\"⋈\"\\\"\"\"∾@+10‿13 ⋄ 1↓¯1↓{n←i⊐𝕩 ⋄ \"Unknown escape\"!∧´n≠≠i ⋄ n⊏o}⌾((s/»e)⊸/) s/𝕩}"), bi_N, bi_N); + gc_add(escape_parser); + } + return c1(escape_parser, x); +} + i64 readInt(char** p) { char* c = *p; i64 am = 0; @@ -58,7 +68,6 @@ i64 readInt(char** p) { } void cbqn_runLine0(char* ln, i64 read) { if (ln[0]==10) return; - if (ln[read-1]==10) ln[--read] = 0; B code; int output; // 0-no; 1-formatter; 2-internal @@ -74,6 +83,16 @@ void cbqn_runLine0(char* ln, i64 read) { } else if (isCmd(cmdS, &cmdE, "r ")) { code = utf8Decode0(cmdE); output = 0; + } else if (isCmd(cmdS, &cmdE, "escaped ")) { + B u = simple_unescape(utf8Decode0(cmdE)); + u64 len = utf8lenB(u); + TALLOC(char, ascii, len+1); + toUTF8(u, ascii); + dec(u); + ascii[len] = '\0'; + cbqn_runLine0(ascii, len+1); + TFREE(ascii); + return; } else if (isCmd(cmdS, &cmdE, "t ") || isCmd(cmdS, &cmdE, "time ")) { code = utf8Decode0(cmdE); time = -1; @@ -234,10 +253,6 @@ void cbqn_runLine0(char* ln, i64 read) { } } else dec(res); - #ifdef HEAP_VERIFY - heapVerify(); - #endif - gc_maybeGC(); } void cbqn_runLine(char* ln, i64 len) { @@ -254,6 +269,10 @@ void cbqn_runLine(char* ln, i64 len) { } cbqn_takeInterrupts(true); cbqn_runLine0(ln, len); + #ifdef HEAP_VERIFY + heapVerify(); + #endif + gc_maybeGC(); cbqn_takeInterrupts(false); popCatch(); } @@ -396,6 +415,7 @@ int main(int argc, char* argv[]) { size_t gl = 0; i64 read = getline(&ln, &gl, stdin); if (read<=0 || ln[0]==0) { if(!silentREPL) putchar('\n'); break; } + if (ln[read-1]==10) ln[--read] = 0; cbqn_runLine(ln, read); free(ln); } diff --git a/src/opt/gc.c b/src/opt/gc.c index 338327c6..98a2417c 100644 --- a/src/opt/gc.c +++ b/src/opt/gc.c @@ -33,7 +33,7 @@ static void gc_tryFree(Value* v) { if (t==t_freed) err("GC found t_freed\n"); #endif if (t!=t_empty && !(v->mmInfo&0x80)) { - if (t==t_shape) return; + if (t==t_shape || t==t_temp) return; #ifdef DONT_FREE v->flags = t; #else