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/,\ | ||||
| 				 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\ | ||||
| 				 value.c vm.c wrap.c) | ||||
| DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES)) | ||||
| @@ -78,7 +79,7 @@ $(DST_TARGET): $(DST_CORE_OBJECTS) | ||||
| CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST | ||||
|  | ||||
| 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) | ||||
|  | ||||
| %.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h | ||||
| @@ -88,6 +89,7 @@ unit: $(DST_UNIT_BINARIES) | ||||
| 	unittests/array_test.out | ||||
| 	unittests/asm_test.out | ||||
| 	unittests/buffer_test.out | ||||
| 	unittests/compile_test.out | ||||
| 	unittests/fiber_test.out | ||||
| 	unittests/parse_test.out | ||||
| 	unittests/strtod_test.out | ||||
|   | ||||
							
								
								
									
										10
									
								
								core/array.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								core/array.c
									
									
									
									
									
								
							| @@ -24,10 +24,12 @@ | ||||
|  | ||||
| /* Iniializes an array */ | ||||
| DstArray *dst_array_init(DstArray *array, int32_t capacity) { | ||||
|     if (capacity < 0) capacity = 0; | ||||
|     DstValue *data = (DstValue *) malloc(sizeof(DstValue) * capacity); | ||||
|     if (NULL == data) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     DstValue *data = NULL; | ||||
|     if (capacity > 0) { | ||||
|         data = (DstValue *) malloc(sizeof(DstValue) * capacity); | ||||
|         if (NULL == data) { | ||||
|             DST_OUT_OF_MEMORY; | ||||
|         } | ||||
|     } | ||||
|     array->count = 0; | ||||
|     array->capacity = capacity; | ||||
|   | ||||
							
								
								
									
										203
									
								
								core/asm.c
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								core/asm.c
									
									
									
									
									
								
							| @@ -518,6 +518,9 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | ||||
|     def->flags = 0; | ||||
|     def->slotcount = 0; | ||||
|     def->arity = 0; | ||||
|     def->source = NULL; | ||||
|     def->sourcepath = NULL; | ||||
|     def->sourcemap = NULL; | ||||
|     def->constants_length = 0; | ||||
|     def->bytecode_length = 0; | ||||
|     def->environments_length = 1; | ||||
| @@ -544,7 +547,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | ||||
|             dst_asm_deinit(&a); | ||||
|             longjmp(a.parent->on_error, 1); | ||||
|         } | ||||
|         result.result.error = a.errmessage; | ||||
|         result.error = a.errmessage; | ||||
|         result.status = DST_ASSEMBLE_ERROR; | ||||
|         if (a.errmap != NULL) { | ||||
|             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")); | ||||
|     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 */ | ||||
|     x = dst_struct_get(st, dst_csymbolv("slots")); | ||||
|     if (dst_seq_view(x, &arr, &count)) { | ||||
| @@ -586,10 +606,10 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | ||||
|     } | ||||
|  | ||||
|     /* 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)) { | ||||
|         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++) { | ||||
|             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"); | ||||
| @@ -690,12 +710,38 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) | ||||
|     } else { | ||||
|         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 */ | ||||
|     dst_asm_deinit(&a); | ||||
|     def->environments = | ||||
|         realloc(def->environments, def->environments_length * sizeof(int32_t)); | ||||
|     result.result.def = def; | ||||
|     result.funcdef = def; | ||||
|     result.status = DST_ASSEMBLE_OK; | ||||
|     return result; | ||||
| } | ||||
| @@ -711,7 +757,154 @@ DstFunction *dst_asm_func(DstAssembleResult result) { | ||||
|         return NULL; | ||||
|     } | ||||
|     DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); | ||||
|     func->def = result.result.def; | ||||
|     func->def = result.funcdef; | ||||
|     func->envs = NULL; | ||||
|     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)); | ||||
| } | ||||
|   | ||||
							
								
								
									
										356
									
								
								core/compile.c
									
									
									
									
									
								
							
							
						
						
									
										356
									
								
								core/compile.c
									
									
									
									
									
								
							| @@ -24,29 +24,17 @@ | ||||
