mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	More work on compiler. Add compiler unit test that currently
segfaults alot. Added dst_disasm to reconstruct dsts assembly from a funcdef.
This commit is contained in:
		
							
								
								
									
										230
									
								
								3
									
									
									
									
									
								
							
							
						
						
									
										230
									
								
								3
									
									
									
									
									
								
							| @@ -1,230 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2017 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_COMPILE_H |  | ||||||
| #define DST_COMPILE_H |  | ||||||
|  |  | ||||||
| #include <dst/dst.h> |  | ||||||
| #include <setjmp.h> |  | ||||||
|  |  | ||||||
| /* Compiler typedefs */ |  | ||||||
| typedef struct DstCompiler DstCompiler; |  | ||||||
| typedef struct FormOptions FormOptions; |  | ||||||
| typedef struct SlotTracker SlotTracker; |  | ||||||
| typedef struct DstScope DstScope; |  | ||||||
| typedef struct DstCFunctionOptimizer DstCFunctionOptimizer; |  | ||||||
|  |  | ||||||
| #define DST_SLOT_CONSTANT 0x10000 |  | ||||||
| #define DST_SLOT_NAMED 0x20000 |  | ||||||
| #define DST_SLOT_RETURNED 0x40000 |  | ||||||
| #define DST_SLOT_NIL 0x80000 |  | ||||||
| #define DST_SLOT_MUTABLE 0x100000 |  | ||||||
|  |  | ||||||
| #define DST_SLOTTYPE_ANY 0xFFFF |  | ||||||
|  |  | ||||||
| /* A stack slot */ |  | ||||||
| struct DstSlot { |  | ||||||
|     int32_t index; |  | ||||||
|     int32_t envindex; /* 0 is local, positive number is an upvalue */ |  | ||||||
|     uint32_t flags; |  | ||||||
|     DstValue constant; /* If the slot has a constant value */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Most forms that return a constant will not generate any bytecode */ |  | ||||||
|  |  | ||||||
| /* Special forms that need support */ |  | ||||||
| /* cond |  | ||||||
|  * while (continue, break) |  | ||||||
|  * quote |  | ||||||
|  * fn |  | ||||||
|  * def |  | ||||||
|  * var |  | ||||||
|  * varset |  | ||||||
|  * do |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #define DST_OPTIMIZER_CONSTANTS 0x10000 |  | ||||||
| #define DST_OPTIMIZER_BYTECODE 0x20000 |  | ||||||
| #define DST_OPTIMIZER_PARTIAL_CONSTANTS 0x40000 |  | ||||||
| #define DST_OPTIMIZER_SYSCALL 0x80000 |  | ||||||
|  |  | ||||||
| /* A grouping of optimization on a cfunction given certain conditions |  | ||||||
|  * on the arguments (such as all constants, or some known types). The appropriate |  | ||||||
|  * optimizations should be tried before compiling a normal function call. */ |  | ||||||
| struct DstCFunctionOptimizer { |  | ||||||
|     uint32_t flags; /* Indicate what kind of optimizations can be performed. */ |  | ||||||
|         /*Also what kind of types can be returned*/ |  | ||||||
|     int32_t syscall; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define DST_SCOPE_FUNCTION 1 |  | ||||||
| #define DST_SCOPE_LASTSLOT 2 |  | ||||||
| #define DST_SCOPE_FIRSTSLOT 4 |  | ||||||
| #define DST_SCOPE_ENV |  | ||||||
|  |  | ||||||
| /* A lexical scope during compilation */ |  | ||||||
| struct DstScope { |  | ||||||
|     DstArray constants; /* Constants for the funcdef */ |  | ||||||
|     DstTable symbols; /* Map symbols -> Slot inidices */ |  | ||||||
|  |  | ||||||
|     /* Hold all slots in use. Data structures that store |  | ||||||
|      * slots should link them to this datatstructure */ |  | ||||||
|     DstSlot *slots; |  | ||||||
|     int32_t slotcount; |  | ||||||
|     int32_t slotcap; |  | ||||||
|  |  | ||||||
|     /* A vector of freed slots. */ |  | ||||||
|     int32_t *freeslots; |  | ||||||
|     int32_t freeslotcount; |  | ||||||
|     int32_t freeslotcap; |  | ||||||
|  |  | ||||||
|     int32_t lastslot; |  | ||||||
|     int32_t nextslot; |  | ||||||
|  |  | ||||||
|     /* Referenced closure environemts. The values at each index correspond |  | ||||||
|      * to which index to get the environment from in the parent. The enironment |  | ||||||
|      * that corresponds to the direct parent's stack will always have value 0. */ |  | ||||||
|     int32_t *envs; |  | ||||||
|     int32_t envcount; |  | ||||||
|     int32_t envcap; |  | ||||||
|  |  | ||||||
|     int32_t buffer_offset; /* Where the bytecode for this scope begins */ |  | ||||||
|  |  | ||||||
|     uint32_t flags; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Compilation state */ |  | ||||||
| struct DstCompiler { |  | ||||||
|     jump_buf on_error; |  | ||||||
|     int32_t scopecount; |  | ||||||
|     int32_t scopecap; |  | ||||||
|     DstScope *scopes; |  | ||||||
|     DstBuffer buffer; |  | ||||||
|     DstBuffer mapbuffer; |  | ||||||
|     int32_t error_start; |  | ||||||
|     int32_t error_end; |  | ||||||
|     DstValue error; |  | ||||||
|     int recursion_guard; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #define DST_FOPTS_TAIL 0x10000 |  | ||||||
| #define DST_FOPTS_FORCESLOT 0x20000 |  | ||||||
|  |  | ||||||
| /* Compiler state */ |  | ||||||
| struct DstFormOptions { |  | ||||||
|     DstCompiler *compiler; |  | ||||||
|     DstValue x; |  | ||||||
|     const DstValue *sourcemap; |  | ||||||
|     uint32_t flags; /* bit set of accepted primitive types */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| typedef enum DstCompileStatus { |  | ||||||
|     DST_COMPILE_OK, |  | ||||||
|     DST_COMPILE_ERROR |  | ||||||
| } DstCompileStatus; |  | ||||||
|  |  | ||||||
| /* Results of compilation */ |  | ||||||
| typedef struct DstCompileResults { |  | ||||||
|     DstCompileStatus status; |  | ||||||
|     DstFuncDef *funcdef; |  | ||||||
|     const uint8_t *error; |  | ||||||
| } DstCompileResults; |  | ||||||
|  |  | ||||||
| typedef struct DstCompileOptions { |  | ||||||
|     uint32_t flags; |  | ||||||
|     const DstValue *sourcemap; |  | ||||||
|     DstValue src; |  | ||||||
|     int32_t target; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* Compiler handlers. Used to compile different kinds of expressions. */ |  | ||||||
| typedef DstSlot (*DstFormCompiler)(DstFormOptions opts); |  | ||||||
|  |  | ||||||
| /* Dispatch to correct form compiler */ |  | ||||||
| DstSlot dst_compile_value(DstFormOptions opts); |  | ||||||
|  |  | ||||||
| /* Compile basic types */ |  | ||||||
| DstSlot dst_compile_constant(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_symbol(DstFormOptions opts); |  | ||||||
| DstSlot dst_copmile_array(DstFormOptions opts); |  | ||||||
| DstSlot dst_copmile_struct(DstFormOptions opts); |  | ||||||
| DstSlot dst_copmile_table(DstFormOptions opts); |  | ||||||
|  |  | ||||||
| /* Tuple compiliation will handle much of the work */ |  | ||||||
| DstSlot dst_compile_tuple(DstFormOptions opts); |  | ||||||
|  |  | ||||||
| /* Compile special forms */ |  | ||||||
| DstSlot dst_compile_do(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_fn(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_cond(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_while(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_quote(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_def(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_var(DstFormOptions opts); |  | ||||||
| DstSlot dst_compile_varset(DstFormOptions opts); |  | ||||||
|  |  | ||||||
| /* Compile source code into FuncDef. */ |  | ||||||
| DstCompileResults dst_compile(DstCompileOptions opts); |  | ||||||
|  |  | ||||||
| /****************************************************/ |  | ||||||
|  |  | ||||||
| DstSlot dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m); |  | ||||||
| DstSlot dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m); |  | ||||||
|  |  | ||||||
| /* Use these to get sub options. They will traverse the source map so |  | ||||||
|  * compiler errors make sense. Then modify the returned options. */ |  | ||||||
| DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index); |  | ||||||
| DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key); |  | ||||||
| DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key); |  | ||||||
|  |  | ||||||
| void dst_compile_scope(DstCompiler *c, int newfn); |  | ||||||
| DstSlot dst_compile_popscope(DstCompiler *c); |  | ||||||
|  |  | ||||||
| int dst_compile_slotmatch(DstFormOptions opts, DstSlot slot); |  | ||||||
| DstSlot dst_compile_normalslot(DstCompiler *c, uint32_t types); |  | ||||||
| DstSlot dst_compile_constantslot(DstCompiler *c, DstValue x); |  | ||||||
| void dst_compile_freeslot(DstCompiler *c, DstSlot slot); |  | ||||||
| void dst_compile_freeslotarray(DstCompiler *c, DstArray *slots); |  | ||||||
|  |  | ||||||
| /* Search for a symbol */ |  | ||||||
| DstSlot dst_compile_resolve(DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym); |  | ||||||
|  |  | ||||||
| /* Get a local slot that can be used as the desination for whatever is compiling. */ |  | ||||||
| DstSlot dst_compile_targetslot(DstFormOptions opts, DstSlot s); |  | ||||||
|  |  | ||||||
| /* Coerce any slot into the target slot. If no target is specified, return |  | ||||||
|  * the slot unaltered. Otherwise, move and load upvalues as necesarry to set the slot. */ |  | ||||||
| DstSlot dst_compile_coercetargetslot(DstFormOptions opts, DstSlot s); |  | ||||||
|  |  | ||||||
| DstSlot dst_compile_realizeslot(DstCompiler *c, DstSlot s); |  | ||||||
| DstSlot dst_compile_returnslot(DstCompiler *c, DstSlot s); |  | ||||||
|  |  | ||||||
| /* Emit instructions. */ |  | ||||||
|  |  | ||||||
| DstSlot dst_compile_emit_movenear(DstCompiler *c, DstSlot slot); |  | ||||||
| void dst_compile_emit_movefar(DstCompiler *c, DstSlot near, DstSlot orig); |  | ||||||
|  |  | ||||||
| void dst_compile_emit_ss(DstCompiler *c, DstOpCode op, DstSlot dest, DstSlot src); |  | ||||||
| void dst_compile_emit_sss(DstCompiler *c, DstOpCode op, DstSlot dest, DstSlot s1, DstSlot s2); |  | ||||||
| void dst_compile_emit_sss_src(DstCompiler *c, DstOpCode op, DstSlot s1, DstSlot s2, DstSlot s3); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -59,7 +59,8 @@ $(DST_XXD): libs/xxd.c | |||||||
| ################################### | ################################### | ||||||
|  |  | ||||||
| DST_CORE_SOURCES=$(addprefix core/,\ | DST_CORE_SOURCES=$(addprefix core/,\ | ||||||
| 				 array.c asm.c buffer.c compile.c fiber.c func.c gc.c parse.c string.c strtod.c\ | 				 array.c asm.c buffer.c compile.c compile_slotpool.c \ | ||||||
|  | 				 fiber.c func.c gc.c parse.c string.c strtod.c\ | ||||||
| 				 struct.c symcache.c syscalls.c table.c tuple.c userdata.c util.c\ | 				 struct.c symcache.c syscalls.c table.c tuple.c userdata.c util.c\ | ||||||
| 				 value.c vm.c wrap.c) | 				 value.c vm.c wrap.c) | ||||||
| DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES)) | DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES)) | ||||||
| @@ -78,7 +79,7 @@ $(DST_TARGET): $(DST_CORE_OBJECTS) | |||||||
| CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST | CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST | ||||||
|  |  | ||||||
| DST_UNIT_BINARIES=$(addprefix unittests/,\ | DST_UNIT_BINARIES=$(addprefix unittests/,\ | ||||||
| 				  asm_test.out array_test.out buffer_test.out fiber_test.out \ | 				  asm_test.out array_test.out buffer_test.out compile_test.out fiber_test.out \ | ||||||
| 				  parse_test.out strtod_test.out table_test.out) | 				  parse_test.out strtod_test.out table_test.out) | ||||||
|  |  | ||||||
| %.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h | %.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h | ||||||
| @@ -88,6 +89,7 @@ unit: $(DST_UNIT_BINARIES) | |||||||
| 	unittests/array_test.out | 	unittests/array_test.out | ||||||
| 	unittests/asm_test.out | 	unittests/asm_test.out | ||||||
| 	unittests/buffer_test.out | 	unittests/buffer_test.out | ||||||
|  | 	unittests/compile_test.out | ||||||
| 	unittests/fiber_test.out | 	unittests/fiber_test.out | ||||||
| 	unittests/parse_test.out | 	unittests/parse_test.out | ||||||
| 	unittests/strtod_test.out | 	unittests/strtod_test.out | ||||||
|   | |||||||
| @@ -24,11 +24,13 @@ | |||||||
|  |  | ||||||
| /* Iniializes an array */ | /* Iniializes an array */ | ||||||
| DstArray *dst_array_init(DstArray *array, int32_t capacity) { | DstArray *dst_array_init(DstArray *array, int32_t capacity) { | ||||||
|     if (capacity < 0) capacity = 0; |     DstValue *data = NULL; | ||||||
|     DstValue *data = (DstValue *) malloc(sizeof(DstValue) * capacity); |     if (capacity > 0) { | ||||||
|  |         data = (DstValue *) malloc(sizeof(DstValue) * capacity); | ||||||
|         if (NULL == data) { |         if (NULL == data) { | ||||||
|             DST_OUT_OF_MEMORY; |             DST_OUT_OF_MEMORY; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|     array->count = 0; |     array->count = 0; | ||||||
|     array->capacity = capacity; |     array->capacity = capacity; | ||||||
|     array->data = data; |     array->data = data; | ||||||
|   | |||||||
							
								
								
									
										203
									
								
								core/asm.c
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								core/asm.c
									
									
									
									
									
								
							| @@ -518,6 +518,9 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | |||||||
|     def->flags = 0; |     def->flags = 0; | ||||||
|     def->slotcount = 0; |     def->slotcount = 0; | ||||||
|     def->arity = 0; |     def->arity = 0; | ||||||
|  |     def->source = NULL; | ||||||
|  |     def->sourcepath = NULL; | ||||||
|  |     def->sourcemap = NULL; | ||||||
|     def->constants_length = 0; |     def->constants_length = 0; | ||||||
|     def->bytecode_length = 0; |     def->bytecode_length = 0; | ||||||
|     def->environments_length = 1; |     def->environments_length = 1; | ||||||
| @@ -544,7 +547,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | |||||||
|             dst_asm_deinit(&a); |             dst_asm_deinit(&a); | ||||||
|             longjmp(a.parent->on_error, 1); |             longjmp(a.parent->on_error, 1); | ||||||
|         } |         } | ||||||
|         result.result.error = a.errmessage; |         result.error = a.errmessage; | ||||||
|         result.status = DST_ASSEMBLE_ERROR; |         result.status = DST_ASSEMBLE_ERROR; | ||||||
|         if (a.errmap != NULL) { |         if (a.errmap != NULL) { | ||||||
|             result.error_start = dst_unwrap_integer(a.errmap[0]); |             result.error_start = dst_unwrap_integer(a.errmap[0]); | ||||||
| @@ -560,6 +563,23 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | |||||||
|     x = dst_struct_get(st, dst_csymbolv("arity")); |     x = dst_struct_get(st, dst_csymbolv("arity")); | ||||||
|     def->arity = dst_checktype(x, DST_INTEGER) ? dst_unwrap_integer(x) : 0; |     def->arity = dst_checktype(x, DST_INTEGER) ? dst_unwrap_integer(x) : 0; | ||||||
|  |  | ||||||
|  |     /* Check vararg */ | ||||||
|  |     x = dst_struct_get(st, dst_csymbolv("vararg")); | ||||||
|  |     if (dst_truthy(x)) | ||||||
|  |         def->flags |= DST_FUNCDEF_FLAG_VARARG; | ||||||
|  |  | ||||||
|  |     /* Check source */ | ||||||
|  |     x = dst_struct_get(st, dst_csymbolv("source")); | ||||||
|  |     if (dst_checktype(x, DST_STRING)) { | ||||||
|  |         def->source = dst_unwrap_string(x); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Check source path */ | ||||||
|  |     x = dst_struct_get(st, dst_csymbolv("sourcepath")); | ||||||
|  |     if (dst_checktype(x, DST_STRING)) { | ||||||
|  |         def->sourcepath = dst_unwrap_string(x); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Create slot aliases */ |     /* Create slot aliases */ | ||||||
|     x = dst_struct_get(st, dst_csymbolv("slots")); |     x = dst_struct_get(st, dst_csymbolv("slots")); | ||||||
|     if (dst_seq_view(x, &arr, &count)) { |     if (dst_seq_view(x, &arr, &count)) { | ||||||
| @@ -586,10 +606,10 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Create environment aliases */ |     /* Create environment aliases */ | ||||||
|     x = dst_struct_get(st, dst_csymbolv("environments")); |     x = dst_struct_get(st, dst_csymbolv("captures")); | ||||||
|     if (dst_seq_view(x, &arr, &count)) { |     if (dst_seq_view(x, &arr, &count)) { | ||||||
|         const DstValue *emap = |         const DstValue *emap = | ||||||
|             dst_parse_submap_value(opts.sourcemap, dst_csymbolv("environments")); |             dst_parse_submap_value(opts.sourcemap, dst_csymbolv("captures")); | ||||||
|         for (i = 0; i < count; i++) { |         for (i = 0; i < count; i++) { | ||||||
|             const DstValue *imap = dst_parse_submap_index(emap, i); |             const DstValue *imap = dst_parse_submap_index(emap, i); | ||||||
|             dst_asm_assert(&a, dst_checktype(arr[i], DST_SYMBOL), imap, "environment must be a symbol"); |             dst_asm_assert(&a, dst_checktype(arr[i], DST_SYMBOL), imap, "environment must be a symbol"); | ||||||
| @@ -691,11 +711,37 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | |||||||
|         dst_asm_error(&a, opts.sourcemap, "bytecode expected"); |         dst_asm_error(&a, opts.sourcemap, "bytecode expected"); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     /* Check for source mapping */ | ||||||
|  |     x = dst_struct_get(st, dst_csymbolv("sourcemap")); | ||||||
|  |     if (dst_seq_view(x, &arr, &count)) { | ||||||
|  |         const DstValue *bmap = | ||||||
|  |             dst_parse_submap_value(opts.sourcemap, dst_csymbolv("sourcemap")); | ||||||
|  |         dst_asm_assert(&a, count != 2 * def->bytecode_length, bmap, "sourcemap must have twice the length of the bytecode"); | ||||||
|  |         def->sourcemap = malloc(sizeof(int32_t) * 2 * count); | ||||||
|  |         for (i = 0; i < count; i += 2) { | ||||||
|  |             DstValue start = arr[i]; | ||||||
|  |             DstValue end = arr[i + 1]; | ||||||
|  |             if (!(dst_checktype(start, DST_INTEGER) || | ||||||
|  |                 dst_unwrap_integer(start) < 0)) { | ||||||
|  |                 const DstValue *submap = dst_parse_submap_index(bmap, i); | ||||||
|  |                 dst_asm_error(&a, submap, "expected positive integer"); | ||||||
|  |             } | ||||||
|  |             if (!(dst_checktype(end, DST_INTEGER) || | ||||||
|  |                 dst_unwrap_integer(end) < 0)) { | ||||||
|  |                 const DstValue *submap = dst_parse_submap_index(bmap, i + 1); | ||||||
|  |                 dst_asm_error(&a, submap, "expected positive integer"); | ||||||
|  |             } | ||||||
|  |             def->sourcemap[i] = dst_unwrap_integer(start); | ||||||
|  |             def->sourcemap[i+1] = dst_unwrap_integer(end); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Finish everything and return funcdef */ |     /* Finish everything and return funcdef */ | ||||||
|     dst_asm_deinit(&a); |     dst_asm_deinit(&a); | ||||||
|     def->environments = |     def->environments = | ||||||
|         realloc(def->environments, def->environments_length * sizeof(int32_t)); |         realloc(def->environments, def->environments_length * sizeof(int32_t)); | ||||||
|     result.result.def = def; |     result.funcdef = def; | ||||||
|     result.status = DST_ASSEMBLE_OK; |     result.status = DST_ASSEMBLE_OK; | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| @@ -711,7 +757,154 @@ DstFunction *dst_asm_func(DstAssembleResult result) { | |||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); |     DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); | ||||||
|     func->def = result.result.def; |     func->def = result.funcdef; | ||||||
|     func->envs = NULL; |     func->envs = NULL; | ||||||
|     return func; |     return func; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Disassembly */ | ||||||
|  |  | ||||||
|  | /* Find the deinfintion of an instruction given the instruction word. Return | ||||||
|  |  * NULL if not found. */ | ||||||
|  | static const DstInstructionDef *dst_asm_reverse_lookup(uint32_t instr) { | ||||||
|  |     size_t i; | ||||||
|  |     uint32_t opcode = instr & 0xFF; | ||||||
|  |     for (i = 0; i < sizeof(dst_ops)/sizeof(DstInstructionDef); i++) { | ||||||
|  |         const DstInstructionDef *def = dst_ops + i; | ||||||
|  |         if (def->opcode == opcode)  | ||||||
|  |             return def; | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Create some constant sized tuples */ | ||||||
|  | static DstValue tup1(DstValue x) { | ||||||
|  |     DstValue *tup = dst_tuple_begin(1); | ||||||
|  |     tup[0] = x; | ||||||
|  |     return dst_wrap_tuple(dst_tuple_end(tup)); | ||||||
|  | } | ||||||
|  | static DstValue tup2(DstValue x, DstValue y) { | ||||||
|  |     DstValue *tup = dst_tuple_begin(2); | ||||||
|  |     tup[0] = x; | ||||||
|  |     tup[1] = y; | ||||||
|  |     return dst_wrap_tuple(dst_tuple_end(tup)); | ||||||
|  | } | ||||||
|  | static DstValue tup3(DstValue x, DstValue y, DstValue z) { | ||||||
|  |     DstValue *tup = dst_tuple_begin(3); | ||||||
|  |     tup[0] = x; | ||||||
|  |     tup[1] = y; | ||||||
|  |     tup[2] = z; | ||||||
|  |     return dst_wrap_tuple(dst_tuple_end(tup)); | ||||||
|  | } | ||||||
|  | static DstValue tup4(DstValue w, DstValue x, DstValue y, DstValue z) { | ||||||
|  |     DstValue *tup = dst_tuple_begin(4); | ||||||
|  |     tup[0] = w; | ||||||
|  |     tup[1] = x; | ||||||
|  |     tup[2] = y; | ||||||
|  |     tup[3] = z; | ||||||
|  |     return dst_wrap_tuple(dst_tuple_end(tup)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Given an argument, convert it to the appriate integer or symbol */ | ||||||
|  | static DstValue dst_asm_decode_instruction(uint32_t instr) { | ||||||
|  |     const DstInstructionDef *def = dst_asm_reverse_lookup(instr); | ||||||
|  |     DstValue name; | ||||||
|  |     if (NULL == def) { | ||||||
|  |         return dst_wrap_integer((int32_t)instr); | ||||||
|  |     } | ||||||
|  |     name = dst_csymbolv(def->name); | ||||||
|  | #define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask)) | ||||||
|  |     switch (def->type) { | ||||||
|  |         case DIT_0: | ||||||
|  |             return tup1(name); | ||||||
|  |         case DIT_S: | ||||||
|  |             return tup2(name, dst_wrap_integer(oparg(1, 0xFFFFFF))); | ||||||
|  |         case DIT_L: | ||||||
|  |             return tup2(name, dst_wrap_integer((int32_t)instr >> 8)); | ||||||
|  |         case DIT_SS: | ||||||
|  |         case DIT_ST: | ||||||
|  |         case DIT_SC: | ||||||
|  |         case DIT_SU: | ||||||
|  |             return tup3(name,  | ||||||
|  |                     dst_wrap_integer(oparg(1, 0xFF)), | ||||||
|  |                     dst_wrap_integer(oparg(2, 0xFFFF))); | ||||||
|  |         case DIT_SI: | ||||||
|  |         case DIT_SL: | ||||||
|  |             return tup3(name,  | ||||||
|  |                     dst_wrap_integer(oparg(1, 0xFF)), | ||||||
|  |                     dst_wrap_integer((int32_t)instr >> 16)); | ||||||
|  |         case DIT_SSS: | ||||||
|  |         case DIT_SES: | ||||||
|  |         case DIT_SSU: | ||||||
|  |             return tup4(name,  | ||||||
|  |                     dst_wrap_integer(oparg(1, 0xFF)), | ||||||
|  |                     dst_wrap_integer(oparg(2, 0xFF)), | ||||||
|  |                     dst_wrap_integer(oparg(3, 0xFF))); | ||||||
|  |         case DIT_SSI: | ||||||
|  |             return tup4(name,  | ||||||
|  |                     dst_wrap_integer(oparg(1, 0xFF)), | ||||||
|  |                     dst_wrap_integer(oparg(2, 0xFF)), | ||||||
|  |                     dst_wrap_integer((int32_t)instr >> 24)); | ||||||
|  |     } | ||||||
|  | #undef oparg | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DstValue dst_disasm(DstFuncDef *def) { | ||||||
|  |     int32_t i; | ||||||
|  |     DstArray *bcode = dst_array(def->bytecode_length); | ||||||
|  |     DstArray *constants = dst_array(def->constants_length); | ||||||
|  |     DstTable *ret = dst_table(10); | ||||||
|  |     dst_table_put(ret, dst_csymbolv("arity"), dst_wrap_integer(def->arity)); | ||||||
|  |     dst_table_put(ret, dst_csymbolv("bytecode"), dst_wrap_array(bcode)); | ||||||
|  |     dst_table_put(ret, dst_csymbolv("constants"), dst_wrap_array(constants)); | ||||||
|  |     if (def->sourcepath) { | ||||||
|  |         dst_table_put(ret, dst_csymbolv("sourcepath"), dst_wrap_string(def->sourcepath)); | ||||||
|  |     } | ||||||
|  |     if (def->source) { | ||||||
|  |         dst_table_put(ret, dst_csymbolv("source"), dst_wrap_string(def->source)); | ||||||
|  |     } | ||||||
|  |     if (def->flags & DST_FUNCDEF_FLAG_VARARG) { | ||||||
|  |         dst_table_put(ret, dst_csymbolv("vararg"), dst_wrap_true()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Add constants */ | ||||||
|  |     for (i = 0; i < def->constants_length; i++) { | ||||||
|  |         DstValue src = def->constants[i]; | ||||||
|  |         DstValue dest; | ||||||
|  |         if (dst_checktype(src, DST_TUPLE)) { | ||||||
|  |             dest = tup2(dst_csymbolv("quote"), src); | ||||||
|  |         } else { | ||||||
|  |             dest = src; | ||||||
|  |         } | ||||||
|  |         constants->data[i] = dest; | ||||||
|  |     } | ||||||
|  |     constants->count = def->constants_length; | ||||||
|  |  | ||||||
|  |     /* Add bytecode */ | ||||||
|  |     for (i = 0; i < def->bytecode_length; i++) { | ||||||
|  |         bcode->data[i] = dst_asm_decode_instruction(def->bytecode[i]); | ||||||
|  |     } | ||||||
|  |     bcode->count = def->bytecode_length; | ||||||
|  |  | ||||||
|  |     /* Add source map */ | ||||||
|  |     if (def->sourcemap) { | ||||||
|  |         DstArray *sourcemap = dst_array(def->bytecode_length * 2); | ||||||
|  |         for (i = 0; i < def->bytecode_length * 2; i++) { | ||||||
|  |             sourcemap->data[i] = dst_wrap_integer(def->sourcemap[i]); | ||||||
|  |         } | ||||||
|  |         sourcemap->count = def->bytecode_length * 2; | ||||||
|  |         dst_table_put(ret, dst_csymbolv("sourcemap"), dst_wrap_array(sourcemap)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Add environments */ | ||||||
|  |     if (def->environments) { | ||||||
|  |         DstArray *envs = dst_array(def->environments_length); | ||||||
|  |         for (i = 0; i < def->environments_length; i++) { | ||||||
|  |             envs->data[i] = dst_wrap_integer(def->environments[i]); | ||||||
|  |         } | ||||||
|  |         envs->count = def->environments_length; | ||||||
|  |         dst_table_put(ret, dst_csymbolv("environments"), dst_wrap_array(envs)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dst_wrap_struct(dst_table_to_struct(ret)); | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										354
									
								
								core/compile.c
									
									
									
									
									
								
							
							
						
						
									
										354
									
								
								core/compile.c
									
									
									
									
									
								
							| @@ -24,29 +24,17 @@ | |||||||
| #include "compile.h" | #include "compile.h" | ||||||
|  |  | ||||||
| /* Lazily sort the optimizers */ | /* Lazily sort the optimizers */ | ||||||
| static int optimizers_sorted = 0; | /*static int optimizers_sorted = 0;*/ | ||||||
|  |  | ||||||
| /* Lookups for specials and optimizable c functions. */ | /* Lookups for specials and optimizable c functions. */ | ||||||
| DstCFunctionOptimizer dst_compiler_optimizers[255]; | /*DstCFunctionOptimizer dst_compiler_optimizers[255];*/ | ||||||
| DstSpecial dst_compiler_specials[16]; | /*DstSpecial dst_compiler_specials[16];*/ | ||||||
|  |  | ||||||
| /* Deinitialize a compiler struct */ |  | ||||||
| static void dst_compile_cleanup(DstCompiler *c) { |  | ||||||
|     while (c->scopecount) |  | ||||||
|         dst_compile_popscope(c); |  | ||||||
|     free(c->scopes); |  | ||||||
|     free(c->buffer); |  | ||||||
|     free(c->mapbuffer); |  | ||||||
|     c->buffer = NULL; |  | ||||||
|     c->mapbuffer = NULL; |  | ||||||
|     c->scopes = NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Throw an error with a dst string */ | /* Throw an error with a dst string */ | ||||||
| void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) { | void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) { | ||||||
|     c->error_start = dst_unwrap_integer(sourcemap[0]); |     c->results.error_start = dst_unwrap_integer(sourcemap[0]); | ||||||
|     c->error_end = dst_unwrap_integer(sourcemap[1]); |     c->results.error_end = dst_unwrap_integer(sourcemap[1]); | ||||||
|     c->error = dst_wrap_string(m); |     c->results.error = m; | ||||||
|     longjmp(c->on_error, 1); |     longjmp(c->on_error, 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -77,72 +65,6 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) { | |||||||
|     opts.sourcemap = sourcemap; |     opts.sourcemap = sourcemap; | ||||||
|     return opts; |     return opts; | ||||||
| } | } | ||||||
|  |  | ||||||
| void dst_compile_slotpool_init(DstSlotPool *pool) { |  | ||||||
|     pool->s = NULL; |  | ||||||
|     pool->count = 0; |  | ||||||
|     pool->free = 0; |  | ||||||
|     pool->cap = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dst_compile_slotpool_deinit(DstSlotPool *pool) { |  | ||||||
|     free(pool->s); |  | ||||||
|     pool->s = NULL; |  | ||||||
|     pool->cap = 0; |  | ||||||
|     pool->count = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) { |  | ||||||
|     int32_t i; |  | ||||||
|     int32_t newcount = pool->count + extra; |  | ||||||
|     if (newcount > pool->cap) { |  | ||||||
|         int32_t newcap = 2 * newcount; |  | ||||||
|         pool->s = realloc(pool->s, newcap * sizeof(DstSlot)); |  | ||||||
|         if (NULL == pool->s) { |  | ||||||
|             DST_OUT_OF_MEMORY; |  | ||||||
|         } |  | ||||||
|         pool->cap = newcap; |  | ||||||
|     } |  | ||||||
|     /* Mark all slots as free */ |  | ||||||
|     for (i = pool->count; i < newcount; i++) { |  | ||||||
|         pool->s[i].flags = 0; |  | ||||||
|     } |  | ||||||
|     pool->count = newcount; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) { |  | ||||||
|     int32_t oldcount = pool->count; |  | ||||||
|     int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1; |  | ||||||
|     while (pool->free < pool->count) { |  | ||||||
|         if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) { |  | ||||||
|             return pool->s + pool->free;  |  | ||||||
|         } |  | ||||||
|         pool->free++; |  | ||||||
|     } |  | ||||||
|     dst_compile_slotpool_extend(pool, newcount - oldcount); |  | ||||||
|     pool->s[oldcount].flags = DST_SLOT_NOTEMPTY; |  | ||||||
|     pool->s[oldcount].index = newcount - 1; |  | ||||||
|     return pool->s + newcount - 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) { |  | ||||||
|     if (index > 0 && index < pool->count) { |  | ||||||
|         pool->s[index].flags = 0; |  | ||||||
|         if (index < pool->free) |  | ||||||
|             pool->free = index; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) { |  | ||||||
|     DstSlot *oldfree = pool->s + pool->free; |  | ||||||
|     if (s >= pool->s && s < (pool->s + pool->count)) { |  | ||||||
|         if (s < oldfree) { |  | ||||||
|             pool->free = s - pool->s; |  | ||||||
|         } |  | ||||||
|         s->flags = 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Eneter a new scope */ | /* Eneter a new scope */ | ||||||
| void dst_compile_scope(DstCompiler *c, int newfn) { | void dst_compile_scope(DstCompiler *c, int newfn) { | ||||||
|     int32_t newcount, oldcount; |     int32_t newcount, oldcount; | ||||||
| @@ -154,7 +76,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { | |||||||
|         ? c->scopes[c->scopecount - 1].level |         ? c->scopes[c->scopecount - 1].level | ||||||
|         : 0; |         : 0; | ||||||
|     newlevel = oldlevel + newfn; |     newlevel = oldlevel + newfn; | ||||||
|     if (newcount < c->scopecap) { |     if (newcount > c->scopecap) { | ||||||
|         int32_t newcap = 2 * newcount; |         int32_t newcap = 2 * newcount; | ||||||
|         c->scopes = realloc(c->scopes, newcap * sizeof(DstScope)); |         c->scopes = realloc(c->scopes, newcap * sizeof(DstScope)); | ||||||
|         if (NULL == c->scopes) { |         if (NULL == c->scopes) { | ||||||
| @@ -164,7 +86,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { | |||||||
|     } |     } | ||||||
|     scope = c->scopes + oldcount; |     scope = c->scopes + oldcount; | ||||||
|     c->scopecount = newcount; |     c->scopecount = newcount; | ||||||
|     dst_array_init(&scope->constants, 0); |     dst_array_init(&(scope->constants), 0); | ||||||
|     dst_table_init(&scope->symbols, 4); |     dst_table_init(&scope->symbols, 4); | ||||||
|     dst_table_init(&scope->constantrev, 4); |     dst_table_init(&scope->constantrev, 4); | ||||||
|  |  | ||||||
| @@ -206,7 +128,7 @@ DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x) { | |||||||
|     ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY; |     ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY; | ||||||
|     ret->index = -1; |     ret->index = -1; | ||||||
|     ret->constant = x; |     ret->constant = x; | ||||||
|     ret->envindex = scope->level; |     ret->envindex = 0; | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -331,72 +253,13 @@ DstSlot *dst_compile_resolve( | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv) { |  | ||||||
|     DstScope *scope; |  | ||||||
|     DstSlot *rvalue; |  | ||||||
|     DstFormOptions subopts; |  | ||||||
|     DstValue check; |  | ||||||
|     if (argn != 2) |  | ||||||
|         dst_compile_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments"); |  | ||||||
|     if (!dst_checktype(argv[0], DST_SYMBOL)) |  | ||||||
|         dst_compile_cerror(opts.compiler, opts.sourcemap, "expected symbol"); |  | ||||||
|     scope = dst_compile_topscope(opts.compiler); |  | ||||||
|     check = dst_table_get(&scope->symbols, argv[0]); |  | ||||||
|     if (dst_checktype(check, DST_INTEGER)) { |  | ||||||
|         dst_compile_cerror(opts.compiler, opts.sourcemap, "cannot redefine symbol"); |  | ||||||
|     } |  | ||||||
|     subopts = dst_compile_getopts_index(opts, 1); |  | ||||||
|     rvalue = dst_compile_value(subopts); |  | ||||||
|     dst_table_put(&scope->symbols, argv[0], dst_wrap_userdata(rvalue)); |  | ||||||
|     return rvalue; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Compile an array */ |  | ||||||
|  |  | ||||||
| /* Compile a single value */ |  | ||||||
| DstSlot *dst_compile_value(DstFormOptions opts) { |  | ||||||
|     DstSlot *ret; |  | ||||||
|     if (opts.compiler->recursion_guard <= 0) { |  | ||||||
|         dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); |  | ||||||
|     } |  | ||||||
|     opts.compiler->recursion_guard--; |  | ||||||
|     switch (dst_type(opts.x)) { |  | ||||||
|         default: |  | ||||||
|             ret = dst_compile_constantslot(opts.compiler, opts.x); |  | ||||||
|             break; |  | ||||||
|         case DST_SYMBOL: |  | ||||||
|             { |  | ||||||
|                 const uint8_t *sym = dst_unwrap_symbol(opts.x); |  | ||||||
|                 if (dst_string_length(sym) > 0 && sym[0] != ':') |  | ||||||
|                     ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym); |  | ||||||
|                 else |  | ||||||
|                     ret = dst_compile_constantslot(opts.compiler, opts.x); |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         /*case DST_TUPLE:*/ |  | ||||||
|             /*ret = dst_compile_tuple(opts); */ |  | ||||||
|             /*break;*/ |  | ||||||
|         /*case DST_ARRAY:*/ |  | ||||||
|             /*ret = dst_compile_array(opts); */ |  | ||||||
|             /*break;*/ |  | ||||||
|         /*case DST_STRUCT:*/ |  | ||||||
|             /*ret = dst_compile_struct(opts); */ |  | ||||||
|             /*break;*/ |  | ||||||
|         /*case DST_TABLE:*/ |  | ||||||
|             /*ret = dst_compile_table(opts);*/ |  | ||||||
|             /*break;*/ |  | ||||||
|     } |  | ||||||
|     opts.compiler->recursion_guard++; |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Emit a raw instruction with source mapping. */ | /* Emit a raw instruction with source mapping. */ | ||||||
| void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) { | void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) { | ||||||
|     int32_t index = c->buffercount; |     int32_t index = c->buffercount; | ||||||
|     int32_t newcount = index + 1; |     int32_t newcount = index + 1; | ||||||
|     if (newcount > c->buffercap) { |     if (newcount > c->buffercap) { | ||||||
|         int32_t newcap = 2 * newcount; |         int32_t newcap = 2 * newcount; | ||||||
|         c->buffer = realloc(c->buffer, newcap * sizeof(int32_t)); |         c->buffer = realloc(c->buffer, newcap * sizeof(uint32_t)); | ||||||
|         c->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2); |         c->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2); | ||||||
|         if (NULL == c->buffer || NULL == c->mapbuffer) { |         if (NULL == c->buffer || NULL == c->mapbuffer) { | ||||||
|             DST_OUT_OF_MEMORY; |             DST_OUT_OF_MEMORY; | ||||||
| @@ -405,8 +268,8 @@ void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) | |||||||
|     } |     } | ||||||
|     c->buffercount = newcount; |     c->buffercount = newcount; | ||||||
|     if (NULL != sourcemap) { |     if (NULL != sourcemap) { | ||||||
|         c->mapbuffer[index][0] = dst_unwrap_integer(sourcemap[0]); |         c->mapbuffer[index * 2] = dst_unwrap_integer(sourcemap[0]); | ||||||
|         c->mapbuffer[index][1] = dst_unwrap_integer(sourcemap[1]); |         c->mapbuffer[index * 2 + 1] = dst_unwrap_integer(sourcemap[1]); | ||||||
|     } |     } | ||||||
|     c->buffer[index] = instr; |     c->buffer[index] = instr; | ||||||
| } | } | ||||||
| @@ -569,30 +432,168 @@ static void dst_compile_slot_post( | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void dst_compile_pop_funcdef(DstCompiler *c) { | /* Generate the return instruction for a slot. */ | ||||||
|     DstScope *scope = dst_compiler_topscope(c); | static void dst_compile_return(DstCompiler *c, const DstValue *sourcemap, DstSlot *s) { | ||||||
|  |     if (s->flags & DST_SLOT_CONSTANT && dst_checktype(s->constant, DST_NIL)) { | ||||||
|  |             dst_compile_emit(c, sourcemap, DOP_RETURN_NIL); | ||||||
|  |     } else { | ||||||
|  |         DstLocalSlot ls = dst_compile_slot_pre( | ||||||
|  |                 c, sourcemap, 0xFFFF, -1, | ||||||
|  |                 1, 1, s); | ||||||
|  |         dst_compile_emit(c, sourcemap, DOP_RETURN | (ls.index << 8)); | ||||||
|  |         dst_compile_slot_post(c, sourcemap, ls); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv) { | ||||||
|  |     DstScope *scope; | ||||||
|  |     DstSlot *rvalue; | ||||||
|  |     DstFormOptions subopts; | ||||||
|  |     DstValue check; | ||||||
|  |     if (argn != 2) | ||||||
|  |         dst_compile_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments"); | ||||||
|  |     if (!dst_checktype(argv[0], DST_SYMBOL)) | ||||||
|  |         dst_compile_cerror(opts.compiler, opts.sourcemap, "expected symbol"); | ||||||
|  |     scope = dst_compile_topscope(opts.compiler); | ||||||
|  |     check = dst_table_get(&scope->symbols, argv[0]); | ||||||
|  |     if (dst_checktype(check, DST_INTEGER)) { | ||||||
|  |         dst_compile_cerror(opts.compiler, opts.sourcemap, "cannot redefine symbol"); | ||||||
|  |     } | ||||||
|  |     subopts = dst_compile_getopts_index(opts, 1); | ||||||
|  |     rvalue = dst_compile_value(subopts); | ||||||
|  |     dst_table_put(&scope->symbols, argv[0], dst_wrap_userdata(rvalue)); | ||||||
|  |     return rvalue; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Compile an array */ | ||||||
|  |  | ||||||
|  | /* Compile a single value */ | ||||||
|  | DstSlot *dst_compile_value(DstFormOptions opts) { | ||||||
|  |     DstSlot *ret; | ||||||
|  |     int doreturn = opts.flags & DST_FOPTS_TAIL; | ||||||
|  |     if (opts.compiler->recursion_guard <= 0) { | ||||||
|  |         dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); | ||||||
|  |     } | ||||||
|  |     opts.compiler->recursion_guard--; | ||||||
|  |     switch (dst_type(opts.x)) { | ||||||
|  |         default: | ||||||
|  |             ret = dst_compile_constantslot(opts.compiler, opts.x); | ||||||
|  |             break; | ||||||
|  |         case DST_SYMBOL: | ||||||
|  |             { | ||||||
|  |                 const uint8_t *sym = dst_unwrap_symbol(opts.x); | ||||||
|  |                 if (dst_string_length(sym) > 0 && sym[0] != ':') { | ||||||
|  |                     ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym); | ||||||
|  |                 } else { | ||||||
|  |                     ret = dst_compile_constantslot(opts.compiler, opts.x); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         /*case DST_TUPLE:*/ | ||||||
|  |             /*ret = dst_compile_tuple(opts); */ | ||||||
|  |             /*break;*/ | ||||||
|  |         /*case DST_ARRAY:*/ | ||||||
|  |             /*ret = dst_compile_array(opts); */ | ||||||
|  |             /*break;*/ | ||||||
|  |         /*case DST_STRUCT:*/ | ||||||
|  |             /*ret = dst_compile_struct(opts); */ | ||||||
|  |             /*break;*/ | ||||||
|  |         /*case DST_TABLE:*/ | ||||||
|  |             /*ret = dst_compile_table(opts);*/ | ||||||
|  |             /*break;*/ | ||||||
|  |     } | ||||||
|  |     if (doreturn) { | ||||||
|  |         dst_compile_return(opts.compiler, opts.sourcemap, ret); | ||||||
|  |     } | ||||||
|  |     opts.compiler->recursion_guard++; | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Compile a funcdef */ | ||||||
|  | static DstFuncDef *dst_compile_pop_funcdef(DstCompiler *c) { | ||||||
|  |     DstScope *scope = dst_compile_topscope(c); | ||||||
|     DstFuncDef *def; |     DstFuncDef *def; | ||||||
|  |  | ||||||
|     /* Initialize funcdef */ |     /* Initialize funcdef */ | ||||||
|     def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef)); |     def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef)); | ||||||
|     def->environments = NULL; |     def->environments_length = scope->envcount; | ||||||
|     def->constants = NULL; |     def->environments = malloc(sizeof(int32_t) * def->environments_length); | ||||||
|     def->bytecode = NULL; |  | ||||||
|     def->flags = 0; |  | ||||||
|     def->slotcount = 0; |  | ||||||
|     def->arity = 0; |  | ||||||
|     def->constants_length = 0; |     def->constants_length = 0; | ||||||
|     def->bytecode_length = 0; |     def->constants = malloc(sizeof(DstValue) * scope->constants.count); | ||||||
|     def->environments_length = 1; |     def->bytecode_length = c->buffercount - scope->bytecode_start; | ||||||
|  |     def->bytecode = malloc(sizeof(uint32_t) * def->bytecode_length); | ||||||
|  |     def->slotcount = scope->slots.count; | ||||||
|  |  | ||||||
|  |     if (NULL == def->environments || | ||||||
|  |         NULL == def->constants || | ||||||
|  |         NULL == def->bytecode) { | ||||||
|  |         DST_OUT_OF_MEMORY; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     memcpy(def->environments, scope->envs, def->environments_length * sizeof(int32_t)); | ||||||
|  |     memcpy(def->constants, scope->constants.data, def->constants_length * sizeof(DstValue)); | ||||||
|  |     memcpy(def->bytecode, c->buffer + c->buffercount, def->bytecode_length * sizeof(uint32_t)); | ||||||
|  |  | ||||||
|  |     if (c->mapbuffer) { | ||||||
|  |         def->sourcemap = malloc(sizeof(uint32_t) * 2 * def->bytecode_length); | ||||||
|  |         if (NULL == def->sourcemap) { | ||||||
|  |             DST_OUT_OF_MEMORY; | ||||||
|  |         } | ||||||
|  |         memcpy(def->sourcemap, c->mapbuffer + 2 * c->buffercount, def->bytecode_length * 2 * sizeof(uint32_t)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Reset bytecode gen */ | ||||||
|  |     c->buffercount = scope->bytecode_start; | ||||||
|  |  | ||||||
|  |     /* Manually set arity and flags later */ | ||||||
|  |     def->flags = 0; | ||||||
|  |     def->arity = 0; | ||||||
|  |  | ||||||
|  |     /* Set some flags */ | ||||||
|  |     if (scope->flags & DST_SCOPE_ENV) { | ||||||
|  |         def->flags |= DST_FUNCDEF_FLAG_NEEDSENV; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* Pop the scope */ | ||||||
|  |     dst_compile_popscope(c); | ||||||
|  |  | ||||||
|  |     return def; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Print a slot for debugging */ | ||||||
|  | /*static void print_slot(DstSlot *s) {*/ | ||||||
|  |     /*if (!(s->flags & DST_SLOT_NOTEMPTY)) {*/ | ||||||
|  |         /*printf("X");*/ | ||||||
|  |     /*} else if (s->flags & DST_SLOT_CONSTANT) {*/ | ||||||
|  |         /*dst_puts(dst_short_description(s->constant));*/ | ||||||
|  |     /*} else if (s->envindex > 0) {*/ | ||||||
|  |         /*printf("UP%d[%d]", s->envindex, s->index);*/ | ||||||
|  |     /*} else {*/ | ||||||
|  |         /*printf("%d", s->index);*/ | ||||||
|  |     /*}*/ | ||||||
|  | /*}*/ | ||||||
|  |  | ||||||
|  | /* Deinitialize a compiler struct */ | ||||||
|  | static void dst_compile_cleanup(DstCompiler *c) { | ||||||
|  |     while (c->scopecount) | ||||||
|  |         dst_compile_popscope(c); | ||||||
|  |     free(c->scopes); | ||||||
|  |     free(c->buffer); | ||||||
|  |     free(c->mapbuffer); | ||||||
|  |     c->buffer = NULL; | ||||||
|  |     c->mapbuffer = NULL; | ||||||
|  |     c->scopes = NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| DstCompileResults dst_compile(DstCompileOptions opts) { | DstCompileResults dst_compile(DstCompileOptions opts) { | ||||||
|     DstCompiler c; |     DstCompiler c; | ||||||
|  |     DstFormOptions fopts; | ||||||
|  |     DstSlot *s; | ||||||
|  |  | ||||||
|     if (setjmp(c.on_error)) { |     if (setjmp(c.on_error)) { | ||||||
|         c.results.status = DST_COMPILE_ERROR; |         c.results.status = DST_COMPILE_ERROR; | ||||||
|         dst_compile_cleanup(&c); |         dst_compile_cleanup(&c); | ||||||
|         results.funcdef = NULL; |         c.results.funcdef = NULL; | ||||||
|         return c.results; |         return c.results; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -602,9 +603,36 @@ DstCompileResults dst_compile(DstCompileOptions opts) { | |||||||
|     c.scopes = NULL; |     c.scopes = NULL; | ||||||
|     c.buffercap = 0; |     c.buffercap = 0; | ||||||
|     c.buffercount = 0; |     c.buffercount = 0; | ||||||
|     c->buffer = NULL; |     c.buffer = NULL; | ||||||
|     c->mapbuffer; |     c.mapbuffer = NULL; | ||||||
|     c->recursion_guard = 1024; |     c.recursion_guard = 1024; | ||||||
|  |  | ||||||
|  |     /* Push a function scope */ | ||||||
|  |     dst_compile_scope(&c, 1); | ||||||
|  |  | ||||||
|  |     fopts.compiler = &c; | ||||||
|  |     fopts.sourcemap = opts.sourcemap; | ||||||
|  |     fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY; | ||||||
|  |     fopts.hint = 0; | ||||||
|  |     fopts.x = opts.source; | ||||||
|  |  | ||||||
|  |     /* Compile the value */ | ||||||
|  |     s = dst_compile_value(fopts); | ||||||
|  |  | ||||||
|  |     c.results.funcdef = dst_compile_pop_funcdef(&c); | ||||||
|  |     c.results.status = DST_COMPILE_OK; | ||||||
|  |  | ||||||
|  |     dst_compile_cleanup(&c); | ||||||
|  |  | ||||||
|  |     return c.results; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DstFunction *dst_compile_func(DstCompileResults res) { | ||||||
|  |     if (res.status != DST_COMPILE_OK) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); | ||||||
|  |     func->def = res.funcdef; | ||||||
|  |     func->envs = NULL; | ||||||
|  |     return func; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -38,10 +38,8 @@ typedef struct DstCFunctionOptimizer DstCFunctionOptimizer; | |||||||
|  |  | ||||||
| #define DST_SLOT_CONSTANT 0x10000 | #define DST_SLOT_CONSTANT 0x10000 | ||||||
| #define DST_SLOT_NAMED 0x20000 | #define DST_SLOT_NAMED 0x20000 | ||||||
| #define DST_SLOT_RETURNED 0x40000 | #define DST_SLOT_MUTABLE 0x40000 | ||||||
| #define DST_SLOT_NIL 0x80000 | #define DST_SLOT_NOTEMPTY 0x80000 | ||||||
| #define DST_SLOT_MUTABLE 0x100000 |  | ||||||
| #define DST_SLOT_NOTEMPTY 0x200000 |  | ||||||
|  |  | ||||||
| #define DST_SLOTTYPE_ANY 0xFFFF | #define DST_SLOTTYPE_ANY 0xFFFF | ||||||
|  |  | ||||||
| @@ -116,7 +114,7 @@ struct DstCompiler { | |||||||
|     int32_t buffercap; |     int32_t buffercap; | ||||||
|     int32_t buffercount; |     int32_t buffercount; | ||||||
|     uint32_t *buffer; |     uint32_t *buffer; | ||||||
|     int32_t (*mapbuffer)[2]; |     int32_t *mapbuffer; | ||||||
|  |  | ||||||
|     DstCompileResults results; |     DstCompileResults results; | ||||||
| }; | }; | ||||||
| @@ -130,6 +128,7 @@ struct DstFormOptions { | |||||||
|     DstValue x; |     DstValue x; | ||||||
|     const DstValue *sourcemap; |     const DstValue *sourcemap; | ||||||
|     uint32_t flags; /* bit set of accepted primitive types */ |     uint32_t flags; /* bit set of accepted primitive types */ | ||||||
|  |     int32_t hint; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* A grouping of optimizations on a cfunction given certain conditions | /* A grouping of optimizations on a cfunction given certain conditions | ||||||
|   | |||||||
							
								
								
									
										92
									
								
								core/compile_slotpool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								core/compile_slotpool.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2017 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 "compile.h" | ||||||
|  |  | ||||||
|  | void dst_compile_slotpool_init(DstSlotPool *pool) { | ||||||
|  |     pool->s = NULL; | ||||||
|  |     pool->count = 0; | ||||||
|  |     pool->free = 0; | ||||||
|  |     pool->cap = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dst_compile_slotpool_deinit(DstSlotPool *pool) { | ||||||
|  |     free(pool->s); | ||||||
|  |     pool->s = NULL; | ||||||
|  |     pool->cap = 0; | ||||||
|  |     pool->count = 0; | ||||||
|  |     pool->free = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) { | ||||||
|  |     int32_t i; | ||||||
|  |     int32_t newcount = pool->count + extra; | ||||||
|  |     if (newcount > pool->cap) { | ||||||
|  |         int32_t newcap = 2 * newcount; | ||||||
|  |         pool->s = realloc(pool->s, newcap * sizeof(DstSlot)); | ||||||
|  |         if (NULL == pool->s) { | ||||||
|  |             DST_OUT_OF_MEMORY; | ||||||
|  |         } | ||||||
|  |         pool->cap = newcap; | ||||||
|  |     } | ||||||
|  |     /* Mark all new slots as free */ | ||||||
|  |     for (i = pool->count; i < newcount; i++) { | ||||||
|  |         pool->s[i].flags = 0; | ||||||
|  |     } | ||||||
|  |     pool->count = newcount; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) { | ||||||
|  |     int32_t oldcount = pool->count; | ||||||
|  |     int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1; | ||||||
|  |     int32_t index = newcount - 1; | ||||||
|  |     while (pool->free < pool->count) { | ||||||
|  |         if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) { | ||||||
|  |             return pool->s + pool->free;  | ||||||
|  |         } | ||||||
|  |         pool->free++; | ||||||
|  |     } | ||||||
|  |     dst_compile_slotpool_extend(pool, newcount - oldcount); | ||||||
|  |     pool->s[index].flags = DST_SLOT_NOTEMPTY; | ||||||
|  |     pool->s[index].index = index; | ||||||
|  |     return pool->s + index; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) { | ||||||
|  |     if (index > 0 && index < pool->count) { | ||||||
|  |         pool->s[index].flags = 0; | ||||||
|  |         if (index < pool->free) | ||||||
|  |             pool->free = index; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) { | ||||||
|  |     DstSlot *oldfree = pool->s + pool->free; | ||||||
|  |     if (s >= pool->s && s < (pool->s + pool->count)) { | ||||||
|  |         if (s < oldfree) { | ||||||
|  |             pool->free = s - pool->s; | ||||||
|  |         } | ||||||
|  |         s->flags = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -179,6 +179,10 @@ static void dst_mark_funcdef(DstFuncDef *def) { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if (def->source) | ||||||
|  |         dst_mark_string(def->source); | ||||||
|  |     if (def->sourcepath) | ||||||
|  |         dst_mark_string(def->sourcepath); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void dst_mark_function(DstFunction *func) { | static void dst_mark_function(DstFunction *func) { | ||||||
| @@ -263,6 +267,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) { | |||||||
|                 free(def->environments); |                 free(def->environments); | ||||||
|                 free(def->constants); |                 free(def->constants); | ||||||
|                 free(def->bytecode); |                 free(def->bytecode); | ||||||
|  |                 free(def->sourcemap); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -423,10 +423,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) { | |||||||
|     res.bytes_read = (int32_t) (newsrc - src); |     res.bytes_read = (int32_t) (newsrc - src); | ||||||
|  |  | ||||||
|     if (args.errmsg) { |     if (args.errmsg) { | ||||||
|         res.result.error = dst_cstring(args.errmsg); |         res.error = dst_cstring(args.errmsg); | ||||||
|  |         res.value = dst_wrap_nil(); | ||||||
|         res.map = NULL; |         res.map = NULL; | ||||||
|     } else { |     } else { | ||||||
|         res.result.value = dst_array_pop(&args.stack); |         res.value = dst_array_pop(&args.stack); | ||||||
|  |         res.error = NULL; | ||||||
|         res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack)); |         res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ int dst_sys_asm(DstValue *argv, int32_t argn) { | |||||||
|         dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res)); |         dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res)); | ||||||
|         return 0; |         return 0; | ||||||
|     } else { |     } else { | ||||||
|         dst_vm_fiber->ret = dst_wrap_string(res.result.error); |         dst_vm_fiber->ret = dst_wrap_string(res.error); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -175,7 +175,7 @@ DstValue dst_table_next(DstTable *t, DstValue key) { | |||||||
| const DstValue *dst_table_to_struct(DstTable *t) { | const DstValue *dst_table_to_struct(DstTable *t) { | ||||||
|     int32_t i; |     int32_t i; | ||||||
|     DstValue *st = dst_struct_begin(t->count); |     DstValue *st = dst_struct_begin(t->count); | ||||||
|     for (i = 0; i < t->capacity; i++) { |     for (i = 0; i < t->capacity; i += 2) { | ||||||
|         if (!dst_checktype(t->data[i], DST_NIL)) |         if (!dst_checktype(t->data[i], DST_NIL)) | ||||||
|             dst_struct_put(st, t->data[i], t->data[i + 1]); |             dst_struct_put(st, t->data[i], t->data[i + 1]); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								dsttest/basic.dst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								dsttest/basic.dst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | # A really basic for to compile. for testing the compiler. Will extend | ||||||
|  | # as compiler is extended. | ||||||
|  | 123 | ||||||
|  |  | ||||||
| @@ -5,7 +5,7 @@ | |||||||
| { | { | ||||||
|     arity 3 |     arity 3 | ||||||
|     source "source file path" |     source "source file path" | ||||||
|     varargs false |     vararg false | ||||||
| # Name for reference by nested funcdefs | # Name for reference by nested funcdefs | ||||||
|     name outerfunc |     name outerfunc | ||||||
| # Contains the bytecode for this function. This can be assembly | # Contains the bytecode for this function. This can be assembly | ||||||
| @@ -22,9 +22,7 @@ | |||||||
|         (return 0) |         (return 0) | ||||||
|     ] |     ] | ||||||
| # A source map is optional. The sourcemap corresponds with the byte code. | # A source map is optional. The sourcemap corresponds with the byte code. | ||||||
| # Each number is a 64 bit integer, the concatenation of two 32 bit integers. | # Each instruction has two source map entries, offset start and offset end. | ||||||
| # These integers represent source character index for each instruction. |  | ||||||
| # This format may change. |  | ||||||
| #    map [ | #    map [ | ||||||
| #       1 | #       1 | ||||||
| #       2 | #       2 | ||||||
| @@ -45,7 +43,7 @@ | |||||||
|         z |         z | ||||||
|      ] |      ] | ||||||
| # Captured outer environments that are referenced | # Captured outer environments that are referenced | ||||||
|      environments [   ] |      captures [   ] | ||||||
| # Constants are an array or tuple. For named constants, use a tuple that begins with let | # Constants are an array or tuple. For named constants, use a tuple that begins with let | ||||||
| # For a literal tuple, use (quote tuple), or 'tuple. Without names, constants must be indexed | # For a literal tuple, use (quote tuple), or 'tuple. Without names, constants must be indexed | ||||||
| # from their number | # from their number | ||||||
| @@ -18,7 +18,7 @@ | |||||||
|     (return-nil) |     (return-nil) | ||||||
|      |      | ||||||
|     :extra |     :extra | ||||||
|     (push 2r1010101010101010) |     (push 2) | ||||||
|   ] |   ] | ||||||
|   constants [ |   constants [ | ||||||
|     (def lookup "0123456789abcdef") |     (def lookup "0123456789abcdef") | ||||||
| @@ -432,6 +432,11 @@ struct DstFuncDef { | |||||||
|     DstValue *constants; /* Contains strings, FuncDefs, etc. */ |     DstValue *constants; /* Contains strings, FuncDefs, etc. */ | ||||||
|     uint32_t *bytecode; |     uint32_t *bytecode; | ||||||
|  |  | ||||||
|  |     /* Various debug information */ | ||||||
|  |     int32_t *sourcemap; | ||||||
|  |     const uint8_t *source; | ||||||
|  |     const uint8_t *sourcepath; | ||||||
|  |  | ||||||
|     uint32_t flags; |     uint32_t flags; | ||||||
|     int32_t slotcount; /* The amount of stack space required for the function */ |     int32_t slotcount; /* The amount of stack space required for the function */ | ||||||
|     int32_t arity; /* Not including varargs */ |     int32_t arity; /* Not including varargs */ | ||||||
| @@ -543,6 +548,7 @@ int dst_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen, | |||||||
| const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len); | 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_cstring_unique(const char *s); | ||||||
| const uint8_t *dst_description(DstValue x); | const uint8_t *dst_description(DstValue x); | ||||||
|  | const uint8_t *dst_short_description(DstValue x); | ||||||
| const uint8_t *dst_to_string(DstValue x); | const uint8_t *dst_to_string(DstValue x); | ||||||
| #define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr)) | #define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr)) | ||||||
| const uint8_t *dst_formatc(const char *format, ...); | const uint8_t *dst_formatc(const char *format, ...); | ||||||
| @@ -608,10 +614,8 @@ typedef enum { | |||||||
| typedef struct DstAssembleResult DstAssembleResult; | typedef struct DstAssembleResult DstAssembleResult; | ||||||
| typedef struct DstAssembleOptions DstAssembleOptions; | typedef struct DstAssembleOptions DstAssembleOptions; | ||||||
| struct DstAssembleResult { | struct DstAssembleResult { | ||||||
|     union { |     DstFuncDef *funcdef; | ||||||
|         DstFuncDef *def; |  | ||||||
|     const uint8_t *error; |     const uint8_t *error; | ||||||
|     } result; |  | ||||||
|     int32_t error_start; |     int32_t error_start; | ||||||
|     int32_t error_end; |     int32_t error_end; | ||||||
|     DstAssembleStatus status; |     DstAssembleStatus status; | ||||||
| @@ -623,6 +627,7 @@ struct DstAssembleOptions { | |||||||
| }; | }; | ||||||
| DstAssembleResult dst_asm(DstAssembleOptions opts); | DstAssembleResult dst_asm(DstAssembleOptions opts); | ||||||
| DstFunction *dst_asm_func(DstAssembleResult result); | DstFunction *dst_asm_func(DstAssembleResult result); | ||||||
|  | DstValue dst_disasm(DstFuncDef *def); | ||||||
|  |  | ||||||
| /* Treat similar types through uniform interfaces for iteration */ | /* Treat similar types through uniform interfaces for iteration */ | ||||||
| int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len); | int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len); | ||||||
| @@ -659,10 +664,8 @@ typedef enum { | |||||||
| } DstParseStatus; | } DstParseStatus; | ||||||
| typedef struct DstParseResult DstParseResult; | typedef struct DstParseResult DstParseResult; | ||||||
| struct DstParseResult { | struct DstParseResult { | ||||||
|     union { |  | ||||||
|     DstValue value; |     DstValue value; | ||||||
|     const uint8_t *error; |     const uint8_t *error; | ||||||
|     } result; |  | ||||||
|     const DstValue *map; |     const DstValue *map; | ||||||
|     int32_t bytes_read; |     int32_t bytes_read; | ||||||
|     DstParseStatus status; |     DstParseStatus status; | ||||||
| @@ -698,11 +701,12 @@ typedef struct DstCompileResults { | |||||||
| typedef struct DstCompileOptions { | typedef struct DstCompileOptions { | ||||||
|     uint32_t flags; |     uint32_t flags; | ||||||
|     const DstValue *sourcemap; |     const DstValue *sourcemap; | ||||||
|     DstValue src; |     DstValue source; | ||||||
| } DstCompileOptions; | } DstCompileOptions; | ||||||
|  |  | ||||||
| /* Compile source code into FuncDef. */ | /* Compile source code into FuncDef. */ | ||||||
| DstCompileResults dst_compile(DstCompileOptions opts); | DstCompileResults dst_compile(DstCompileOptions opts); | ||||||
|  | DstFunction *dst_compile_func(DstCompileResults results); | ||||||
|  |  | ||||||
| /* GC */ | /* GC */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ int main() { | |||||||
|     DstAssembleResult ares; |     DstAssembleResult ares; | ||||||
|     DstFunction *func; |     DstFunction *func; | ||||||
|  |  | ||||||
|     printf("sizeof(DstValue) = %lu\n", sizeof(DstValue)); |     FILE *f = fopen("./dsttest/minimal.dsts", "rb"); | ||||||
|  |  | ||||||
|     FILE *f = fopen("./dsts/minimal.dsts", "rb"); |  | ||||||
|     fseek(f, 0, SEEK_END); |     fseek(f, 0, SEEK_END); | ||||||
|     long fsize = ftell(f); |     long fsize = ftell(f); | ||||||
|     fseek(f, 0, SEEK_SET);  //same as rewind(f); |     fseek(f, 0, SEEK_SET);  //same as rewind(f); | ||||||
| @@ -26,19 +24,19 @@ int main() { | |||||||
|     free(string); |     free(string); | ||||||
|  |  | ||||||
|     if (pres.status == DST_PARSE_ERROR) { |     if (pres.status == DST_PARSE_ERROR) { | ||||||
|         dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.result.error)); |         dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error)); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     assert(pres.status == DST_PARSE_OK); |     assert(pres.status == DST_PARSE_OK); | ||||||
|     dst_puts(dst_formatc("\nparse result: %v\n\n", pres.result.value)); |     dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value)); | ||||||
|  |  | ||||||
|     opts.flags = 0; |     opts.flags = 0; | ||||||
|     opts.source = pres.result.value; |     opts.source = pres.value; | ||||||
|     opts.sourcemap = pres.map; |     opts.sourcemap = pres.map; | ||||||
|  |  | ||||||
|     ares = dst_asm(opts); |     ares = dst_asm(opts); | ||||||
|     if (ares.status == DST_ASSEMBLE_ERROR) { |     if (ares.status == DST_ASSEMBLE_ERROR) { | ||||||
|         dst_puts(dst_formatc("assembly error: %S\n", ares.result.error)); |         dst_puts(dst_formatc("assembly error: %S\n", ares.error)); | ||||||
|         dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end)); |         dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end)); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
| @@ -46,6 +44,8 @@ int main() { | |||||||
|  |  | ||||||
|     func = dst_asm_func(ares); |     func = dst_asm_func(ares); | ||||||
|  |  | ||||||
|  |     dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(ares.funcdef))); | ||||||
|  |      | ||||||
|     dst_run(dst_wrap_function(func)); |     dst_run(dst_wrap_function(func)); | ||||||
|     dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret)); |     dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret)); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										55
									
								
								unittests/compile_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								unittests/compile_test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | #include "unit.h" | ||||||
|  | #include <dst/dst.h> | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |     DstParseResult pres; | ||||||
|  |     DstCompileOptions opts; | ||||||
|  |     DstCompileResults cres; | ||||||
|  |     DstFunction *func; | ||||||
|  |  | ||||||
|  |     FILE *f = fopen("./dsttest/basic.dst", "rb"); | ||||||
|  |     fseek(f, 0, SEEK_END); | ||||||
|  |     long fsize = ftell(f); | ||||||
|  |     fseek(f, 0, SEEK_SET);  //same as rewind(f); | ||||||
|  |  | ||||||
|  |     char *string = malloc(fsize + 1); | ||||||
|  |     fread(string, fsize, 1, f); | ||||||
|  |     fclose(f); | ||||||
|  |  | ||||||
|  |     string[fsize] = 0; | ||||||
|  |  | ||||||
|  |     dst_init(); | ||||||
|  |  | ||||||
|  |     pres = dst_parsec(string); | ||||||
|  |     free(string); | ||||||
|  |  | ||||||
|  |     if (pres.status == DST_PARSE_ERROR) { | ||||||
|  |         dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error)); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     assert(pres.status == DST_PARSE_OK); | ||||||
|  |     dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value)); | ||||||
|  |  | ||||||
|  |     opts.flags = 0; | ||||||
|  |     opts.source = pres.value; | ||||||
|  |     opts.sourcemap = pres.map; | ||||||
|  |  | ||||||
|  |     cres = dst_compile(opts); | ||||||
|  |     if (cres.status == DST_COMPILE_ERROR) { | ||||||
|  |         dst_puts(dst_formatc("compilation error: %S\n", cres.error)); | ||||||
|  |         dst_puts(dst_formatc("error location: %d, %d\n", cres.error_start, cres.error_end)); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     assert(cres.status == DST_COMPILE_OK); | ||||||
|  |  | ||||||
|  |     dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(cres.funcdef))); | ||||||
|  |      | ||||||
|  |     func = dst_compile_func(cres); | ||||||
|  |      | ||||||
|  |     dst_run(dst_wrap_function(func)); | ||||||
|  |     dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret)); | ||||||
|  |  | ||||||
|  |     dst_deinit(); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
| @@ -10,9 +10,9 @@ int main() { | |||||||
|     pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")"); |     pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")"); | ||||||
|  |  | ||||||
|     assert(pres.status == DST_PARSE_OK); |     assert(pres.status == DST_PARSE_OK); | ||||||
|     assert(dst_checktype(pres.result.value, DST_TUPLE)); |     assert(dst_checktype(pres.value, DST_TUPLE)); | ||||||
|  |  | ||||||
|     str = dst_to_string(pres.result.value); |     str = dst_to_string(pres.value); | ||||||
|     printf("%.*s\n", dst_string_length(str), (const char *) str); |     printf("%.*s\n", dst_string_length(str), (const char *) str); | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bakpakin
					bakpakin