#include "core.h" #include "vm.h" #include "utils/utf.h" // TODO these are hacks around not needing tiny headers Block* bqn_comp(B str, B path, B args); Block* bqn_compSc(B str, B path, B args, Scope* sc, bool repl); void rtWrap_print(); static B replPath; static Scope* gsc; static bool init = false; static void repl_init() { if (init) return; cbqn_init(); replPath = m_str32(U"REPL"); gc_add(replPath); Block* initBlock = bqn_comp(m_str32(U"\"(REPL initializer)\""), inc(replPath), m_f64(0)); gsc = m_scope(initBlock->body, NULL, 0); gc_add(tag(gsc,OBJ_TAG)); ptr_dec(initBlock); init = true; } static B gsc_exec_inline(B src, B path, B args) { Block* block = bqn_compSc(src, path, args, gsc, true); ptr_dec(gsc->body); ptr_inc(block->body); // redirect new errors to the newly executed code; initial scope had 0 vars, so this is safe gsc->body = block->body; B r = evalBC(block->body, gsc); ptr_dec(block); return r; } int main(int argc, char* argv[]) { // expects a copy of mlochbaum/BQN/src/c.bqn to be at the execution directory (with •args replaced with the array in glyphs.bqn) #if defined(COMP_COMP) || defined(COMP_COMP_TIME) repl_init(); char* c_src = NULL; u64 c_len; FILE* f = fopen("c.bqn", "rb"); if (f) { fseek(f, 0, SEEK_END); c_len = ftell(f); fseek(f, 0, SEEK_SET); c_src = malloc(c_len); if (c_src) fread(c_src, 1, c_len, f); fclose(f); } else { c_src = NULL; } if (c_src) { B srcB = fromUTF8(c_src, c_len); #ifdef COMP_COMP_TIME gc_add(srcB); for (i32 i = 0; i < 100; i++) { dec(bqn_exec(inc(srcB), bi_N, bi_N)); gc_maybeGC(); } rtWrap_print(); CTR_FOR(CTR_PRINT) exit(0); #endif bqn_setComp(bqn_exec(srcB, bi_N, bi_N)); } else { printf("couldn't read c.bqn\n"); exit(1); } #endif bool startREPL = argc==1; if (!startREPL) { i32 i = 1; while (i!=argc) { char* carg = argv[i]; if (carg[0]!='-') break; i++; if (carg[1]=='-') { if (!strcmp(carg, "--help")) { printf( "Usage: %s [options] [file.bqn [arguments]]\n" "Options:\n" "-f file: execute the contents of the file with all further arguments as •args\n" "-e code: execute the argument as BQN\n" "-p code: execute the argument as BQN and print its result pretty-printed\n" "-o code: execute the argument as BQN and print its raw result\n" "-M num : set maximum heap size to num megabytes\n" "-r : start the REPL after all further arguments\n" , argv[0]); exit(0); } else { printf("%s: Unknown option: %s\n", argv[0], carg); exit(1); } } else { carg++; char c; while ((c=*carg++) != '\0') { switch(c) { default: fprintf(stderr, "%s: Unknown option: -%c\n", argv[0], c); exit(1); #define REQARG(X) if(*carg) { fprintf(stderr, "%s: -%s must end the option\n", argv[0], #X); exit(1); } if (i==argc) { fprintf(stderr, "%s: -%s requires an argument\n", argv[0], #X); exit(1); } case 'f': repl_init(); REQARG(f); goto execFile; case 'e': { repl_init(); REQARG(e); dec(gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-e)"), inc(bi_emptyHVec))); break; } case 'p': { repl_init(); REQARG(p); B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-p)"), inc(bi_emptyHVec)); print(r); dec(r); printf("\n"); break; } case 'o': { repl_init(); REQARG(o); B r = gsc_exec_inline(fromUTF8l(argv[i++]), m_str32(U"(-o)"), inc(bi_emptyHVec)); printRaw(r); dec(r); printf("\n"); break; } case 'M': { REQARG(M); char* str = argv[i++]; u64 am = 0; while (*str) { char c = *str++; if (c<'0' | c>'9') { printf("%s: -M: Argument not a number\n", argv[0]); exit(1); } if (am>1ULL<<48) { printf("%s: -M: Too large\n", argv[0]); exit(1); } am = am*10 + c-48; } mm_heapMax = am*1024*1024; break; } case 'r': { startREPL = true; break; } } } } } execFile: if (i!=argc) { repl_init(); B src = fromUTF8l(argv[i++]); B args; if (i==argc) { args = inc(bi_emptyHVec); } else { HArr_p ap = m_harrUv(argc-i); // eh whatever, erroring will exit anyways for (usz j = 0; j < argc-i; j++) { ap.a[j] = fromUTF8l(argv[i+j]); } args = ap.b; } dec(bqn_execFile(src, args)); } } if (startREPL) { repl_init(); while (CATCH) { printf("Error: "); print(catchMessage); putchar('\n'); vm_pst(envCurr, envStart+envPrevHeight); dec(catchMessage); #ifdef HEAP_VERIFY heapVerify(); #endif gc_maybeGC(); } while (true) { // exit by evaluating an empty expression char* ln = NULL; size_t gl = 0; i64 read = getline(&ln, &gl, stdin); if (read<=0 || ln[0]==0 || ln[0]==10) break; Block* block = bqn_compSc(fromUTF8(ln, strlen(ln)), inc(replPath), inc(bi_emptyHVec), gsc, true); free(ln); ptr_dec(gsc->body); ptr_inc(block->body); gsc->body = block->body; #ifdef TIME u64 sns = nsTime(); B res = evalBC(block->body, gsc); u64 ens = nsTime(); printf("%fms\n", (ens-sns)/1e6); #else B res = evalBC(block->body, gsc); #endif ptr_dec(block); #ifdef FORMATTER B resFmt = bqn_fmt(res); printRaw(resFmt); dec(resFmt); putchar('\n'); #else print(res); putchar('\n'); fflush(stdout); dec(res); #endif #ifdef HEAP_VERIFY heapVerify(); #endif gc_maybeGC(); } popCatch(); } #ifdef HEAP_VERIFY heapVerify(); #endif rtWrap_print(); CTR_FOR(CTR_PRINT) // printf("done\n");fflush(stdout); while(1); printAllocStats(); #undef INIT }