| #include "compile.h" | ||||
|  | ||||
| /* Lazily sort the optimizers */ | ||||
| static int optimizers_sorted = 0; | ||||
| /*static int optimizers_sorted = 0;*/ | ||||
|  | ||||
| /* Lookups for specials and optimizable c functions. */ | ||||
| DstCFunctionOptimizer dst_compiler_optimizers[255]; | ||||
| 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; | ||||
| } | ||||
| /*DstCFunctionOptimizer dst_compiler_optimizers[255];*/ | ||||
| /*DstSpecial dst_compiler_specials[16];*/ | ||||
|  | ||||
| /* Throw an error with a dst string */ | ||||
| void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) { | ||||
|     c->error_start = dst_unwrap_integer(sourcemap[0]); | ||||
|     c->error_end = dst_unwrap_integer(sourcemap[1]); | ||||
|     c->error = dst_wrap_string(m); | ||||
|     c->results.error_start = dst_unwrap_integer(sourcemap[0]); | ||||
|     c->results.error_end = dst_unwrap_integer(sourcemap[1]); | ||||
|     c->results.error = m; | ||||
|     longjmp(c->on_error, 1); | ||||
| } | ||||
|  | ||||
| @@ -77,72 +65,6 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) { | ||||
|     opts.sourcemap = sourcemap; | ||||
|     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 */ | ||||
| void dst_compile_scope(DstCompiler *c, int newfn) { | ||||
|     int32_t newcount, oldcount; | ||||
| @@ -154,7 +76,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { | ||||
|         ? c->scopes[c->scopecount - 1].level | ||||
|         : 0; | ||||
|     newlevel = oldlevel + newfn; | ||||
|     if (newcount < c->scopecap) { | ||||
|     if (newcount > c->scopecap) { | ||||
|         int32_t newcap = 2 * newcount; | ||||
|         c->scopes = realloc(c->scopes, newcap * sizeof(DstScope)); | ||||
|         if (NULL == c->scopes) { | ||||
| @@ -164,7 +86,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { | ||||
|     } | ||||
|     scope = c->scopes + oldcount; | ||||
|     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->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->index = -1; | ||||
|     ret->constant = x; | ||||
|     ret->envindex = scope->level; | ||||
|     ret->envindex = 0; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @@ -331,72 +253,13 @@ DstSlot *dst_compile_resolve( | ||||
|     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. */ | ||||
| void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) { | ||||
|     int32_t index = c->buffercount; | ||||
|     int32_t newcount = index + 1; | ||||
|     if (newcount > c->buffercap) { | ||||
|         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); | ||||
|         if (NULL == c->buffer || NULL == c->mapbuffer) { | ||||
|             DST_OUT_OF_MEMORY; | ||||
| @@ -405,8 +268,8 @@ void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) | ||||
|     } | ||||
|     c->buffercount = newcount; | ||||
|     if (NULL != sourcemap) { | ||||
|         c->mapbuffer[index][0] = dst_unwrap_integer(sourcemap[0]); | ||||
|         c->mapbuffer[index][1] = dst_unwrap_integer(sourcemap[1]); | ||||
|         c->mapbuffer[index * 2] = dst_unwrap_integer(sourcemap[0]); | ||||
|         c->mapbuffer[index * 2 + 1] = dst_unwrap_integer(sourcemap[1]); | ||||
|     } | ||||
|     c->buffer[index] = instr; | ||||
| } | ||||
| @@ -569,30 +432,168 @@ static void dst_compile_slot_post( | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void dst_compile_pop_funcdef(DstCompiler *c) { | ||||
|     DstScope *scope = dst_compiler_topscope(c); | ||||
| /* Generate the return instruction for a slot. */ | ||||
| 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; | ||||
|  | ||||
|     /* Initialize funcdef */ | ||||
|     def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef)); | ||||
|     def->environments = NULL; | ||||
|     def->constants = NULL; | ||||
|     def->bytecode = NULL; | ||||
|     def->flags = 0; | ||||
|     def->slotcount = 0; | ||||
|     def->arity = 0; | ||||
|     def->environments_length = scope->envcount; | ||||
|     def->environments = malloc(sizeof(int32_t) * def->environments_length); | ||||
|     def->constants_length = 0; | ||||
|     def->bytecode_length = 0; | ||||
|     def->environments_length = 1; | ||||
|     def->constants = malloc(sizeof(DstValue) * scope->constants.count); | ||||
|     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) { | ||||
|     DstCompiler c; | ||||
|     DstFormOptions fopts; | ||||
|     DstSlot *s; | ||||
|  | ||||
|     if (setjmp(c.on_error)) { | ||||
|         c.results.status = DST_COMPILE_ERROR; | ||||
|         dst_compile_cleanup(&c); | ||||
|         results.funcdef = NULL; | ||||
|         c.results.funcdef = NULL; | ||||
|         return c.results; | ||||
|     } | ||||
|  | ||||
| @@ -602,9 +603,36 @@ DstCompileResults dst_compile(DstCompileOptions opts) { | ||||
|     c.scopes = NULL; | ||||
|     c.buffercap = 0; | ||||
|     c.buffercount = 0; | ||||
|     c->buffer = NULL; | ||||
|     c->mapbuffer; | ||||
|     c->recursion_guard = 1024; | ||||
|     c.buffer = NULL; | ||||
|     c.mapbuffer = NULL; | ||||
|     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_NAMED 0x20000 | ||||
| #define DST_SLOT_RETURNED 0x40000 | ||||
| #define DST_SLOT_NIL 0x80000 | ||||
| #define DST_SLOT_MUTABLE 0x100000 | ||||
| #define DST_SLOT_NOTEMPTY 0x200000 | ||||
| #define DST_SLOT_MUTABLE 0x40000 | ||||
| #define DST_SLOT_NOTEMPTY 0x80000 | ||||
|  | ||||
| #define DST_SLOTTYPE_ANY 0xFFFF | ||||
|  | ||||
| @@ -116,7 +114,7 @@ struct DstCompiler { | ||||
|     int32_t buffercap; | ||||
|     int32_t buffercount; | ||||
|     uint32_t *buffer; | ||||
|     int32_t (*mapbuffer)[2]; | ||||
|     int32_t *mapbuffer; | ||||
|  | ||||
|     DstCompileResults results; | ||||
| }; | ||||
| @@ -130,6 +128,7 @@ struct DstFormOptions { | ||||
|     DstValue x; | ||||
|     const DstValue *sourcemap; | ||||
|     uint32_t flags; /* bit set of accepted primitive types */ | ||||
|     int32_t hint; | ||||
| }; | ||||
|  | ||||
| /* 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) { | ||||
| @@ -263,6 +267,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) { | ||||
|                 free(def->environments); | ||||
|                 free(def->constants); | ||||
|                 free(def->bytecode); | ||||
|                 free(def->sourcemap); | ||||
|             } | ||||
|             break; | ||||
|     } | ||||
|   | ||||
| @@ -423,10 +423,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) { | ||||
|     res.bytes_read = (int32_t) (newsrc - src); | ||||
|  | ||||
|     if (args.errmsg) { | ||||
|         res.result.error = dst_cstring(args.errmsg); | ||||
|         res.error = dst_cstring(args.errmsg); | ||||
|         res.value = dst_wrap_nil(); | ||||
|         res.map = NULL; | ||||
|     } 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)); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -55,7 +55,7 @@ int dst_sys_asm(DstValue *argv, int32_t argn) { | ||||
|         dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res)); | ||||
|         return 0; | ||||
|     } else { | ||||
|         dst_vm_fiber->ret = dst_wrap_string(res.result.error); | ||||
|         dst_vm_fiber->ret = dst_wrap_string(res.error); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -175,7 +175,7 @@ DstValue dst_table_next(DstTable *t, DstValue key) { | ||||
| const DstValue *dst_table_to_struct(DstTable *t) { | ||||
|     int32_t i; | ||||
|     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)) | ||||
|             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 | ||||
|     source "source file path" | ||||
|     varargs false | ||||
|     vararg false | ||||
| # Name for reference by nested funcdefs | ||||
|     name outerfunc | ||||
| # Contains the bytecode for this function. This can be assembly | ||||
| @@ -22,9 +22,7 @@ | ||||
|         (return 0) | ||||
|     ] | ||||
| # 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. | ||||
| # These integers represent source character index for each instruction. | ||||
| # This format may change. | ||||
| # Each instruction has two source map entries, offset start and offset end. | ||||
| #    map [ | ||||
| #       1 | ||||
| #       2 | ||||
| @@ -45,7 +43,7 @@ | ||||
|         z | ||||
|      ] | ||||
| # Captured outer environments that are referenced | ||||
|      environments [   ] | ||||
|      captures [   ] | ||||
| # 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 | ||||
| # from their number | ||||
| @@ -18,7 +18,7 @@ | ||||
|     (return-nil) | ||||
|      | ||||
|     :extra | ||||
|     (push 2r1010101010101010) | ||||
|     (push 2) | ||||
|   ] | ||||
|   constants [ | ||||
|     (def lookup "0123456789abcdef") | ||||
| @@ -432,6 +432,11 @@ struct DstFuncDef { | ||||
|     DstValue *constants; /* Contains strings, FuncDefs, etc. */ | ||||
|     uint32_t *bytecode; | ||||
|  | ||||
|     /* Various debug information */ | ||||
|     int32_t *sourcemap; | ||||
|     const uint8_t *source; | ||||
|     const uint8_t *sourcepath; | ||||
|  | ||||
|     uint32_t flags; | ||||
|     int32_t slotcount; /* The amount of stack space required for the function */ | ||||
|     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_cstring_unique(const char *s); | ||||
| const uint8_t *dst_description(DstValue x); | ||||
| const uint8_t *dst_short_description(DstValue x); | ||||
| const uint8_t *dst_to_string(DstValue x); | ||||
| #define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr)) | ||||
| const uint8_t *dst_formatc(const char *format, ...); | ||||
| @@ -608,10 +614,8 @@ typedef enum { | ||||
| typedef struct DstAssembleResult DstAssembleResult; | ||||
| typedef struct DstAssembleOptions DstAssembleOptions; | ||||
| struct DstAssembleResult { | ||||
|     union { | ||||
|         DstFuncDef *def; | ||||
|         const uint8_t *error; | ||||
|     } result; | ||||
|     DstFuncDef *funcdef; | ||||
|     const uint8_t *error; | ||||
|     int32_t error_start; | ||||
|     int32_t error_end; | ||||
|     DstAssembleStatus status; | ||||
| @@ -623,6 +627,7 @@ struct DstAssembleOptions { | ||||
| }; | ||||
| DstAssembleResult dst_asm(DstAssembleOptions opts); | ||||
| DstFunction *dst_asm_func(DstAssembleResult result); | ||||
| DstValue dst_disasm(DstFuncDef *def); | ||||
|  | ||||
| /* Treat similar types through uniform interfaces for iteration */ | ||||
| int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len); | ||||
| @@ -659,10 +664,8 @@ typedef enum { | ||||
| } DstParseStatus; | ||||
| typedef struct DstParseResult DstParseResult; | ||||
| struct DstParseResult { | ||||
|     union { | ||||
|         DstValue value; | ||||
|         const uint8_t *error; | ||||
|     } result; | ||||
|     DstValue value; | ||||
|     const uint8_t *error; | ||||
|     const DstValue *map; | ||||
|     int32_t bytes_read; | ||||
|     DstParseStatus status; | ||||
| @@ -698,11 +701,12 @@ typedef struct DstCompileResults { | ||||
| typedef struct DstCompileOptions { | ||||
|     uint32_t flags; | ||||
|     const DstValue *sourcemap; | ||||
|     DstValue src; | ||||
|     DstValue source; | ||||
| } DstCompileOptions; | ||||
|  | ||||
| /* Compile source code into FuncDef. */ | ||||
| DstCompileResults dst_compile(DstCompileOptions opts); | ||||
| DstFunction *dst_compile_func(DstCompileResults results); | ||||
|  | ||||
| /* GC */ | ||||
|  | ||||
|   | ||||
| @@ -7,9 +7,7 @@ int main() { | ||||
|     DstAssembleResult ares; | ||||
|     DstFunction *func; | ||||
|  | ||||
|     printf("sizeof(DstValue) = %lu\n", sizeof(DstValue)); | ||||
|  | ||||
|     FILE *f = fopen("./dsts/minimal.dsts", "rb"); | ||||
|     FILE *f = fopen("./dsttest/minimal.dsts", "rb"); | ||||
|     fseek(f, 0, SEEK_END); | ||||
|     long fsize = ftell(f); | ||||
|     fseek(f, 0, SEEK_SET);  //same as rewind(f); | ||||
| @@ -26,25 +24,27 @@ int main() { | ||||
|     free(string); | ||||
|  | ||||
|     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; | ||||
|     } | ||||
|     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.source = pres.result.value; | ||||
|     opts.source = pres.value; | ||||
|     opts.sourcemap = pres.map; | ||||
|  | ||||
|     ares = dst_asm(opts); | ||||
|     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)); | ||||
|         return 1; | ||||
|     } | ||||
|     assert(ares.status == DST_ASSEMBLE_OK); | ||||
|  | ||||
|     func = dst_asm_func(ares); | ||||
|  | ||||
|     dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(ares.funcdef))); | ||||
|      | ||||
|     dst_run(dst_wrap_function(func)); | ||||
|     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\")"); | ||||
|  | ||||
|     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); | ||||
|  | ||||
|     return 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bakpakin
					bakpakin