mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33:01 +00:00 
			
		
		
		
	Major refactor. Move files around, merge compiler into
core and other changes, work on inlining many c functions.
This commit is contained in:
		
							
								
								
									
										31
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								Makefile
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ BINDIR=$(PREFIX)/bin | ||||
| # TODO - when api is finalized, only export public symbols instead of using rdynamic | ||||
| # which exports all symbols. Saves a few KB in binary. | ||||
|  | ||||
| CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 | ||||
| CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -Os -s | ||||
| CLIBS=-lm -ldl | ||||
| PREFIX=/usr/local | ||||
| DST_TARGET=dst | ||||
| @@ -49,18 +49,11 @@ else | ||||
| endif | ||||
|  | ||||
| # Source headers | ||||
| DST_GENERATED_HEADERS=$(sort $(wildcard src/include/generated/*.h)) | ||||
| DST_HEADERS=$(sort $(wildcard src/include/dst/*.h)) | ||||
| DST_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h)) | ||||
| DST_LIBHEADERS=$(sort $(wildcard src/include/headerlibs/*.h)) | ||||
| DST_GENERATED_HEADERS=src/mainclient/clientinit.gen.h \ | ||||
| 					  src/compiler/dststlbootstrap.gen.h | ||||
| DST_ALL_HEADERS=$(DST_LOCAL_HEADERS) \ | ||||
| 				$(DST_HEADERS) \ | ||||
| 				$(DST_LIB_HEADERS) \ | ||||
| 				$(DST_GENERATED_HEADERS) | ||||
|  | ||||
| # Source files | ||||
| DST_COMPILER_SOURCES=$(sort $(wildcard src/compiler/*.c)) | ||||
| DST_CORE_SOURCES=$(sort $(wildcard src/core/*.c)) | ||||
| DST_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c)) | ||||
|  | ||||
| @@ -77,33 +70,33 @@ xxd: src/tools/xxd.c | ||||
| ##### Generated Headers ##### | ||||
| ############################# | ||||
|  | ||||
| src/mainclient/clientinit.gen.h: src/mainclient/init.dst xxd | ||||
| src/include/generated/init.h: src/mainclient/init.dst xxd | ||||
| 	./xxd $< $@ dst_mainclient_init  | ||||
|  | ||||
| src/compiler/dststlbootstrap.gen.h: src/compiler/boot.dst xxd | ||||
| src/include/generated/boot.h: src/core/boot.dst xxd | ||||
| 	./xxd $< $@ dst_stl_bootstrap_gen | ||||
|  | ||||
| # Only a few files depend on the generated headers | ||||
| src/core/corelib.o: src/include/generated/boot.h | ||||
| src/mainclient/main.o: src/include/generated/init.h | ||||
|  | ||||
| ########################################################## | ||||
| ##### The main interpreter program and shared object ##### | ||||
| ########################################################## | ||||
|  | ||||
| DST_LIB_SOURCES=$(DST_COMPILER_SOURCES) \ | ||||
| 				$(DST_CONTEXT_SOURCES) \ | ||||
| 				$(DST_CORE_SOURCES) | ||||
|  | ||||
| DST_ALL_SOURCES=$(DST_LIB_SOURCES) \ | ||||
| DST_ALL_SOURCES=$(DST_CORE_SOURCES) \ | ||||
| 				$(DST_MAINCLIENT_SOURCES) | ||||
|  | ||||
| DST_LIB_OBJECTS=$(patsubst %.c,%.o,$(DST_LIB_SOURCES)) | ||||
| DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES)) | ||||
| DST_ALL_OBJECTS=$(patsubst %.c,%.o,$(DST_ALL_SOURCES)) | ||||
|  | ||||
| %.o: %.c $(DST_ALL_HEADERS) | ||||
| %.o: %.c $(DST_HEADERS) $(DST_LOCAL_HEADERS) | ||||
| 	$(CC) $(CFLAGS) -o $@ -c $< | ||||
|  | ||||
| $(DST_TARGET): $(DST_ALL_OBJECTS) | ||||
| 	$(CC) $(CFLAGS) -o $(DST_TARGET) $^ $(CLIBS) | ||||
|  | ||||
| $(DST_LIBRARY): $(DST_LIB_OBJECTS) | ||||
| $(DST_LIBRARY): $(DST_CORE_OBJECTS) | ||||
| 	$(CC) $(CFLAGS) -shared -o $(DST_LIBRARY) $^ $(CLIBS) | ||||
|  | ||||
| ################### | ||||
|   | ||||
| @@ -1,246 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include "compile.h" | ||||
|  | ||||
| /* Generated header */ | ||||
| #include "dststlbootstrap.gen.h" | ||||
|  | ||||
| static const DstReg cfuns[] = { | ||||
|     {"native", dst_core_native}, | ||||
|     {"print", dst_core_print}, | ||||
|     {"describe", dst_core_describe}, | ||||
|     {"string", dst_core_string}, | ||||
|     {"symbol", dst_core_symbol}, | ||||
|     {"buffer", dst_core_buffer}, | ||||
|     {"table", dst_core_table}, | ||||
|     {"array", dst_core_array}, | ||||
|     {"scan-number", dst_core_scannumber}, | ||||
|     {"scan-integer", dst_core_scaninteger}, | ||||
|     {"scan-real", dst_core_scanreal}, | ||||
|     {"tuple", dst_core_tuple}, | ||||
|     {"struct", dst_core_struct}, | ||||
|     {"buffer", dst_core_buffer}, | ||||
|     {"gensym", dst_core_gensym}, | ||||
|     {"gccollect", dst_core_gccollect}, | ||||
|     {"gcsetinterval", dst_core_gcsetinterval}, | ||||
|     {"gcinterval", dst_core_gcinterval}, | ||||
|     {"type", dst_core_type}, | ||||
|     {"next", dst_core_next}, | ||||
|     {"hash", dst_core_hash}, | ||||
|     {NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* Utility for inline assembly */ | ||||
| static void dst_quick_asm( | ||||
|         DstTable *env, | ||||
|         int32_t flags, | ||||
|         const char *name, | ||||
|         int32_t arity, | ||||
|         int32_t slots, | ||||
|         const uint32_t *bytecode, | ||||
|         size_t bytecode_size) { | ||||
|     DstFuncDef *def = dst_funcdef_alloc(); | ||||
|     def->arity = arity; | ||||
|     def->flags = flags; | ||||
|     def->slotcount = slots; | ||||
|     def->bytecode = malloc(bytecode_size); | ||||
|     def->bytecode_length = bytecode_size / sizeof(uint32_t); | ||||
|     def->name = dst_cstring(name); | ||||
|     if (!def->bytecode) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     } | ||||
|     memcpy(def->bytecode, bytecode, bytecode_size); | ||||
|     dst_env_def(env, name, dst_wrap_function(dst_thunk(def))); | ||||
| } | ||||
|  | ||||
| #define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24)) | ||||
| #define SS(op, a, b) SSS(op, a, b, 0) | ||||
| #define S(op, a) SSS(op, a, 0, 0) | ||||
| /* Variadic operator assembly. Must be templatized for each different opcode. */ | ||||
| /* Reg 0: Argument tuple (args) */ | ||||
| /* Reg 1: Argument count (argn) */ | ||||
| /* Reg 2: Jump flag (jump?) */ | ||||
| /* Reg 3: Accumulator (accum) */ | ||||
| /* Reg 4: Next operand (operand) */ | ||||
| /* Reg 5: Loop iterator (i) */ | ||||
| static DST_THREAD_LOCAL uint32_t varop_asm[] = { | ||||
|     DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */ | ||||
|  | ||||
|     /* Cheack nullary */ | ||||
|     DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */ | ||||
|     /* Nullary */ | ||||
|     DOP_LOAD_INTEGER | (3 << 8),  /* accum = nullary value */ | ||||
|     DOP_RETURN | (3 << 8), /* return accum */ | ||||
|  | ||||
|     /* Check unary */ | ||||
|     DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */ | ||||
|     /* Unary */ | ||||
|     DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */ | ||||
|     DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */ | ||||
|     DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ | ||||
|     DOP_RETURN | (3 << 8), /* return accum */ | ||||
|  | ||||
|     /* Mutli (2 or more) arity */ | ||||
|     /* Prime loop */ | ||||
|     DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */ | ||||
|     DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */ | ||||
|     /* Main loop */ | ||||
|     DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */ | ||||
|     DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ | ||||
|     DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */ | ||||
|     DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */ | ||||
|     /* Done, do last and return accumulator */ | ||||
|     DOP_RETURN | (3 << 8) /* return accum */ | ||||
| }; | ||||
|  | ||||
| #define VAROP_NULLARY_LOC 3 | ||||
| #define VAROP_UNARY_LOC 7 | ||||
| #define VAROP_OP_LOC1 9 | ||||
| #define VAROP_OP_LOC2 14 | ||||
|  | ||||
| /* Templatize a varop */ | ||||
| static void templatize_varop( | ||||
|         DstTable *env, | ||||
|         int32_t flags, | ||||
|         const char *name, | ||||
|         int32_t nullary, | ||||
|         int32_t unary, | ||||
|         uint32_t op) { | ||||
|     varop_asm[VAROP_NULLARY_LOC] = SS(DOP_LOAD_INTEGER, 3, nullary); | ||||
|     varop_asm[VAROP_UNARY_LOC] = SS(DOP_LOAD_INTEGER, 3, unary); | ||||
|     varop_asm[VAROP_OP_LOC1] = SSS(op, 3, 3, 4); | ||||
|     varop_asm[VAROP_OP_LOC2] = SSS(op, 3, 3, 4); | ||||
|     dst_quick_asm( | ||||
|             env, | ||||
|             flags | DST_FUNCDEF_FLAG_VARARG, | ||||
|             name, | ||||
|             0, | ||||
|             6, | ||||
|             varop_asm, | ||||
|             sizeof(varop_asm)); | ||||
| } | ||||
|  | ||||
| DstTable *dst_stl_env(int flags) { | ||||
|     static uint32_t error_asm[] = { | ||||
|         DOP_ERROR | ||||
|     }; | ||||
|     static uint32_t apply_asm[] = { | ||||
|        DOP_PUSH_ARRAY | (1 << 8), | ||||
|        DOP_TAILCALL | ||||
|     }; | ||||
|     static uint32_t debug_asm[] = { | ||||
|        DOP_SIGNAL | (2 << 24), | ||||
|        DOP_RETURN_NIL | ||||
|     }; | ||||
|     static uint32_t yield_asm[] = { | ||||
|         DOP_SIGNAL | (3 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t resume_asm[] = { | ||||
|         DOP_RESUME | (1 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t get_asm[] = { | ||||
|         DOP_GET | (1 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t put_asm[] = { | ||||
|         DOP_PUT | (1 << 16) | (2 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t length_asm[] = { | ||||
|         DOP_LENGTH, | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|  | ||||
|     DstTable *env = dst_table(0); | ||||
|     Dst ret = dst_wrap_table(env); | ||||
|  | ||||
|     /* Load main functions */ | ||||
|     dst_env_cfuns(env, cfuns); | ||||
|  | ||||
|     dst_quick_asm(env, DST_FUN_YIELD, "debug", 0, 1, debug_asm, sizeof(debug_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_ERROR, "error", 1, 1, error_asm, sizeof(error_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_APPLY1, "apply1", 2, 2, apply_asm, sizeof(apply_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_YIELD, "yield", 1, 2, yield_asm, sizeof(yield_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_RESUME, "resume", 2, 2, resume_asm, sizeof(resume_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_GET, "get", 2, 2, get_asm, sizeof(get_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm)); | ||||
|  | ||||
|     /* Variadic ops */ | ||||
|     templatize_varop(env, DST_FUN_ADD, "+", 0, 0, DOP_ADD); | ||||
|     templatize_varop(env, DST_FUN_SUBTRACT, "-", 0, 0, DOP_SUBTRACT); | ||||
|     templatize_varop(env, DST_FUN_MULTIPLY, "*", 1, 1, DOP_MULTIPLY); | ||||
|     templatize_varop(env, DST_FUN_DIVIDE, "/", 1, 1, DOP_DIVIDE); | ||||
|     templatize_varop(env, DST_FUN_BAND, "&", -1, -1, DOP_BAND); | ||||
|     templatize_varop(env, DST_FUN_BOR, "|", 0, 0, DOP_BOR); | ||||
|     templatize_varop(env, DST_FUN_BXOR, "^", 0, 0, DOP_BXOR); | ||||
|     templatize_varop(env, DST_FUN_LSHIFT, "<<", 1, 1, DOP_SHIFT_LEFT); | ||||
|     templatize_varop(env, DST_FUN_RSHIFT, ">>", 1, 1, DOP_SHIFT_RIGHT); | ||||
|     templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED); | ||||
|  | ||||
|     dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION)); | ||||
|  | ||||
|     /* Set as gc root */ | ||||
|     dst_gcroot(dst_wrap_table(env)); | ||||
|  | ||||
|     /* Load auxiliary envs */ | ||||
|     { | ||||
|         DstArgs args; | ||||
|         args.n = 1; | ||||
|         args.v = &ret; | ||||
|         args.ret = &ret; | ||||
|         dst_lib_io(args); | ||||
|         dst_lib_math(args); | ||||
|         dst_lib_array(args); | ||||
|         dst_lib_tuple(args); | ||||
|         dst_lib_buffer(args); | ||||
|         dst_lib_table(args); | ||||
|         dst_lib_fiber(args); | ||||
|         dst_lib_os(args); | ||||
|         dst_lib_parse(args); | ||||
|         dst_lib_compile(args); | ||||
|         dst_lib_asm(args); | ||||
|         dst_lib_string(args); | ||||
|         dst_lib_marsh(args); | ||||
|     } | ||||
|  | ||||
|     /* Allow references to the environment */ | ||||
|     dst_env_def(env, "_env", ret); | ||||
|  | ||||
|     /* Run bootstrap source */ | ||||
|     dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen), "boot.dst"); | ||||
|  | ||||
|     if (flags & DST_STL_NOGCROOT) | ||||
|         dst_gcunroot(dst_wrap_table(env)); | ||||
|  | ||||
|     return env; | ||||
| } | ||||
| @@ -21,8 +21,8 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "gc.h" | ||||
| #include <string.h> | ||||
|  | ||||
| /* Initializes an array */ | ||||
| DstArray *dst_array_init(DstArray *array, int32_t capacity) { | ||||
| @@ -49,6 +49,19 @@ DstArray *dst_array(int32_t capacity) { | ||||
|     return dst_array_init(array, capacity); | ||||
| } | ||||
|  | ||||
| /* Creates a new array from n elements. */ | ||||
| DstArray *dst_array_n(const Dst *elements, int32_t n) { | ||||
|     DstArray *array = dst_gcalloc(DST_MEMORY_ARRAY, sizeof(DstArray)); | ||||
|     array->capacity = n; | ||||
|     array->count = n; | ||||
|     array->data = malloc(sizeof(Dst) * n); | ||||
|     if (!array->data) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     } | ||||
|     memcpy(array->data, elements, sizeof(Dst) * n); | ||||
|     return array; | ||||
| } | ||||
|  | ||||
| /* Ensure the array has enough capacity for elements */ | ||||
| void dst_array_ensure(DstArray *array, int32_t capacity) { | ||||
|     Dst *newData; | ||||
|   | ||||
| @@ -21,10 +21,8 @@ | ||||
| */ | ||||
|  | ||||
| #include <setjmp.h> | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include <headerlibs/strbinsearch.h> | ||||
| #include "util.h" | ||||
|  | ||||
| /* Convert a slot to to an integer for bytecode */ | ||||
|  | ||||
| @@ -118,6 +116,12 @@ static const DstInstructionDef dst_ops[] = { | ||||
|     {"ltim", DOP_LESS_THAN_IMMEDIATE}, | ||||
|     {"ltr", DOP_LESS_THAN_REAL}, | ||||
|     {"lter", DOP_LESS_THAN_EQUAL_REAL}, | ||||
|     {"mkarr", DOP_MAKE_ARRAY}, | ||||
|     {"mkbuf", DOP_MAKE_BUFFER}, | ||||
|     {"mktab", DOP_MAKE_TABLE}, | ||||
|     {"mktup", DOP_MAKE_TUPLE}, | ||||
|     {"mkstr", DOP_MAKE_STRING}, | ||||
|     {"mkstu", DOP_MAKE_STRUCT}, | ||||
|     {"movf", DOP_MOVE_FAR}, | ||||
|     {"movn", DOP_MOVE_NEAR}, | ||||
|     {"mul", DOP_MULTIPLY}, | ||||
| @@ -376,7 +380,7 @@ static uint32_t read_instruction( | ||||
|         { | ||||
|             if (dst_tuple_length(argt) != 2) | ||||
|                 dst_asm_error(a, "expected 1 argument: (op, slot)"); | ||||
|             instr |= doarg(a, DST_OAT_SLOT, 1, 3, 0, argt[1]); | ||||
|             instr |= doarg(a, DST_OAT_SLOT, 1, 2, 0, argt[1]); | ||||
|             break; | ||||
|         } | ||||
|         case DIT_L: | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|   "Define a function. Equivalent to (def name (fn name [args] ...))." | ||||
|   (fn defn [name & more] | ||||
|     (def len (length more)) | ||||
|     (def fstart  | ||||
|     (def fstart | ||||
|       (fn recur [i] | ||||
|         (def {i ith} more) | ||||
|         (def t (type ith)) | ||||
| @@ -88,9 +88,9 @@ | ||||
| (defn true? [x] (= x true)) | ||||
| (defn false? [x] (= x false)) | ||||
| (defn nil? [x] (= x nil)) | ||||
| (def atomic?  | ||||
| (def atomic? | ||||
|   (do | ||||
|     (def non-atomic-types  | ||||
|     (def non-atomic-types | ||||
|       {:array true | ||||
|        :tuple true | ||||
|        :table true | ||||
| @@ -301,8 +301,8 @@ | ||||
|   evaluates to false." | ||||
|   [& forms] | ||||
|   (def len (length forms)) | ||||
|   (if (= len 0)  | ||||
|     true  | ||||
|   (if (= len 0) | ||||
|     true | ||||
|     ((fn aux [i] | ||||
|        (cond | ||||
|          (>= (inc i) len) (get forms i) | ||||
| @@ -313,8 +313,8 @@ | ||||
|   evaluates to true." | ||||
|   [& forms] | ||||
|   (def len (length forms)) | ||||
|   (if (= len 0)  | ||||
|     false  | ||||
|   (if (= len 0) | ||||
|     false | ||||
|     ((fn aux [i] | ||||
|        (def fi (get forms i)) | ||||
|        (if | ||||
| @@ -971,7 +971,7 @@ | ||||
|   (def p (parser.new)) | ||||
| 
 | ||||
|   # Fiber stream of characters | ||||
|   (def chars  | ||||
|   (def chars | ||||
|     (coro | ||||
|       (def buf @"") | ||||
|       (var len 1) | ||||
| @@ -984,7 +984,7 @@ | ||||
|       0)) | ||||
| 
 | ||||
|   # Fiber stream of values | ||||
|   (def vals  | ||||
|   (def vals | ||||
|     (coro | ||||
|       (while going | ||||
|         (switch (parser.status p) | ||||
| @@ -1002,21 +1002,22 @@ | ||||
|   # Evaluate 1 source form | ||||
|   (defn eval1 [source] | ||||
|     (var good true) | ||||
|     (def f  | ||||
|       (fiber.new  | ||||
|     (def f | ||||
|       (fiber.new | ||||
|         (fn [] | ||||
|           (def res (compile source env where)) | ||||
|           (if (= (type res) :function) | ||||
|             (res) | ||||
|             (do | ||||
|               (:= good false) | ||||
|               (def {:error err :error-line errl :error-column errc} res) | ||||
|               (onerr  | ||||
|                 where  | ||||
|               (def {:error err :line errl :column errc :fiber errf} res) | ||||
|               (onerr | ||||
|                 where | ||||
|                 "compile" | ||||
|                 (if (< 0 errl) | ||||
|                   (string err " in form at line " errl ", column " errc) | ||||
|                   err))))) | ||||
|                   (string err "\n  in a form at line " errl ", column " errc) | ||||
|                   err) | ||||
|                 errf)))) | ||||
|         :a)) | ||||
|     (def res (resume f)) | ||||
|     (when good | ||||
| @@ -1043,7 +1044,7 @@ | ||||
|     (pp x)) | ||||
|   (when f | ||||
|     (def st (fiber.stack f)) | ||||
|     (loop  | ||||
|     (loop | ||||
|       [{ | ||||
|         :function func | ||||
|         :tail tail | ||||
| @@ -1051,20 +1052,26 @@ | ||||
|         :c c | ||||
|         :name name | ||||
|         :source source | ||||
|         :source-line source-line | ||||
|         :source-column source-col | ||||
|         :line source-line | ||||
|         :column source-col | ||||
|         } :in st] | ||||
|       (file.write stdout "  in") | ||||
|       (when c (file.write stdout " cfunction")) | ||||
|       (if name | ||||
|         (file.write stdout " " name) | ||||
|         (when func (file.write stdout " " (string func)))) | ||||
|       (if source  | ||||
|       (if source | ||||
|         (do | ||||
|           (file.write stdout " [" source "]") | ||||
|           (if source-line (file.write stdout " on line " | ||||
|                                       (string source-line) ", column " (string source-col))))) | ||||
|       (if pc (file.write stdout " (pc=" (string pc) ")")) | ||||
|           (if source-line  | ||||
|             (file.write  | ||||
|               stdout | ||||
|               " on line " | ||||
|               (string source-line)  | ||||
|               ", column " | ||||
|               (string source-col))))) | ||||
|       (if (and (not source-line) pc) | ||||
|         (file.write stdout " (pc=" (string pc) ")")) | ||||
|       (when tail (file.write stdout " (tailcall)")) | ||||
|       (file.write stdout "\n")))) | ||||
| 
 | ||||
| @@ -1082,7 +1089,7 @@ | ||||
|   (run-context *env* chunks (fn [x] (:= returnval x)) default-error-handler "eval") | ||||
|   returnval) | ||||
| 
 | ||||
| (def module.paths  | ||||
| (def module.paths | ||||
|   @["./?.dst" | ||||
|     "./?/init.dst" | ||||
|     "./dst_modules/?.dst" | ||||
| @@ -1090,7 +1097,7 @@ | ||||
|     "/usr/local/dst/0.0.0/?.dst" | ||||
|     "/usr/local/dst/0.0.0/?/init.dst"]) | ||||
| 
 | ||||
| (def module.native-paths  | ||||
| (def module.native-paths | ||||
|   @["./?.so" | ||||
|     "./?/??.so" | ||||
|     "./dst_modules/?.so" | ||||
| @@ -1143,8 +1150,8 @@ | ||||
|         (error (string "circular dependency: module " path " is loading"))) | ||||
|       (def {:exit exit-on-error} (or args {})) | ||||
|       (def check (get cache path)) | ||||
|       (if check  | ||||
|         check  | ||||
|       (if check | ||||
|         check | ||||
|         (do | ||||
|           (def newenv (make-env)) | ||||
|           (put cache path newenv) | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "gc.h" | ||||
|  | ||||
| /* Initialize a buffer */ | ||||
|   | ||||
| @@ -20,8 +20,7 @@ | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #include <dst/dsttypes.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include <dst/dst.h> | ||||
| #include "gc.h" | ||||
|  | ||||
| /* Look up table for instructions */ | ||||
| @@ -97,7 +96,13 @@ enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT] = { | ||||
|     DIT_SSS, /* DOP_PUT, */ | ||||
|     DIT_SSU, /* DOP_GET_INDEX, */ | ||||
|     DIT_SSU, /* DOP_PUT_INDEX, */ | ||||
|     DIT_SS /* DOP_LENGTH */ | ||||
|     DIT_SS, /* DOP_LENGTH */ | ||||
|     DIT_S, /* DOP_MAKE_ARRAY */ | ||||
|     DIT_S, /* DOP_MAKE_BUFFER */ | ||||
|     DIT_S, /* DOP_MAKE_TUPLE */ | ||||
|     DIT_S, /* DOP_MAKE_STRUCT */ | ||||
|     DIT_S, /* DOP_MAKE_TABLE */ | ||||
|     DIT_S /* DOP_MAKE_STRING */ | ||||
| }; | ||||
|  | ||||
| /* Verify some bytecode */ | ||||
|   | ||||
| @@ -21,12 +21,9 @@ | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "compile.h" | ||||
| #define DST_V_NODEF_GROW | ||||
| #include <headerlibs/vector.h> | ||||
| #undef DST_V_NODEF_GROW | ||||
| #include "emit.h" | ||||
| #include "vector.h" | ||||
| 
 | ||||
| static int fixarity0(DstFopts opts, DstSlot *args) { | ||||
|     (void) opts; | ||||
| @@ -41,41 +38,17 @@ static int fixarity2(DstFopts opts, DstSlot *args) { | ||||
|     return dst_v_count(args) == 2; | ||||
| } | ||||
| 
 | ||||
| /* Generic hanldling for $A = B op $C */ | ||||
| static DstSlot genericSSS(DstFopts opts, int op, Dst leftval, DstSlot s) { | ||||
|     DstSlot target = dstc_gettarget(opts); | ||||
|     DstSlot zero = dstc_cslot(leftval); | ||||
|     int32_t lhs = dstc_regnear(opts.compiler, zero, DSTC_REGTEMP_0); | ||||
|     int32_t rhs = dstc_regnear(opts.compiler, s, DSTC_REGTEMP_1); | ||||
|     dstc_emit(opts.compiler, op | | ||||
|             (target.index << 8) |  | ||||
|             (lhs << 16) | | ||||
|             (rhs << 24)); | ||||
|     dstc_free_reg(opts.compiler, zero, lhs); | ||||
|     dstc_free_reg(opts.compiler, s, rhs); | ||||
|     return target; | ||||
| } | ||||
| 
 | ||||
| /* Generic hanldling for $A = op $B */ | ||||
| static DstSlot genericSS(DstFopts opts, int op, DstSlot s) { | ||||
|     DstSlot target = dstc_gettarget(opts); | ||||
|     int32_t rhs = dstc_regfar(opts.compiler, s, DSTC_REGTEMP_0); | ||||
|     dstc_emit(opts.compiler, op | | ||||
|             (target.index << 8) |  | ||||
|             (rhs << 16)); | ||||
|     dstc_free_reg(opts.compiler, s, rhs); | ||||
|     dstc_emit_ss(opts.compiler, op, target, s, 1); | ||||
|     return target; | ||||
| } | ||||
| 
 | ||||
| /* Generic hanldling for $A = $B op I */ | ||||
| static DstSlot genericSSI(DstFopts opts, int op, DstSlot s, int32_t imm) { | ||||
|     DstSlot target = dstc_gettarget(opts); | ||||
|     int32_t rhs = dstc_regnear(opts.compiler, s, DSTC_REGTEMP_0); | ||||
|     dstc_emit(opts.compiler, op | | ||||
|             (target.index << 8) |  | ||||
|             (rhs << 16) | | ||||
|             (imm << 24)); | ||||
|     dstc_free_reg(opts.compiler, s, rhs); | ||||
|     dstc_emit_ssi(opts.compiler, op, target, s, imm, 1); | ||||
|     return target; | ||||
| } | ||||
| 
 | ||||
| @@ -92,29 +65,21 @@ static DstSlot opreduce( | ||||
|     if (len == 0) { | ||||
|         return dstc_cslot(nullary); | ||||
|     } else if (len == 1) { | ||||
|         return genericSSS(opts, op, nullary, args[0]); | ||||
|         t = dstc_gettarget(opts); | ||||
|         dstc_emit_sss(c, op, t, dstc_cslot(nullary), args[0], 1); | ||||
|         return t; | ||||
|     } | ||||
|     t = dstc_gettarget(opts); | ||||
|     /* Compile initial two arguments */ | ||||
|     int32_t lhs = dstc_regnear(c, args[0], DSTC_REGTEMP_0); | ||||
|     int32_t rhs = dstc_regnear(c, args[1], DSTC_REGTEMP_1); | ||||
|     dstc_emit(c, op | (t.index << 8) | (lhs << 16) | (rhs << 24)); | ||||
|     dstc_free_reg(c, args[0], lhs); | ||||
|     dstc_free_reg(c, args[1], rhs); | ||||
|     /* Don't release t */ | ||||
|     /* Compile the rest of the arguments */ | ||||
|     for (i = 2; i < len; i++) { | ||||
|         rhs = dstc_regnear(c, args[i], DSTC_REGTEMP_0); | ||||
|         dstc_emit(c, op | (t.index << 8) | (t.index << 16) | (rhs << 24)); | ||||
|         dstc_free_reg(c, args[i], rhs); | ||||
|     } | ||||
|     dstc_emit_sss(c, op, t, args[0], args[1], 1); | ||||
|     for (i = 2; i < len; i++) | ||||
|         dstc_emit_sss(c, op, t, t, args[i], 1); | ||||
|     return t; | ||||
| } | ||||
| 
 | ||||
| /* Function optimizers */ | ||||
| 
 | ||||
| static DstSlot do_error(DstFopts opts, DstSlot *args) { | ||||
|     dstc_emit_s(opts.compiler, DOP_ERROR, args[0]); | ||||
|     dstc_emit_s(opts.compiler, DOP_ERROR, args[0], 0); | ||||
|     return dstc_cslot(dst_wrap_nil()); | ||||
| } | ||||
| static DstSlot do_debug(DstFopts opts, DstSlot *args) { | ||||
| @@ -139,23 +104,17 @@ static DstSlot do_resume(DstFopts opts, DstSlot *args) { | ||||
| } | ||||
| static DstSlot do_apply1(DstFopts opts, DstSlot *args) { | ||||
|     /* Push phase */ | ||||
|     int32_t array_reg = dstc_regfar(opts.compiler, args[1], DSTC_REGTEMP_1); | ||||
|     dstc_emit(opts.compiler, DOP_PUSH_ARRAY | (array_reg << 8)); | ||||
|     dstc_free_reg(opts.compiler, args[1], array_reg); | ||||
|     dstc_emit_s(opts.compiler, DOP_PUSH_ARRAY, args[1], 0); | ||||
|     /* Call phase */ | ||||
|     int32_t fun_reg = dstc_regnear(opts.compiler, args[0], DSTC_REGTEMP_0); | ||||
|     DstSlot target; | ||||
|     if (opts.flags & DST_FOPTS_TAIL) { | ||||
|         dstc_emit(opts.compiler, DOP_TAILCALL | (fun_reg << 8)); | ||||
|         dstc_emit_s(opts.compiler, DOP_TAILCALL, args[0], 0); | ||||
|         target = dstc_cslot(dst_wrap_nil()); | ||||
|         target.flags |= DST_SLOT_RETURNED; | ||||
|     } else { | ||||
|         target = dstc_gettarget(opts); | ||||
|         dstc_emit(opts.compiler, DOP_CALL | | ||||
|                 (target.index << 8) |  | ||||
|                 (fun_reg << 16)); | ||||
|         dstc_emit_ss(opts.compiler, DOP_CALL, target, args[0], 1); | ||||
|     } | ||||
|     dstc_free_reg(opts.compiler, args[0], fun_reg); | ||||
|     return target; | ||||
| } | ||||
| 
 | ||||
| @@ -21,13 +21,9 @@ | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "compile.h" | ||||
| #include "emit.h" | ||||
| 
 | ||||
| #define DST_V_DEF_FLATTENMEM | ||||
| #include <headerlibs/vector.h> | ||||
| #undef DST_V_DEF_FLATTENMEM | ||||
| #include "vector.h" | ||||
| 
 | ||||
| DstFopts dstc_fopts_default(DstCompiler *c) { | ||||
|     DstFopts ret; | ||||
| @@ -97,17 +93,7 @@ DstSlot dstc_cslot(Dst x) { | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /* Get a temp near slot */ | ||||
| DstSlot dstc_nearslot(DstCompiler *c, DstcRegisterTemp tag) { | ||||
|     DstSlot ret; | ||||
|     ret.flags = DST_SLOTTYPE_ANY; | ||||
|     ret.index = dstc_allocnear(c, tag); | ||||
|     ret.constant = dst_wrap_nil(); | ||||
|     ret.envindex = -1; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /* Get a temp near slot */ | ||||
| /* Get a local slot */ | ||||
| DstSlot dstc_farslot(DstCompiler *c) { | ||||
|     DstSlot ret; | ||||
|     ret.flags = DST_SLOTTYPE_ANY; | ||||
| @@ -296,14 +282,13 @@ DstSlot dstc_return(DstCompiler *c, DstSlot s) { | ||||
|         if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL)) | ||||
|             dstc_emit(c, DOP_RETURN_NIL); | ||||
|         else | ||||
|             dstc_emit_s(c, DOP_RETURN, s); | ||||
|             dstc_emit_s(c, DOP_RETURN, s, 0); | ||||
|         s.flags |= DST_SLOT_RETURNED; | ||||
|     } | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
| /* Get a target slot for emitting an instruction. Will always return
 | ||||
|  * a local slot. */ | ||||
| /* Get a target slot for emitting an instruction. */ | ||||
| DstSlot dstc_gettarget(DstFopts opts) { | ||||
|     DstSlot slot; | ||||
|     if ((opts.flags & DST_FOPTS_HINT) && | ||||
| @@ -314,7 +299,7 @@ DstSlot dstc_gettarget(DstFopts opts) { | ||||
|         slot.envindex = -1; | ||||
|         slot.constant = dst_wrap_nil(); | ||||
|         slot.flags = 0; | ||||
|         slot.index = dstc_allocnear(opts.compiler, DSTC_REGTEMP_TARGET); | ||||
|         slot.index = dstc_allocfar(opts.compiler); | ||||
|     } | ||||
|     return slot; | ||||
| } | ||||
| @@ -346,11 +331,11 @@ DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds) { | ||||
| void dstc_pushslots(DstCompiler *c, DstSlot *slots) { | ||||
|     int32_t i; | ||||
|     for (i = 0; i < dst_v_count(slots) - 2; i += 3) | ||||
|         dstc_emit_sss(c, DOP_PUSH_3, slots[i], slots[i+1], slots[i+2]); | ||||
|         dstc_emit_sss(c, DOP_PUSH_3, slots[i], slots[i+1], slots[i+2], 0); | ||||
|     if (i == dst_v_count(slots) - 2) | ||||
|         dstc_emit_ss(c, DOP_PUSH_2, slots[i], slots[i+1]); | ||||
|         dstc_emit_ss(c, DOP_PUSH_2, slots[i], slots[i+1], 0); | ||||
|     else if (i == dst_v_count(slots) - 1) | ||||
|         dstc_emit_s(c, DOP_PUSH, slots[i]); | ||||
|         dstc_emit_s(c, DOP_PUSH, slots[i], 0); | ||||
| } | ||||
| 
 | ||||
| /* Free slots loaded via dstc_toslots */ | ||||
| @@ -399,159 +384,185 @@ static DstSlot dstc_call(DstFopts opts, DstSlot *slots, DstSlot fun) { | ||||
|     if (!specialized) { | ||||
|         dstc_pushslots(c, slots); | ||||
|         if (opts.flags & DST_FOPTS_TAIL) { | ||||
|             dstc_emit_s(c, DOP_TAILCALL, fun); | ||||
|             dstc_emit_s(c, DOP_TAILCALL, fun, 0); | ||||
|             retslot = dstc_cslot(dst_wrap_nil()); | ||||
|             retslot.flags = DST_SLOT_RETURNED; | ||||
|         } else { | ||||
|             retslot = dstc_gettarget(opts); | ||||
|             int32_t fun_register = dstc_regnear(c, fun, DSTC_REGTEMP_0); | ||||
|             dstc_emit(c, DOP_CALL | | ||||
|                     (retslot.index << 8) | | ||||
|                     (fun_register << 16)); | ||||
|             /* Don't free ret register */ | ||||
|             dstc_free_reg(c, fun, fun_register); | ||||
|             dstc_emit_ss(c, DOP_CALL, retslot, fun, 1); | ||||
|         } | ||||
|     } | ||||
|     dstc_freeslots(c, slots); | ||||
|     return retslot; | ||||
| } | ||||
| 
 | ||||
| static DstSlot dstc_maker(DstFopts opts, DstSlot *slots, int op) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstSlot retslot; | ||||
|     dstc_pushslots(c, slots); | ||||
|     dstc_freeslots(c, slots); | ||||
|     retslot = dstc_gettarget(opts); | ||||
|     dstc_emit_s(c, op, retslot, 1); | ||||
|     return retslot; | ||||
| } | ||||
| 
 | ||||
| static DstSlot dstc_array(DstFopts opts, Dst x) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstArray *a = dst_unwrap_array(x); | ||||
|     return dstc_call(opts, | ||||
|     return dstc_maker(opts, | ||||
|             dstc_toslots(c, a->data, a->count), | ||||
|             dstc_cslot(dst_wrap_cfunction(dst_core_array))); | ||||
|             DOP_MAKE_ARRAY); | ||||
| } | ||||
| 
 | ||||
| static DstSlot dstc_tablector(DstFopts opts, Dst x, DstCFunction cfun) { | ||||
| static DstSlot dstc_tablector(DstFopts opts, Dst x, int op) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     return dstc_call(opts, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun))); | ||||
|     return dstc_maker(opts,  | ||||
|             dstc_toslotskv(c, x), | ||||
|             op); | ||||
| } | ||||
| 
 | ||||
| static DstSlot dstc_bufferctor(DstFopts opts, Dst x) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstBuffer *b = dst_unwrap_buffer(x); | ||||
|     Dst onearg = dst_stringv(b->data, b->count); | ||||
|     return dstc_call(opts, | ||||
|     return dstc_maker(opts, | ||||
|             dstc_toslots(c, &onearg, 1), | ||||
|             dstc_cslot(dst_wrap_cfunction(dst_core_buffer))); | ||||
|             DOP_MAKE_BUFFER); | ||||
| } | ||||
| 
 | ||||
| /* Compile a symbol */ | ||||
| DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) { | ||||
| static DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) { | ||||
|     if (dst_string_length(sym) && sym[0] != ':') { | ||||
|         /* Non keyword */ | ||||
|         return dstc_resolve(opts.compiler, sym); | ||||
|     } else { | ||||
|         /* Keyword */ | ||||
|         return dstc_cslot(dst_wrap_symbol(sym)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Expand a macro one time. Also get the special form compiler if we
 | ||||
|  * find that instead. */ | ||||
| static int macroexpand1( | ||||
|         DstCompiler *c,  | ||||
|         Dst x,  | ||||
|         Dst *out,  | ||||
|         const DstSpecial **spec) { | ||||
|     if (!dst_checktype(x, DST_TUPLE)) | ||||
|         return 0; | ||||
|     const Dst *form = dst_unwrap_tuple(x); | ||||
|     if (dst_tuple_length(form) == 0) | ||||
|         return 0; | ||||
|     /* Source map - only set when we get a tuple */ | ||||
|     if (dst_tuple_sm_line(form) > 0) { | ||||
|         c->current_mapping.line = dst_tuple_sm_line(form); | ||||
|         c->current_mapping.column = dst_tuple_sm_col(form); | ||||
|     } | ||||
|     if (!dst_checktype(form[0], DST_SYMBOL)) | ||||
|         return 0; | ||||
|     const uint8_t *name = dst_unwrap_symbol(form[0]); | ||||
|     const DstSpecial *s = dstc_special(name); | ||||
|     if (s) { | ||||
|         *spec = s; | ||||
|         return 0; | ||||
|     } | ||||
|     Dst macroval; | ||||
|     DstBindingType btype = dst_env_resolve(c->env, name, ¯oval); | ||||
|     if (btype != DST_BINDING_MACRO || | ||||
|             !dst_checktype(macroval, DST_FUNCTION)) | ||||
|         return 0; | ||||
| 
 | ||||
| 
 | ||||
|     /* Evaluate macro */ | ||||
|     DstFiber *fiberp; | ||||
|     DstFunction *macro = dst_unwrap_function(macroval); | ||||
|     int lock = dst_gclock(); | ||||
|     DstSignal status = dst_call( | ||||
|             macro,  | ||||
|             dst_tuple_length(form) - 1, | ||||
|             form + 1,  | ||||
|             &x, | ||||
|             &fiberp); | ||||
|     dst_gcunlock(lock); | ||||
|     if (status != DST_SIGNAL_OK) { | ||||
|         const uint8_t *es = dst_formatc("(macro) %V", x); | ||||
|         c->result.macrofiber = fiberp; | ||||
|         dstc_error(c, es); | ||||
|     } else { | ||||
|         *out = x; | ||||
|     } | ||||
| 
 | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| /* Compile a single value */ | ||||
| DstSlot dstc_value(DstFopts opts, Dst x) { | ||||
|     DstSlot ret; | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     int macrorecur = 0; | ||||
|     DstSourceMapping last_mapping = c->current_mapping; | ||||
|     opts.compiler->recursion_guard--; | ||||
| recur: | ||||
|     if (dstc_iserr(&opts)) { | ||||
|     c->recursion_guard--; | ||||
| 
 | ||||
|     /* Guard against previous errors and unbounded recursion */ | ||||
|     if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); | ||||
|     if (c->recursion_guard <= 0) { | ||||
|         dstc_cerror(c, "recursed too deeply"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     if (opts.compiler->recursion_guard <= 0) { | ||||
|         dstc_cerror(opts.compiler, "recursed too deeply"); | ||||
| 
 | ||||
|     /* Macro expand. Also gets possible special form and
 | ||||
|      * refines source mapping cursor if possible. */ | ||||
|     const DstSpecial *spec = NULL; | ||||
|     int macroi = DST_RECURSION_GUARD; | ||||
|     while (macroi && !dstc_iserr(&opts) && macroexpand1(c, x, &x, &spec)) | ||||
|         macroi--; | ||||
|     if (macroi == 0) { | ||||
|         dstc_cerror(c, "recursed too deeply in macro expansion"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     switch (dst_type(x)) { | ||||
|         default: | ||||
|             ret = dstc_cslot(x); | ||||
|             break; | ||||
|         case DST_SYMBOL: | ||||
|             { | ||||
|                 const uint8_t *sym = dst_unwrap_symbol(x); | ||||
|                 ret = dstc_symbol(opts, sym); | ||||
|                 break; | ||||
|             } | ||||
|         case DST_TUPLE: | ||||
|             { | ||||
|                 int compiled = 0; | ||||
|                 Dst headval; | ||||
|                 DstSlot head; | ||||
|                 DstFopts subopts = dstc_fopts_default(c); | ||||
|                 const Dst *tup = dst_unwrap_tuple(x); | ||||
|                 /* Get ast mapping */ | ||||
|                 if (dst_tuple_sm_line(tup) > 0) { | ||||
|                     c->current_mapping.line = dst_tuple_sm_line(tup); | ||||
|                     c->current_mapping.column = dst_tuple_sm_col(tup); | ||||
|                 } | ||||
|                 /* Empty tuple is tuple literal */ | ||||
|                 if (dst_tuple_length(tup) == 0) { | ||||
|                     compiled = 1; | ||||
|                     ret = dstc_cslot(x); | ||||
|                 } else { | ||||
|                     /* Symbols could be specials */ | ||||
|                     headval = tup[0]; | ||||
|                     if (dst_checktype(headval, DST_SYMBOL)) { | ||||
|                         const uint8_t *headsym = dst_unwrap_symbol(headval); | ||||
|                         const DstSpecial *s = dstc_special(headsym); | ||||
|                         if (NULL != s) { | ||||
|                             ret = s->compile(opts, dst_tuple_length(tup) - 1, tup + 1); | ||||
|                             compiled = 1; | ||||
|                         } else { | ||||
|                             /* Check macro */ | ||||
|                             Dst macVal; | ||||
|                             DstBindingType btype = dst_env_resolve(c->env, headsym, &macVal); | ||||
|                             if (btype == DST_BINDING_MACRO && | ||||
|                                     dst_checktype(macVal, DST_FUNCTION)) { | ||||
|                                 if (macrorecur++ > DST_RECURSION_GUARD) { | ||||
|                                     dstc_cerror(c, "macro expansion recursed too deeply"); | ||||
|                                     return dstc_cslot(dst_wrap_nil()); | ||||
|                                 } else { | ||||
|                                     DstFunction *f = dst_unwrap_function(macVal); | ||||
|                                     int lock = dst_gclock(); | ||||
|                                     DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x); | ||||
|                                     dst_gcunlock(lock); | ||||
|                                     if (status != DST_SIGNAL_OK) { | ||||
|                                         const uint8_t *es = dst_formatc("error in macro expansion: %V", x); | ||||
|                                         dstc_error(c, es); | ||||
|                                     } | ||||
|                                     /* Tail recur on the value */ | ||||
|                                     goto recur; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     if (!compiled) { | ||||
|                         /* Compile the head of the tuple */ | ||||
| 
 | ||||
|     /* Special forms */ | ||||
|     if (spec) { | ||||
|         const Dst *tup = dst_unwrap_tuple(x); | ||||
|         ret = spec->compile(opts, dst_tuple_length(tup) - 1, tup + 1); | ||||
|     } else { | ||||
|         switch (dst_type(x)) { | ||||
|             case DST_TUPLE: | ||||
|                 { | ||||
|                     DstFopts subopts = dstc_fopts_default(c); | ||||
|                     const Dst *tup = dst_unwrap_tuple(x); | ||||
|                     /* Empty tuple is tuple literal */ | ||||
|                     if (dst_tuple_length(tup) == 0) { | ||||
|                         ret = dstc_cslot(x); | ||||
|                     } else { | ||||
|                         DstSlot head = dstc_value(subopts, tup[0]); | ||||
|                         subopts.flags = DST_FUNCTION | DST_CFUNCTION; | ||||
|                         head = dstc_value(subopts, tup[0]); | ||||
|                         /* Add compile function call */ | ||||
|                         ret = dstc_call(opts, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head); | ||||
|                         dstc_freeslot(c, head); | ||||
|                     } | ||||
|                 } | ||||
|                 /* Pop source mapping */ | ||||
|                 if (c->result.status != DST_COMPILE_ERROR) | ||||
|                     c->current_mapping = last_mapping; | ||||
|             } | ||||
|             break; | ||||
|         case DST_ARRAY: | ||||
|             ret = dstc_array(opts, x); | ||||
|             break; | ||||
|         case DST_STRUCT: | ||||
|             ret = dstc_tablector(opts, x, dst_core_struct); | ||||
|             break; | ||||
|         case DST_TABLE: | ||||
|             ret = dstc_tablector(opts, x, dst_core_table); | ||||
|             break; | ||||
|         case DST_BUFFER: | ||||
|             ret = dstc_bufferctor(opts, x); | ||||
|             break; | ||||
|                 break; | ||||
|             case DST_SYMBOL: | ||||
|                 ret = dstc_symbol(opts, dst_unwrap_symbol(x)); | ||||
|                 break; | ||||
|             case DST_ARRAY: | ||||
|                 ret = dstc_array(opts, x); | ||||
|                 break; | ||||
|             case DST_STRUCT: | ||||
|                 ret = dstc_tablector(opts, x, DOP_MAKE_STRUCT); | ||||
|                 break; | ||||
|             case DST_TABLE: | ||||
|                 ret = dstc_tablector(opts, x, DOP_MAKE_TABLE); | ||||
|                 break; | ||||
|             case DST_BUFFER: | ||||
|                 ret = dstc_bufferctor(opts, x); | ||||
|                 break; | ||||
|             default: | ||||
|                 ret = dstc_cslot(x); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (dstc_iserr(&opts)) { | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     c->current_mapping = last_mapping; | ||||
|     if (opts.flags & DST_FOPTS_TAIL) { | ||||
|         ret = dstc_return(opts.compiler, ret); | ||||
|     } | ||||
| @@ -631,6 +642,7 @@ static void dstc_init(DstCompiler *c, DstTable *env, const uint8_t *where) { | ||||
|     c->result.error = NULL; | ||||
|     c->result.status = DST_COMPILE_OK; | ||||
|     c->result.funcdef = NULL; | ||||
|     c->result.macrofiber = NULL; | ||||
|     c->result.error_mapping.line = 0; | ||||
|     c->result.error_mapping.column = 0; | ||||
| } | ||||
| @@ -691,10 +703,13 @@ static int cfun(DstArgs args) { | ||||
|     if (res.status == DST_COMPILE_OK) { | ||||
|         DST_RETURN_FUNCTION(args, dst_thunk(res.funcdef)); | ||||
|     } else { | ||||
|         t = dst_table(2); | ||||
|         t = dst_table(4); | ||||
|         dst_table_put(t, dst_csymbolv(":error"), dst_wrap_string(res.error)); | ||||
|         dst_table_put(t, dst_csymbolv(":error-line"), dst_wrap_integer(res.error_mapping.line)); | ||||
|         dst_table_put(t, dst_csymbolv(":error-column"), dst_wrap_integer(res.error_mapping.column)); | ||||
|         dst_table_put(t, dst_csymbolv(":line"), dst_wrap_integer(res.error_mapping.line)); | ||||
|         dst_table_put(t, dst_csymbolv(":column"), dst_wrap_integer(res.error_mapping.column)); | ||||
|         if (res.macrofiber) { | ||||
|             dst_table_put(t, dst_csymbolv(":fiber"), dst_wrap_fiber(res.macrofiber)); | ||||
|         } | ||||
|         DST_RETURN_TABLE(args, t); | ||||
|     } | ||||
| } | ||||
| @@ -24,8 +24,6 @@ | ||||
| #define DST_COMPILE_H | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include "regalloc.h" | ||||
| 
 | ||||
| /* Tags for some functions for the prepared inliner */ | ||||
| @@ -185,7 +183,6 @@ const DstKV *dstc_next(Dst ds, const DstKV *kv); | ||||
| 
 | ||||
| void dstc_freeslot(DstCompiler *c, DstSlot s); | ||||
| void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s); | ||||
| DstSlot dstc_nearslot(DstCompiler *c, DstcRegisterTemp tag); | ||||
| DstSlot dstc_farslot(DstCompiler *c); | ||||
| 
 | ||||
| /* Throw away some code after checking that it is well formed. */ | ||||
| @@ -21,9 +21,64 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "corelib.h" | ||||
| #include "compile.h" | ||||
| #include "state.h" | ||||
|  | ||||
| /* Generated header */ | ||||
| #include <generated/boot.h> | ||||
|  | ||||
| /* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries | ||||
|  * with native code. */ | ||||
| #ifdef DST_WINDOWS | ||||
| #include <windows.h> | ||||
| typedef HINSTANCE Clib; | ||||
| #define load_clib(name) LoadLibrary((name)) | ||||
| #define symbol_clib(lib, sym) GetProcAddress((lib), (sym)) | ||||
| #define error_clib() "could not load dynamic library" | ||||
| #elif defined(DST_WEB) | ||||
| #include <emscripten.h> | ||||
| /* TODO - figure out how loading modules will work in JS */ | ||||
| typedef int Clib; | ||||
| #define load_clib(name) 0 | ||||
| #define symbol_clib(lib, sym) 0 | ||||
| #define error_clib() "dynamic libraries not supported" | ||||
| #else | ||||
| #include <dlfcn.h> | ||||
| typedef void *Clib; | ||||
| #define load_clib(name) dlopen((name), RTLD_NOW) | ||||
| #define symbol_clib(lib, sym) dlsym((lib), (sym)) | ||||
| #define error_clib() dlerror() | ||||
| #endif | ||||
|  | ||||
| DstCFunction dst_native(const char *name, const uint8_t **error) { | ||||
|     Clib lib = load_clib(name); | ||||
|     DstCFunction init; | ||||
|     if (!lib) { | ||||
|         *error = dst_cstring(error_clib()); | ||||
|         return NULL; | ||||
|     } | ||||
|     init = (DstCFunction) symbol_clib(lib, "_dst_init"); | ||||
|     if (!init) { | ||||
|         *error = dst_cstring("could not find _dst_init symbol"); | ||||
|         return NULL; | ||||
|     } | ||||
|     return init; | ||||
| } | ||||
|  | ||||
| int dst_core_native(DstArgs args) { | ||||
|     DstCFunction init; | ||||
|     const uint8_t *error = NULL; | ||||
|     const uint8_t *path = NULL; | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_ARG_STRING(path, args, 0); | ||||
|     init = dst_native((const char *)path, &error); | ||||
|     if (!init) { | ||||
|         DST_THROWV(args, dst_wrap_string(error)); | ||||
|     } | ||||
|     DST_RETURN_CFUNCTION(args, init); | ||||
| } | ||||
|  | ||||
| int dst_core_print(DstArgs args) { | ||||
|     int32_t i; | ||||
|     for (i = 0; i < args.n; ++i) { | ||||
| @@ -232,3 +287,219 @@ int dst_core_hash(DstArgs args) { | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_RETURN_INTEGER(args, dst_hash(args.v[0])); | ||||
| } | ||||
|  | ||||
| static const DstReg cfuns[] = { | ||||
|     {"native", dst_core_native}, | ||||
|     {"print", dst_core_print}, | ||||
|     {"describe", dst_core_describe}, | ||||
|     {"string", dst_core_string}, | ||||
|     {"symbol", dst_core_symbol}, | ||||
|     {"buffer", dst_core_buffer}, | ||||
|     {"table", dst_core_table}, | ||||
|     {"array", dst_core_array}, | ||||
|     {"scan-number", dst_core_scannumber}, | ||||
|     {"scan-integer", dst_core_scaninteger}, | ||||
|     {"scan-real", dst_core_scanreal}, | ||||
|     {"tuple", dst_core_tuple}, | ||||
|     {"struct", dst_core_struct}, | ||||
|     {"buffer", dst_core_buffer}, | ||||
|     {"gensym", dst_core_gensym}, | ||||
|     {"gccollect", dst_core_gccollect}, | ||||
|     {"gcsetinterval", dst_core_gcsetinterval}, | ||||
|     {"gcinterval", dst_core_gcinterval}, | ||||
|     {"type", dst_core_type}, | ||||
|     {"next", dst_core_next}, | ||||
|     {"hash", dst_core_hash}, | ||||
|     {NULL, NULL} | ||||
| }; | ||||
|  | ||||
| /* Utility for inline assembly */ | ||||
| static void dst_quick_asm( | ||||
|         DstTable *env, | ||||
|         int32_t flags, | ||||
|         const char *name, | ||||
|         int32_t arity, | ||||
|         int32_t slots, | ||||
|         const uint32_t *bytecode, | ||||
|         size_t bytecode_size) { | ||||
|     DstFuncDef *def = dst_funcdef_alloc(); | ||||
|     def->arity = arity; | ||||
|     def->flags = flags; | ||||
|     def->slotcount = slots; | ||||
|     def->bytecode = malloc(bytecode_size); | ||||
|     def->bytecode_length = bytecode_size / sizeof(uint32_t); | ||||
|     def->name = dst_cstring(name); | ||||
|     if (!def->bytecode) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     } | ||||
|     memcpy(def->bytecode, bytecode, bytecode_size); | ||||
|     dst_env_def(env, name, dst_wrap_function(dst_thunk(def))); | ||||
| } | ||||
|  | ||||
| #define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24)) | ||||
| #define SS(op, a, b) SSS(op, a, b, 0) | ||||
| #define S(op, a) SSS(op, a, 0, 0) | ||||
| /* Variadic operator assembly. Must be templatized for each different opcode. */ | ||||
| /* Reg 0: Argument tuple (args) */ | ||||
| /* Reg 1: Argument count (argn) */ | ||||
| /* Reg 2: Jump flag (jump?) */ | ||||
| /* Reg 3: Accumulator (accum) */ | ||||
| /* Reg 4: Next operand (operand) */ | ||||
| /* Reg 5: Loop iterator (i) */ | ||||
| static DST_THREAD_LOCAL uint32_t varop_asm[] = { | ||||
|     DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */ | ||||
|  | ||||
|     /* Cheack nullary */ | ||||
|     DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */ | ||||
|     /* Nullary */ | ||||
|     DOP_LOAD_INTEGER | (3 << 8),  /* accum = nullary value */ | ||||
|     DOP_RETURN | (3 << 8), /* return accum */ | ||||
|  | ||||
|     /* Check unary */ | ||||
|     DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */ | ||||
|     /* Unary */ | ||||
|     DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */ | ||||
|     DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */ | ||||
|     DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ | ||||
|     DOP_RETURN | (3 << 8), /* return accum */ | ||||
|  | ||||
|     /* Mutli (2 or more) arity */ | ||||
|     /* Prime loop */ | ||||
|     DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */ | ||||
|     DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */ | ||||
|     /* Main loop */ | ||||
|     DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */ | ||||
|     DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */ | ||||
|     DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */ | ||||
|     DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */ | ||||
|     DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */ | ||||
|     /* Done, do last and return accumulator */ | ||||
|     DOP_RETURN | (3 << 8) /* return accum */ | ||||
| }; | ||||
|  | ||||
| #define VAROP_NULLARY_LOC 3 | ||||
| #define VAROP_UNARY_LOC 7 | ||||
| #define VAROP_OP_LOC1 9 | ||||
| #define VAROP_OP_LOC2 14 | ||||
|  | ||||
| /* Templatize a varop */ | ||||
| static void templatize_varop( | ||||
|         DstTable *env, | ||||
|         int32_t flags, | ||||
|         const char *name, | ||||
|         int32_t nullary, | ||||
|         int32_t unary, | ||||
|         uint32_t op) { | ||||
|     varop_asm[VAROP_NULLARY_LOC] = SS(DOP_LOAD_INTEGER, 3, nullary); | ||||
|     varop_asm[VAROP_UNARY_LOC] = SS(DOP_LOAD_INTEGER, 3, unary); | ||||
|     varop_asm[VAROP_OP_LOC1] = SSS(op, 3, 3, 4); | ||||
|     varop_asm[VAROP_OP_LOC2] = SSS(op, 3, 3, 4); | ||||
|     dst_quick_asm( | ||||
|             env, | ||||
|             flags | DST_FUNCDEF_FLAG_VARARG, | ||||
|             name, | ||||
|             0, | ||||
|             6, | ||||
|             varop_asm, | ||||
|             sizeof(varop_asm)); | ||||
| } | ||||
|  | ||||
| DstTable *dst_stl_env(int flags) { | ||||
|     static uint32_t error_asm[] = { | ||||
|         DOP_ERROR | ||||
|     }; | ||||
|     static uint32_t apply_asm[] = { | ||||
|        DOP_PUSH_ARRAY | (1 << 8), | ||||
|        DOP_TAILCALL | ||||
|     }; | ||||
|     static uint32_t debug_asm[] = { | ||||
|        DOP_SIGNAL | (2 << 24), | ||||
|        DOP_RETURN_NIL | ||||
|     }; | ||||
|     static uint32_t yield_asm[] = { | ||||
|         DOP_SIGNAL | (3 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t resume_asm[] = { | ||||
|         DOP_RESUME | (1 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t get_asm[] = { | ||||
|         DOP_GET | (1 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t put_asm[] = { | ||||
|         DOP_PUT | (1 << 16) | (2 << 24), | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|     static uint32_t length_asm[] = { | ||||
|         DOP_LENGTH, | ||||
|         DOP_RETURN | ||||
|     }; | ||||
|  | ||||
|     DstTable *env = dst_table(0); | ||||
|     Dst ret = dst_wrap_table(env); | ||||
|  | ||||
|     /* Load main functions */ | ||||
|     dst_env_cfuns(env, cfuns); | ||||
|  | ||||
|     dst_quick_asm(env, DST_FUN_YIELD, "debug", 0, 1, debug_asm, sizeof(debug_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_ERROR, "error", 1, 1, error_asm, sizeof(error_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_APPLY1, "apply1", 2, 2, apply_asm, sizeof(apply_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_YIELD, "yield", 1, 2, yield_asm, sizeof(yield_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_RESUME, "resume", 2, 2, resume_asm, sizeof(resume_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_GET, "get", 2, 2, get_asm, sizeof(get_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm)); | ||||
|     dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm)); | ||||
|  | ||||
|     /* Variadic ops */ | ||||
|     templatize_varop(env, DST_FUN_ADD, "+", 0, 0, DOP_ADD); | ||||
|     templatize_varop(env, DST_FUN_SUBTRACT, "-", 0, 0, DOP_SUBTRACT); | ||||
|     templatize_varop(env, DST_FUN_MULTIPLY, "*", 1, 1, DOP_MULTIPLY); | ||||
|     templatize_varop(env, DST_FUN_DIVIDE, "/", 1, 1, DOP_DIVIDE); | ||||
|     templatize_varop(env, DST_FUN_BAND, "&", -1, -1, DOP_BAND); | ||||
|     templatize_varop(env, DST_FUN_BOR, "|", 0, 0, DOP_BOR); | ||||
|     templatize_varop(env, DST_FUN_BXOR, "^", 0, 0, DOP_BXOR); | ||||
|     templatize_varop(env, DST_FUN_LSHIFT, "<<", 1, 1, DOP_SHIFT_LEFT); | ||||
|     templatize_varop(env, DST_FUN_RSHIFT, ">>", 1, 1, DOP_SHIFT_RIGHT); | ||||
|     templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED); | ||||
|  | ||||
|     dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION)); | ||||
|  | ||||
|     /* Set as gc root */ | ||||
|     dst_gcroot(dst_wrap_table(env)); | ||||
|  | ||||
|     /* Load auxiliary envs */ | ||||
|     { | ||||
|         DstArgs args; | ||||
|         args.n = 1; | ||||
|         args.v = &ret; | ||||
|         args.ret = &ret; | ||||
|         dst_lib_io(args); | ||||
|         dst_lib_math(args); | ||||
|         dst_lib_array(args); | ||||
|         dst_lib_tuple(args); | ||||
|         dst_lib_buffer(args); | ||||
|         dst_lib_table(args); | ||||
|         dst_lib_fiber(args); | ||||
|         dst_lib_os(args); | ||||
|         dst_lib_parse(args); | ||||
|         dst_lib_compile(args); | ||||
|         dst_lib_asm(args); | ||||
|         dst_lib_string(args); | ||||
|         dst_lib_marsh(args); | ||||
|     } | ||||
|  | ||||
|     /* Allow references to the environment */ | ||||
|     dst_env_def(env, "_env", ret); | ||||
|  | ||||
|     /* Run bootstrap source */ | ||||
|     dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen), "boot.dst"); | ||||
|  | ||||
|     if (flags & DST_STL_NOGCROOT) | ||||
|         dst_gcunroot(dst_wrap_table(env)); | ||||
|  | ||||
|     return env; | ||||
| } | ||||
|   | ||||
| @@ -20,39 +20,7 @@ | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef DST_COMPILE_H_defined | ||||
| #define DST_COMPILE_H_defined | ||||
| #ifndef DST_CORELIB_H | ||||
| #define DST_CORELIB_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include "dsttypes.h" | ||||
| 
 | ||||
| typedef struct DstCompileOptions DstCompileOptions; | ||||
| typedef struct DstCompileResult DstCompileResult; | ||||
| enum DstCompileStatus { | ||||
|     DST_COMPILE_OK, | ||||
|     DST_COMPILE_ERROR | ||||
| }; | ||||
| struct DstCompileResult { | ||||
|     enum DstCompileStatus status; | ||||
|     DstFuncDef *funcdef; | ||||
|     const uint8_t *error; | ||||
|     DstSourceMapping error_mapping; | ||||
| }; | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where); | ||||
| int dst_compile_cfun(DstArgs args); | ||||
| int dst_lib_compile(DstArgs args); | ||||
| 
 | ||||
| /* Get the default environment for dst */ | ||||
| DstTable *dst_stl_env(); | ||||
| 
 | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath); | ||||
| int dst_dostring(DstTable *env, const char *str, const char *sourcePath); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  | ||||
| @@ -20,9 +20,10 @@ | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dstcompile.h> | ||||
| #include <headerlibs/vector.h> | ||||
| #include <dst/dst.h> | ||||
| #include "emit.h" | ||||
| #include "vector.h" | ||||
| #include "regalloc.h" | ||||
| 
 | ||||
| /* Get a register */ | ||||
| int32_t dstc_allocfar(DstCompiler *c) { | ||||
| @@ -106,77 +107,104 @@ static void dstc_loadconst(DstCompiler *c, Dst k, int32_t reg) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Convert a slot to a two byte register */ | ||||
| int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) { | ||||
|     int32_t reg; | ||||
|     if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { | ||||
|         reg = dstc_allocnear(c, tag); | ||||
|         dstc_loadconst(c, s.constant, reg); | ||||
| /* Move a slot to a near register */ | ||||
| static void dstc_movenear(DstCompiler *c, | ||||
|         int32_t dest, | ||||
|         DstSlot src) { | ||||
|     if (src.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { | ||||
|         dstc_loadconst(c, src.constant, dest); | ||||
|         /* If we also are a reference, deref the one element array */ | ||||
|         if (s.flags & DST_SLOT_REF) { | ||||
|         if (src.flags & DST_SLOT_REF) { | ||||
|             dstc_emit(c, | ||||
|                     (reg << 16) | | ||||
|                     (reg << 8) | | ||||
|                     (dest << 16) | | ||||
|                     (dest << 8) | | ||||
|                     DOP_GET_INDEX); | ||||
|         } | ||||
|     } else if (s.envindex >= 0) { | ||||
|         reg = dstc_allocnear(c, tag); | ||||
|     } else if (src.envindex >= 0) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(s.index) << 24) | | ||||
|                 ((uint32_t)(s.envindex) << 16) | | ||||
|                 ((uint32_t)(reg) << 8) | | ||||
|                 ((uint32_t)(src.index) << 24) | | ||||
|                 ((uint32_t)(src.envindex) << 16) | | ||||
|                 ((uint32_t)(dest) << 8) | | ||||
|                 DOP_LOAD_UPVALUE); | ||||
|     } else if (src.index > 0xFF || src.index != dest) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(src.index) << 16) | | ||||
|                 ((uint32_t)(dest) << 8) | | ||||
|                     DOP_MOVE_NEAR); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Move a near register to a Slot. */ | ||||
| static void dstc_moveback(DstCompiler *c, | ||||
|         DstSlot dest, | ||||
|         int32_t src) { | ||||
|     if (dest.flags & DST_SLOT_REF) { | ||||
|         int32_t refreg = dstc_regalloc_temp(&c->scope->ra, DSTC_REGTEMP_5); | ||||
|         dstc_loadconst(c, dest.constant, refreg); | ||||
|         dstc_emit(c, | ||||
|                (src << 16) | | ||||
|                (refreg << 8) | | ||||
|                DOP_PUT_INDEX); | ||||
|         dstc_regalloc_freetemp(&c->scope->ra, refreg, DSTC_REGTEMP_5); | ||||
|     } else if (dest.envindex >= 0) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 24) | | ||||
|                 ((uint32_t)(dest.envindex) << 16) | | ||||
|                 ((uint32_t)(src) << 8) | | ||||
|                 DOP_SET_UPVALUE); | ||||
|     } else if (dest.index != src) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 16) | | ||||
|                 ((uint32_t)(src) << 8) | | ||||
|                     DOP_MOVE_FAR); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Call this to release a register after emitting the instruction. */ | ||||
| static void dstc_free_regnear(DstCompiler *c, DstSlot s, int32_t reg, DstcRegisterTemp tag) { | ||||
|     if (reg != s.index ||  | ||||
|             s.envindex >= 0 ||  | ||||
|             s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { | ||||
|         /* We need to free the temporary slot */ | ||||
|         dstc_regalloc_freetemp(&c->scope->ra, reg, tag); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Convert a slot to a two byte register */ | ||||
| static int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) { | ||||
|     /* check if already near register */ | ||||
|     if (s.envindex < 0 && s.index >= 0) { | ||||
|         return s.index; | ||||
|     } | ||||
|     int32_t reg; | ||||
|     int32_t nearreg = dstc_regalloc_temp(&c->scope->ra, tag); | ||||
|     dstc_movenear(c, nearreg, s); | ||||
|     if (nearreg >= 0xF0) { | ||||
|         reg = dstc_allocfar(c); | ||||
|         dstc_emit(c, DOP_MOVE_FAR | (nearreg << 8) | (reg << 16)); | ||||
|         dstc_regalloc_freetemp(&c->scope->ra, nearreg, tag); | ||||
|     } else { | ||||
|         /* We have a normal slot that fits in the required bit width */ | ||||
|         reg = s.index; | ||||
|         reg = nearreg; | ||||
|         dstc_regalloc_freetemp(&c->scope->ra, nearreg, tag); | ||||
|         dstc_regalloc_touch(&c->scope->ra, reg); | ||||
|     } | ||||
|     return reg; | ||||
| } | ||||
| 
 | ||||
| /* Convert a slot to a temporary 1 byte register */ | ||||
| int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) { | ||||
|     int32_t reg; | ||||
|     if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { | ||||
|         reg = dstc_allocnear(c, tag); | ||||
|         dstc_loadconst(c, s.constant, reg); | ||||
|         /* If we also are a reference, deref the one element array */ | ||||
|         if (s.flags & DST_SLOT_REF) { | ||||
|             dstc_emit(c, | ||||
|                     (reg << 16) | | ||||
|                     (reg << 8) | | ||||
|                     DOP_GET_INDEX); | ||||
|         } | ||||
|     } else if (s.envindex >= 0) { | ||||
|         reg = dstc_allocnear(c, tag); | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(s.index) << 24) | | ||||
|                 ((uint32_t)(s.envindex) << 16) | | ||||
|                 ((uint32_t)(reg) << 8) | | ||||
|                 DOP_LOAD_UPVALUE); | ||||
|     } else if (s.index > 0xFF) { | ||||
|         reg = dstc_allocnear(c, tag); | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(s.index) << 16) | | ||||
|                 ((uint32_t)(reg) << 8) | | ||||
|                     DOP_MOVE_NEAR); | ||||
|     } else { | ||||
|         /* We have a normal slot that fits in the required bit width */ | ||||
|         reg = s.index; | ||||
| static int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) { | ||||
|     /* check if already near register */ | ||||
|     if (s.envindex < 0 && s.index >= 0 && s.index <= 0xFF) { | ||||
|         return s.index; | ||||
|     } | ||||
|     int32_t reg = dstc_regalloc_temp(&c->scope->ra, tag); | ||||
|     dstc_movenear(c, reg, s); | ||||
|     return reg; | ||||
| } | ||||
| 
 | ||||
| /* Call this to release a register after emitting the instruction. */ | ||||
| void dstc_free_reg(DstCompiler *c, DstSlot s, int32_t reg) { | ||||
|     if (reg != s.index || s.envindex >= 0 || s.flags & DST_SLOT_CONSTANT) { | ||||
|         /* We need to free the temporary slot */ | ||||
|         dstc_regalloc_free(&c->scope->ra, reg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Check if two slots are equal */ | ||||
| static int dstc_sequal(DstSlot lhs, DstSlot rhs) { | ||||
|     if (lhs.flags == rhs.flags && | ||||
|     if ((lhs.flags & ~DST_SLOTTYPE_ANY) == (rhs.flags & ~DST_SLOTTYPE_ANY) && | ||||
|             lhs.index == rhs.index && | ||||
|             lhs.envindex == rhs.envindex) { | ||||
|         if (lhs.flags & (DST_SLOT_REF | DST_SLOT_CONSTANT)) { | ||||
| @@ -194,131 +222,48 @@ void dstc_copy( | ||||
|         DstCompiler *c, | ||||
|         DstSlot dest, | ||||
|         DstSlot src) { | ||||
|     int writeback = 0; | ||||
|     int32_t destlocal = -1; | ||||
|     int32_t srclocal = -1; | ||||
|     int32_t reflocal = -1; | ||||
| 
 | ||||
|     /* Can't write to constants */ | ||||
|     if (dest.flags & DST_SLOT_CONSTANT) { | ||||
|         dstc_cerror(c, "cannot write to constant"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /* Short circuit if dest and source are equal */ | ||||
|     if (dstc_sequal(dest, src)) return; | ||||
| 
 | ||||
|     /* Types of slots - src */ | ||||
|     /* constants */ | ||||
|     /* upvalues */ | ||||
|     /* refs */ | ||||
|     /* near index */ | ||||
|     /* far index */ | ||||
| 
 | ||||
|     /* Types of slots - dest */ | ||||
|     /* upvalues */ | ||||
|     /* refs */ | ||||
|     /* near index */ | ||||
|     /* far index */ | ||||
| 
 | ||||
|     /* If dest is a near index, do some optimization */ | ||||
|     /* If dest is a near register */ | ||||
|     if (dest.envindex < 0 && dest.index >= 0 && dest.index <= 0xFF) { | ||||
|         if (src.flags & DST_SLOT_CONSTANT) { | ||||
|             dstc_loadconst(c, src.constant, dest.index); | ||||
|         } else if (src.flags & DST_SLOT_REF) { | ||||
|             dstc_loadconst(c, src.constant, dest.index); | ||||
|             dstc_emit(c, | ||||
|                     (dest.index << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_GET_INDEX); | ||||
|         } else if (src.envindex >= 0) { | ||||
|             dstc_emit(c, | ||||
|                     (src.index << 24) | | ||||
|                     (src.envindex << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_LOAD_UPVALUE); | ||||
|         } else { | ||||
|             dstc_emit(c, | ||||
|                     (src.index << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_MOVE_NEAR); | ||||
|         } | ||||
|         dstc_movenear(c, dest.index, src); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /* Process: src -> srclocal -> destlocal -> dest */ | ||||
| 
 | ||||
|     /* src -> srclocal */ | ||||
|     srclocal = dstc_regnear(c, src, DSTC_REGTEMP_0); | ||||
| 
 | ||||
|     /* Pull down dest (find destlocal) */ | ||||
|     if (dest.flags & DST_SLOT_REF) { | ||||
|         writeback = 1; | ||||
|         destlocal = srclocal; | ||||
|         reflocal = dstc_allocnear(c, DSTC_REGTEMP_1); | ||||
|         dstc_emit(c, | ||||
|                 (dstc_const(c, dest.constant) << 16) | | ||||
|                 (reflocal << 8) | | ||||
|                 DOP_LOAD_CONSTANT); | ||||
|     } else if (dest.envindex >= 0) { | ||||
|         writeback = 2; | ||||
|         destlocal = srclocal; | ||||
|     } else if (dest.index > 0xFF) { | ||||
|         writeback = 3; | ||||
|         destlocal = srclocal; | ||||
|     } else { | ||||
|         destlocal = dest.index; | ||||
|     /* If src is a near register */ | ||||
|     if (src.envindex < 0 && src.index >= 0 && src.index <= 0xFF) { | ||||
|         dstc_moveback(c, dest, src.index); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /* srclocal -> destlocal */ | ||||
|     if (srclocal != destlocal) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(srclocal) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_MOVE_NEAR); | ||||
|     } | ||||
| 
 | ||||
|     /* destlocal -> dest */ | ||||
|     if (writeback == 1) { | ||||
|         dstc_emit(c, | ||||
|                 (destlocal << 16) | | ||||
|                 (reflocal << 8) | | ||||
|                 DOP_PUT_INDEX); | ||||
|     } else if (writeback == 2) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 24) | | ||||
|                 ((uint32_t)(dest.envindex) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_SET_UPVALUE); | ||||
|     } else if (writeback == 3) { | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_MOVE_FAR); | ||||
|     } | ||||
| 
 | ||||
|     /* Process: src -> near -> dest */ | ||||
|     int32_t near = dstc_allocnear(c, DSTC_REGTEMP_3); | ||||
|     dstc_movenear(c, near, src); | ||||
|     dstc_moveback(c, dest, near); | ||||
|     /* Cleanup */ | ||||
|     if (reflocal >= 0) { | ||||
|         dstc_regalloc_free(&c->scope->ra, reflocal); | ||||
|     } | ||||
|     dstc_free_reg(c, src, srclocal); | ||||
| } | ||||
|     dstc_regalloc_freetemp(&c->scope->ra, near, DSTC_REGTEMP_3); | ||||
| 
 | ||||
| } | ||||
| /* Instruction templated emitters */ | ||||
| 
 | ||||
| static int32_t emit1s(DstCompiler *c, uint8_t op, DstSlot s, int32_t rest) { | ||||
| static int32_t emit1s(DstCompiler *c, uint8_t op, DstSlot s, int32_t rest, int wr) { | ||||
|     int32_t reg = dstc_regnear(c, s, DSTC_REGTEMP_0); | ||||
|     int32_t label = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, op | (reg << 8) | (rest << 16)); | ||||
|     dstc_free_reg(c, s, reg); | ||||
|     if (wr) | ||||
|         dstc_moveback(c, s, reg); | ||||
|     dstc_free_regnear(c, s, reg, DSTC_REGTEMP_0); | ||||
|     return label; | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s) { | ||||
| int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s, int wr) { | ||||
|     int32_t reg = dstc_regfar(c, s, DSTC_REGTEMP_0); | ||||
|     int32_t label = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, op | (reg << 8)); | ||||
|     dstc_free_reg(c, s, reg); | ||||
|     if (wr) | ||||
|         dstc_moveback(c, s, reg); | ||||
|     dstc_free_regnear(c, s, reg, DSTC_REGTEMP_0); | ||||
|     return label; | ||||
| } | ||||
| 
 | ||||
| @@ -328,57 +273,63 @@ int32_t dstc_emit_sl(DstCompiler *c, uint8_t op, DstSlot s, int32_t label) { | ||||
|     if (jump < INT16_MIN || jump > INT16_MAX) { | ||||
|         dstc_cerror(c, "jump is too far"); | ||||
|     } | ||||
|     return emit1s(c, op, s, jump); | ||||
|     return emit1s(c, op, s, jump, 0); | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_st(DstCompiler *c, uint8_t op, DstSlot s, int32_t tflags) { | ||||
|     return emit1s(c, op, s, tflags); | ||||
|     return emit1s(c, op, s, tflags, 0); | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate) { | ||||
|     return emit1s(c, op, s, immediate); | ||||
| int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate, int wr) { | ||||
|     return emit1s(c, op, s, immediate, wr); | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate) { | ||||
|     return emit1s(c, op, s, (int32_t) immediate); | ||||
| int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate, int wr) { | ||||
|     return emit1s(c, op, s, (int32_t) immediate, wr); | ||||
| } | ||||
| 
 | ||||
| static int32_t emit2s(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int32_t rest) { | ||||
| static int32_t emit2s(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int32_t rest, int wr) { | ||||
|     int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0); | ||||
|     int32_t reg2 = dstc_regnear(c, s2, DSTC_REGTEMP_1); | ||||
|     int32_t label = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (rest << 24)); | ||||
|     dstc_free_reg(c, s1, reg1); | ||||
|     dstc_free_reg(c, s2, reg2); | ||||
|     dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1); | ||||
|     if (wr) | ||||
|         dstc_moveback(c, s1, reg1); | ||||
|     dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0); | ||||
|     return label; | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2) { | ||||
| int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int wr) { | ||||
|     int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0); | ||||
|     int32_t reg2 = dstc_regfar(c, s2, DSTC_REGTEMP_1); | ||||
|     int32_t label = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, op | (reg1 << 8) | (reg2 << 16)); | ||||
|     dstc_free_reg(c, s1, reg1); | ||||
|     dstc_free_reg(c, s2, reg2); | ||||
|     dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1); | ||||
|     if (wr) | ||||
|         dstc_moveback(c, s1, reg1); | ||||
|     dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0); | ||||
|     return label; | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate) { | ||||
|     return emit2s(c, op, s1, s2, immediate); | ||||
| int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate, int wr) { | ||||
|     return emit2s(c, op, s1, s2, immediate, wr); | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate) { | ||||
|     return emit2s(c, op, s1, s2, (int32_t) immediate); | ||||
| int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate, int wr) { | ||||
|     return emit2s(c, op, s1, s2, (int32_t) immediate, wr); | ||||
| } | ||||
| 
 | ||||
| int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3) { | ||||
| int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3, int wr) { | ||||
|     int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0); | ||||
|     int32_t reg2 = dstc_regnear(c, s2, DSTC_REGTEMP_1); | ||||
|     int32_t reg3 = dstc_regnear(c, s3, DSTC_REGTEMP_2); | ||||
|     int32_t label = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (reg3 << 24)); | ||||
|     dstc_free_reg(c, s1, reg1); | ||||
|     dstc_free_reg(c, s2, reg2); | ||||
|     dstc_free_reg(c, s3, reg3); | ||||
|     dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1); | ||||
|     dstc_free_regnear(c, s3, reg3, DSTC_REGTEMP_2); | ||||
|     if (wr) | ||||
|         dstc_moveback(c, s1, reg1); | ||||
|     dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0); | ||||
|     return label; | ||||
| } | ||||
| @@ -30,19 +30,15 @@ void dstc_emit(DstCompiler *c, uint32_t instr); | ||||
| int32_t dstc_allocfar(DstCompiler *c); | ||||
| int32_t dstc_allocnear(DstCompiler *c, DstcRegisterTemp); | ||||
| 
 | ||||
| int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag); | ||||
| int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag); | ||||
| void dstc_free_reg(DstCompiler *c, DstSlot s, int32_t reg); | ||||
| 
 | ||||
| int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s); | ||||
| int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s, int wr); | ||||
| int32_t dstc_emit_sl(DstCompiler *c, uint8_t op, DstSlot s, int32_t label); | ||||
| int32_t dstc_emit_st(DstCompiler *c, uint8_t op, DstSlot s, int32_t tflags); | ||||
| int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate); | ||||
| int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate); | ||||
| int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2); | ||||
| int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate); | ||||
| int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate); | ||||
| int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3); | ||||
| int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate, int wr); | ||||
| int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate, int wr); | ||||
| int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int wr); | ||||
| int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate, int wr); | ||||
| int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate, int wr); | ||||
| int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3, int wr); | ||||
| 
 | ||||
| /* Move value from one slot to another. Cannot copy to constant slots. */ | ||||
| void dstc_copy(DstCompiler *c, DstSlot dest, DstSlot src); | ||||
| @@ -21,8 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "fiber.h" | ||||
| #include "state.h" | ||||
| #include "gc.h" | ||||
| @@ -365,8 +363,8 @@ static Dst doframe(DstStackFrame *frame) { | ||||
|         dst_table_put(t, dst_csymbolv(":pc"), dst_wrap_integer(off)); | ||||
|         if (def->sourcemap) { | ||||
|             DstSourceMapping mapping = def->sourcemap[off]; | ||||
|             dst_table_put(t, dst_csymbolv(":source-line"), dst_wrap_integer(mapping.line)); | ||||
|             dst_table_put(t, dst_csymbolv(":source-column"), dst_wrap_integer(mapping.column)); | ||||
|             dst_table_put(t, dst_csymbolv(":line"), dst_wrap_integer(mapping.line)); | ||||
|             dst_table_put(t, dst_csymbolv(":column"), dst_wrap_integer(mapping.column)); | ||||
|         } | ||||
|         if (def->source) { | ||||
|             dst_table_put(t, dst_csymbolv(":source"), dst_wrap_string(def->source)); | ||||
|   | ||||
| @@ -20,8 +20,9 @@ | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #define _DEFAULT_SOURCE | ||||
| #include <stdio.h> | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #define IO_WRITE 1 | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <math.h> | ||||
|  | ||||
| /* Get a random number */ | ||||
|   | ||||
| @@ -1,75 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
|  | ||||
| /* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries | ||||
|  * with native code. */ | ||||
| #ifdef DST_WINDOWS | ||||
| #include <windows.h> | ||||
| typedef HINSTANCE Clib; | ||||
| #define load_clib(name) LoadLibrary((name)) | ||||
| #define symbol_clib(lib, sym) GetProcAddress((lib), (sym)) | ||||
| #define error_clib() "could not load dynamic library" | ||||
| #elif defined(DST_WEB) | ||||
| #include <emscripten.h> | ||||
| /* TODO - figure out how loading modules will work in JS */ | ||||
| typedef int Clib; | ||||
| #define load_clib(name) 0 | ||||
| #define symbol_clib(lib, sym) 0 | ||||
| #define error_clib() "dynamic libraries not supported" | ||||
| #else | ||||
| #include <dlfcn.h> | ||||
| typedef void *Clib; | ||||
| #define load_clib(name) dlopen((name), RTLD_NOW) | ||||
| #define symbol_clib(lib, sym) dlsym((lib), (sym)) | ||||
| #define error_clib() dlerror() | ||||
| #endif | ||||
|  | ||||
| DstCFunction dst_native(const char *name, const uint8_t **error) { | ||||
|     Clib lib = load_clib(name); | ||||
|     DstCFunction init; | ||||
|     if (!lib) { | ||||
|         *error = dst_cstring(error_clib()); | ||||
|         return NULL; | ||||
|     } | ||||
|     init = (DstCFunction) symbol_clib(lib, "_dst_init"); | ||||
|     if (!init) { | ||||
|         *error = dst_cstring("could not find _dst_init symbol"); | ||||
|         return NULL; | ||||
|     } | ||||
|     return init; | ||||
| } | ||||
|  | ||||
| int dst_core_native(DstArgs args) { | ||||
|     DstCFunction init; | ||||
|     const uint8_t *error = NULL; | ||||
|     const uint8_t *path = NULL; | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_ARG_STRING(path, args, 0); | ||||
|     init = dst_native((const char *)path, &error); | ||||
|     if (!init) { | ||||
|         DST_THROWV(args, dst_wrap_string(error)); | ||||
|     } | ||||
|     DST_RETURN_CFUNCTION(args, init); | ||||
| } | ||||
| @@ -21,8 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
|  | ||||
|   | ||||
| @@ -20,9 +20,8 @@ | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include "regalloc.h" | ||||
| #include <stdlib.h> | ||||
| #include <dst/dst.h> | ||||
| #include "regalloc.h" | ||||
| 
 | ||||
| void dstc_regalloc_init(DstcRegisterAllocator *ra) { | ||||
|     ra->chunks = NULL; | ||||
| @@ -66,6 +65,7 @@ void dstc_regalloc_clone(DstcRegisterAllocator *dest, DstcRegisterAllocator *src | ||||
|     dest->max = src->max; | ||||
|     size = sizeof(uint32_t) * dest->capacity; | ||||
|     dest->chunks = malloc(size); | ||||
|     dest->regtemps = 0; | ||||
|     if (!dest->chunks) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     } | ||||
| @@ -126,17 +126,7 @@ int32_t dstc_regalloc_1(DstcRegisterAllocator *ra) { | ||||
| /* Free a register. The register must have been previously allocated
 | ||||
|  * without being freed. */ | ||||
| void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg) { | ||||
|     /* We cannot free reserved slots */ | ||||
|     if (reg < 0) | ||||
|         return; | ||||
|     if (reg >= 0xF0 && reg <= 0xFF) { | ||||
|         ra->regtemps &= ~(1 << (reg - 0xF0)); | ||||
|         return; | ||||
|     } | ||||
|     int32_t chunk = reg >> 5; | ||||
|     /* Outside normal chunk range */ | ||||
|     if (chunk >= ra->count) | ||||
|         return; | ||||
|     int32_t bit = reg & 0x1F; | ||||
|     ra->chunks[chunk] &= ~ithbit(bit); | ||||
| } | ||||
| @@ -146,9 +136,11 @@ void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg) { | ||||
|  * on the returned register before. */ | ||||
| int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth) { | ||||
|     int32_t oldmax = ra->max; | ||||
|     int32_t reg = dstc_regalloc_1(ra); | ||||
|     dst_assert(~(ra->regtemps & (1 << nth)), "regtemp already allocated"); | ||||
|     if (ra->regtemps & (1 << nth)) { | ||||
|         dst_exit("regtemp already allocated"); | ||||
|     } | ||||
|     ra->regtemps |= 1 << nth; | ||||
|     int32_t reg = dstc_regalloc_1(ra); | ||||
|     if (reg > 0xFF) { | ||||
|         reg = 0xF0 + nth; | ||||
|         ra->max = (reg > oldmax) ? reg : oldmax; | ||||
| @@ -156,6 +148,12 @@ int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth) { | ||||
|     return reg; | ||||
| } | ||||
| 
 | ||||
| void dstc_regalloc_freetemp(DstcRegisterAllocator *ra, int32_t reg, DstcRegisterTemp nth) { | ||||
|     ra->regtemps &= ~(1 << nth); | ||||
|     if (reg < 0xF0) | ||||
|         dstc_regalloc_free(ra, reg); | ||||
| } | ||||
| 
 | ||||
| /* Disable multi-slot allocation for now. */ | ||||
| 
 | ||||
| /*
 | ||||
| @@ -36,7 +36,7 @@ typedef enum { | ||||
|     DSTC_REGTEMP_4, | ||||
|     DSTC_REGTEMP_5, | ||||
|     DSTC_REGTEMP_6, | ||||
|     DSTC_REGTEMP_TARGET | ||||
|     DSTC_REGTEMP_7 | ||||
| } DstcRegisterTemp; | ||||
| 
 | ||||
| typedef struct { | ||||
| @@ -53,6 +53,7 @@ void dstc_regalloc_deinit(DstcRegisterAllocator *ra); | ||||
| int32_t dstc_regalloc_1(DstcRegisterAllocator *ra); | ||||
| void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg); | ||||
| int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth); | ||||
| void dstc_regalloc_freetemp(DstcRegisterAllocator *ra, int32_t reg, DstcRegisterTemp nth); | ||||
| void dstc_regalloc_clone(DstcRegisterAllocator *dest, DstcRegisterAllocator *src); | ||||
| void dstc_regalloc_touch(DstcRegisterAllocator *ra, int32_t reg); | ||||
| 
 | ||||
| @@ -21,8 +21,49 @@ | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include "state.h" | ||||
| 
 | ||||
| /* Error reporting */ | ||||
| static void print_error_report(DstFiber *fiber, const char *errtype, Dst err) { | ||||
|     const char *errstr = (const char *)dst_to_string(err); | ||||
|     printf("%s error: %s\n", errtype, errstr); | ||||
|     if (!fiber) return; | ||||
|     int32_t i = fiber->frame; | ||||
|     while (i > 0) { | ||||
|         DstStackFrame *frame = (DstStackFrame *)(fiber->data + i - DST_FRAME_SIZE); | ||||
|         DstFuncDef *def = NULL; | ||||
|         i = frame->prevframe; | ||||
|          | ||||
|         printf("  at"); | ||||
| 
 | ||||
|         if (frame->func) { | ||||
|             def = frame->func->def; | ||||
|             printf(" %s", def->name ? (const char *)def->name : "<anonymous>"); | ||||
|             if (def->source) { | ||||
|                 printf(" %s", (const char *)def->source); | ||||
|             } | ||||
|         } else { | ||||
|             DstCFunction cfun = (DstCFunction)(frame->pc); | ||||
|             if (cfun) { | ||||
|                 Dst name = dst_table_get(dst_vm_registry, dst_wrap_cfunction(cfun)); | ||||
|                 if (!dst_checktype(name, DST_NIL)) | ||||
|                     printf(" [%s]", (const char *)dst_to_string(name)); | ||||
|             } | ||||
|         } | ||||
|         if (frame->flags & DST_STACKFRAME_TAILCALL) | ||||
|             printf(" (tailcall)"); | ||||
|         if (frame->func && frame->pc) { | ||||
|             int32_t off = (int32_t) (frame->pc - def->bytecode); | ||||
|             if (def->sourcemap) { | ||||
|                 DstSourceMapping mapping = def->sourcemap[off]; | ||||
|                 printf(" on line %d, column %d", mapping.line, mapping.column); | ||||
|             } else { | ||||
|                 printf(" pc=%d", off); | ||||
|             } | ||||
|         } | ||||
|         printf("\n"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Run a string */ | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath) { | ||||
| @@ -47,18 +88,19 @@ int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *so | ||||
|                         Dst ret = dst_wrap_nil(); | ||||
|                         DstSignal status = dst_run(fiber, &ret); | ||||
|                         if (status != DST_SIGNAL_OK) { | ||||
|                             printf("internal runtime error: %s\n", (const char *) dst_to_string(ret)); | ||||
|                             print_error_report(fiber, "runtime", ret); | ||||
|                             errflags |= 0x01; | ||||
|                         } | ||||
|                     } else { | ||||
|                         printf("internal compile error: %s\n", (const char *) cres.error); | ||||
|                         print_error_report(cres.macrofiber, "compile", | ||||
|                                 dst_wrap_string(cres.error)); | ||||
|                         errflags |= 0x02; | ||||
|                     } | ||||
|                 } | ||||
|                 break; | ||||
|             case DST_PARSE_ERROR: | ||||
|                 errflags |= 0x04; | ||||
|                 printf("internal parse error: %s\n", dst_parser_error(&parser)); | ||||
|                 printf("parse error: %s\n", dst_parser_error(&parser)); | ||||
|                 break; | ||||
|             case DST_PARSE_PENDING: | ||||
|                 if (index >= len) { | ||||
| @@ -21,11 +21,9 @@ | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include "compile.h" | ||||
| #include <headerlibs/strbinsearch.h> | ||||
| #include <headerlibs/vector.h> | ||||
| #include "util.h" | ||||
| #include "vector.h" | ||||
| #include "emit.h" | ||||
| 
 | ||||
| DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
| @@ -37,11 +35,12 @@ DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
| } | ||||
| 
 | ||||
| /* Preform destructuring. Be careful to
 | ||||
|  * keep the order registers are freed. */ | ||||
| static void destructure(DstCompiler *c, | ||||
|  * keep the order registers are freed.  | ||||
|  * Returns if the slot 'right' can be freed. */ | ||||
| static int destructure(DstCompiler *c, | ||||
|         Dst left, | ||||
|         DstSlot right, | ||||
|         void (*leaf)(DstCompiler *c, | ||||
|         int (*leaf)(DstCompiler *c, | ||||
|             const uint8_t *sym, | ||||
|             DstSlot s, | ||||
|             DstTable *attr), | ||||
| @@ -49,73 +48,43 @@ static void destructure(DstCompiler *c, | ||||
|     switch (dst_type(left)) { | ||||
|         default: | ||||
|             dstc_cerror(c, "unexpected type in destructuring"); | ||||
|             break; | ||||
|             return 1; | ||||
|         case DST_SYMBOL: | ||||
|             /* Leaf, assign right to left */ | ||||
|             leaf(c, dst_unwrap_symbol(left), right, attr); | ||||
|             break; | ||||
|             return leaf(c, dst_unwrap_symbol(left), right, attr); | ||||
|         case DST_TUPLE: | ||||
|         case DST_ARRAY: | ||||
|             { | ||||
|                 int32_t i, len, right_register, subval_register; | ||||
|                 int32_t i, len; | ||||
|                 const Dst *values; | ||||
|                 dst_seq_view(left, &values, &len); | ||||
|                 for (i = 0; i < len; i++) { | ||||
|                     DstSlot nextright; | ||||
|                     DstSlot nextright = dstc_farslot(c); | ||||
|                     Dst subval = values[i]; | ||||
|                     right_register = dstc_regnear(c, right, DSTC_REGTEMP_0); | ||||
|                     subval_register = dstc_allocnear(c, DSTC_REGTEMP_1); | ||||
|                     if (i < 0x100) { | ||||
|                         dstc_emit(c, DOP_GET_INDEX | | ||||
|                                 (subval_register << 8) | | ||||
|                                 (right_register << 16) | | ||||
|                                 (i << 24)); | ||||
|                         dstc_emit_ssu(c, DOP_GET_INDEX, nextright, right, (uint8_t) i, 1); | ||||
|                     } else { | ||||
|                         DstSlot islot = dstc_cslot(dst_wrap_integer(i)); | ||||
|                         int32_t i_register = dstc_regnear(c, islot, DSTC_REGTEMP_2); | ||||
|                         dstc_emit(c, DOP_GET_INDEX | | ||||
|                                 (subval_register << 8) | | ||||
|                                 (right_register << 16) | | ||||
|                                 (i_register << 24)); | ||||
|                         dstc_free_reg(c, islot, i_register); | ||||
|                         DstSlot k = dstc_cslot(dst_wrap_integer(i)); | ||||
|                         dstc_emit_sss(c, DOP_GET, nextright, right, k, 1); | ||||
|                     } | ||||
|                     nextright.index = subval_register; | ||||
|                     nextright.envindex = -1; | ||||
|                     nextright.constant = dst_wrap_nil(); | ||||
|                     nextright.flags = DST_SLOTTYPE_ANY; | ||||
|                     destructure(c, subval, nextright, leaf, attr); | ||||
|                     /* Free right_register AFTER sub destructuring */ | ||||
|                     dstc_free_reg(c, right, right_register); | ||||
|                     if (destructure(c, subval, nextright, leaf, attr)) | ||||
|                         dstc_freeslot(c, nextright); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|             return 1; | ||||
|         case DST_TABLE: | ||||
|         case DST_STRUCT: | ||||
|             { | ||||
|                 int32_t right_register, subval_register, k_register; | ||||
|                 const DstKV *kv = NULL; | ||||
|                 while ((kv = dstc_next(left, kv))) { | ||||
|                     DstSlot nextright; | ||||
|                     DstSlot kslot = dstc_value(dstc_fopts_default(c), kv->key); | ||||
| 
 | ||||
|                     right_register = dstc_regnear(c, right, DSTC_REGTEMP_0); | ||||
|                     subval_register = dstc_allocnear(c, DSTC_REGTEMP_1); | ||||
|                     k_register = dstc_regnear(c, kslot, DSTC_REGTEMP_2); | ||||
|                     dstc_emit(c, DOP_GET | | ||||
|                             (subval_register << 8) | | ||||
|                             (right_register << 16) | | ||||
|                             (k_register << 24)); | ||||
|                     dstc_free_reg(c, kslot, k_register); | ||||
|                     nextright.index = subval_register; | ||||
|                     nextright.envindex = -1; | ||||
|                     nextright.constant = dst_wrap_nil(); | ||||
|                     nextright.flags = DST_SLOTTYPE_ANY; | ||||
|                     destructure(c, kv->value, nextright, leaf, attr); | ||||
|                     /* Free right_register AFTER sub destructuring */ | ||||
|                     dstc_free_reg(c, right, right_register); | ||||
|                     DstSlot nextright = dstc_farslot(c); | ||||
|                     DstSlot k = dstc_value(dstc_fopts_default(c), kv->key); | ||||
|                     dstc_emit_sss(c, DOP_GET, nextright, right, k, 1); | ||||
|                     if (destructure(c, kv->value, nextright, leaf, attr)) | ||||
|                         dstc_freeslot(c, nextright); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|             return 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @@ -180,28 +149,22 @@ static DstSlot dohead(DstCompiler *c, DstFopts opts, Dst *head, int32_t argn, co | ||||
| } | ||||
| 
 | ||||
| /* Def or var a symbol in a local scope */ | ||||
| static DstSlot namelocal(DstCompiler *c, Dst head, int32_t flags, DstSlot ret) { | ||||
|     /* Non root scope, bring to local slot */ | ||||
|     if (ret.flags & DST_SLOT_NAMED || | ||||
|             ret.envindex >= 0 || | ||||
|             ret.index < 0 || | ||||
|             ret.index > 0xFF) { | ||||
| static int namelocal(DstCompiler *c, const uint8_t *head, int32_t flags, DstSlot ret) { | ||||
|     int isUnnamedRegister = !(ret.flags & DST_SLOT_NAMED) && | ||||
|         ret.index > 0 && | ||||
|         ret.envindex >= 0; | ||||
|     if (!isUnnamedRegister) { | ||||
|         /* Slot is not able to be named */ | ||||
|         DstSlot localslot; | ||||
|         localslot.index = dstc_allocfar(c); | ||||
|         /* infer type? */ | ||||
|         localslot.flags = flags; | ||||
|         localslot.envindex = -1; | ||||
|         localslot.constant = dst_wrap_nil(); | ||||
|         DstSlot localslot = dstc_farslot(c); | ||||
|         dstc_copy(c, localslot, ret); | ||||
|         ret = localslot; | ||||
|     } | ||||
|     ret.flags |= flags; | ||||
|     dstc_nameslot(c, dst_unwrap_symbol(head), ret); | ||||
|     return ret; | ||||
|     dstc_nameslot(c, head, ret); | ||||
|     return !isUnnamedRegister; | ||||
| } | ||||
| 
 | ||||
| static void varleaf( | ||||
| static int varleaf( | ||||
|         DstCompiler *c, | ||||
|         const uint8_t *sym, | ||||
|         DstSlot s, | ||||
| @@ -216,9 +179,10 @@ static void varleaf( | ||||
|         dst_table_put(reftab, dst_csymbolv(":ref"), dst_wrap_array(ref)); | ||||
|         dst_table_put(c->env, dst_wrap_symbol(sym), dst_wrap_table(reftab)); | ||||
|         refslot = dstc_cslot(dst_wrap_array(ref)); | ||||
|         dstc_emit_ssu(c, DOP_PUT_INDEX, refslot, s, 0); | ||||
|         dstc_emit_ssu(c, DOP_PUT_INDEX, refslot, s, 0, 0); | ||||
|         return 1; | ||||
|     } else { | ||||
|         namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED | DST_SLOT_MUTABLE, s) ; | ||||
|         return namelocal(c, sym, DST_SLOT_MUTABLE, s); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @@ -227,11 +191,12 @@ DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     Dst head; | ||||
|     DstSlot ret = dohead(c, opts, &head, argn, argv); | ||||
|     if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); | ||||
|     destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv)); | ||||
|     if (destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv))) | ||||
|         dstc_freeslot(c, ret); | ||||
|     return dstc_cslot(dst_wrap_nil()); | ||||
| } | ||||
| 
 | ||||
| static void defleaf( | ||||
| static int defleaf( | ||||
|         DstCompiler *c, | ||||
|         const uint8_t *sym, | ||||
|         DstSlot s, | ||||
| @@ -246,9 +211,10 @@ static void defleaf( | ||||
|         dst_table_put(c->env, dst_wrap_symbol(sym), dst_wrap_table(tab)); | ||||
| 
 | ||||
|         /* Put value in table when evaulated */ | ||||
|         dstc_emit_sss(c, DOP_PUT, tabslot, valsym, s); | ||||
|         dstc_emit_sss(c, DOP_PUT, tabslot, valsym, s, 0); | ||||
|         return 1; | ||||
|     } else { | ||||
|         namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED, s); | ||||
|         return namelocal(c, sym, 0, s); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @@ -258,7 +224,8 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     opts.flags &= ~DST_FOPTS_HINT; | ||||
|     DstSlot ret = dohead(c, opts, &head, argn, argv); | ||||
|     if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); | ||||
|     destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv)); | ||||
|     if (destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv))) | ||||
|         dstc_freeslot(c, ret); | ||||
|     return dstc_cslot(dst_wrap_nil()); | ||||
| } | ||||
| 
 | ||||
| @@ -321,7 +288,7 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|         : dstc_gettarget(opts); | ||||
| 
 | ||||
|     /* Compile jump to right */ | ||||
|     labeljr = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0); | ||||
|     labeljr = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0, 0); | ||||
| 
 | ||||
|     /* Condition left body */ | ||||
|     dstc_scope(&tempscope, c, 0, "if-true"); | ||||
| @@ -414,7 +381,7 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
| 
 | ||||
|     /* Infinite loop does not need to check condition */ | ||||
|     if (!infinite) { | ||||
|         labelc = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0); | ||||
|         labelc = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0, 0); | ||||
|     } else { | ||||
|         labelc = 0; | ||||
|     } | ||||
| @@ -459,7 +426,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstSlot ret; | ||||
|     Dst head, paramv; | ||||
|     DstScope fnscope; | ||||
|     int32_t paramcount, argi, parami, arity, localslot, defindex; | ||||
|     int32_t paramcount, argi, parami, arity, defindex; | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
|     const Dst *params; | ||||
|     const char *errmsg = NULL; | ||||
| @@ -517,7 +484,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     if (selfref) { | ||||
|         DstSlot slot = dstc_farslot(c); | ||||
|         slot.flags = DST_SLOT_NAMED | DST_FUNCTION; | ||||
|         dstc_emit_s(c, DOP_LOAD_SELF, slot); | ||||
|         dstc_emit_s(c, DOP_LOAD_SELF, slot, 1); | ||||
|         dstc_nameslot(c, dst_unwrap_symbol(head), slot); | ||||
|     } | ||||
| 
 | ||||
| @@ -525,10 +492,8 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     if (parami + 1 == argn) { | ||||
|         dstc_emit(c, DOP_RETURN_NIL); | ||||
|     } else for (argi = parami + 1; argi < argn; argi++) { | ||||
|         DstSlot s; | ||||
|         subopts.flags = (argi == (argn - 1)) ? DST_FOPTS_TAIL : DST_FOPTS_DROP; | ||||
|         s = dstc_value(subopts, argv[argi]); | ||||
|         dstc_freeslot(c, s); | ||||
|         dstc_value(subopts, argv[argi]); | ||||
|         if (dstc_iserr(&opts)) | ||||
|             goto error2; | ||||
|     } | ||||
| @@ -545,20 +510,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
| 
 | ||||
|     /* Instantiate closure */ | ||||
|     ret = dstc_gettarget(opts); | ||||
| 
 | ||||
|     localslot = ret.index > 0xF0 ? 0xF1 : ret.index; | ||||
|     dstc_emit(c, | ||||
|             (defindex << 16) | | ||||
|             (localslot << 8) | | ||||
|             DOP_CLOSURE); | ||||
| 
 | ||||
|     if (ret.index != localslot) { | ||||
|         dstc_emit(c, | ||||
|                 (ret.index << 16) | | ||||
|                 (localslot << 8) | | ||||
|                 DOP_MOVE_FAR); | ||||
|     } | ||||
| 
 | ||||
|     dstc_emit_su(c, DOP_CLOSURE, ret, defindex, 1); | ||||
|     return ret; | ||||
| 
 | ||||
| error: | ||||
| @@ -23,13 +23,7 @@ | ||||
| #ifndef DST_STATE_H_defined | ||||
| #define DST_STATE_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <dst/dstconfig.h> | ||||
| #include <dst/dsttypes.h> | ||||
|  | ||||
| /* The VM state. Rather than a struct that is passed | ||||
|  * around, the vm state is global for simplicity. If | ||||
| @@ -66,8 +60,4 @@ extern DST_THREAD_LOCAL Dst *dst_vm_roots; | ||||
| extern DST_THREAD_LOCAL uint32_t dst_vm_root_count; | ||||
| extern DST_THREAD_LOCAL uint32_t dst_vm_root_capacity; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_STATE_H_defined */ | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "gc.h" | ||||
| #include "util.h" | ||||
| #include "state.h" | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "gc.h" | ||||
| #include "util.h" | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "symcache.h" | ||||
| #include "gc.h" | ||||
| #include "util.h" | ||||
|   | ||||
| @@ -110,6 +110,33 @@ int dst_cstrcmp(const uint8_t *str, const char *other) { | ||||
|     return (other[index] == '\0') ? 0 : -1; | ||||
| } | ||||
|  | ||||
| /* Do a binary search on a static array of structs. Each struct must | ||||
|  * have a string as its first element, and the struct must be sorted | ||||
|  * lexogrpahically by that element. */ | ||||
| const void *dst_strbinsearch( | ||||
|         const void *tab, | ||||
|         size_t tabcount, | ||||
|         size_t itemsize, | ||||
|         const uint8_t *key) { | ||||
|     size_t low = 0; | ||||
|     size_t hi = tabcount; | ||||
|     const char *t = (const char *)tab; | ||||
|     while (low < hi) { | ||||
|         size_t mid = low + ((hi - low) / 2); | ||||
|         const char **item = (const char **)(t + mid * itemsize); | ||||
|         const char *name = *item; | ||||
|         int comp = dst_cstrcmp(key, name); | ||||
|         if (comp < 0) { | ||||
|             hi = mid; | ||||
|         } else if (comp > 0) { | ||||
|             low = mid + 1; | ||||
|         } else { | ||||
|             return (const void *)item; | ||||
|         } | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| /* Add a module definition */ | ||||
| void dst_env_def(DstTable *env, const char *name, Dst val) { | ||||
|     DstTable *subt = dst_table(1); | ||||
| @@ -238,26 +265,29 @@ int dst_type_err(DstArgs args, int32_t n, DstType expected) { | ||||
|     DST_THROWV(args, dst_wrap_string(message)); | ||||
| } | ||||
|  | ||||
| int dst_typemany_err(DstArgs args, int32_t n, int expected) { | ||||
|     int i; | ||||
| void dst_buffer_push_types(DstBuffer *buffer, int types) { | ||||
|     int first = 1; | ||||
|     int i = 0; | ||||
|     while (types) { | ||||
|         if (1 & types) { | ||||
|             if (first) { | ||||
|                 first = 0; | ||||
|             } else { | ||||
|                 dst_buffer_push_u8(buffer, '|'); | ||||
|             } | ||||
|             dst_buffer_push_cstring(buffer, dst_type_names[i] + 1); | ||||
|         } | ||||
|         i++; | ||||
|         types >>= 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int dst_typemany_err(DstArgs args, int32_t n, int expected) { | ||||
|     const uint8_t *message; | ||||
|     DstBuffer buf; | ||||
|     dst_buffer_init(&buf, 20); | ||||
|     dst_buffer_push_string(&buf, dst_formatc("bad slot #%d, expected ", n)); | ||||
|     i = 0; | ||||
|     while (expected) { | ||||
|         if (1 & expected) { | ||||
|             if (first) { | ||||
|                 first = 0; | ||||
|             } else { | ||||
|                 dst_buffer_push_u8(&buf, '|'); | ||||
|             } | ||||
|             dst_buffer_push_cstring(&buf, dst_type_names[i] + 1); | ||||
|         } | ||||
|         i++; | ||||
|         expected >>= 1; | ||||
|     } | ||||
|     dst_buffer_push_types(&buf, expected); | ||||
|     dst_buffer_push_cstring(&buf, ", got "); | ||||
|     dst_buffer_push_cstring(&buf, typestr(args, n)); | ||||
|     message = dst_string(buf.data, buf.count); | ||||
|   | ||||
| @@ -31,5 +31,11 @@ int32_t dst_array_calchash(const Dst *array, int32_t len); | ||||
| int32_t dst_kv_calchash(const DstKV *kvs, int32_t len); | ||||
| int32_t dst_string_calchash(const uint8_t *str, int32_t len); | ||||
| int32_t dst_tablen(int32_t n); | ||||
| void dst_buffer_push_types(DstBuffer *buffer, int types); | ||||
| const void *dst_strbinsearch( | ||||
|         const void *tab, | ||||
|         size_t tabcount, | ||||
|         size_t itemsize, | ||||
|         const uint8_t *key); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										76
									
								
								src/core/vector.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/core/vector.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #include "vector.h" | ||||
|  | ||||
| /* Grow the buffer dynamically. Used for push operations. */ | ||||
| void *dst_v_grow(void *v, int32_t increment, int32_t itemsize) { | ||||
|     int32_t dbl_cur = (NULL != v) ? 2 * dst_v__cap(v) : 0; | ||||
|     int32_t min_needed = dst_v_count(v) + increment; | ||||
|     int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed; | ||||
|     int32_t *p = (int32_t *) realloc(v ? dst_v__raw(v) : 0, itemsize * m + sizeof(int32_t)*2); | ||||
|     if (NULL != p) { | ||||
|         if (!v) p[1] = 0; | ||||
|         p[0] = m; | ||||
|         return p + 2; | ||||
|    } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return (void *) (2 * sizeof(int32_t)); | ||||
|    } | ||||
| } | ||||
|  | ||||
| /* Clone a buffer. */ | ||||
| void *dst_v_copymem(void *v, int32_t itemsize) { | ||||
|     int32_t *p; | ||||
|     if (NULL == v) return NULL; | ||||
|     p = malloc(2 * sizeof(int32_t) + itemsize * dst_v__cap(v)); | ||||
|     if (NULL != p) { | ||||
|         memcpy(p, dst_v__raw(v), 2 * sizeof(int32_t) + itemsize * dst_v__cnt(v)); | ||||
|         return p + 2; | ||||
|     } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return (void *) (2 * sizeof(int32_t)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Convert a buffer to normal allocated memory (forget capacity) */ | ||||
| void *dst_v_flattenmem(void *v, int32_t itemsize) { | ||||
|     int32_t *p; | ||||
|     int32_t sizen; | ||||
|     if (NULL == v) return NULL; | ||||
|     sizen = itemsize * dst_v__cnt(v); | ||||
|     p = malloc(sizen); | ||||
|     if (NULL != p) { | ||||
|         memcpy(p, v, sizen); | ||||
|         return p; | ||||
|     } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -23,6 +23,8 @@ | ||||
| #ifndef DST_VECTOR_H_defined | ||||
| #define DST_VECTOR_H_defined | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * vector code modified from | ||||
|  * https://github.com/nothings/stb/blob/master/stretchy_buffer.h
 | ||||
| @@ -50,65 +52,9 @@ | ||||
| #define dst_v__maybegrow(v, n) (dst_v__needgrow((v), (n)) ? dst_v__grow((v), (n)) : 0) | ||||
| #define dst_v__grow(v, n)      ((v) = dst_v_grow((v), (n), sizeof(*(v)))) | ||||
| 
 | ||||
| 
 | ||||
| /* Vector code */ | ||||
| 
 | ||||
| /* Grow the buffer dynamically. Used for push operations. */ | ||||
| #ifndef DST_V_NODEF_GROW | ||||
| static void *dst_v_grow(void *v, int32_t increment, int32_t itemsize) { | ||||
|     int32_t dbl_cur = (NULL != v) ? 2 * dst_v__cap(v) : 0; | ||||
|     int32_t min_needed = dst_v_count(v) + increment; | ||||
|     int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed; | ||||
|     int32_t *p = (int32_t *) realloc(v ? dst_v__raw(v) : 0, itemsize * m + sizeof(int32_t)*2); | ||||
|     if (NULL != p) { | ||||
|         if (!v) p[1] = 0; | ||||
|         p[0] = m; | ||||
|         return p + 2; | ||||
|    } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
 | ||||
|    } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* Clone a buffer. */ | ||||
| #ifdef DST_V_DEF_COPYMEM | ||||
| static void *dst_v_copymem(void *v, int32_t itemsize) { | ||||
|     int32_t *p; | ||||
|     if (NULL == v) return NULL; | ||||
|     p = malloc(2 * sizeof(int32_t) + itemsize * dst_v__cap(v)); | ||||
|     if (NULL != p) { | ||||
|         memcpy(p, dst_v__raw(v), 2 * sizeof(int32_t) + itemsize * dst_v__cnt(v)); | ||||
|         return p + 2; | ||||
|     } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
 | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* Convert a buffer to normal allocated memory (forget capacity) */ | ||||
| #ifdef DST_V_DEF_FLATTENMEM | ||||
| static void *dst_v_flattenmem(void *v, int32_t itemsize) { | ||||
|     int32_t *p; | ||||
|     int32_t sizen; | ||||
|     if (NULL == v) return NULL; | ||||
|     sizen = itemsize * dst_v__cnt(v); | ||||
|     p = malloc(sizen); | ||||
|     if (NULL != p) { | ||||
|         memcpy(p, v, sizen); | ||||
|         return p; | ||||
|     } else { | ||||
|        { | ||||
|            DST_OUT_OF_MEMORY; | ||||
|        } | ||||
|        return NULL; | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| /* Actual functions defined in vector.c */ | ||||
| void *dst_v_grow(void *v, int32_t increment, int32_t itemsize); | ||||
| void *dst_v_copymem(void *v, int32_t itemsize); | ||||
| void *dst_v_flattenmem(void *v, int32_t itemsize); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										203
									
								
								src/core/vm.c
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								src/core/vm.c
									
									
									
									
									
								
							| @@ -21,11 +21,11 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstopcodes.h> | ||||
| #include "state.h" | ||||
| #include "fiber.h" | ||||
| #include "gc.h" | ||||
| #include "symcache.h" | ||||
| #include "util.h" | ||||
|  | ||||
| /* VM state */ | ||||
| DST_THREAD_LOCAL DstTable *dst_vm_registry; | ||||
| @@ -51,6 +51,9 @@ DstSignal dst_continue(DstFiber *fiber, Dst in, Dst *out) { | ||||
|      * Values stored here should be used immediately */ | ||||
|     Dst retreg; | ||||
|  | ||||
|     /* Expected types on type error */ | ||||
|     uint16_t expected_types; | ||||
|  | ||||
|     /* Signal to return when done */ | ||||
|     DstSignal signal = DST_SIGNAL_OK; | ||||
|  | ||||
| @@ -181,6 +184,12 @@ static void *op_lookup[255] = { | ||||
|     &&label_DOP_GET_INDEX, | ||||
|     &&label_DOP_PUT_INDEX, | ||||
|     &&label_DOP_LENGTH, | ||||
|     &&label_DOP_MAKE_ARRAY, | ||||
|     &&label_DOP_MAKE_BUFFER, | ||||
|     &&label_DOP_MAKE_STRING, | ||||
|     &&label_DOP_MAKE_STRUCT, | ||||
|     &&label_DOP_MAKE_TABLE, | ||||
|     &&label_DOP_MAKE_TUPLE, | ||||
|     &&label_unknown_op | ||||
| }; | ||||
| #else | ||||
| @@ -195,6 +204,20 @@ static void *op_lookup[255] = { | ||||
|  | ||||
| #define vm_throw(e) do { retreg = dst_cstringv(e); goto vm_error; } while (0) | ||||
| #define vm_assert(cond, e) do {if (!(cond)) vm_throw((e)); } while (0) | ||||
| #define vm_assert_type(X, T) do { \ | ||||
|     if (!(dst_checktype((X), (T)))) { \ | ||||
|         expected_types = 1 << (T); \ | ||||
|         retreg = (X); \ | ||||
|         goto vm_type_error; \ | ||||
|     } \ | ||||
| } while (0) | ||||
| #define vm_assert_types(X, TS) do { \ | ||||
|     if (!((1 << dst_type(X)) & (TS))) { \ | ||||
|         expected_types = (TS); \ | ||||
|         retreg = (X); \ | ||||
|         goto vm_type_error; \ | ||||
|     } \ | ||||
| } while (0) | ||||
|  | ||||
| #define vm_binop_integer(op) \ | ||||
|     stack[oparg(1, 0xFF)] = dst_wrap_integer(\ | ||||
| @@ -221,8 +244,8 @@ static void *op_lookup[255] = { | ||||
|     {\ | ||||
|         Dst op1 = stack[oparg(2, 0xFF)];\ | ||||
|         Dst op2 = stack[oparg(3, 0xFF)];\ | ||||
|         vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number");\ | ||||
|         vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number");\ | ||||
|         vm_assert_types(op1, DST_TFLAG_NUMBER);\ | ||||
|         vm_assert_types(op2, DST_TFLAG_NUMBER);\ | ||||
|         stack[oparg(1, 0xFF)] = dst_checktype(op1, DST_INTEGER)\ | ||||
|             ? (dst_checktype(op2, DST_INTEGER)\ | ||||
|                 ? dst_wrap_integer(dst_unwrap_integer(op1) op dst_unwrap_integer(op2))\ | ||||
| @@ -333,8 +356,8 @@ static void *op_lookup[255] = { | ||||
|     { | ||||
|         Dst op1 = stack[oparg(2, 0xFF)]; | ||||
|         Dst op2 = stack[oparg(3, 0xFF)]; | ||||
|         vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number"); | ||||
|         vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number"); | ||||
|         vm_assert_types(op1, DST_TFLAG_NUMBER); | ||||
|         vm_assert_types(op2, DST_TFLAG_NUMBER); | ||||
|         if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == 0) | ||||
|             vm_throw("integer divide by zero"); | ||||
|         if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == -1 && | ||||
| @@ -688,7 +711,9 @@ static void *op_lookup[255] = { | ||||
|         if (dst_seq_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) { | ||||
|             dst_fiber_pushn(fiber, vals, len); | ||||
|         } else { | ||||
|             vm_throw("expected array/tuple"); | ||||
|             retreg = stack[oparg(1, 0xFFFFFF)]; | ||||
|             expected_types = DST_TFLAG_INDEXED; | ||||
|             goto vm_type_error; | ||||
|         } | ||||
|     } | ||||
|     pc++; | ||||
| @@ -721,7 +746,9 @@ static void *op_lookup[255] = { | ||||
|             } | ||||
|             goto vm_return_cfunc; | ||||
|         } | ||||
|         vm_throw("expected function"); | ||||
|         expected_types = DST_TFLAG_CALLABLE; | ||||
|         retreg = callee; | ||||
|         goto vm_type_error; | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_TAILCALL) | ||||
| @@ -745,13 +772,15 @@ static void *op_lookup[255] = { | ||||
|             } | ||||
|             goto vm_return_cfunc_tail; | ||||
|         } | ||||
|         vm_throw("expected function"); | ||||
|         expected_types = DST_TFLAG_CALLABLE; | ||||
|         retreg = callee; | ||||
|         goto vm_type_error; | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_RESUME) | ||||
|     { | ||||
|         Dst fiberval = stack[oparg(2, 0xFF)]; | ||||
|         vm_assert(dst_checktype(fiberval, DST_FIBER), "expected fiber"); | ||||
|         vm_assert_type(fiberval, DST_FIBER); | ||||
|         retreg = stack[oparg(3, 0xFF)]; | ||||
|         fiber->child = dst_unwrap_fiber(fiberval); | ||||
|         goto vm_resume_child; | ||||
| @@ -775,12 +804,15 @@ static void *op_lookup[255] = { | ||||
|         Dst value = stack[oparg(3, 0xFF)]; | ||||
|         switch (dst_type(ds)) { | ||||
|             default: | ||||
|                 vm_throw("expected mutable data structure"); | ||||
|                 expected_types = DST_TFLAG_ARRAY | DST_TFLAG_BUFFER | DST_TFLAG_TABLE; | ||||
|                 retreg = ds; | ||||
|                 goto vm_type_error; | ||||
|             case DST_ARRAY: | ||||
|             { | ||||
|                 int32_t index; | ||||
|                 DstArray *array = dst_unwrap_array(ds); | ||||
|                 if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0) | ||||
|                 vm_assert_type(key, DST_INTEGER); | ||||
|                 if (dst_unwrap_integer(key) < 0) | ||||
|                     vm_throw("expected non-negative integer key"); | ||||
|                 index = dst_unwrap_integer(key); | ||||
|                 if (index == INT32_MAX) | ||||
| @@ -795,13 +827,13 @@ static void *op_lookup[255] = { | ||||
|             { | ||||
|                 int32_t index; | ||||
|                 DstBuffer *buffer = dst_unwrap_buffer(ds); | ||||
|                 if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0) | ||||
|                 vm_assert_type(key, DST_INTEGER); | ||||
|                 if (dst_unwrap_integer(key) < 0) | ||||
|                     vm_throw("expected non-negative integer key"); | ||||
|                 index = dst_unwrap_integer(key); | ||||
|                 if (index == INT32_MAX) | ||||
|                     vm_throw("key too large"); | ||||
|                 if (!dst_checktype(value, DST_INTEGER)) | ||||
|                     vm_throw("expected integer value"); | ||||
|                 vm_assert_type(value, DST_INTEGER); | ||||
|                 if (index >= buffer->count) { | ||||
|                     dst_buffer_setcount(buffer, index + 1); | ||||
|                 } | ||||
| @@ -823,7 +855,9 @@ static void *op_lookup[255] = { | ||||
|         int32_t index = oparg(3, 0xFF); | ||||
|         switch (dst_type(ds)) { | ||||
|             default: | ||||
|                 vm_throw("expected mutable indexed data structure"); | ||||
|                 expected_types = DST_TFLAG_ARRAY | DST_TFLAG_BUFFER; | ||||
|                 retreg = ds; | ||||
|                 goto vm_type_error; | ||||
|             case DST_ARRAY: | ||||
|                 if (index >= dst_unwrap_array(ds)->count) { | ||||
|                     dst_array_ensure(dst_unwrap_array(ds), 2 * index); | ||||
| @@ -832,8 +866,7 @@ static void *op_lookup[255] = { | ||||
|                 dst_unwrap_array(ds)->data[index] = value; | ||||
|                 break; | ||||
|             case DST_BUFFER: | ||||
|                 if (!dst_checktype(value, DST_INTEGER))\ | ||||
|                     vm_throw("expected integer to set in buffer"); | ||||
|                 vm_assert_type(value, DST_INTEGER); | ||||
|                 if (index >= dst_unwrap_buffer(ds)->count) { | ||||
|                     dst_buffer_ensure(dst_unwrap_buffer(ds), 2 * index); | ||||
|                     dst_unwrap_buffer(ds)->count = index + 1; | ||||
| @@ -852,7 +885,9 @@ static void *op_lookup[255] = { | ||||
|         Dst value; | ||||
|         switch (dst_type(ds)) { | ||||
|             default: | ||||
|                 vm_throw("expected data structure"); | ||||
|                 expected_types = DST_TFLAG_LENGTHABLE; | ||||
|                 retreg = ds; | ||||
|                 goto vm_type_error; | ||||
|             case DST_STRUCT: | ||||
|                 value = dst_struct_get(dst_unwrap_struct(ds), key); | ||||
|                 break; | ||||
| @@ -863,8 +898,7 @@ static void *op_lookup[255] = { | ||||
|                 { | ||||
|                     DstArray *array = dst_unwrap_array(ds); | ||||
|                     int32_t index; | ||||
|                     if (!dst_checktype(key, DST_INTEGER)) | ||||
|                         vm_throw("expected integer key"); | ||||
|                     vm_assert_type(key, DST_INTEGER); | ||||
|                     index = dst_unwrap_integer(key); | ||||
|                     if (index < 0 || index >= array->count) { | ||||
|                         /*vm_throw("index out of bounds");*/ | ||||
| @@ -878,8 +912,7 @@ static void *op_lookup[255] = { | ||||
|                 { | ||||
|                     const Dst *tuple = dst_unwrap_tuple(ds); | ||||
|                     int32_t index; | ||||
|                     if (!dst_checktype(key, DST_INTEGER)) | ||||
|                         vm_throw("expected integer key"); | ||||
|                     vm_assert_type(key, DST_INTEGER); | ||||
|                     index = dst_unwrap_integer(key); | ||||
|                     if (index < 0 || index >= dst_tuple_length(tuple)) { | ||||
|                         /*vm_throw("index out of bounds");*/ | ||||
| @@ -893,8 +926,7 @@ static void *op_lookup[255] = { | ||||
|                 { | ||||
|                     DstBuffer *buffer = dst_unwrap_buffer(ds); | ||||
|                     int32_t index; | ||||
|                     if (!dst_checktype(key, DST_INTEGER)) | ||||
|                         vm_throw("expected integer key"); | ||||
|                     vm_assert_type(key, DST_INTEGER); | ||||
|                     index = dst_unwrap_integer(key); | ||||
|                     if (index < 0 || index >= buffer->count) { | ||||
|                         /*vm_throw("index out of bounds");*/ | ||||
| @@ -909,8 +941,7 @@ static void *op_lookup[255] = { | ||||
|                 { | ||||
|                     const uint8_t *str = dst_unwrap_string(ds); | ||||
|                     int32_t index; | ||||
|                     if (!dst_checktype(key, DST_INTEGER)) | ||||
|                         vm_throw("expected integer key"); | ||||
|                     vm_assert_type(key, DST_INTEGER); | ||||
|                     index = dst_unwrap_integer(key); | ||||
|                     if (index < 0 || index >= dst_string_length(str)) { | ||||
|                         /*vm_throw("index out of bounds");*/ | ||||
| @@ -933,7 +964,9 @@ static void *op_lookup[255] = { | ||||
|         Dst value; | ||||
|         switch (dst_type(ds)) { | ||||
|             default: | ||||
|                 vm_throw("expected indexed data structure"); | ||||
|                 expected_types = DST_TFLAG_LENGTHABLE; | ||||
|                 retreg = ds; | ||||
|                 goto vm_type_error; | ||||
|             case DST_STRING: | ||||
|             case DST_SYMBOL: | ||||
|                 if (index >= dst_string_length(dst_unwrap_string(ds))) { | ||||
| @@ -967,6 +1000,12 @@ static void *op_lookup[255] = { | ||||
|                     value = dst_unwrap_tuple(ds)[index]; | ||||
|                 } | ||||
|                 break; | ||||
|             case DST_TABLE: | ||||
|                 value = dst_table_get(dst_unwrap_table(ds), dst_wrap_integer(index)); | ||||
|                 break; | ||||
|             case DST_STRUCT: | ||||
|                 value = dst_struct_get(dst_unwrap_struct(ds), dst_wrap_integer(index)); | ||||
|                 break; | ||||
|         } | ||||
|         stack[oparg(1, 0xFF)] = value; | ||||
|         ++pc; | ||||
| @@ -979,7 +1018,9 @@ static void *op_lookup[255] = { | ||||
|         int32_t len; | ||||
|         switch (dst_type(x)) { | ||||
|             default: | ||||
|                 vm_throw("expected data structure"); | ||||
|                 expected_types = DST_TFLAG_LENGTHABLE; | ||||
|                 retreg = x; | ||||
|                 goto vm_type_error; | ||||
|             case DST_STRING: | ||||
|             case DST_SYMBOL: | ||||
|                 len = dst_string_length(dst_unwrap_string(x)); | ||||
| @@ -1005,6 +1046,84 @@ static void *op_lookup[255] = { | ||||
|         vm_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_ARRAY) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_wrap_array(dst_array_n(mem, count)); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_TUPLE) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_wrap_tuple(dst_tuple_n(mem, count)); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_TABLE) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         if (count & 1) | ||||
|             vm_throw("expected even number of arguments to table constructor"); | ||||
|         DstTable *table = dst_table(count / 2); | ||||
|         for (int32_t i = 0; i < count; i += 2) | ||||
|             dst_table_put(table, mem[i], mem[i + 1]); | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_wrap_table(table); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_STRUCT) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         if (count & 1) | ||||
|             vm_throw("expected even number of arguments to struct constructor"); | ||||
|         DstKV *st = dst_struct_begin(count / 2); | ||||
|         for (int32_t i = 0; i < count; i += 2) | ||||
|             dst_struct_put(st, mem[i], mem[i + 1]); | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_wrap_struct(dst_struct_end(st)); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_STRING) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         DstBuffer buffer; | ||||
|         dst_buffer_init(&buffer, 10 * count); | ||||
|         for (int32_t i = 0; i < count; i++) | ||||
|             dst_to_string_b(&buffer, mem[i]); | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_stringv(buffer.data, buffer.count); | ||||
|         dst_buffer_deinit(&buffer); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     VM_OP(DOP_MAKE_BUFFER) | ||||
|     { | ||||
|         int32_t count = fiber->stacktop - fiber->stackstart; | ||||
|         Dst *mem = fiber->data + fiber->stackstart; | ||||
|         DstBuffer *buffer = dst_buffer(10 * count); | ||||
|         for (int32_t i = 0; i < count; i++) | ||||
|             dst_to_string_b(buffer, mem[i]); | ||||
|         stack[oparg(1, 0xFFFFFF)] = dst_wrap_buffer(buffer); | ||||
|         fiber->stacktop = fiber->stackstart; | ||||
|         ++pc; | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     /* Return from c function. Simpler than returning from dst function */ | ||||
|     vm_return_cfunc: | ||||
|     { | ||||
| @@ -1059,6 +1178,22 @@ static void *op_lookup[255] = { | ||||
|         vm_checkgc_next(); | ||||
|     } | ||||
|  | ||||
|     /* Handle type errors. The found type is the type of retreg, | ||||
|      * the expected types are in the expected_types field. */ | ||||
|     vm_type_error: | ||||
|     { | ||||
|         DstBuffer errbuf; | ||||
|         dst_buffer_init(&errbuf, 10); | ||||
|         dst_buffer_push_cstring(&errbuf, "expected "); | ||||
|         dst_buffer_push_types(&errbuf, expected_types); | ||||
|         dst_buffer_push_cstring(&errbuf, ", got "); | ||||
|         dst_buffer_push_cstring(&errbuf, dst_type_names[dst_type(retreg)] + 1); | ||||
|         retreg = dst_stringv(errbuf.data, errbuf.count); | ||||
|         dst_buffer_deinit(&errbuf); | ||||
|         signal = DST_SIGNAL_ERROR; | ||||
|         goto vm_exit; | ||||
|     } | ||||
|  | ||||
|     /* Handle errors from c functions and vm opcodes */ | ||||
|     vm_error: | ||||
|     { | ||||
| @@ -1108,12 +1243,18 @@ static void *op_lookup[255] = { | ||||
|  | ||||
| } | ||||
|  | ||||
| DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out) { | ||||
| DstSignal dst_call( | ||||
|         DstFunction *fun, | ||||
|         int32_t argn, | ||||
|         const Dst *argv, | ||||
|         Dst *out, | ||||
|         DstFiber **f) { | ||||
|     int32_t i; | ||||
|     DstFiber *fiber = dst_fiber(fun, 64); | ||||
|     for (i = 0; i < argn; i++) { | ||||
|     if (f) | ||||
|         *f = fiber; | ||||
|     for (i = 0; i < argn; i++) | ||||
|         dst_fiber_push(fiber, argv[i]); | ||||
|     } | ||||
|     dst_fiber_funcframe(fiber, fiber->root); | ||||
|     /* Prevent push an extra value on the stack */ | ||||
|     dst_fiber_set_status(fiber, DST_STATUS_PENDING); | ||||
|   | ||||
| @@ -27,14 +27,786 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "dstconfig.h" | ||||
| /***** START SECTION CONFIG *****/ | ||||
|  | ||||
| #define DST_VERSION "0.0.0 alpha" | ||||
|  | ||||
| /* | ||||
|  * Detect OS and endianess. | ||||
|  * From webkit source. There is likely some extreneous | ||||
|  * detection for unsupported platforms | ||||
|  */ | ||||
|  | ||||
| /* Check Unix */ | ||||
| #if defined(_AIX) \ | ||||
|     || defined(__APPLE__) /* Darwin */ \ | ||||
|     || defined(__FreeBSD__) || defined(__DragonFly__) \ | ||||
|     || defined(__FreeBSD_kernel__) \ | ||||
|     || defined(__GNU__) /* GNU/Hurd */ \ | ||||
|     || defined(__linux__) \ | ||||
|     || defined(__NetBSD__) \ | ||||
|     || defined(__OpenBSD__) \ | ||||
|     || defined(__QNXNTO__) \ | ||||
|     || defined(sun) || defined(__sun) /* Solaris */ \ | ||||
|     || defined(unix) || defined(__unix) || defined(__unix__) | ||||
| #define DST_UNIX 1 | ||||
| /* Enable certain posix features */ | ||||
| #ifndef _POSIX_C_SOURCE | ||||
| #define _POSIX_C_SOURCE 200112L | ||||
| #endif | ||||
| #elif defined(__EMSCRIPTEN__) | ||||
| #define DST_WEB 1 | ||||
| #elif defined(WIN32) || defined(_WIN32) | ||||
| #define DST_WINDOWS 1 | ||||
| #endif | ||||
|  | ||||
| /* Check 64-bit vs 32-bit */ | ||||
| #if ((defined(__x86_64__) || defined(_M_X64)) \ | ||||
|      && (defined(DST_UNIX) || defined(DST_WINDOWS))) \ | ||||
| 	|| (defined(_WIN64)) /* Windows 64 bit */ \ | ||||
|     || (defined(__ia64__) && defined(__LP64__)) /* Itanium in LP64 mode */ \ | ||||
|     || defined(__alpha__) /* DEC Alpha */ \ | ||||
|     || (defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)) /* BE */ \ | ||||
|     || defined(__s390x__) /* S390 64-bit (BE) */ \ | ||||
|     || (defined(__ppc64__) || defined(__PPC64__)) \ | ||||
|     || defined(__aarch64__) /* ARM 64-bit */ | ||||
| #define DST_64 1 | ||||
| #else | ||||
| #define DST_32 1 | ||||
| #endif | ||||
|  | ||||
| /* Check big endian */ | ||||
| #if defined(__MIPSEB__) /* MIPS 32-bit */ \ | ||||
|     || defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \ | ||||
|     || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \ | ||||
|     || defined(_M_PPC) || defined(__PPC) \ | ||||
|     || defined(__ppc64__) || defined(__PPC64__) /* PowerPC 64-bit */ \ | ||||
|     || defined(__sparc)   /* Sparc 32bit */  \ | ||||
|     || defined(__sparc__) /* Sparc 64-bit */ \ | ||||
|     || defined(__s390x__) /* S390 64-bit */ \ | ||||
|     || defined(__s390__)  /* S390 32-bit */ \ | ||||
|     || defined(__ARMEB__) /* ARM big endian */ \ | ||||
|     || ((defined(__CC_ARM) || defined(__ARMCC__)) /* ARM RealView compiler */ \ | ||||
|         && defined(__BIG_ENDIAN)) | ||||
| #define DST_BIG_ENDIAN 1 | ||||
| #else | ||||
| #define DST_LITTLE_ENDIAN 1 | ||||
| #endif | ||||
|  | ||||
| /* Define how global dst state is declared */ | ||||
| #ifdef DST_SINGLE_THREADED | ||||
| #define DST_THREAD_LOCAL | ||||
| #elif defined(__GNUC__) | ||||
| #define DST_THREAD_LOCAL __thread | ||||
| #elif defined(_MSC_BUILD) | ||||
| #define DST_THREAD_LOCAL __declspec(thread) | ||||
| #else | ||||
| #define DST_THREAD_LOCAL | ||||
| #endif | ||||
|  | ||||
| /* Handle runtime errors */ | ||||
| #ifndef dst_exit | ||||
| #include <stdio.h> | ||||
| #define dst_exit(m) do { \ | ||||
|     printf("C runtime error at line %d in file %s: %s\n",\ | ||||
|         __LINE__,\ | ||||
|         __FILE__,\ | ||||
|         (m));\ | ||||
|     exit(1);\ | ||||
| } while (0) | ||||
| #endif | ||||
|  | ||||
| #define dst_assert(c, m) do { \ | ||||
|     if (!(c)) dst_exit((m)); \ | ||||
| } while (0) | ||||
|  | ||||
| /* What to do when out of memory */ | ||||
| #ifndef DST_OUT_OF_MEMORY | ||||
| #include <stdio.h> | ||||
| #define DST_OUT_OF_MEMORY do { printf("dst out of memory\n"); exit(1); } while (0) | ||||
| #endif | ||||
|  | ||||
| /* Helper for debugging */ | ||||
| #define dst_trace(x) dst_puts(dst_formatc("DST TRACE %s, %d: %v\n", __FILE__, __LINE__, x)) | ||||
|  | ||||
| /* Prevent some recursive functions from recursing too deeply | ||||
|  * ands crashing (the parser). Instead, error out. */ | ||||
| #define DST_RECURSION_GUARD 1024 | ||||
|  | ||||
| /* Maximum depth to follow table prototypes before giving up and returning nil. */ | ||||
| #define DST_MAX_PROTO_DEPTH 200 | ||||
|  | ||||
| /* Define max stack size for stacks before raising a stack overflow error. | ||||
|  * If this is not defined, fiber stacks can grow without limit (until memory | ||||
|  * runs out) */ | ||||
| #define DST_STACK_MAX 8192 | ||||
|  | ||||
| /* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. */ | ||||
| #define DST_NANBOX | ||||
| #define DST_NANBOX_47 | ||||
|  | ||||
| /* Alignment for pointers */ | ||||
| #ifdef DST_32 | ||||
| #define DST_WALIGN 4 | ||||
| #else | ||||
| #define DST_WALIGN 8 | ||||
| #endif | ||||
|  | ||||
| /***** END SECTION CONFIG *****/ | ||||
|  | ||||
| /***** START SECTION TYPES *****/ | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
|  | ||||
| #include "dsttypes.h" | ||||
| /* Names of all of the types */ | ||||
| extern const char *const dst_type_names[16]; | ||||
|  | ||||
| /* Fiber signals */ | ||||
| typedef enum { | ||||
|     DST_SIGNAL_OK, | ||||
|     DST_SIGNAL_ERROR, | ||||
|     DST_SIGNAL_DEBUG, | ||||
|     DST_SIGNAL_YIELD, | ||||
|     DST_SIGNAL_USER0, | ||||
|     DST_SIGNAL_USER1, | ||||
|     DST_SIGNAL_USER2, | ||||
|     DST_SIGNAL_USER3, | ||||
|     DST_SIGNAL_USER4, | ||||
|     DST_SIGNAL_USER5, | ||||
|     DST_SIGNAL_USER6, | ||||
|     DST_SIGNAL_USER7, | ||||
|     DST_SIGNAL_USER8, | ||||
|     DST_SIGNAL_USER9 | ||||
| } DstSignal; | ||||
|  | ||||
| /* Fiber statuses - mostly corresponds to signals. */ | ||||
| typedef enum { | ||||
|     DST_STATUS_DEAD, | ||||
|     DST_STATUS_ERROR, | ||||
|     DST_STATUS_DEBUG, | ||||
|     DST_STATUS_PENDING, | ||||
|     DST_STATUS_USER0, | ||||
|     DST_STATUS_USER1, | ||||
|     DST_STATUS_USER2, | ||||
|     DST_STATUS_USER3, | ||||
|     DST_STATUS_USER4, | ||||
|     DST_STATUS_USER5, | ||||
|     DST_STATUS_USER6, | ||||
|     DST_STATUS_USER7, | ||||
|     DST_STATUS_USER8, | ||||
|     DST_STATUS_USER9, | ||||
|     DST_STATUS_NEW, | ||||
|     DST_STATUS_ALIVE | ||||
| } DstFiberStatus; | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
| typedef union Dst Dst; | ||||
| #else | ||||
| typedef struct Dst Dst; | ||||
| #endif | ||||
|  | ||||
| /* All of the dst types */ | ||||
| typedef struct DstFunction DstFunction; | ||||
| typedef struct DstArray DstArray; | ||||
| typedef struct DstBuffer DstBuffer; | ||||
| typedef struct DstTable DstTable; | ||||
| typedef struct DstFiber DstFiber; | ||||
|  | ||||
| /* Other structs */ | ||||
| typedef struct DstAbstractHeader DstAbstractHeader; | ||||
| typedef struct DstFuncDef DstFuncDef; | ||||
| typedef struct DstFuncEnv DstFuncEnv; | ||||
| typedef struct DstKV DstKV; | ||||
| typedef struct DstStackFrame DstStackFrame; | ||||
| typedef struct DstAbstractType DstAbstractType; | ||||
| typedef struct DstArgs DstArgs; | ||||
| typedef struct DstReg DstReg; | ||||
| typedef struct DstSourceMapping DstSourceMapping; | ||||
| typedef int (*DstCFunction)(DstArgs args); | ||||
|  | ||||
| /* Basic types for all Dst Values */ | ||||
| typedef enum DstType { | ||||
|     DST_NIL, | ||||
|     DST_FALSE, | ||||
|     DST_TRUE, | ||||
|     DST_FIBER, | ||||
|     DST_INTEGER, | ||||
|     DST_REAL, | ||||
|     DST_STRING, | ||||
|     DST_SYMBOL, | ||||
|     DST_ARRAY, | ||||
|     DST_TUPLE, | ||||
|     DST_TABLE, | ||||
|     DST_STRUCT, | ||||
|     DST_BUFFER, | ||||
|     DST_FUNCTION, | ||||
|     DST_CFUNCTION, | ||||
|     DST_ABSTRACT | ||||
| } DstType; | ||||
|  | ||||
| #define DST_COUNT_TYPES (DST_ABSTRACT + 1) | ||||
|  | ||||
| /* Type flags */ | ||||
| #define DST_TFLAG_NIL (1 << DST_NIL) | ||||
| #define DST_TFLAG_FALSE (1 << DST_FALSE) | ||||
| #define DST_TFLAG_TRUE (1 << DST_TRUE) | ||||
| #define DST_TFLAG_FIBER (1 << DST_FIBER) | ||||
| #define DST_TFLAG_INTEGER (1 << DST_INTEGER) | ||||
| #define DST_TFLAG_REAL (1 << DST_REAL) | ||||
| #define DST_TFLAG_STRING (1 << DST_STRING) | ||||
| #define DST_TFLAG_SYMBOL (1 << DST_SYMBOL) | ||||
| #define DST_TFLAG_ARRAY (1 << DST_ARRAY) | ||||
| #define DST_TFLAG_TUPLE (1 << DST_TUPLE) | ||||
| #define DST_TFLAG_TABLE (1 << DST_TABLE) | ||||
| #define DST_TFLAG_STRUCT (1 << DST_STRUCT) | ||||
| #define DST_TFLAG_BUFFER (1 << DST_BUFFER) | ||||
| #define DST_TFLAG_FUNCTION (1 << DST_FUNCTION) | ||||
| #define DST_TFLAG_CFUNCTION (1 << DST_CFUNCTION) | ||||
| #define DST_TFLAG_ABSTRACT (1 << DST_ABSTRACT) | ||||
|  | ||||
| /* Some abstractions */ | ||||
| #define DST_TFLAG_BOOLEAN (DST_TFLAG_TRUE | DST_TFLAG_FALSE) | ||||
| #define DST_TFLAG_NUMBER (DST_TFLAG_REAL | DST_TFLAG_INTEGER) | ||||
| #define DST_TFLAG_CALLABLE (DST_TFLAG_FUNCTION | DST_TFLAG_CFUNCTION) | ||||
| #define DST_TFLAG_BYTES (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER) | ||||
| #define DST_TFLAG_INDEXED (DST_TFLAG_ARRAY | DST_TFLAG_TUPLE) | ||||
| #define DST_TFLAG_DICTIONARY (DST_TFLAG_TABLE | DST_TFLAG_STRUCT) | ||||
| #define DST_TFLAG_LENGTHABLE (DST_TFLAG_BYTES | DST_TFLAG_INDEXED | DST_TFLAG_DICTIONARY) | ||||
|  | ||||
| /* We provide two possible implemenations of Dsts. The preferred | ||||
|  * nanboxing approach, and the standard C version. Code in the rest of the | ||||
|  * application must interact through exposed interface. */ | ||||
|  | ||||
| /* Required interface for Dst */ | ||||
| /* wrap and unwrap for all types */ | ||||
| /* Get type quickly */ | ||||
| /* Check against type quickly */ | ||||
| /* Small footprint */ | ||||
| /* 32 bit integer support */ | ||||
|  | ||||
| /* dst_type(x) | ||||
|  * dst_checktype(x, t) | ||||
|  * dst_wrap_##TYPE(x) | ||||
|  * dst_unwrap_##TYPE(x) | ||||
|  * dst_truthy(x) | ||||
|  * dst_memclear(p, n) - clear memory for hash tables to nils | ||||
|  * dst_u64(x) - get 64 bits of payload for hashing | ||||
|  */ | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| union Dst { | ||||
|     uint64_t u64; | ||||
|     int64_t i64; | ||||
|     double real; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).u64) | ||||
|  | ||||
| /* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style | ||||
|  * 47 bit payload representaion is that the type bits are no long contiguous. Type | ||||
|  * checking can still be fast, but typewise polymorphism takes a bit longer. However,  | ||||
|  * hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers | ||||
|  * in a 48 bit address space (Linux on ARM). If DST_NANBOX_47 is set, use 47 bit tagged pointers. */ | ||||
|  | ||||
| /*                    |.......Tag.......|.......................Payload..................| */ | ||||
| /* Non-double:        t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
| /* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */ | ||||
|  | ||||
| /* Double (no NaNs):   x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
|  | ||||
| #if defined (DST_NANBOX_47) || defined (DST_32) | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF800000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu | ||||
|  | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((uint64_t)(type) | 0x1FFF0) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 47) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xF) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #else /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF000000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFllu | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1)) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 48) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #endif /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| /* 32 bit mode will not use the full payload for pointers. */ | ||||
| #ifdef DST_32 | ||||
|  | ||||
| #define DST_NANBOX_POINTERBITS 0xFFFFFFFFllu | ||||
| #else | ||||
| #define DST_NANBOX_POINTERBITS DST_NANBOX_PAYLOADBITS | ||||
| #endif | ||||
|  | ||||
| #define dst_nanbox_checkauxtype(x, type) \ | ||||
|     (((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type))) | ||||
|  | ||||
| #define dst_nanbox_isreal(x) \ | ||||
|     (!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL)) | ||||
|  | ||||
| #define dst_checktype(x, t) \ | ||||
|     (((t) == DST_REAL) \ | ||||
|         ? dst_nanbox_isreal(x) \ | ||||
|         : dst_nanbox_checkauxtype((x), (t))) | ||||
|  | ||||
| void *dst_nanbox_to_pointer(Dst x); | ||||
| void dst_nanbox_memempty(DstKV *mem, int32_t count); | ||||
| void *dst_nanbox_memalloc_empty(int32_t count); | ||||
| Dst dst_nanbox_from_pointer(void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_cpointer(const void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_double(double d); | ||||
| Dst dst_nanbox_from_bits(uint64_t bits); | ||||
|  | ||||
| #define dst_memempty(mem, len) dst_nanbox_memempty((mem), (len)) | ||||
| #define dst_memalloc_empty(count) dst_nanbox_memalloc_empty(count) | ||||
|  | ||||
| /* Todo - check for single mask operation */ | ||||
| #define dst_truthy(x) \ | ||||
|     (!(dst_checktype((x), DST_NIL) || dst_checktype((x), DST_FALSE))) | ||||
|  | ||||
| #define dst_nanbox_from_payload(t, p) \ | ||||
|     dst_nanbox_from_bits(dst_nanbox_tag(t) | (p)) | ||||
|  | ||||
| #define dst_nanbox_wrap_(p, t) \ | ||||
|     dst_nanbox_from_pointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| #define dst_nanbox_wrap_c(p, t) \ | ||||
|     dst_nanbox_from_cpointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| /* Wrap the simple types */ | ||||
| #define dst_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1) | ||||
| #define dst_wrap_true() dst_nanbox_from_payload(DST_TRUE, 1) | ||||
| #define dst_wrap_false() dst_nanbox_from_payload(DST_FALSE, 1) | ||||
| #define dst_wrap_boolean(b) dst_nanbox_from_payload((b) ? DST_TRUE : DST_FALSE, 1) | ||||
| #define dst_wrap_integer(i) dst_nanbox_from_payload(DST_INTEGER, (uint32_t)(i)) | ||||
| #define dst_wrap_real(r) dst_nanbox_from_double(r) | ||||
|  | ||||
| /* Unwrap the simple types */ | ||||
| #define dst_unwrap_boolean(x) \ | ||||
|     (dst_checktype(x, DST_TRUE)) | ||||
| #define dst_unwrap_integer(x) \ | ||||
|     ((int32_t)((x).u64 & 0xFFFFFFFFlu)) | ||||
| #define dst_unwrap_real(x) ((x).real) | ||||
|  | ||||
| /* Wrap the pointer types */ | ||||
| #define dst_wrap_struct(s) dst_nanbox_wrap_c((s), DST_STRUCT) | ||||
| #define dst_wrap_tuple(s) dst_nanbox_wrap_c((s), DST_TUPLE) | ||||
| #define dst_wrap_fiber(s) dst_nanbox_wrap_((s), DST_FIBER) | ||||
| #define dst_wrap_array(s) dst_nanbox_wrap_((s), DST_ARRAY) | ||||
| #define dst_wrap_table(s) dst_nanbox_wrap_((s), DST_TABLE) | ||||
| #define dst_wrap_buffer(s) dst_nanbox_wrap_((s), DST_BUFFER) | ||||
| #define dst_wrap_string(s) dst_nanbox_wrap_c((s), DST_STRING) | ||||
| #define dst_wrap_symbol(s) dst_nanbox_wrap_c((s), DST_SYMBOL) | ||||
| #define dst_wrap_abstract(s) dst_nanbox_wrap_((s), DST_ABSTRACT) | ||||
| #define dst_wrap_function(s) dst_nanbox_wrap_((s), DST_FUNCTION) | ||||
| #define dst_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION) | ||||
|  | ||||
| /* Unwrap the pointer types */ | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_table(x) ((DstTable *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_abstract(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_pointer(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)dst_nanbox_to_pointer(x)) | ||||
|  | ||||
| /* End of [#ifdef DST_NANBOX] */ | ||||
| #else | ||||
|  | ||||
| /* A general dst value type */ | ||||
| struct Dst { | ||||
|     union { | ||||
|         uint64_t u64; | ||||
|         double real; | ||||
|         int32_t integer; | ||||
|         void *pointer; | ||||
|         const void *cpointer; | ||||
|     } as; | ||||
|     DstType type; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).as.u64) | ||||
| #define dst_memempty(mem, count) memset((mem), 0, sizeof(DstKV) * (count)) | ||||
| #define dst_memalloc_empty(count) calloc((count), sizeof(DstKV)) | ||||
| #define dst_type(x) ((x).type) | ||||
| #define dst_checktype(x, t) ((x).type == (t)) | ||||
| #define dst_truthy(x) \ | ||||
|     ((x).type != DST_NIL && (x).type != DST_FALSE) | ||||
|  | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)(x).as.pointer) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)(x).as.pointer) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)(x).as.pointer) | ||||
| #define dst_unwrap_array(x) ((DstArray *)(x).as.pointer) | ||||
| #define dst_unwrap_table(x) ((DstTable *)(x).as.pointer) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)(x).as.pointer) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_abstract(x) ((x).as.pointer) | ||||
| #define dst_unwrap_pointer(x) ((x).as.pointer) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)(x).as.pointer) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)(x).as.pointer) | ||||
| #define dst_unwrap_boolean(x) ((x).type == DST_TRUE) | ||||
| #define dst_unwrap_integer(x) ((x).as.integer) | ||||
| #define dst_unwrap_real(x) ((x).as.real) | ||||
|  | ||||
| Dst dst_wrap_nil(void); | ||||
| Dst dst_wrap_real(double x); | ||||
| Dst dst_wrap_integer(int32_t x); | ||||
| Dst dst_wrap_true(void); | ||||
| Dst dst_wrap_false(void); | ||||
| Dst dst_wrap_boolean(int x); | ||||
| Dst dst_wrap_string(const uint8_t *x); | ||||
| Dst dst_wrap_symbol(const uint8_t *x); | ||||
| Dst dst_wrap_array(DstArray *x); | ||||
| Dst dst_wrap_tuple(const Dst *x); | ||||
| Dst dst_wrap_struct(const DstKV *x); | ||||
| Dst dst_wrap_fiber(DstFiber *x); | ||||
| Dst dst_wrap_buffer(DstBuffer *x); | ||||
| Dst dst_wrap_function(DstFunction *x); | ||||
| Dst dst_wrap_cfunction(DstCFunction x); | ||||
| Dst dst_wrap_table(DstTable *x); | ||||
| Dst dst_wrap_abstract(void *x); | ||||
|  | ||||
| /* End of tagged union implementation */ | ||||
| #endif | ||||
|  | ||||
| /* Hold components of arguments passed to DstCFunction. */ | ||||
| struct DstArgs { | ||||
|     int32_t n; | ||||
|     Dst *v; | ||||
|     Dst *ret; | ||||
| }; | ||||
|  | ||||
| /* Fiber flags */ | ||||
| #define DST_FIBER_FLAG_SIGNAL_WAITING (1 << 30) | ||||
|  | ||||
| /* Fiber signal masks. */ | ||||
| #define DST_FIBER_MASK_ERROR 2 | ||||
| #define DST_FIBER_MASK_DEBUG 4 | ||||
| #define DST_FIBER_MASK_YIELD 8 | ||||
|  | ||||
| #define DST_FIBER_MASK_USER0 (16 << 0) | ||||
| #define DST_FIBER_MASK_USER1 (16 << 1) | ||||
| #define DST_FIBER_MASK_USER2 (16 << 2) | ||||
| #define DST_FIBER_MASK_USER3 (16 << 3) | ||||
| #define DST_FIBER_MASK_USER4 (16 << 4) | ||||
| #define DST_FIBER_MASK_USER5 (16 << 5) | ||||
| #define DST_FIBER_MASK_USER6 (16 << 6) | ||||
| #define DST_FIBER_MASK_USER7 (16 << 7) | ||||
| #define DST_FIBER_MASK_USER8 (16 << 8) | ||||
| #define DST_FIBER_MASK_USER9 (16 << 9) | ||||
|  | ||||
| #define DST_FIBER_MASK_USERN(N) (16 << (N)) | ||||
| #define DST_FIBER_MASK_USER 0x3FF0 | ||||
|  | ||||
| #define DST_FIBER_STATUS_MASK 0xFF0000 | ||||
| #define DST_FIBER_STATUS_OFFSET 16 | ||||
|  | ||||
| /* A lightweight green thread in dst. Does not correspond to | ||||
|  * operating system threads. */ | ||||
| struct DstFiber { | ||||
|     Dst *data; | ||||
|     DstFiber *child; /* Keep linked list of fibers for restarting pending fibers */ | ||||
|     DstFunction *root; /* First value */ | ||||
|     int32_t frame; /* Index of the stack frame */ | ||||
|     int32_t stackstart; /* Beginning of next args */ | ||||
|     int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ | ||||
|     int32_t capacity; | ||||
|     int32_t maxstack; /* Arbitrary defined limit for stack overflow */ | ||||
|     uint32_t flags; /* Various flags */ | ||||
| }; | ||||
|  | ||||
| /* Mark if a stack frame is a tail call for debugging */ | ||||
| #define DST_STACKFRAME_TAILCALL 1 | ||||
|  | ||||
| /* A stack frame on the fiber. Is stored along with the stack values. */ | ||||
| struct DstStackFrame { | ||||
|     DstFunction *func; | ||||
|     uint32_t *pc; | ||||
|     DstFuncEnv *env; | ||||
|     int32_t prevframe; | ||||
|     uint32_t flags; | ||||
| }; | ||||
|  | ||||
| /* Number of Dsts a frame takes up in the stack */ | ||||
| #define DST_FRAME_SIZE ((sizeof(DstStackFrame) + sizeof(Dst) - 1) / sizeof(Dst)) | ||||
|  | ||||
| /* A dynamic array type. */ | ||||
| struct DstArray { | ||||
|     Dst *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A bytebuffer type. Used as a mutable string or string builder. */ | ||||
| struct DstBuffer { | ||||
|     uint8_t *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A mutable associative data type. Backed by a hashtable. */ | ||||
| struct DstTable { | ||||
|     DstKV *data; | ||||
|     DstTable *proto; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
|     int32_t deleted; | ||||
| }; | ||||
|  | ||||
| /* A key value pair in a struct or table */ | ||||
| struct DstKV { | ||||
|     Dst key; | ||||
|     Dst value; | ||||
| }; | ||||
|  | ||||
| /* Some function defintion flags */ | ||||
| #define DST_FUNCDEF_FLAG_VARARG 0x10000 | ||||
| #define DST_FUNCDEF_FLAG_NEEDSENV 0x20000 | ||||
| #define DST_FUNCDEF_FLAG_FIXARITY 0x40000 | ||||
| #define DST_FUNCDEF_FLAG_TAG 0xFFFF | ||||
|  | ||||
| /* Source mapping structure for a bytecode instruction */ | ||||
| struct DstSourceMapping { | ||||
|     int32_t line; | ||||
|     int32_t column; | ||||
| }; | ||||
|  | ||||
| /* A function definition. Contains information needed to instantiate closures. */ | ||||
| struct DstFuncDef { | ||||
|     int32_t *environments; /* Which environments to capture from parent. */ | ||||
|     Dst *constants; | ||||
|     DstFuncDef **defs; | ||||
|     uint32_t *bytecode; | ||||
|  | ||||
|     /* Various debug information */ | ||||
|     DstSourceMapping *sourcemap; | ||||
|     const uint8_t *source; | ||||
|     const uint8_t *name; | ||||
|  | ||||
|     uint32_t flags; | ||||
|     int32_t slotcount; /* The amount of stack space required for the function */ | ||||
|     int32_t arity; /* Not including varargs */ | ||||
|     int32_t constants_length; | ||||
|     int32_t bytecode_length; | ||||
|     int32_t environments_length;  | ||||
|     int32_t defs_length;  | ||||
| }; | ||||
|  | ||||
| /* A fuction environment */ | ||||
| struct DstFuncEnv { | ||||
|     union { | ||||
|         DstFiber *fiber; | ||||
|         Dst *values; | ||||
|     } as; | ||||
|     int32_t length; /* Size of environment */ | ||||
|     int32_t offset; /* Stack offset when values still on stack. If offset is <= 0, then | ||||
|         environment is no longer on the stack. */ | ||||
| }; | ||||
|  | ||||
| /* A function */ | ||||
| struct DstFunction { | ||||
|     DstFuncDef *def; | ||||
|     DstFuncEnv *envs[]; | ||||
| }; | ||||
|  | ||||
| typedef struct DstParseState DstParseState; | ||||
| typedef struct DstParser DstParser; | ||||
|  | ||||
| enum DstParserStatus { | ||||
|     DST_PARSE_ROOT, | ||||
|     DST_PARSE_ERROR, | ||||
|     DST_PARSE_FULL, | ||||
|     DST_PARSE_PENDING | ||||
| }; | ||||
|  | ||||
| /* A dst parser */ | ||||
| struct DstParser { | ||||
|     Dst* args; | ||||
|     const char *error; | ||||
|     DstParseState *states; | ||||
|     uint8_t *buf; | ||||
|     size_t argcount; | ||||
|     size_t argcap; | ||||
|     size_t statecount; | ||||
|     size_t statecap; | ||||
|     size_t bufcount; | ||||
|     size_t bufcap; | ||||
|     size_t line; | ||||
|     size_t col; | ||||
|     int lookback; | ||||
| }; | ||||
|  | ||||
| /* Defines an abstract type */ | ||||
| struct DstAbstractType { | ||||
|     const char *name; | ||||
|     int (*gc)(void *data, size_t len); | ||||
|     int (*gcmark)(void *data, size_t len); | ||||
| }; | ||||
|  | ||||
| /* Contains information about userdata */ | ||||
| struct DstAbstractHeader { | ||||
|     const DstAbstractType *type; | ||||
|     size_t size; | ||||
| }; | ||||
|  | ||||
| struct DstReg { | ||||
|     const char *name; | ||||
|     DstCFunction cfun; | ||||
| }; | ||||
|  | ||||
| /***** END SECTION TYPES *****/ | ||||
|  | ||||
| /***** START SECTION OPCODES *****/ | ||||
|  | ||||
| /* Bytecode op argument types */ | ||||
| enum DstOpArgType { | ||||
|     DST_OAT_SLOT, | ||||
|     DST_OAT_ENVIRONMENT, | ||||
|     DST_OAT_CONSTANT, | ||||
|     DST_OAT_INTEGER, | ||||
|     DST_OAT_TYPE, | ||||
|     DST_OAT_SIMPLETYPE, | ||||
|     DST_OAT_LABEL, | ||||
|     DST_OAT_FUNCDEF | ||||
| }; | ||||
|  | ||||
| /* Various types of instructions */ | ||||
| enum DstInstructionType { | ||||
|     DIT_0, /* No args */ | ||||
|     DIT_S, /* Slot(3) */ | ||||
|     DIT_L, /* Label(3) */ | ||||
|     DIT_SS, /* Slot(1), Slot(2) */ | ||||
|     DIT_SL, /* Slot(1), Label(2) */ | ||||
|     DIT_ST, /* Slot(1), Slot(2) */ | ||||
|     DIT_SI, /* Slot(1), Immediate(2) */ | ||||
|     DIT_SD, /* Slot(1), Closure(2) */ | ||||
|     DIT_SU, /* Slot(1), Unsigned Immediate(2) */ | ||||
|     DIT_SSS, /* Slot(1), Slot(1), Slot(1) */ | ||||
|     DIT_SSI, /* Slot(1), Slot(1), Immediate(1) */ | ||||
|     DIT_SSU, /* Slot(1), Slot(1), Unsigned Immediate(1) */ | ||||
|     DIT_SES, /* Slot(1), Environment(1), Far Slot(1) */ | ||||
|     DIT_SC /* Slot(1), Constant(2) */ | ||||
| }; | ||||
|  | ||||
| enum DstOpCode { | ||||
|     DOP_NOOP, | ||||
|     DOP_ERROR, | ||||
|     DOP_TYPECHECK, | ||||
|     DOP_RETURN, | ||||
|     DOP_RETURN_NIL, | ||||
|     DOP_ADD_INTEGER, | ||||
|     DOP_ADD_IMMEDIATE, | ||||
|     DOP_ADD_REAL, | ||||
|     DOP_ADD, | ||||
|     DOP_SUBTRACT_INTEGER, | ||||
|     DOP_SUBTRACT_REAL, | ||||
|     DOP_SUBTRACT, | ||||
|     DOP_MULTIPLY_INTEGER, | ||||
|     DOP_MULTIPLY_IMMEDIATE, | ||||
|     DOP_MULTIPLY_REAL, | ||||
|     DOP_MULTIPLY, | ||||
|     DOP_DIVIDE_INTEGER, | ||||
|     DOP_DIVIDE_IMMEDIATE, | ||||
|     DOP_DIVIDE_REAL, | ||||
|     DOP_DIVIDE, | ||||
|     DOP_BAND, | ||||
|     DOP_BOR, | ||||
|     DOP_BXOR, | ||||
|     DOP_BNOT, | ||||
|     DOP_SHIFT_LEFT, | ||||
|     DOP_SHIFT_LEFT_IMMEDIATE, | ||||
|     DOP_SHIFT_RIGHT, | ||||
|     DOP_SHIFT_RIGHT_IMMEDIATE, | ||||
|     DOP_SHIFT_RIGHT_UNSIGNED, | ||||
|     DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, | ||||
|     DOP_MOVE_FAR, | ||||
|     DOP_MOVE_NEAR, | ||||
|     DOP_JUMP, | ||||
|     DOP_JUMP_IF, | ||||
|     DOP_JUMP_IF_NOT, | ||||
|     DOP_GREATER_THAN, | ||||
|     DOP_GREATER_THAN_INTEGER, | ||||
|     DOP_GREATER_THAN_IMMEDIATE, | ||||
|     DOP_GREATER_THAN_REAL, | ||||
|     DOP_GREATER_THAN_EQUAL_REAL, | ||||
|     DOP_LESS_THAN, | ||||
|     DOP_LESS_THAN_INTEGER, | ||||
|     DOP_LESS_THAN_IMMEDIATE, | ||||
|     DOP_LESS_THAN_REAL, | ||||
|     DOP_LESS_THAN_EQUAL_REAL, | ||||
|     DOP_EQUALS, | ||||
|     DOP_EQUALS_INTEGER, | ||||
|     DOP_EQUALS_IMMEDIATE, | ||||
|     DOP_EQUALS_REAL, | ||||
|     DOP_COMPARE, | ||||
|     DOP_LOAD_NIL, | ||||
|     DOP_LOAD_TRUE, | ||||
|     DOP_LOAD_FALSE, | ||||
|     DOP_LOAD_INTEGER, | ||||
|     DOP_LOAD_CONSTANT, | ||||
|     DOP_LOAD_UPVALUE, | ||||
|     DOP_LOAD_SELF, | ||||
|     DOP_SET_UPVALUE, | ||||
|     DOP_CLOSURE, | ||||
|     DOP_PUSH, | ||||
|     DOP_PUSH_2, | ||||
|     DOP_PUSH_3, | ||||
|     DOP_PUSH_ARRAY, | ||||
|     DOP_CALL, | ||||
|     DOP_TAILCALL, | ||||
|     DOP_RESUME, | ||||
|     DOP_SIGNAL, | ||||
|     DOP_GET, | ||||
|     DOP_PUT, | ||||
|     DOP_GET_INDEX, | ||||
|     DOP_PUT_INDEX, | ||||
|     DOP_LENGTH, | ||||
|     DOP_MAKE_ARRAY, | ||||
|     DOP_MAKE_BUFFER, | ||||
|     DOP_MAKE_STRING, | ||||
|     DOP_MAKE_STRUCT, | ||||
|     DOP_MAKE_TABLE, | ||||
|     DOP_MAKE_TUPLE, | ||||
|     DOP_INSTRUCTION_COUNT | ||||
| }; | ||||
|  | ||||
| /* Info about all instructions */ | ||||
| extern enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT]; | ||||
|  | ||||
| /***** END SECTION OPCODES *****/ | ||||
|  | ||||
| /***** START SECTION MAIN *****/ | ||||
|  | ||||
| /* Parsing */ | ||||
| void dst_parser_init(DstParser *parser); | ||||
| @@ -62,6 +834,28 @@ DstAssembleResult dst_asm(Dst source, int flags); | ||||
| Dst dst_disasm(DstFuncDef *def); | ||||
| Dst dst_asm_decode_instruction(uint32_t instr); | ||||
|  | ||||
| /* Compilation */ | ||||
| typedef struct DstCompileOptions DstCompileOptions; | ||||
| typedef struct DstCompileResult DstCompileResult; | ||||
| enum DstCompileStatus { | ||||
|     DST_COMPILE_OK, | ||||
|     DST_COMPILE_ERROR | ||||
| }; | ||||
| struct DstCompileResult { | ||||
|     enum DstCompileStatus status; | ||||
|     DstFuncDef *funcdef; | ||||
|     const uint8_t *error; | ||||
|     DstFiber *macrofiber; | ||||
|     DstSourceMapping error_mapping; | ||||
| }; | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where); | ||||
|  | ||||
| /* Get the default environment for dst */ | ||||
| DstTable *dst_stl_env(); | ||||
|  | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath); | ||||
| int dst_dostring(DstTable *env, const char *str, const char *sourcePath); | ||||
|  | ||||
| /* Number scanning */ | ||||
| Dst dst_scan_number(const uint8_t *src, int32_t len); | ||||
| int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err); | ||||
| @@ -69,6 +863,7 @@ double dst_scan_real(const uint8_t *str, int32_t len, int *err); | ||||
|  | ||||
| /* Array functions */ | ||||
| DstArray *dst_array(int32_t capacity); | ||||
| DstArray *dst_array_n(const Dst *elements, int32_t n); | ||||
| DstArray *dst_array_init(DstArray *array, int32_t capacity); | ||||
| void dst_array_deinit(DstArray *array); | ||||
| void dst_array_ensure(DstArray *array, int32_t capacity); | ||||
| @@ -119,6 +914,8 @@ const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len); | ||||
| const uint8_t *dst_cstring_unique(const char *s); | ||||
| const uint8_t *dst_description(Dst x); | ||||
| const uint8_t *dst_to_string(Dst x); | ||||
| void dst_to_string_b(DstBuffer *buffer, Dst x); | ||||
| void dst_to_description_b(DstBuffer *buffer, Dst x); | ||||
| const char *dst_to_zerostring(Dst x); | ||||
| #define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr)) | ||||
| #define dst_stringv(str, len) dst_wrap_string(dst_string((str), (len))) | ||||
| @@ -208,7 +1005,7 @@ int dst_init(void); | ||||
| void dst_deinit(void); | ||||
| DstSignal dst_continue(DstFiber *fiber, Dst in, Dst *out); | ||||
| #define dst_run(F,O) dst_continue(F, dst_wrap_nil(), O) | ||||
| DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out); | ||||
| DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out, DstFiber **f); | ||||
|  | ||||
| /* Env helpers */ | ||||
| typedef enum { | ||||
| @@ -233,6 +1030,25 @@ int dst_type_err(DstArgs args, int32_t n, DstType expected); | ||||
| int dst_typemany_err(DstArgs args, int32_t n, int expected); | ||||
| int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at); | ||||
|  | ||||
| /* Initialize builtin libraries */ | ||||
| int dst_lib_io(DstArgs args); | ||||
| int dst_lib_math(DstArgs args); | ||||
| int dst_lib_array(DstArgs args); | ||||
| int dst_lib_tuple(DstArgs args); | ||||
| int dst_lib_buffer(DstArgs args); | ||||
| int dst_lib_table(DstArgs args); | ||||
| int dst_lib_fiber(DstArgs args); | ||||
| int dst_lib_os(DstArgs args); | ||||
| int dst_lib_string(DstArgs args); | ||||
| int dst_lib_marsh(DstArgs args); | ||||
| int dst_lib_parse(DstArgs args); | ||||
| int dst_lib_asm(DstArgs args); | ||||
| int dst_lib_compile(DstArgs args); | ||||
|  | ||||
| /***** END SECTION MAIN *****/ | ||||
|  | ||||
| /***** START SECTION MACROS *****/ | ||||
|  | ||||
| /* Macros */ | ||||
| #define DST_THROW(a, e) return (*((a).ret) = dst_cstringv(e), DST_SIGNAL_ERROR) | ||||
| #define DST_THROWV(a, v) return (*((a).ret) = (v), DST_SIGNAL_ERROR) | ||||
| @@ -343,6 +1159,8 @@ int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at); | ||||
| #define DST_RETURN_CSTRING(A, X) DST_RETURN(A, dst_cstringv(X)) | ||||
| #define DST_RETURN_CSYMBOL(A, X) DST_RETURN(A, dst_csymbolv(X)) | ||||
|  | ||||
| /**** END SECTION MACROS *****/ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -1,163 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_CONFIG_H_defined | ||||
| #define DST_CONFIG_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #define DST_VERSION "0.0.0 alpha" | ||||
|  | ||||
| /* | ||||
|  * Detect OS and endianess. | ||||
|  * From webkit source. There is likely some extreneous | ||||
|  * detection for unsupported platforms | ||||
|  */ | ||||
|  | ||||
| /* Check Unix */ | ||||
| #if defined(_AIX) \ | ||||
|     || defined(__APPLE__) /* Darwin */ \ | ||||
|     || defined(__FreeBSD__) || defined(__DragonFly__) \ | ||||
|     || defined(__FreeBSD_kernel__) \ | ||||
|     || defined(__GNU__) /* GNU/Hurd */ \ | ||||
|     || defined(__linux__) \ | ||||
|     || defined(__NetBSD__) \ | ||||
|     || defined(__OpenBSD__) \ | ||||
|     || defined(__QNXNTO__) \ | ||||
|     || defined(sun) || defined(__sun) /* Solaris */ \ | ||||
|     || defined(unix) || defined(__unix) || defined(__unix__) | ||||
| #define DST_UNIX 1 | ||||
| /* Enable certain posix features */ | ||||
| #ifndef _POSIX_C_SOURCE | ||||
| #define _POSIX_C_SOURCE 200112L | ||||
| #endif | ||||
| #elif defined(__EMSCRIPTEN__) | ||||
| #define DST_WEB 1 | ||||
| #elif defined(WIN32) || defined(_WIN32) | ||||
| #define DST_WINDOWS 1 | ||||
| #endif | ||||
|  | ||||
| /* Check 64-bit vs 32-bit */ | ||||
| #if ((defined(__x86_64__) || defined(_M_X64)) \ | ||||
|      && (defined(DST_UNIX) || defined(DST_WINDOWS))) \ | ||||
| 	|| (defined(_WIN64)) /* Windows 64 bit */ \ | ||||
|     || (defined(__ia64__) && defined(__LP64__)) /* Itanium in LP64 mode */ \ | ||||
|     || defined(__alpha__) /* DEC Alpha */ \ | ||||
|     || (defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)) /* BE */ \ | ||||
|     || defined(__s390x__) /* S390 64-bit (BE) */ \ | ||||
|     || (defined(__ppc64__) || defined(__PPC64__)) \ | ||||
|     || defined(__aarch64__) /* ARM 64-bit */ | ||||
| #define DST_64 1 | ||||
| #else | ||||
| #define DST_32 1 | ||||
| #endif | ||||
|  | ||||
| /* Check big endian */ | ||||
| #if defined(__MIPSEB__) /* MIPS 32-bit */ \ | ||||
|     || defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \ | ||||
|     || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \ | ||||
|     || defined(_M_PPC) || defined(__PPC) \ | ||||
|     || defined(__ppc64__) || defined(__PPC64__) /* PowerPC 64-bit */ \ | ||||
|     || defined(__sparc)   /* Sparc 32bit */  \ | ||||
|     || defined(__sparc__) /* Sparc 64-bit */ \ | ||||
|     || defined(__s390x__) /* S390 64-bit */ \ | ||||
|     || defined(__s390__)  /* S390 32-bit */ \ | ||||
|     || defined(__ARMEB__) /* ARM big endian */ \ | ||||
|     || ((defined(__CC_ARM) || defined(__ARMCC__)) /* ARM RealView compiler */ \ | ||||
|         && defined(__BIG_ENDIAN)) | ||||
| #define DST_BIG_ENDIAN 1 | ||||
| #else | ||||
| #define DST_LITTLE_ENDIAN 1 | ||||
| #endif | ||||
|  | ||||
| /* Define how global dst state is declared */ | ||||
| #ifdef DST_SINGLE_THREADED | ||||
| #define DST_THREAD_LOCAL | ||||
| #else | ||||
| #if defined(__GNUC__) | ||||
| #define DST_THREAD_LOCAL __thread | ||||
| #elif defined(_MSC_BUILD) | ||||
| #define DST_THREAD_LOCAL __declspec(thread) | ||||
| #else | ||||
| #define DST_THREAD_LOCAL | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| /* Include default headers */ | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* Handle runtime errors */ | ||||
| #ifndef dst_exit | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #define dst_exit(m) do { \ | ||||
|     printf("runtime error at line %d in file %s: %s\n",\ | ||||
|         __LINE__,\ | ||||
|         __FILE__,\ | ||||
|         (m));\ | ||||
|     exit(1);\ | ||||
| } while (0) | ||||
| #endif | ||||
|  | ||||
| #define dst_assert(c, m) do { \ | ||||
|     if (!(c)) dst_exit((m)); \ | ||||
| } while (0) | ||||
|  | ||||
| /* What to do when out of memory */ | ||||
| #ifndef DST_OUT_OF_MEMORY | ||||
| #include <stdio.h> | ||||
| #define DST_OUT_OF_MEMORY do { printf("dst out of memory\n"); exit(1); } while (0) | ||||
| #endif | ||||
|  | ||||
| /* Helper for debugging */ | ||||
| #define dst_trace(x) dst_puts(dst_formatc("DST TRACE %s, %d: %v\n", __FILE__, __LINE__, x)) | ||||
|  | ||||
| /* Prevent some recursive functions from recursing too deeply | ||||
|  * ands crashing (the parser). Instead, error out. */ | ||||
| #define DST_RECURSION_GUARD 1024 | ||||
|  | ||||
| /* Maximum depth to follow table prototypes before giving up and returning nil. */ | ||||
| #define DST_MAX_PROTO_DEPTH 200 | ||||
|  | ||||
| /* Define max stack size for stacks before raising a stack overflow error. | ||||
|  * If this is not defined, fiber stacks can grow without limit (until memory | ||||
|  * runs out) */ | ||||
| #define DST_STACK_MAX 8192 | ||||
|  | ||||
| /* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. */ | ||||
| #define DST_NANBOX | ||||
| #define DST_NANBOX_47 | ||||
|  | ||||
| /* Alignment for pointers */ | ||||
| #ifdef DST_32 | ||||
| #define DST_WALIGN 4 | ||||
| #else | ||||
| #define DST_WALIGN 8 | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_CONFIG_H_defined */ | ||||
| @@ -1,88 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_CORELIB_H_defined | ||||
| #define DST_CORELIB_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "dsttypes.h" | ||||
|  | ||||
| /* Native */ | ||||
| int dst_core_native(DstArgs args); | ||||
|  | ||||
| /* Arithmetic */ | ||||
| int dst_int(DstArgs args); | ||||
| int dst_real(DstArgs args); | ||||
| int dst_rand(DstArgs args); | ||||
| int dst_srand(DstArgs args); | ||||
| int dst_remainder(DstArgs args); | ||||
|  | ||||
| /* Misc core functions */ | ||||
| int dst_core_print(DstArgs args); | ||||
| int dst_core_describe(DstArgs args); | ||||
| int dst_core_string(DstArgs args); | ||||
| int dst_core_symbol(DstArgs args); | ||||
| int dst_core_buffer(DstArgs args); | ||||
| int dst_core_scannumber(DstArgs args); | ||||
| int dst_core_scaninteger(DstArgs args); | ||||
| int dst_core_scanreal(DstArgs args); | ||||
| int dst_core_tuple(DstArgs args); | ||||
| int dst_core_array(DstArgs args); | ||||
| int dst_core_table(DstArgs args); | ||||
| int dst_core_struct(DstArgs args); | ||||
| int dst_core_buffer(DstArgs args); | ||||
| int dst_core_gensym(DstArgs args); | ||||
| int dst_core_type(DstArgs args); | ||||
| int dst_core_next(DstArgs args); | ||||
| int dst_core_hash(DstArgs args); | ||||
|  | ||||
| /* GC */ | ||||
| int dst_core_gccollect(DstArgs args); | ||||
| int dst_core_gcsetinterval(DstArgs args); | ||||
| int dst_core_gcinterval(DstArgs args); | ||||
|  | ||||
| /* Initialize builtin libraries */ | ||||
| int dst_lib_io(DstArgs args); | ||||
| int dst_lib_math(DstArgs args); | ||||
| int dst_lib_array(DstArgs args); | ||||
| int dst_lib_tuple(DstArgs args); | ||||
| int dst_lib_buffer(DstArgs args); | ||||
| int dst_lib_table(DstArgs args); | ||||
| int dst_lib_fiber(DstArgs args); | ||||
| int dst_lib_os(DstArgs args); | ||||
| int dst_lib_string(DstArgs args); | ||||
| int dst_lib_marsh(DstArgs args); | ||||
| int dst_lib_parse(DstArgs args); | ||||
| int dst_lib_asm(DstArgs args); | ||||
|  | ||||
| /* Useful for compiler */ | ||||
| Dst dst_op_add(Dst lhs, Dst rhs); | ||||
| Dst dst_op_subtract(Dst lhs, Dst rhs); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_CORELIB_H_defined */ | ||||
| @@ -1,143 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_OPCODES_H_defined | ||||
| #define DST_OPCODES_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* Bytecode op argument types */ | ||||
| enum DstOpArgType { | ||||
|     DST_OAT_SLOT, | ||||
|     DST_OAT_ENVIRONMENT, | ||||
|     DST_OAT_CONSTANT, | ||||
|     DST_OAT_INTEGER, | ||||
|     DST_OAT_TYPE, | ||||
|     DST_OAT_SIMPLETYPE, | ||||
|     DST_OAT_LABEL, | ||||
|     DST_OAT_FUNCDEF | ||||
| }; | ||||
|  | ||||
| /* Various types of instructions */ | ||||
| enum DstInstructionType { | ||||
|     DIT_0, /* No args */ | ||||
|     DIT_S, /* Slot(3) */ | ||||
|     DIT_L, /* Label(3) */ | ||||
|     DIT_SS, /* Slot(1), Slot(2) */ | ||||
|     DIT_SL, /* Slot(1), Label(2) */ | ||||
|     DIT_ST, /* Slot(1), Slot(2) */ | ||||
|     DIT_SI, /* Slot(1), Immediate(2) */ | ||||
|     DIT_SD, /* Slot(1), Closure(2) */ | ||||
|     DIT_SU, /* Slot(1), Unsigned Immediate(2) */ | ||||
|     DIT_SSS, /* Slot(1), Slot(1), Slot(1) */ | ||||
|     DIT_SSI, /* Slot(1), Slot(1), Immediate(1) */ | ||||
|     DIT_SSU, /* Slot(1), Slot(1), Unsigned Immediate(1) */ | ||||
|     DIT_SES, /* Slot(1), Environment(1), Far Slot(1) */ | ||||
|     DIT_SC /* Slot(1), Constant(2) */ | ||||
| }; | ||||
|  | ||||
| enum DstOpCode { | ||||
|     DOP_NOOP, | ||||
|     DOP_ERROR, | ||||
|     DOP_TYPECHECK, | ||||
|     DOP_RETURN, | ||||
|     DOP_RETURN_NIL, | ||||
|     DOP_ADD_INTEGER, | ||||
|     DOP_ADD_IMMEDIATE, | ||||
|     DOP_ADD_REAL, | ||||
|     DOP_ADD, | ||||
|     DOP_SUBTRACT_INTEGER, | ||||
|     DOP_SUBTRACT_REAL, | ||||
|     DOP_SUBTRACT, | ||||
|     DOP_MULTIPLY_INTEGER, | ||||
|     DOP_MULTIPLY_IMMEDIATE, | ||||
|     DOP_MULTIPLY_REAL, | ||||
|     DOP_MULTIPLY, | ||||
|     DOP_DIVIDE_INTEGER, | ||||
|     DOP_DIVIDE_IMMEDIATE, | ||||
|     DOP_DIVIDE_REAL, | ||||
|     DOP_DIVIDE, | ||||
|     DOP_BAND, | ||||
|     DOP_BOR, | ||||
|     DOP_BXOR, | ||||
|     DOP_BNOT, | ||||
|     DOP_SHIFT_LEFT, | ||||
|     DOP_SHIFT_LEFT_IMMEDIATE, | ||||
|     DOP_SHIFT_RIGHT, | ||||
|     DOP_SHIFT_RIGHT_IMMEDIATE, | ||||
|     DOP_SHIFT_RIGHT_UNSIGNED, | ||||
|     DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, | ||||
|     DOP_MOVE_FAR, | ||||
|     DOP_MOVE_NEAR, | ||||
|     DOP_JUMP, | ||||
|     DOP_JUMP_IF, | ||||
|     DOP_JUMP_IF_NOT, | ||||
|     DOP_GREATER_THAN, | ||||
|     DOP_GREATER_THAN_INTEGER, | ||||
|     DOP_GREATER_THAN_IMMEDIATE, | ||||
|     DOP_GREATER_THAN_REAL, | ||||
|     DOP_GREATER_THAN_EQUAL_REAL, | ||||
|     DOP_LESS_THAN, | ||||
|     DOP_LESS_THAN_INTEGER, | ||||
|     DOP_LESS_THAN_IMMEDIATE, | ||||
|     DOP_LESS_THAN_REAL, | ||||
|     DOP_LESS_THAN_EQUAL_REAL, | ||||
|     DOP_EQUALS, | ||||
|     DOP_EQUALS_INTEGER, | ||||
|     DOP_EQUALS_IMMEDIATE, | ||||
|     DOP_EQUALS_REAL, | ||||
|     DOP_COMPARE, | ||||
|     DOP_LOAD_NIL, | ||||
|     DOP_LOAD_TRUE, | ||||
|     DOP_LOAD_FALSE, | ||||
|     DOP_LOAD_INTEGER, | ||||
|     DOP_LOAD_CONSTANT, | ||||
|     DOP_LOAD_UPVALUE, | ||||
|     DOP_LOAD_SELF, | ||||
|     DOP_SET_UPVALUE, | ||||
|     DOP_CLOSURE, | ||||
|     DOP_PUSH, | ||||
|     DOP_PUSH_2, | ||||
|     DOP_PUSH_3, | ||||
|     DOP_PUSH_ARRAY, | ||||
|     DOP_CALL, | ||||
|     DOP_TAILCALL, | ||||
|     DOP_RESUME, | ||||
|     DOP_SIGNAL, | ||||
|     DOP_GET, | ||||
|     DOP_PUT, | ||||
|     DOP_GET_INDEX, | ||||
|     DOP_PUT_INDEX, | ||||
|     DOP_LENGTH, | ||||
|     DOP_INSTRUCTION_COUNT | ||||
| }; | ||||
|  | ||||
| /* Info about all instructions */ | ||||
| extern enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT]; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,562 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_TYPES_H_defined | ||||
| #define DST_TYPES_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "dstconfig.h" | ||||
|  | ||||
| /* Names of all of the types */ | ||||
| extern const char *const dst_type_names[16]; | ||||
|  | ||||
| /* Fiber signals */ | ||||
| typedef enum { | ||||
|     DST_SIGNAL_OK, | ||||
|     DST_SIGNAL_ERROR, | ||||
|     DST_SIGNAL_DEBUG, | ||||
|     DST_SIGNAL_YIELD, | ||||
|     DST_SIGNAL_USER0, | ||||
|     DST_SIGNAL_USER1, | ||||
|     DST_SIGNAL_USER2, | ||||
|     DST_SIGNAL_USER3, | ||||
|     DST_SIGNAL_USER4, | ||||
|     DST_SIGNAL_USER5, | ||||
|     DST_SIGNAL_USER6, | ||||
|     DST_SIGNAL_USER7, | ||||
|     DST_SIGNAL_USER8, | ||||
|     DST_SIGNAL_USER9 | ||||
| } DstSignal; | ||||
|  | ||||
| /* Fiber statuses - mostly corresponds to signals. */ | ||||
| typedef enum { | ||||
|     DST_STATUS_DEAD, | ||||
|     DST_STATUS_ERROR, | ||||
|     DST_STATUS_DEBUG, | ||||
|     DST_STATUS_PENDING, | ||||
|     DST_STATUS_USER0, | ||||
|     DST_STATUS_USER1, | ||||
|     DST_STATUS_USER2, | ||||
|     DST_STATUS_USER3, | ||||
|     DST_STATUS_USER4, | ||||
|     DST_STATUS_USER5, | ||||
|     DST_STATUS_USER6, | ||||
|     DST_STATUS_USER7, | ||||
|     DST_STATUS_USER8, | ||||
|     DST_STATUS_USER9, | ||||
|     DST_STATUS_NEW, | ||||
|     DST_STATUS_ALIVE | ||||
| } DstFiberStatus; | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
| typedef union Dst Dst; | ||||
| #else | ||||
| typedef struct Dst Dst; | ||||
| #endif | ||||
|  | ||||
| /* All of the dst types */ | ||||
| typedef struct DstFunction DstFunction; | ||||
| typedef struct DstArray DstArray; | ||||
| typedef struct DstBuffer DstBuffer; | ||||
| typedef struct DstTable DstTable; | ||||
| typedef struct DstFiber DstFiber; | ||||
|  | ||||
| /* Other structs */ | ||||
| typedef struct DstAbstractHeader DstAbstractHeader; | ||||
| typedef struct DstFuncDef DstFuncDef; | ||||
| typedef struct DstFuncEnv DstFuncEnv; | ||||
| typedef struct DstKV DstKV; | ||||
| typedef struct DstStackFrame DstStackFrame; | ||||
| typedef struct DstAbstractType DstAbstractType; | ||||
| typedef struct DstArgs DstArgs; | ||||
| typedef struct DstReg DstReg; | ||||
| typedef struct DstSourceMapping DstSourceMapping; | ||||
| typedef int (*DstCFunction)(DstArgs args); | ||||
|  | ||||
| /* Basic types for all Dst Values */ | ||||
| typedef enum DstType { | ||||
|     DST_NIL, | ||||
|     DST_FALSE, | ||||
|     DST_TRUE, | ||||
|     DST_FIBER, | ||||
|     DST_INTEGER, | ||||
|     DST_REAL, | ||||
|     DST_STRING, | ||||
|     DST_SYMBOL, | ||||
|     DST_ARRAY, | ||||
|     DST_TUPLE, | ||||
|     DST_TABLE, | ||||
|     DST_STRUCT, | ||||
|     DST_BUFFER, | ||||
|     DST_FUNCTION, | ||||
|     DST_CFUNCTION, | ||||
|     DST_ABSTRACT | ||||
| } DstType; | ||||
|  | ||||
| #define DST_COUNT_TYPES (DST_ABSTRACT + 1) | ||||
|  | ||||
| /* Type flags */ | ||||
| #define DST_TFLAG_NIL (1 << DST_NIL) | ||||
| #define DST_TFLAG_FALSE (1 << DST_FALSE) | ||||
| #define DST_TFLAG_TRUE (1 << DST_TRUE) | ||||
| #define DST_TFLAG_FIBER (1 << DST_FIBER) | ||||
| #define DST_TFLAG_INTEGER (1 << DST_INTEGER) | ||||
| #define DST_TFLAG_REAL (1 << DST_REAL) | ||||
| #define DST_TFLAG_STRING (1 << DST_STRING) | ||||
| #define DST_TFLAG_SYMBOL (1 << DST_SYMBOL) | ||||
| #define DST_TFLAG_ARRAY (1 << DST_ARRAY) | ||||
| #define DST_TFLAG_TUPLE (1 << DST_TUPLE) | ||||
| #define DST_TFLAG_TABLE (1 << DST_TABLE) | ||||
| #define DST_TFLAG_STRUCT (1 << DST_STRUCT) | ||||
| #define DST_TFLAG_BUFFER (1 << DST_BUFFER) | ||||
| #define DST_TFLAG_FUNCTION (1 << DST_FUNCTION) | ||||
| #define DST_TFLAG_CFUNCTION (1 << DST_CFUNCTION) | ||||
| #define DST_TFLAG_ABSTRACT (1 << DST_ABSTRACT) | ||||
|  | ||||
| /* Some abstractions */ | ||||
| #define DST_TFLAG_BOOLEAN (DST_TFLAG_TRUE | DST_TFLAG_FALSE) | ||||
| #define DST_TFLAG_NUMBER (DST_TFLAG_REAL | DST_TFLAG_INTEGER) | ||||
| #define DST_TFLAG_CALLABLE (DST_TFLAG_FUNCTION | DST_TFLAG_CFUNCTION) | ||||
| #define DST_TFLAG_BYTES (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER) | ||||
| #define DST_TFLAG_INDEXED (DST_TFLAG_ARRAY | DST_TFLAG_TUPLE) | ||||
| #define DST_TFLAG_DICTIONARY (DST_TFLAG_TABLE | DST_TFLAG_STRUCT) | ||||
| #define DST_TFLAG_LENGTHABLE (DST_TFLAG_CHARS | DST_TFLAG_INDEXED | DST_TFLAG_DICTIONARY) | ||||
|  | ||||
| /* We provide two possible implemenations of Dsts. The preferred | ||||
|  * nanboxing approach, and the standard C version. Code in the rest of the | ||||
|  * application must interact through exposed interface. */ | ||||
|  | ||||
| /* Required interface for Dst */ | ||||
| /* wrap and unwrap for all types */ | ||||
| /* Get type quickly */ | ||||
| /* Check against type quickly */ | ||||
| /* Small footprint */ | ||||
| /* 32 bit integer support */ | ||||
|  | ||||
| /* dst_type(x) | ||||
|  * dst_checktype(x, t) | ||||
|  * dst_wrap_##TYPE(x) | ||||
|  * dst_unwrap_##TYPE(x) | ||||
|  * dst_truthy(x) | ||||
|  * dst_memclear(p, n) - clear memory for hash tables to nils | ||||
|  * dst_u64(x) - get 64 bits of payload for hashing | ||||
|  */ | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| union Dst { | ||||
|     uint64_t u64; | ||||
|     int64_t i64; | ||||
|     double real; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).u64) | ||||
|  | ||||
| /* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style | ||||
|  * 47 bit payload representaion is that the type bits are no long contiguous. Type | ||||
|  * checking can still be fast, but typewise polymorphism takes a bit longer. However,  | ||||
|  * hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers | ||||
|  * in a 48 bit address space (Linux on ARM). If DST_NANBOX_47 is set, use 47 bit tagged pointers. */ | ||||
|  | ||||
| /*                    |.......Tag.......|.......................Payload..................| */ | ||||
| /* Non-double:        t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
| /* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */ | ||||
|  | ||||
| /* Double (no NaNs):   x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
|  | ||||
| #if defined (DST_NANBOX_47) || defined (DST_32) | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF800000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu | ||||
|  | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((uint64_t)(type) | 0x1FFF0) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 47) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xF) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #else /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF000000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFllu | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1)) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 48) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #endif /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| /* 32 bit mode will not use the full payload for pointers. */ | ||||
| #ifdef DST_32 | ||||
|  | ||||
| #define DST_NANBOX_POINTERBITS 0xFFFFFFFFllu | ||||
| #else | ||||
| #define DST_NANBOX_POINTERBITS DST_NANBOX_PAYLOADBITS | ||||
| #endif | ||||
|  | ||||
| #define dst_nanbox_checkauxtype(x, type) \ | ||||
|     (((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type))) | ||||
|  | ||||
| #define dst_nanbox_isreal(x) \ | ||||
|     (!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL)) | ||||
|  | ||||
| #define dst_checktype(x, t) \ | ||||
|     (((t) == DST_REAL) \ | ||||
|         ? dst_nanbox_isreal(x) \ | ||||
|         : dst_nanbox_checkauxtype((x), (t))) | ||||
|  | ||||
| void *dst_nanbox_to_pointer(Dst x); | ||||
| void dst_nanbox_memempty(DstKV *mem, int32_t count); | ||||
| void *dst_nanbox_memalloc_empty(int32_t count); | ||||
| Dst dst_nanbox_from_pointer(void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_cpointer(const void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_double(double d); | ||||
| Dst dst_nanbox_from_bits(uint64_t bits); | ||||
|  | ||||
| #define dst_memempty(mem, len) dst_nanbox_memempty((mem), (len)) | ||||
| #define dst_memalloc_empty(count) dst_nanbox_memalloc_empty(count) | ||||
|  | ||||
| /* Todo - check for single mask operation */ | ||||
| #define dst_truthy(x) \ | ||||
|     (!(dst_checktype((x), DST_NIL) || dst_checktype((x), DST_FALSE))) | ||||
|  | ||||
| #define dst_nanbox_from_payload(t, p) \ | ||||
|     dst_nanbox_from_bits(dst_nanbox_tag(t) | (p)) | ||||
|  | ||||
| #define dst_nanbox_wrap_(p, t) \ | ||||
|     dst_nanbox_from_pointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| #define dst_nanbox_wrap_c(p, t) \ | ||||
|     dst_nanbox_from_cpointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| /* Wrap the simple types */ | ||||
| #define dst_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1) | ||||
| #define dst_wrap_true() dst_nanbox_from_payload(DST_TRUE, 1) | ||||
| #define dst_wrap_false() dst_nanbox_from_payload(DST_FALSE, 1) | ||||
| #define dst_wrap_boolean(b) dst_nanbox_from_payload((b) ? DST_TRUE : DST_FALSE, 1) | ||||
| #define dst_wrap_integer(i) dst_nanbox_from_payload(DST_INTEGER, (uint32_t)(i)) | ||||
| #define dst_wrap_real(r) dst_nanbox_from_double(r) | ||||
|  | ||||
| /* Unwrap the simple types */ | ||||
| #define dst_unwrap_boolean(x) \ | ||||
|     (dst_checktype(x, DST_TRUE)) | ||||
| #define dst_unwrap_integer(x) \ | ||||
|     ((int32_t)((x).u64 & 0xFFFFFFFFlu)) | ||||
| #define dst_unwrap_real(x) ((x).real) | ||||
|  | ||||
| /* Wrap the pointer types */ | ||||
| #define dst_wrap_struct(s) dst_nanbox_wrap_c((s), DST_STRUCT) | ||||
| #define dst_wrap_tuple(s) dst_nanbox_wrap_c((s), DST_TUPLE) | ||||
| #define dst_wrap_fiber(s) dst_nanbox_wrap_((s), DST_FIBER) | ||||
| #define dst_wrap_array(s) dst_nanbox_wrap_((s), DST_ARRAY) | ||||
| #define dst_wrap_table(s) dst_nanbox_wrap_((s), DST_TABLE) | ||||
| #define dst_wrap_buffer(s) dst_nanbox_wrap_((s), DST_BUFFER) | ||||
| #define dst_wrap_string(s) dst_nanbox_wrap_c((s), DST_STRING) | ||||
| #define dst_wrap_symbol(s) dst_nanbox_wrap_c((s), DST_SYMBOL) | ||||
| #define dst_wrap_abstract(s) dst_nanbox_wrap_((s), DST_ABSTRACT) | ||||
| #define dst_wrap_function(s) dst_nanbox_wrap_((s), DST_FUNCTION) | ||||
| #define dst_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION) | ||||
|  | ||||
| /* Unwrap the pointer types */ | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_table(x) ((DstTable *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_abstract(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_pointer(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)dst_nanbox_to_pointer(x)) | ||||
|  | ||||
| /* End of [#ifdef DST_NANBOX] */ | ||||
| #else | ||||
|  | ||||
| /* A general dst value type */ | ||||
| struct Dst { | ||||
|     union { | ||||
|         uint64_t u64; | ||||
|         double real; | ||||
|         int32_t integer; | ||||
|         void *pointer; | ||||
|         const void *cpointer; | ||||
|     } as; | ||||
|     DstType type; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).as.u64) | ||||
| #define dst_memempty(mem, count) memset((mem), 0, sizeof(DstKV) * (count)) | ||||
| #define dst_memalloc_empty(count) calloc((count), sizeof(DstKV)) | ||||
| #define dst_type(x) ((x).type) | ||||
| #define dst_checktype(x, t) ((x).type == (t)) | ||||
| #define dst_truthy(x) \ | ||||
|     ((x).type != DST_NIL && (x).type != DST_FALSE) | ||||
|  | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)(x).as.pointer) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)(x).as.pointer) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)(x).as.pointer) | ||||
| #define dst_unwrap_array(x) ((DstArray *)(x).as.pointer) | ||||
| #define dst_unwrap_table(x) ((DstTable *)(x).as.pointer) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)(x).as.pointer) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_abstract(x) ((x).as.pointer) | ||||
| #define dst_unwrap_pointer(x) ((x).as.pointer) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)(x).as.pointer) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)(x).as.pointer) | ||||
| #define dst_unwrap_boolean(x) ((x).type == DST_TRUE) | ||||
| #define dst_unwrap_integer(x) ((x).as.integer) | ||||
| #define dst_unwrap_real(x) ((x).as.real) | ||||
|  | ||||
| Dst dst_wrap_nil(void); | ||||
| Dst dst_wrap_real(double x); | ||||
| Dst dst_wrap_integer(int32_t x); | ||||
| Dst dst_wrap_true(void); | ||||
| Dst dst_wrap_false(void); | ||||
| Dst dst_wrap_boolean(int x); | ||||
| Dst dst_wrap_string(const uint8_t *x); | ||||
| Dst dst_wrap_symbol(const uint8_t *x); | ||||
| Dst dst_wrap_array(DstArray *x); | ||||
| Dst dst_wrap_tuple(const Dst *x); | ||||
| Dst dst_wrap_struct(const DstKV *x); | ||||
| Dst dst_wrap_fiber(DstFiber *x); | ||||
| Dst dst_wrap_buffer(DstBuffer *x); | ||||
| Dst dst_wrap_function(DstFunction *x); | ||||
| Dst dst_wrap_cfunction(DstCFunction x); | ||||
| Dst dst_wrap_table(DstTable *x); | ||||
| Dst dst_wrap_abstract(void *x); | ||||
|  | ||||
| /* End of tagged union implementation */ | ||||
| #endif | ||||
|  | ||||
| /* Hold components of arguments passed to DstCFunction. */ | ||||
| struct DstArgs { | ||||
|     int32_t n; | ||||
|     Dst *v; | ||||
|     Dst *ret; | ||||
| }; | ||||
|  | ||||
| /* Fiber flags */ | ||||
| #define DST_FIBER_FLAG_SIGNAL_WAITING (1 << 30) | ||||
|  | ||||
| /* Fiber signal masks. */ | ||||
| #define DST_FIBER_MASK_ERROR 2 | ||||
| #define DST_FIBER_MASK_DEBUG 4 | ||||
| #define DST_FIBER_MASK_YIELD 8 | ||||
|  | ||||
| #define DST_FIBER_MASK_USER0 (16 << 0) | ||||
| #define DST_FIBER_MASK_USER1 (16 << 1) | ||||
| #define DST_FIBER_MASK_USER2 (16 << 2) | ||||
| #define DST_FIBER_MASK_USER3 (16 << 3) | ||||
| #define DST_FIBER_MASK_USER4 (16 << 4) | ||||
| #define DST_FIBER_MASK_USER5 (16 << 5) | ||||
| #define DST_FIBER_MASK_USER6 (16 << 6) | ||||
| #define DST_FIBER_MASK_USER7 (16 << 7) | ||||
| #define DST_FIBER_MASK_USER8 (16 << 8) | ||||
| #define DST_FIBER_MASK_USER9 (16 << 9) | ||||
|  | ||||
| #define DST_FIBER_MASK_USERN(N) (16 << (N)) | ||||
| #define DST_FIBER_MASK_USER 0x3FF0 | ||||
|  | ||||
| #define DST_FIBER_STATUS_MASK 0xFF0000 | ||||
| #define DST_FIBER_STATUS_OFFSET 16 | ||||
|  | ||||
| /* A lightweight green thread in dst. Does not correspond to | ||||
|  * operating system threads. */ | ||||
| struct DstFiber { | ||||
|     Dst *data; | ||||
|     DstFiber *child; /* Keep linked list of fibers for restarting pending fibers */ | ||||
|     DstFunction *root; /* First value */ | ||||
|     int32_t frame; /* Index of the stack frame */ | ||||
|     int32_t stackstart; /* Beginning of next args */ | ||||
|     int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ | ||||
|     int32_t capacity; | ||||
|     int32_t maxstack; /* Arbitrary defined limit for stack overflow */ | ||||
|     uint32_t flags; /* Various flags */ | ||||
| }; | ||||
|  | ||||
| /* Mark if a stack frame is a tail call for debugging */ | ||||
| #define DST_STACKFRAME_TAILCALL 1 | ||||
|  | ||||
| /* A stack frame on the fiber. Is stored along with the stack values. */ | ||||
| struct DstStackFrame { | ||||
|     DstFunction *func; | ||||
|     uint32_t *pc; | ||||
|     DstFuncEnv *env; | ||||
|     int32_t prevframe; | ||||
|     uint32_t flags; | ||||
| }; | ||||
|  | ||||
| /* Number of Dsts a frame takes up in the stack */ | ||||
| #define DST_FRAME_SIZE ((sizeof(DstStackFrame) + sizeof(Dst) - 1) / sizeof(Dst)) | ||||
|  | ||||
| /* A dynamic array type. */ | ||||
| struct DstArray { | ||||
|     Dst *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A bytebuffer type. Used as a mutable string or string builder. */ | ||||
| struct DstBuffer { | ||||
|     uint8_t *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A mutable associative data type. Backed by a hashtable. */ | ||||
| struct DstTable { | ||||
|     DstKV *data; | ||||
|     DstTable *proto; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
|     int32_t deleted; | ||||
| }; | ||||
|  | ||||
| /* A key value pair in a struct or table */ | ||||
| struct DstKV { | ||||
|     Dst key; | ||||
|     Dst value; | ||||
| }; | ||||
|  | ||||
| /* Some function defintion flags */ | ||||
| #define DST_FUNCDEF_FLAG_VARARG 0x10000 | ||||
| #define DST_FUNCDEF_FLAG_NEEDSENV 0x20000 | ||||
| #define DST_FUNCDEF_FLAG_FIXARITY 0x40000 | ||||
| #define DST_FUNCDEF_FLAG_TAG 0xFFFF | ||||
|  | ||||
| /* Source mapping structure for a bytecode instruction */ | ||||
| struct DstSourceMapping { | ||||
|     int32_t line; | ||||
|     int32_t column; | ||||
| }; | ||||
|  | ||||
| /* A function definition. Contains information needed to instantiate closures. */ | ||||
| struct DstFuncDef { | ||||
|     int32_t *environments; /* Which environments to capture from parent. */ | ||||
|     Dst *constants; | ||||
|     DstFuncDef **defs; | ||||
|     uint32_t *bytecode; | ||||
|  | ||||
|     /* Various debug information */ | ||||
|     DstSourceMapping *sourcemap; | ||||
|     const uint8_t *source; | ||||
|     const uint8_t *name; | ||||
|  | ||||
|     uint32_t flags; | ||||
|     int32_t slotcount; /* The amount of stack space required for the function */ | ||||
|     int32_t arity; /* Not including varargs */ | ||||
|     int32_t constants_length; | ||||
|     int32_t bytecode_length; | ||||
|     int32_t environments_length;  | ||||
|     int32_t defs_length;  | ||||
| }; | ||||
|  | ||||
| #define DST_PARSEFLAG_SOURCEMAP 1 | ||||
|  | ||||
| /* A fuction environment */ | ||||
| struct DstFuncEnv { | ||||
|     union { | ||||
|         DstFiber *fiber; | ||||
|         Dst *values; | ||||
|     } as; | ||||
|     int32_t length; /* Size of environment */ | ||||
|     int32_t offset; /* Stack offset when values still on stack. If offset is <= 0, then | ||||
|         environment is no longer on the stack. */ | ||||
| }; | ||||
|  | ||||
| /* A function */ | ||||
| struct DstFunction { | ||||
|     DstFuncDef *def; | ||||
|     DstFuncEnv *envs[]; | ||||
| }; | ||||
|  | ||||
| typedef struct DstParseState DstParseState; | ||||
| typedef struct DstParser DstParser; | ||||
|  | ||||
| enum DstParserStatus { | ||||
|     DST_PARSE_ROOT, | ||||
|     DST_PARSE_ERROR, | ||||
|     DST_PARSE_FULL, | ||||
|     DST_PARSE_PENDING | ||||
| }; | ||||
|  | ||||
| /* A dst parser */ | ||||
| struct DstParser { | ||||
|     Dst* args; | ||||
|     const char *error; | ||||
|     DstParseState *states; | ||||
|     uint8_t *buf; | ||||
|     size_t argcount; | ||||
|     size_t argcap; | ||||
|     size_t statecount; | ||||
|     size_t statecap; | ||||
|     size_t bufcount; | ||||
|     size_t bufcap; | ||||
|     size_t line; | ||||
|     size_t col; | ||||
|     int lookback; | ||||
| }; | ||||
|  | ||||
| /* Defines an abstract type */ | ||||
| struct DstAbstractType { | ||||
|     const char *name; | ||||
|     int (*gc)(void *data, size_t len); | ||||
|     int (*gcmark)(void *data, size_t len); | ||||
| }; | ||||
|  | ||||
| /* Contains information about userdata */ | ||||
| struct DstAbstractHeader { | ||||
|     const DstAbstractType *type; | ||||
|     size_t size; | ||||
| }; | ||||
|  | ||||
| struct DstReg { | ||||
|     const char *name; | ||||
|     DstCFunction cfun; | ||||
| }; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_TYPES_H_defined */ | ||||
							
								
								
									
										0
									
								
								src/include/generated/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/include/generated/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3636
									
								
								src/include/generated/boot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3636
									
								
								src/include/generated/boot.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										193
									
								
								src/include/generated/init.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								src/include/generated/init.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| /* Auto generated - DO NOT EDIT */ | ||||
|  | ||||
| static const unsigned char dst_mainclient_init[] = { | ||||
| 	0x23, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, | ||||
| 	0x74, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x32, 0x30, 0x31, | ||||
| 	0x38, 0x20, 0x28, 0x43, 0x29, 0x20, 0x43, 0x61, 0x6C, 0x76, | ||||
| 	0x69, 0x6E, 0x20, 0x52, 0x6F, 0x73, 0x65, 0x0A, 0x28, 0x74, | ||||
| 	0x61, 0x62, 0x6C, 0x65, 0x2E, 0x73, 0x65, 0x74, 0x70, 0x72, | ||||
| 	0x6F, 0x74, 0x6F, 0x20, 0x40, 0x7B, 0x20, 0x31, 0x20, 0x32, | ||||
| 	0x7D, 0x20, 0x40, 0x7B, 0x7D, 0x29, 0x0A, 0x28, 0x64, 0x6F, | ||||
| 	0x0A, 0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, | ||||
| 	0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, | ||||
| 	0x6C, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, | ||||
| 	0x65, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x6E, 0x6F, 0x2D, | ||||
| 	0x66, 0x69, 0x6C, 0x65, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, | ||||
| 	0x76, 0x61, 0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, | ||||
| 	0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x72, | ||||
| 	0x61, 0x77, 0x2D, 0x73, 0x74, 0x64, 0x69, 0x6E, 0x2A, 0x20, | ||||
| 	0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x66, | ||||
| 	0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20, 0x20, 0x28, 0x76, | ||||
| 	0x61, 0x72, 0x20, 0x2A, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, | ||||
| 	0x6F, 0x70, 0x74, 0x73, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, | ||||
| 	0x76, 0x61, 0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, | ||||
| 	0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x65, | ||||
| 	0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E, 0x2D, 0x65, 0x72, 0x72, | ||||
| 	0x6F, 0x72, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, | ||||
| 	0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0A, 0x0A, | ||||
| 	0x20, 0x20, 0x23, 0x20, 0x46, 0x6C, 0x61, 0x67, 0x20, 0x68, | ||||
| 	0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x73, 0x0A, 0x20, 0x20, | ||||
| 	0x28, 0x64, 0x65, 0x66, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x6C, | ||||
| 	0x65, 0x72, 0x73, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, | ||||
| 	0x74, 0x65, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x22, | ||||
| 	0x68, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20, | ||||
| 	0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x20, 0x22, | ||||
| 	0x75, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x20, 0x22, 0x20, 0x28, | ||||
| 	0x67, 0x65, 0x74, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x30, | ||||
| 	0x29, 0x20, 0x22, 0x20, 0x5B, 0x6F, 0x70, 0x74, 0x69, 0x6F, | ||||
| 	0x6E, 0x73, 0x5D, 0x20, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, | ||||
| 	0x73, 0x2E, 0x2E, 0x2E, 0x22, 0x29, 0x0A, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x70, | ||||
| 	0x72, 0x69, 0x6E, 0x74, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, | ||||
| 	0x4F, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x61, 0x72, | ||||
| 	0x65, 0x3A, 0x0A, 0x20, 0x20, 0x2D, 0x68, 0x20, 0x53, 0x68, | ||||
| 	0x6F, 0x77, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, | ||||
| 	0x6C, 0x70, 0x0A, 0x20, 0x20, 0x2D, 0x76, 0x20, 0x50, 0x72, | ||||
| 	0x69, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x65, | ||||
| 	0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x74, 0x72, 0x69, | ||||
| 	0x6E, 0x67, 0x0A, 0x20, 0x20, 0x2D, 0x73, 0x20, 0x55, 0x73, | ||||
| 	0x65, 0x20, 0x72, 0x61, 0x77, 0x20, 0x73, 0x74, 0x64, 0x69, | ||||
| 	0x6E, 0x20, 0x69, 0x6E, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, | ||||
| 	0x6F, 0x66, 0x20, 0x67, 0x65, 0x74, 0x6C, 0x69, 0x6E, 0x65, | ||||
| 	0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x66, 0x75, 0x6E, 0x63, | ||||
| 	0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x69, 0x74, 0x79, 0x0A, | ||||
| 	0x20, 0x20, 0x2D, 0x65, 0x20, 0x45, 0x78, 0x65, 0x63, 0x75, | ||||
| 	0x74, 0x65, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, | ||||
| 	0x67, 0x20, 0x6F, 0x66, 0x20, 0x64, 0x73, 0x74, 0x0A, 0x20, | ||||
| 	0x20, 0x2D, 0x72, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x20, | ||||
| 	0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x20, 0x61, | ||||
| 	0x66, 0x74, 0x65, 0x72, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, | ||||
| 	0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x63, 0x72, | ||||
| 	0x69, 0x70, 0x74, 0x73, 0x0A, 0x20, 0x20, 0x2D, 0x70, 0x20, | ||||
| 	0x4B, 0x65, 0x65, 0x70, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x78, | ||||
| 	0x65, 0x63, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x66, | ||||
| 	0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, | ||||
| 	0x61, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6C, 0x65, 0x76, 0x65, | ||||
| 	0x6C, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x28, 0x70, | ||||
| 	0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x74, 0x29, | ||||
| 	0x0A, 0x20, 0x20, 0x2D, 0x2D, 0x20, 0x53, 0x74, 0x6F, 0x70, | ||||
| 	0x20, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x69, 0x6E, 0x67, 0x20, | ||||
| 	0x6F, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x60, 0x29, 0x0A, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x28, 0x6F, 0x73, 0x2E, 0x65, 0x78, 0x69, 0x74, 0x20, | ||||
| 	0x30, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x31, 0x29, 0x0A, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x22, 0x76, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20, | ||||
| 	0x5B, 0x5D, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x20, | ||||
| 	0x56, 0x45, 0x52, 0x53, 0x49, 0x4F, 0x4E, 0x29, 0x20, 0x28, | ||||
| 	0x6F, 0x73, 0x2E, 0x65, 0x78, 0x69, 0x74, 0x20, 0x30, 0x29, | ||||
| 	0x20, 0x31, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, | ||||
| 	0x73, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20, | ||||
| 	0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x72, 0x61, 0x77, 0x2D, 0x73, | ||||
| 	0x74, 0x64, 0x69, 0x6E, 0x2A, 0x20, 0x74, 0x72, 0x75, 0x65, | ||||
| 	0x29, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x73, 0x68, 0x6F, | ||||
| 	0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, 0x6C, 0x2A, 0x20, | ||||
| 	0x74, 0x72, 0x75, 0x65, 0x29, 0x20, 0x31, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x22, 0x20, 0x28, 0x66, | ||||
| 	0x6E, 0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, | ||||
| 	0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, | ||||
| 	0x6C, 0x2A, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x20, 0x31, | ||||
| 	0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x22, | ||||
| 	0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A, | ||||
| 	0x3D, 0x20, 0x2A, 0x65, 0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E, | ||||
| 	0x2D, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x2A, 0x20, 0x66, 0x61, | ||||
| 	0x6C, 0x73, 0x65, 0x29, 0x20, 0x31, 0x29, 0x0A, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x22, 0x2D, 0x22, 0x20, 0x28, 0x66, 0x6E, | ||||
| 	0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x68, | ||||
| 	0x61, 0x6E, 0x64, 0x6C, 0x65, 0x6F, 0x70, 0x74, 0x73, 0x2A, | ||||
| 	0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, 0x20, 0x31, 0x29, | ||||
| 	0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x22, 0x20, | ||||
| 	0x28, 0x66, 0x6E, 0x20, 0x5B, 0x69, 0x5D, 0x20, 0x0A, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x6E, 0x6F, 0x2D, 0x66, 0x69, | ||||
| 	0x6C, 0x65, 0x2A, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, | ||||
| 	0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x28, 0x65, 0x76, 0x61, 0x6C, 0x20, 0x28, 0x67, | ||||
| 	0x65, 0x74, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x28, 0x2B, | ||||
| 	0x20, 0x69, 0x20, 0x31, 0x29, 0x29, 0x29, 0x0A, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, | ||||
| 	0x29, 0x7D, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x28, 0x64, 0x65, | ||||
| 	0x66, 0x6E, 0x2D, 0x20, 0x64, 0x6F, 0x68, 0x61, 0x6E, 0x64, | ||||
| 	0x6C, 0x65, 0x72, 0x20, 0x5B, 0x6E, 0x20, 0x69, 0x5D, 0x0A, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66, 0x20, 0x68, | ||||
| 	0x20, 0x28, 0x67, 0x65, 0x74, 0x20, 0x68, 0x61, 0x6E, 0x64, | ||||
| 	0x6C, 0x65, 0x72, 0x73, 0x20, 0x6E, 0x29, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20, 0x68, 0x20, 0x28, | ||||
| 	0x68, 0x20, 0x69, 0x29, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E, | ||||
| 	0x74, 0x20, 0x22, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, | ||||
| 	0x20, 0x66, 0x6C, 0x61, 0x67, 0x20, 0x2D, 0x22, 0x20, 0x6E, | ||||
| 	0x29, 0x29, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x23, 0x20, 0x50, | ||||
| 	0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x72, 0x67, | ||||
| 	0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x0A, 0x20, 0x20, 0x28, | ||||
| 	0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x31, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x28, 0x64, 0x65, 0x66, 0x20, 0x6C, 0x65, 0x6E, 0x61, | ||||
| 	0x72, 0x67, 0x73, 0x20, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74, | ||||
| 	0x68, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x28, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x3C, | ||||
| 	0x20, 0x69, 0x20, 0x6C, 0x65, 0x6E, 0x61, 0x72, 0x67, 0x73, | ||||
| 	0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66, | ||||
| 	0x20, 0x61, 0x72, 0x67, 0x20, 0x28, 0x67, 0x65, 0x74, 0x20, | ||||
| 	0x61, 0x72, 0x67, 0x73, 0x20, 0x69, 0x29, 0x29, 0x0A, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20, 0x28, 0x61, 0x6E, | ||||
| 	0x64, 0x20, 0x2A, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x6F, | ||||
| 	0x70, 0x74, 0x73, 0x2A, 0x20, 0x28, 0x3D, 0x20, 0x22, 0x2D, | ||||
| 	0x22, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, | ||||
| 	0x73, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x72, 0x67, 0x20, | ||||
| 	0x30, 0x20, 0x31, 0x29, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x28, 0x2B, 0x3D, 0x20, 0x69, 0x20, 0x28, | ||||
| 	0x64, 0x6F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x20, | ||||
| 	0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x73, 0x6C, | ||||
| 	0x69, 0x63, 0x65, 0x20, 0x61, 0x72, 0x67, 0x20, 0x31, 0x20, | ||||
| 	0x32, 0x29, 0x20, 0x69, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x28, 0x64, 0x6F, 0x0A, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, | ||||
| 	0x6E, 0x6F, 0x2D, 0x66, 0x69, 0x6C, 0x65, 0x2A, 0x20, 0x66, | ||||
| 	0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x28, 0x69, 0x6D, 0x70, 0x6F, 0x72, | ||||
| 	0x74, 0x2A, 0x20, 0x5F, 0x65, 0x6E, 0x76, 0x20, 0x61, 0x72, | ||||
| 	0x67, 0x20, 0x3A, 0x65, 0x78, 0x69, 0x74, 0x20, 0x2A, 0x65, | ||||
| 	0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E, 0x2D, 0x65, 0x72, 0x72, | ||||
| 	0x6F, 0x72, 0x2A, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x28, 0x2B, 0x2B, 0x20, 0x69, 0x29, 0x29, | ||||
| 	0x29, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x28, 0x77, 0x68, 0x65, | ||||
| 	0x6E, 0x20, 0x28, 0x6F, 0x72, 0x20, 0x2A, 0x73, 0x68, 0x6F, | ||||
| 	0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, 0x6C, 0x2A, 0x20, | ||||
| 	0x2A, 0x6E, 0x6F, 0x2D, 0x66, 0x69, 0x6C, 0x65, 0x2A, 0x29, | ||||
| 	0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20, | ||||
| 	0x2A, 0x72, 0x61, 0x77, 0x2D, 0x73, 0x74, 0x64, 0x69, 0x6E, | ||||
| 	0x2A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72, | ||||
| 	0x65, 0x70, 0x6C, 0x20, 0x6E, 0x69, 0x6C, 0x20, 0x69, 0x64, | ||||
| 	0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x29, 0x0A, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x6F, 0x0A, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x70, 0x72, 0x69, | ||||
| 	0x6E, 0x74, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, | ||||
| 	0x20, 0x22, 0x44, 0x73, 0x74, 0x20, 0x22, 0x20, 0x56, 0x45, | ||||
| 	0x52, 0x53, 0x49, 0x4F, 0x4E, 0x20, 0x22, 0x20, 0x20, 0x43, | ||||
| 	0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, | ||||
| 	0x43, 0x29, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x32, 0x30, | ||||
| 	0x31, 0x38, 0x20, 0x43, 0x61, 0x6C, 0x76, 0x69, 0x6E, 0x20, | ||||
| 	0x52, 0x6F, 0x73, 0x65, 0x22, 0x29, 0x29, 0x0A, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72, 0x65, 0x70, | ||||
| 	0x6C, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x62, 0x75, 0x66, | ||||
| 	0x20, 0x70, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x28, 0x64, 0x65, 0x66, 0x20, 0x5B, 0x6C, 0x69, 0x6E, 0x65, | ||||
| 	0x5D, 0x20, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x2E, | ||||
| 	0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x70, 0x29, 0x29, 0x0A, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66, | ||||
| 	0x20, 0x70, 0x72, 0x6F, 0x6D, 0x70, 0x74, 0x20, 0x28, 0x73, | ||||
| 	0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x22, 0x64, 0x73, 0x74, | ||||
| 	0x3A, 0x22, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x22, 0x3A, | ||||
| 	0x22, 0x20, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x2E, | ||||
| 	0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x70, 0x29, 0x20, 0x22, | ||||
| 	0x3E, 0x20, 0x22, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||
| 	0x20, 0x20, 0x28, 0x67, 0x65, 0x74, 0x6C, 0x69, 0x6E, 0x65, | ||||
| 	0x20, 0x70, 0x72, 0x6F, 0x6D, 0x70, 0x74, 0x20, 0x62, 0x75, | ||||
| 	0x66, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x0A | ||||
| }; | ||||
|  | ||||
| @@ -1,53 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_STRBINSEARCH_H_defined | ||||
| #define DST_STRBINSEARCH_H_defined | ||||
|  | ||||
| /* Do a binary search on a static array of structs. Each struct must | ||||
|  * have a string as its first element, and the struct must be sorted | ||||
|  * lexogrpahically by that element. */ | ||||
| static const void *dst_strbinsearch( | ||||
|         const void *tab, | ||||
|         size_t tabcount, | ||||
|         size_t itemsize, | ||||
|         const uint8_t *key) { | ||||
|     size_t low = 0; | ||||
|     size_t hi = tabcount; | ||||
|     const char *t = (const char *)tab; | ||||
|     while (low < hi) { | ||||
|         size_t mid = low + ((hi - low) / 2); | ||||
|         const char **item = (const char **)(t + mid * itemsize); | ||||
|         const char *name = *item; | ||||
|         int comp = dst_cstrcmp(key, name); | ||||
|         if (comp < 0) { | ||||
|             hi = mid; | ||||
|         } else if (comp > 0) { | ||||
|             low = mid + 1; | ||||
|         } else { | ||||
|             return (const void *)item; | ||||
|         } | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -1,4 +1,5 @@ | ||||
| # Copyright 2017-2018 (C) Calvin Rose | ||||
| (table.setproto @{ 1 2} @{}) | ||||
| (do | ||||
|  | ||||
|   (var *should-repl* :private false) | ||||
|   | ||||
| @@ -83,8 +83,6 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c | ||||
| #include <string.h> | ||||
| #include <signal.h> | ||||
|  | ||||
| #include <headerlibs/vector.h> | ||||
|  | ||||
| /* static state */ | ||||
| #define DST_LINE_MAX 1024 | ||||
| #define DST_HISTORY_MAX 100 | ||||
| @@ -95,7 +93,8 @@ static char buf[DST_LINE_MAX]; | ||||
| static int len = 0; | ||||
| static int pos = 0; | ||||
| static int cols = 80; | ||||
| static char **history = NULL; | ||||
| static char *history[DST_HISTORY_MAX]; | ||||
| static int history_count = 0; | ||||
| static int historyi = 0; | ||||
| static struct termios termios_start; | ||||
|  | ||||
| @@ -238,7 +237,7 @@ static int insert(char c) { | ||||
| } | ||||
|  | ||||
| static void historymove(int delta) { | ||||
|     if (dst_v_count(history) > 1) { | ||||
|     if (history_count > 1) { | ||||
|         free(history[historyi]); | ||||
|         history[historyi] = sdup(buf); | ||||
|  | ||||
| @@ -246,8 +245,8 @@ static void historymove(int delta) { | ||||
|         if (historyi < 0) { | ||||
|             historyi = 0; | ||||
|             return; | ||||
|         } else if (historyi >= dst_v_count(history)) { | ||||
|             historyi = dst_v_count(history) - 1; | ||||
|         } else if (historyi >= history_count) { | ||||
|             historyi = history_count - 1; | ||||
|             return; | ||||
|         } | ||||
|         strncpy(buf, history[historyi], DST_LINE_MAX); | ||||
| @@ -262,9 +261,9 @@ static void addhistory() { | ||||
|     int i, len; | ||||
|     char *newline = sdup(buf); | ||||
|     if (!newline) return; | ||||
|     len = dst_v_count(history); | ||||
|     len = history_count; | ||||
|     if (len < DST_HISTORY_MAX) { | ||||
|         dst_v_push(history, newline); | ||||
|         history[history_count++] = newline; | ||||
|         len++; | ||||
|     } else { | ||||
|         free(history[DST_HISTORY_MAX - 1]); | ||||
| @@ -429,9 +428,8 @@ void dst_line_init() { | ||||
| void dst_line_deinit() { | ||||
|     int i; | ||||
|     norawmode(); | ||||
|     for (i = 0; i < dst_v_count(history); i++) | ||||
|     for (i = 0; i < history_count; i++) | ||||
|         free(history[i]); | ||||
|     dst_v_free(history); | ||||
|     historyi = 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -21,9 +21,8 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcompile.h> | ||||
|  | ||||
| #include "clientinit.gen.h" | ||||
| #include <generated/init.h> | ||||
| #include "line.h" | ||||
|  | ||||
| int main(int argc, char **argv) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose