mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33:01 +00:00 
			
		
		
		
	New sourcemaps v1.
This commit is contained in:
		
							
								
								
									
										574
									
								
								3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										574
									
								
								3
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,574 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_TYPES_H_defined | ||||
| #define DST_TYPES_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "dstconfig.h" | ||||
|  | ||||
| /* Names of all of the types */ | ||||
| extern const char *const dst_type_names[16]; | ||||
|  | ||||
| /* Fiber signals */ | ||||
| typedef enum { | ||||
|     DST_SIGNAL_OK, | ||||
|     DST_SIGNAL_ERROR, | ||||
|     DST_SIGNAL_DEBUG, | ||||
|     DST_SIGNAL_YIELD, | ||||
|     DST_SIGNAL_USER0, | ||||
|     DST_SIGNAL_USER1, | ||||
|     DST_SIGNAL_USER2, | ||||
|     DST_SIGNAL_USER3, | ||||
|     DST_SIGNAL_USER4, | ||||
|     DST_SIGNAL_USER5, | ||||
|     DST_SIGNAL_USER6, | ||||
|     DST_SIGNAL_USER7, | ||||
|     DST_SIGNAL_USER8, | ||||
|     DST_SIGNAL_USER9 | ||||
| } DstSignal; | ||||
|  | ||||
| /* Fiber statuses - mostly corresponds to signals. */ | ||||
| typedef enum { | ||||
|     DST_STATUS_DEAD, | ||||
|     DST_STATUS_ERROR, | ||||
|     DST_STATUS_DEBUG, | ||||
|     DST_STATUS_PENDING, | ||||
|     DST_STATUS_USER0, | ||||
|     DST_STATUS_USER1, | ||||
|     DST_STATUS_USER2, | ||||
|     DST_STATUS_USER3, | ||||
|     DST_STATUS_USER4, | ||||
|     DST_STATUS_USER5, | ||||
|     DST_STATUS_USER6, | ||||
|     DST_STATUS_USER7, | ||||
|     DST_STATUS_USER8, | ||||
|     DST_STATUS_USER9, | ||||
|     DST_STATUS_NEW, | ||||
|     DST_STATUS_ALIVE | ||||
| } DstFiberStatus; | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
| typedef union Dst Dst; | ||||
| #else | ||||
| typedef struct Dst Dst; | ||||
| #endif | ||||
|  | ||||
| /* All of the dst types */ | ||||
| typedef struct DstFunction DstFunction; | ||||
| typedef struct DstArray DstArray; | ||||
| typedef struct DstBuffer DstBuffer; | ||||
| typedef struct DstTable DstTable; | ||||
| typedef struct DstFiber DstFiber; | ||||
|  | ||||
| /* Other structs */ | ||||
| typedef struct DstAbstractHeader DstAbstractHeader; | ||||
| typedef struct DstFuncDef DstFuncDef; | ||||
| typedef struct DstFuncEnv DstFuncEnv; | ||||
| typedef struct DstKV DstKV; | ||||
| typedef struct DstStackFrame DstStackFrame; | ||||
| typedef struct DstAbstractType DstAbstractType; | ||||
| typedef struct DstArgs DstArgs; | ||||
| typedef struct DstReg DstReg; | ||||
| typedef struct DstSourceMapping DstSourceMapping; | ||||
| typedef int (*DstCFunction)(DstArgs args); | ||||
|  | ||||
| /* Basic types for all Dst Values */ | ||||
| typedef enum DstType { | ||||
|     DST_NIL, | ||||
|     DST_FALSE, | ||||
|     DST_TRUE, | ||||
|     DST_FIBER, | ||||
|     DST_INTEGER, | ||||
|     DST_REAL, | ||||
|     DST_STRING, | ||||
|     DST_SYMBOL, | ||||
|     DST_ARRAY, | ||||
|     DST_TUPLE, | ||||
|     DST_TABLE, | ||||
|     DST_STRUCT, | ||||
|     DST_BUFFER, | ||||
|     DST_FUNCTION, | ||||
|     DST_CFUNCTION, | ||||
|     DST_ABSTRACT | ||||
| } DstType; | ||||
|  | ||||
| #define DST_COUNT_TYPES (DST_ABSTRACT + 1) | ||||
|  | ||||
| /* Type flags */ | ||||
| #define DST_TFLAG_NIL (1 << DST_NIL) | ||||
| #define DST_TFLAG_FALSE (1 << DST_FALSE) | ||||
| #define DST_TFLAG_TRUE (1 << DST_TRUE) | ||||
| #define DST_TFLAG_FIBER (1 << DST_FIBER) | ||||
| #define DST_TFLAG_INTEGER (1 << DST_INTEGER) | ||||
| #define DST_TFLAG_REAL (1 << DST_REAL) | ||||
| #define DST_TFLAG_STRING (1 << DST_STRING) | ||||
| #define DST_TFLAG_SYMBOL (1 << DST_SYMBOL) | ||||
| #define DST_TFLAG_ARRAY (1 << DST_ARRAY) | ||||
| #define DST_TFLAG_TUPLE (1 << DST_TUPLE) | ||||
| #define DST_TFLAG_TABLE (1 << DST_TABLE) | ||||
| #define DST_TFLAG_STRUCT (1 << DST_STRUCT) | ||||
| #define DST_TFLAG_BUFFER (1 << DST_BUFFER) | ||||
| #define DST_TFLAG_FUNCTION (1 << DST_FUNCTION) | ||||
| #define DST_TFLAG_CFUNCTION (1 << DST_CFUNCTION) | ||||
| #define DST_TFLAG_ABSTRACT (1 << DST_ABSTRACT) | ||||
|  | ||||
| /* Some abstractions */ | ||||
| #define DST_TFLAG_BOOLEAN (DST_TFLAG_TRUE | DST_TFLAG_FALSE) | ||||
| #define DST_TFLAG_NUMBER (DST_TFLAG_REAL | DST_TFLAG_INTEGER) | ||||
| #define DST_TFLAG_CALLABLE (DST_TFLAG_FUNCTION | DST_TFLAG_CFUNCTION) | ||||
| #define DST_TFLAG_BYTES (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER) | ||||
| #define DST_TFLAG_INDEXED (DST_TFLAG_ARRAY | DST_TFLAG_TUPLE) | ||||
| #define DST_TFLAG_DICTIONARY (DST_TFLAG_TABLE | DST_TFLAG_STRUCT) | ||||
| #define DST_TFLAG_LENGTHABLE (DST_TFLAG_CHARS | DST_TFLAG_INDEXED | DST_TFLAG_DICTIONARY) | ||||
|  | ||||
| /* We provide two possible implemenations of Dsts. The preferred | ||||
|  * nanboxing approach, and the standard C version. Code in the rest of the | ||||
|  * application must interact through exposed interface. */ | ||||
|  | ||||
| /* Required interface for Dst */ | ||||
| /* wrap and unwrap for all types */ | ||||
| /* Get type quickly */ | ||||
| /* Check against type quickly */ | ||||
| /* Small footprint */ | ||||
| /* 32 bit integer support */ | ||||
|  | ||||
| /* dst_type(x) | ||||
|  * dst_checktype(x, t) | ||||
|  * dst_wrap_##TYPE(x) | ||||
|  * dst_unwrap_##TYPE(x) | ||||
|  * dst_truthy(x) | ||||
|  * dst_memclear(p, n) - clear memory for hash tables to nils | ||||
|  * dst_u64(x) - get 64 bits of payload for hashing | ||||
|  */ | ||||
|  | ||||
| #ifdef DST_NANBOX | ||||
|  | ||||
| #include <math.h> | ||||
|  | ||||
| union Dst { | ||||
|     uint64_t u64; | ||||
|     int64_t i64; | ||||
|     double real; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).u64) | ||||
|  | ||||
| /* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style | ||||
|  * 47 bit payload representaion is that the type bits are no long contiguous. Type | ||||
|  * checking can still be fast, but typewise polymorphism takes a bit longer. However,  | ||||
|  * hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers | ||||
|  * in a 48 bit address space (Linux on ARM). If DST_NANBOX_47 is set, use 47 bit tagged pointers. */ | ||||
|  | ||||
| /*                    |.......Tag.......|.......................Payload..................| */ | ||||
| /* Non-double:        t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
| /* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */ | ||||
|  | ||||
| /* Double (no NaNs):   x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ | ||||
|  | ||||
| #if defined (DST_NANBOX_47) || defined (DST_32) | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF800000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu | ||||
|  | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((uint64_t)(type) | 0x1FFF0) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 47) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xF) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #else /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| #define DST_NANBOX_TAGBITS     0xFFFF000000000000llu | ||||
| #define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFllu | ||||
|  | ||||
| #define dst_nanbox_lowtag(type) \ | ||||
|     ((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1)) | ||||
|  | ||||
| #define dst_nanbox_tag(type) \ | ||||
|     (dst_nanbox_lowtag(type) << 48) | ||||
|  | ||||
| #define dst_type(x) \ | ||||
|     (isnan((x).real) \ | ||||
|         ? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \ | ||||
|         : DST_REAL) | ||||
|  | ||||
| #endif /* defined (DST_NANBOX_47) || defined (DST_32) */ | ||||
|  | ||||
| /* 32 bit mode will not use the full payload for pointers. */ | ||||
| #ifdef DST_32 | ||||
|  | ||||
| #define DST_NANBOX_POINTERBITS 0xFFFFFFFFllu | ||||
| #else | ||||
| #define DST_NANBOX_POINTERBITS DST_NANBOX_PAYLOADBITS | ||||
| #endif | ||||
|  | ||||
| #define dst_nanbox_checkauxtype(x, type) \ | ||||
|     (((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type))) | ||||
|  | ||||
| #define dst_nanbox_isreal(x) \ | ||||
|     (!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL)) | ||||
|  | ||||
| #define dst_checktype(x, t) \ | ||||
|     (((t) == DST_REAL) \ | ||||
|         ? dst_nanbox_isreal(x) \ | ||||
|         : dst_nanbox_checkauxtype((x), (t))) | ||||
|  | ||||
| void *dst_nanbox_to_pointer(Dst x); | ||||
| void dst_nanbox_memempty(DstKV *mem, int32_t count); | ||||
| void *dst_nanbox_memalloc_empty(int32_t count); | ||||
| Dst dst_nanbox_from_pointer(void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_cpointer(const void *p, uint64_t tagmask); | ||||
| Dst dst_nanbox_from_double(double d); | ||||
| Dst dst_nanbox_from_bits(uint64_t bits); | ||||
|  | ||||
| #define dst_memempty(mem, len) dst_nanbox_memempty((mem), (len)) | ||||
| #define dst_memalloc_empty(count) dst_nanbox_memalloc_empty(count) | ||||
|  | ||||
| /* Todo - check for single mask operation */ | ||||
| #define dst_truthy(x) \ | ||||
|     (!(dst_checktype((x), DST_NIL) || dst_checktype((x), DST_FALSE))) | ||||
|  | ||||
| #define dst_nanbox_from_payload(t, p) \ | ||||
|     dst_nanbox_from_bits(dst_nanbox_tag(t) | (p)) | ||||
|  | ||||
| #define dst_nanbox_wrap_(p, t) \ | ||||
|     dst_nanbox_from_pointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| #define dst_nanbox_wrap_c(p, t) \ | ||||
|     dst_nanbox_from_cpointer((p), dst_nanbox_tag(t)) | ||||
|  | ||||
| /* Wrap the simple types */ | ||||
| #define dst_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1) | ||||
| #define dst_wrap_true() dst_nanbox_from_payload(DST_TRUE, 1) | ||||
| #define dst_wrap_false() dst_nanbox_from_payload(DST_FALSE, 1) | ||||
| #define dst_wrap_boolean(b) dst_nanbox_from_payload((b) ? DST_TRUE : DST_FALSE, 1) | ||||
| #define dst_wrap_integer(i) dst_nanbox_from_payload(DST_INTEGER, (uint32_t)(i)) | ||||
| #define dst_wrap_real(r) dst_nanbox_from_double(r) | ||||
|  | ||||
| /* Unwrap the simple types */ | ||||
| #define dst_unwrap_boolean(x) \ | ||||
|     (dst_checktype(x, DST_TRUE)) | ||||
| #define dst_unwrap_integer(x) \ | ||||
|     ((int32_t)((x).u64 & 0xFFFFFFFFlu)) | ||||
| #define dst_unwrap_real(x) ((x).real) | ||||
|  | ||||
| /* Wrap the pointer types */ | ||||
| #define dst_wrap_struct(s) dst_nanbox_wrap_c((s), DST_STRUCT) | ||||
| #define dst_wrap_tuple(s) dst_nanbox_wrap_c((s), DST_TUPLE) | ||||
| #define dst_wrap_fiber(s) dst_nanbox_wrap_((s), DST_FIBER) | ||||
| #define dst_wrap_array(s) dst_nanbox_wrap_((s), DST_ARRAY) | ||||
| #define dst_wrap_table(s) dst_nanbox_wrap_((s), DST_TABLE) | ||||
| #define dst_wrap_buffer(s) dst_nanbox_wrap_((s), DST_BUFFER) | ||||
| #define dst_wrap_string(s) dst_nanbox_wrap_c((s), DST_STRING) | ||||
| #define dst_wrap_symbol(s) dst_nanbox_wrap_c((s), DST_SYMBOL) | ||||
| #define dst_wrap_abstract(s) dst_nanbox_wrap_((s), DST_ABSTRACT) | ||||
| #define dst_wrap_function(s) dst_nanbox_wrap_((s), DST_FUNCTION) | ||||
| #define dst_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION) | ||||
|  | ||||
| /* Unwrap the pointer types */ | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_table(x) ((DstTable *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_abstract(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_pointer(x) (dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)dst_nanbox_to_pointer(x)) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)dst_nanbox_to_pointer(x)) | ||||
|  | ||||
| /* End of [#ifdef DST_NANBOX] */ | ||||
| #else | ||||
|  | ||||
| /* A general dst value type */ | ||||
| struct Dst { | ||||
|     union { | ||||
|         uint64_t u64; | ||||
|         double real; | ||||
|         int32_t integer; | ||||
|         void *pointer; | ||||
|         const void *cpointer; | ||||
|     } as; | ||||
|     DstType type; | ||||
| }; | ||||
|  | ||||
| #define dst_u64(x) ((x).as.u64) | ||||
| #define dst_memempty(mem, count) memset((mem), 0, sizeof(DstKV) * (count)) | ||||
| #define dst_memalloc_empty(count) calloc((count), sizeof(DstKV)) | ||||
| #define dst_type(x) ((x).type) | ||||
| #define dst_checktype(x, t) ((x).type == (t)) | ||||
| #define dst_truthy(x) \ | ||||
|     ((x).type != DST_NIL && (x).type != DST_FALSE) | ||||
|  | ||||
| #define dst_unwrap_struct(x) ((const DstKV *)(x).as.pointer) | ||||
| #define dst_unwrap_tuple(x) ((const Dst *)(x).as.pointer) | ||||
| #define dst_unwrap_fiber(x) ((DstFiber *)(x).as.pointer) | ||||
| #define dst_unwrap_array(x) ((DstArray *)(x).as.pointer) | ||||
| #define dst_unwrap_table(x) ((DstTable *)(x).as.pointer) | ||||
| #define dst_unwrap_buffer(x) ((DstBuffer *)(x).as.pointer) | ||||
| #define dst_unwrap_string(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_symbol(x) ((const uint8_t *)(x).as.pointer) | ||||
| #define dst_unwrap_abstract(x) ((x).as.pointer) | ||||
| #define dst_unwrap_pointer(x) ((x).as.pointer) | ||||
| #define dst_unwrap_function(x) ((DstFunction *)(x).as.pointer) | ||||
| #define dst_unwrap_cfunction(x) ((DstCFunction)(x).as.pointer) | ||||
| #define dst_unwrap_boolean(x) ((x).type == DST_TRUE) | ||||
| #define dst_unwrap_integer(x) ((x).as.integer) | ||||
| #define dst_unwrap_real(x) ((x).as.real) | ||||
|  | ||||
| Dst dst_wrap_nil(void); | ||||
| Dst dst_wrap_real(double x); | ||||
| Dst dst_wrap_integer(int32_t x); | ||||
| Dst dst_wrap_true(void); | ||||
| Dst dst_wrap_false(void); | ||||
| Dst dst_wrap_boolean(int x); | ||||
| Dst dst_wrap_string(const uint8_t *x); | ||||
| Dst dst_wrap_symbol(const uint8_t *x); | ||||
| Dst dst_wrap_array(DstArray *x); | ||||
| Dst dst_wrap_tuple(const Dst *x); | ||||
| Dst dst_wrap_struct(const DstKV *x); | ||||
| Dst dst_wrap_fiber(DstFiber *x); | ||||
| Dst dst_wrap_buffer(DstBuffer *x); | ||||
| Dst dst_wrap_function(DstFunction *x); | ||||
| Dst dst_wrap_cfunction(DstCFunction x); | ||||
| Dst dst_wrap_table(DstTable *x); | ||||
| Dst dst_wrap_abstract(void *x); | ||||
|  | ||||
| /* End of tagged union implementation */ | ||||
| #endif | ||||
|  | ||||
| /* Hold components of arguments passed to DstCFunction. */ | ||||
| struct DstArgs { | ||||
|     int32_t n; | ||||
|     Dst *v; | ||||
|     Dst *ret; | ||||
| }; | ||||
|  | ||||
| /* Fiber flags */ | ||||
| #define DST_FIBER_FLAG_SIGNAL_WAITING (1 << 30) | ||||
|  | ||||
| /* Fiber signal masks. */ | ||||
| #define DST_FIBER_MASK_ERROR 2 | ||||
| #define DST_FIBER_MASK_DEBUG 4 | ||||
| #define DST_FIBER_MASK_YIELD 8 | ||||
|  | ||||
| #define DST_FIBER_MASK_USER0 (16 << 0) | ||||
| #define DST_FIBER_MASK_USER1 (16 << 1) | ||||
| #define DST_FIBER_MASK_USER2 (16 << 2) | ||||
| #define DST_FIBER_MASK_USER3 (16 << 3) | ||||
| #define DST_FIBER_MASK_USER4 (16 << 4) | ||||
| #define DST_FIBER_MASK_USER5 (16 << 5) | ||||
| #define DST_FIBER_MASK_USER6 (16 << 6) | ||||
| #define DST_FIBER_MASK_USER7 (16 << 7) | ||||
| #define DST_FIBER_MASK_USER8 (16 << 8) | ||||
| #define DST_FIBER_MASK_USER9 (16 << 9) | ||||
|  | ||||
| #define DST_FIBER_MASK_USERN(N) (16 << (N)) | ||||
| #define DST_FIBER_MASK_USER 0x3FF0 | ||||
|  | ||||
| #define DST_FIBER_STATUS_MASK 0xFF0000 | ||||
| #define DST_FIBER_STATUS_OFFSET 16 | ||||
|  | ||||
| /* A lightweight green thread in dst. Does not correspond to | ||||
|  * operating system threads. */ | ||||
| struct DstFiber { | ||||
|     Dst *data; | ||||
|     DstFiber *child; /* Keep linked list of fibers for restarting pending fibers */ | ||||
|     DstFunction *root; /* First value */ | ||||
|     int32_t frame; /* Index of the stack frame */ | ||||
|     int32_t stackstart; /* Beginning of next args */ | ||||
|     int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ | ||||
|     int32_t capacity; | ||||
|     int32_t maxstack; /* Arbitrary defined limit for stack overflow */ | ||||
|     uint32_t flags; /* Various flags */ | ||||
| }; | ||||
|  | ||||
| /* Mark if a stack frame is a tail call for debugging */ | ||||
| #define DST_STACKFRAME_TAILCALL 1 | ||||
|  | ||||
| /* A stack frame on the fiber. Is stored along with the stack values. */ | ||||
| struct DstStackFrame { | ||||
|     DstFunction *func; | ||||
|     uint32_t *pc; | ||||
|     DstFuncEnv *env; | ||||
|     int32_t prevframe; | ||||
|     uint32_t flags; | ||||
| }; | ||||
|  | ||||
| /* Number of Dsts a frame takes up in the stack */ | ||||
| #define DST_FRAME_SIZE ((sizeof(DstStackFrame) + sizeof(Dst) - 1) / sizeof(Dst)) | ||||
|  | ||||
| /* A dynamic array type. */ | ||||
| struct DstArray { | ||||
|     Dst *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A bytebuffer type. Used as a mutable string or string builder. */ | ||||
| struct DstBuffer { | ||||
|     uint8_t *data; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
| }; | ||||
|  | ||||
| /* A mutable associative data type. Backed by a hashtable. */ | ||||
| struct DstTable { | ||||
|     DstKV *data; | ||||
|     DstTable *proto; | ||||
|     int32_t count; | ||||
|     int32_t capacity; | ||||
|     int32_t deleted; | ||||
| }; | ||||
|  | ||||
| /* A key value pair in a struct or table */ | ||||
| struct DstKV { | ||||
|     Dst key; | ||||
|     Dst value; | ||||
| }; | ||||
|  | ||||
| /* Some function defintion flags */ | ||||
| #define DST_FUNCDEF_FLAG_VARARG 1 | ||||
| #define DST_FUNCDEF_FLAG_NEEDSENV 4 | ||||
|  | ||||
| struct DstSourceMapping { | ||||
|     int32_t start; | ||||
|     int32_t end; | ||||
| }; | ||||
|  | ||||
| /* A function definition. Contains information needed to instantiate closures. */ | ||||
| struct DstFuncDef { | ||||
|     int32_t *environments; /* Which environments to capture from parent. */ | ||||
|     Dst *constants; | ||||
|     DstFuncDef **defs; | ||||
|     uint32_t *bytecode; | ||||
|  | ||||
|     /* Various debug information */ | ||||
|     DstSourceMapping *sourcemap; | ||||
|     const uint8_t *source; | ||||
|     const uint8_t *sourcepath; | ||||
|     const uint8_t *name; | ||||
|  | ||||
|     uint32_t flags; | ||||
|     int32_t slotcount; /* The amount of stack space required for the function */ | ||||
|     int32_t arity; /* Not including varargs */ | ||||
|     int32_t constants_length; | ||||
|     int32_t bytecode_length; | ||||
|     int32_t environments_length;  | ||||
|     int32_t defs_length;  | ||||
| }; | ||||
|  | ||||
| /* A fuction environment */ | ||||
| struct DstFuncEnv { | ||||
|     union { | ||||
|         DstFiber *fiber; | ||||
|         Dst *values; | ||||
|     } as; | ||||
|     int32_t length; /* Size of environment */ | ||||
|     int32_t offset; /* Stack offset when values still on stack. If offset is <= 0, then | ||||
|         environment is no longer on the stack. */ | ||||
| }; | ||||
|  | ||||
| /* A function */ | ||||
| struct DstFunction { | ||||
|     DstFuncDef *def; | ||||
|     DstFuncEnv *envs[]; | ||||
| }; | ||||
|  | ||||
| /* Parser types */ | ||||
| typedef struct { | ||||
|     Dst key; | ||||
|     int32_t start; | ||||
|     int32_t end; | ||||
| } DstParseKV;  | ||||
|  | ||||
| typedef struct { | ||||
|     DstParseKV *kvs; | ||||
|     int32_t capacity; | ||||
|     int32_t count; | ||||
| } DstParseMap; | ||||
|  | ||||
| typedef struct DstParseState DstParseState; | ||||
| typedef struct DstParser DstParser; | ||||
|  | ||||
| enum DstParserStatus { | ||||
|     DST_PARSE_ROOT, | ||||
|     DST_PARSE_ERROR, | ||||
|     DST_PARSE_FULL, | ||||
|     DST_PARSE_PENDING | ||||
| }; | ||||
|  | ||||
| /* A dst parser */ | ||||
| struct DstParser { | ||||
|     Dst* args; | ||||
|     const char *error; | ||||
|     const uint8_t *sourcelink; | ||||
|     DstParseState *states; | ||||
|     uint8_t *buf; | ||||
|  | ||||
|     DstParseMap map; /* optional map */ | ||||
|     size_t argcount; | ||||
|     size_t argcap; | ||||
|     size_t statecount; | ||||
|     size_t statecap; | ||||
|     size_t bufcount; | ||||
|     size_t bufcap; | ||||
|     size_t index; | ||||
|     int lookback; | ||||
|     int flags; | ||||
| }; | ||||
|  | ||||
| /* Defines an abstract type */ | ||||
| struct DstAbstractType { | ||||
|     const char *name; | ||||
|     int (*gc)(void *data, size_t len); | ||||
|     int (*gcmark)(void *data, size_t len); | ||||
| }; | ||||
|  | ||||
| /* Contains information about userdata */ | ||||
| struct DstAbstractHeader { | ||||
|     const DstAbstractType *type; | ||||
|     size_t size; | ||||
| }; | ||||
|  | ||||
| struct DstReg { | ||||
|     const char *name; | ||||
|     DstCFunction cfun; | ||||
| }; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_TYPES_H_defined */ | ||||
| @@ -62,6 +62,7 @@ src/core/marsh.c | ||||
| src/core/math.c | ||||
| src/core/native.c | ||||
| src/core/os.c | ||||
| src/core/parse.c | ||||
| src/core/string.c | ||||
| src/core/strtod.c | ||||
| src/core/struct.c | ||||
| @@ -87,11 +88,6 @@ src/mainclient/line.c | ||||
| src/mainclient/line.h | ||||
| ) | ||||
|  | ||||
| set(PARSER_SOURCES | ||||
| src/parser/ast.c | ||||
| src/parser/parse.c | ||||
| ) | ||||
|  | ||||
| set(TESTLIB_SOURCES | ||||
| src/testlib/testlib.c | ||||
| ) | ||||
| @@ -101,7 +97,6 @@ ${ASSEMBLER_SOURCES} | ||||
| ${COMPILER_SOURCES} | ||||
| ${CORE_SOURCES} | ||||
| ${MAINCLIENT_SOURCES} | ||||
| ${PARSER_SOURCES} | ||||
| ) | ||||
|  | ||||
| # Set Public headers | ||||
| @@ -112,7 +107,6 @@ src/include/dst/dstcompile.h | ||||
| src/include/dst/dstconfig.h | ||||
| src/include/dst/dstcorelib.h | ||||
| src/include/dst/dstopcodes.h | ||||
| src/include/dst/dstparse.h | ||||
| src/include/dst/dsttypes.h | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										24
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Makefile
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ BINDIR=$(PREFIX)/bin | ||||
| # TODO - when api is finalized, only export public symbols instead of using rdynamic | ||||
| # which exports all symbols. Saves a few KB in binary. | ||||
|  | ||||
| CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 | ||||
| CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -s -O2 | ||||
| CLIBS=-lm -ldl | ||||
| PREFIX=/usr/local | ||||
| DST_TARGET=dst | ||||
| @@ -60,7 +60,6 @@ DST_ASM_SOURCES=$(sort $(wildcard src/assembler/*.c)) | ||||
| DST_COMPILER_SOURCES=$(sort $(wildcard src/compiler/*.c)) | ||||
| DST_CORE_SOURCES=$(sort $(wildcard src/core/*.c)) | ||||
| DST_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c)) | ||||
| DST_PARSER_SOURCES=$(sort $(wildcard src/parser/*.c)) | ||||
|  | ||||
| all: $(DST_TARGET) $(DST_LIBRARY) | ||||
|  | ||||
| @@ -88,8 +87,7 @@ src/compiler/dststlbootstrap.gen.h: src/compiler/boot.dst xxd | ||||
| DST_LIB_SOURCES=$(DST_ASM_SOURCES) \ | ||||
| 				$(DST_COMPILER_SOURCES) \ | ||||
| 				$(DST_CONTEXT_SOURCES) \ | ||||
| 				$(DST_CORE_SOURCES) \ | ||||
| 				$(DST_PARSER_SOURCES) | ||||
| 				$(DST_CORE_SOURCES) | ||||
|  | ||||
| DST_ALL_SOURCES=$(DST_LIB_SOURCES) \ | ||||
| 				$(DST_MAINCLIENT_SOURCES) | ||||
| @@ -140,22 +138,22 @@ natives: $(DST_TARGET) | ||||
| ################# | ||||
|  | ||||
| clean: | ||||
| 	rm $(DST_TARGET) || true | ||||
| 	rm src/**/*.o || true | ||||
| 	rm vgcore.* || true | ||||
| 	rm $(DST_GENERATED_HEADERS) || true | ||||
| 	-rm $(DST_TARGET) | ||||
| 	-rm src/**/*.o | ||||
| 	-rm vgcore.* | ||||
| 	-rm $(DST_GENERATED_HEADERS) | ||||
|  | ||||
| install: $(DST_TARGET) | ||||
| 	cp $(DST_TARGET) $(BINDIR)/$(DST_TARGET) | ||||
| 	mkdir -p $(INCLUDEDIR) | ||||
| 	cp $(DST_HEADERS) $(INCLUDEDIR) | ||||
| 	cp $(DST_LIBRARY) $(LIBDIR)/$(DST_LIBRARY) | ||||
| 	ldconfig | ||||
| 	-ldconfig | ||||
|  | ||||
| uninstall: | ||||
| 	rm $(BINDIR)/$(DST_TARGET) | ||||
| 	rm $(LIBDIR)/$(DST_LIBRARY) | ||||
| 	rm -rf $(INCLUDEDIR) | ||||
| 	ldconfig | ||||
| 	-rm $(BINDIR)/$(DST_TARGET) | ||||
| 	-rm $(LIBDIR)/$(DST_LIBRARY) | ||||
| 	-rm -rf $(INCLUDEDIR) | ||||
| 	-ldconfig | ||||
|  | ||||
| .PHONY: clean install repl debug valgrind test valtest install uninstall | ||||
|   | ||||
| @@ -548,10 +548,6 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { | ||||
|     x = dst_get(s, dst_csymbolv("source")); | ||||
|     if (dst_checktype(x, DST_STRING)) def->source = dst_unwrap_string(x); | ||||
|  | ||||
|     /* Check source path */ | ||||
|     x = dst_get(s, dst_csymbolv("sourcepath")); | ||||
|     if (dst_checktype(x, DST_STRING)) def->sourcepath = dst_unwrap_string(x); | ||||
|  | ||||
|     /* Create slot aliases */ | ||||
|     x = dst_get(s, dst_csymbolv("slots")); | ||||
|     if (dst_seq_view(x, &arr, &count)) { | ||||
| @@ -836,10 +832,6 @@ Dst dst_disasm(DstFuncDef *def) { | ||||
|     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)); | ||||
|     if (NULL != def->sourcepath) { | ||||
|         dst_table_put(ret, dst_csymbolv("sourcepath"), | ||||
|                 dst_wrap_string(def->sourcepath)); | ||||
|     } | ||||
|     if (NULL != def->source) { | ||||
|         dst_table_put(ret, dst_csymbolv("source"), dst_wrap_string(def->source)); | ||||
|     } | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
|   (fn [name & more] | ||||
|    (def len (length more)) | ||||
|    (def fstart (fn recur [i] | ||||
|     (def ith (ast.unwrap1 (get more i))) | ||||
|     (def {i ith} more) | ||||
|     (def t (type ith)) | ||||
|     (def tuple? (= t :tuple)) | ||||
|     (def array? (= t :array)) | ||||
| @@ -189,7 +189,7 @@ evaluates to 10." | ||||
| has an odd number of arguments, the last is the default expression. | ||||
| If no match is found, returns nil" | ||||
|  [dispatch & pairs] | ||||
|   (def atm (atomic? (ast.unwrap1 dispatch))) | ||||
|   (def atm (atomic? dispatch)) | ||||
|   (def sym (if atm dispatch (gensym))) | ||||
|   (defn aux [i] | ||||
|     (def restlen (- (length pairs) i)) | ||||
| @@ -209,15 +209,14 @@ If no match is found, returns nil" | ||||
| assigned as if with def, and the body of the let form returns the last | ||||
| value." | ||||
|  [bindings & body] | ||||
|   (def head (ast.unwrap1 bindings)) | ||||
|   (if (odd? (length head)) (error "expected even number of bindings to let")) | ||||
|   (def len (length head)) | ||||
|   (if (odd? (length bindings)) (error "expected even number of bindings to let")) | ||||
|   (def len (length bindings)) | ||||
|   (var i 0) | ||||
|   (var accum @['do]) | ||||
|   (while (< i len) | ||||
|    (array.push accum (tuple 'def | ||||
|                      (get head i) | ||||
|                      (get head (+ 1 i)))) | ||||
|                      (get bindings i) | ||||
|                      (get bindings (+ 1 i)))) | ||||
|    (+= i 2)) | ||||
|   (array.concat accum body) | ||||
|   (apply1 tuple accum)) | ||||
| @@ -225,21 +224,19 @@ value." | ||||
| (defmacro loop | ||||
|   "A general purpose loop macro." | ||||
|   [head & body] | ||||
|   (def head1 (ast.unwrap1 head)) | ||||
|   (def len (length head1)) | ||||
|   (def len (length head)) | ||||
|   (defn doone | ||||
|     [i preds] | ||||
|     (default preds @['and]) | ||||
|     (if (>= i len) | ||||
|       (tuple.prepend body 'do) | ||||
|       (do | ||||
|         (def bindings (get head1 i)) | ||||
|         (def ubindings (ast.unwrap1 bindings)) | ||||
|         (def verb (ast.unwrap1 (get head1 (+ i 1)))) | ||||
|         (def object (ast.unwrap1 (get head1 (+ i 2)))) | ||||
|         (if (keyword? ubindings) | ||||
|         (def bindings (get head i)) | ||||
|         (def verb (get head (+ i 1))) | ||||
|         (def object (get head (+ i 2))) | ||||
|         (if (keyword? bindings) | ||||
|           (switch | ||||
|             ubindings | ||||
|             bindings | ||||
|             :while (do | ||||
|                      (array.push preds verb) | ||||
|                      (doone (+ i 2) preds)) | ||||
| @@ -249,7 +246,7 @@ value." | ||||
|           (switch | ||||
|             verb | ||||
|             :range (do | ||||
|                      (def [start end _inc] (ast.unwrap1 object)) | ||||
|                      (def [start end _inc] object) | ||||
|                      (def inc (if _inc _inc 1)) | ||||
|                      (def endsym (gensym)) | ||||
|                      (def preds @['and (tuple < bindings endsym)]) | ||||
| @@ -318,7 +315,7 @@ evaluates to true." | ||||
|   (if | ||||
|    (>= (inc i) len) fi | ||||
|    (do | ||||
|     (if (atomic? (ast.unwrap1 fi)) | ||||
|     (if (atomic? fi) | ||||
|      (tuple 'if fi fi (aux (inc i))) | ||||
|      (do | ||||
|       (def $fi (gensym)) | ||||
| @@ -335,7 +332,6 @@ evaluates to true." | ||||
|  all the forms with let and evaluates the first expression else | ||||
|  evaluates the second" | ||||
|   [bindings tru fal] | ||||
|   (def bindings (ast.unwrap1 bindings)) | ||||
|   (def len (length bindings)) | ||||
|   (if (zero? len) (error "expected at least 1 binding")) | ||||
|   (if (odd? len) (error "expected an even number of bindings")) | ||||
| @@ -345,7 +341,7 @@ evaluates to true." | ||||
|     (if (>= i len) | ||||
|      tru | ||||
|      (do | ||||
|       (def atm (atomic? (ast.unwrap1 bl))) | ||||
|       (def atm (atomic? bl)) | ||||
|       (def sym (if atm bl (gensym))) | ||||
|       (if atm | ||||
|        # Simple binding | ||||
| @@ -605,8 +601,7 @@ the predicate, and abort on first failure." | ||||
| in form, and inserts the modified firsts form into the second form | ||||
| in the same manner, and so on. Useful for expressing pipelines of data." | ||||
|  [x & forms] | ||||
|  (defn fop [last nextform] | ||||
|   (def n (ast.unwrap1 nextform)) | ||||
|  (defn fop [last n] | ||||
|   (def [h t] (if (= :tuple (type n)) | ||||
|         [tuple (get n 0) (array.slice n 1)] | ||||
|         [tuple n @[]])) | ||||
| @@ -619,8 +614,7 @@ in the same manner, and so on. Useful for expressing pipelines of data." | ||||
| in form, and inserts the modified firsts form into the second form | ||||
| in the same manner, and so on. Useful for expressing pipelines of data." | ||||
|  [x & forms] | ||||
|  (defn fop [last nextform] | ||||
|   (def n (ast.unwrap1 nextform)) | ||||
|  (defn fop [last n] | ||||
|   (def [h t] (if (= :tuple (type n)) | ||||
|         [tuple (get n 0) (array.slice n 1)] | ||||
|         [tuple n @[]])) | ||||
| @@ -865,7 +859,6 @@ to call on any table. Does not print table prototype information." | ||||
|  | ||||
|   (def specs { | ||||
|       ':= expandlast | ||||
|       'ast-quote identity | ||||
|       'def expandlast | ||||
|       'do expandall | ||||
|       'fn expandfn | ||||
| @@ -894,13 +887,12 @@ to call on any table. Does not print table prototype information." | ||||
|   (def res (dotable t)) | ||||
|   (if (= (table.to-struct res) (table.to-struct t)) t res)) | ||||
|  | ||||
|  (def ux (ast.unwrap1 x)) | ||||
|  (switch (type ux) | ||||
|   :tuple (dotup ux) | ||||
|   :array (doarray* ux) | ||||
|   :struct (table.to-struct (dotable ux)) | ||||
|   :table (dotable* ux) | ||||
|   ux)) | ||||
|  (switch (type x) | ||||
|   :tuple (dotup x) | ||||
|   :array (doarray* x) | ||||
|   :struct (table.to-struct (dotable x)) | ||||
|   :table (dotable* x) | ||||
|   x)) | ||||
|  | ||||
| (defn macroexpand | ||||
|  "Expand macros completely." | ||||
| @@ -1013,13 +1005,20 @@ onvalue." | ||||
|     :pc pc | ||||
|     :c c | ||||
|     :name name | ||||
|     :source source | ||||
|     :source-start source-start | ||||
|     :source-end source-end | ||||
|    } :in st] | ||||
|    (file.write stdout "  in") | ||||
|    (when c (file.write stdout " cfunction")) | ||||
|    (if name | ||||
|      (file.write stdout (string " " name)) | ||||
|      (when func (file.write stdout (string " " func)))) | ||||
|    (when pc (file.write stdout (string " (pc=" pc ")"))) | ||||
|      (file.write stdout " " name) | ||||
|      (when func (file.write stdout " " func))) | ||||
|    (if source (file.write stdout " [" source "]")) | ||||
|    (cond | ||||
|      source-start (file.write stdout " at byte range (" | ||||
|       (string source-start) ":" (string source-end) ")") | ||||
|      pc (file.write stdout " at (pc=" (string pc) ")")) | ||||
|    (when tail (file.write stdout " (tailcall)")) | ||||
|    (file.write stdout "\n")))) | ||||
|  | ||||
| @@ -1145,13 +1144,12 @@ returned from compiling and running the file." | ||||
| symbols into the current environment, prepending a given prefix as needed. | ||||
| (use the :as or :prefix option to set a prefix). If no prefix is provided, | ||||
| use the name of the module as a prefix." | ||||
|   (def upath (string (ast.unwrap path))) | ||||
|   (def argm (map (fn [x] | ||||
|                     (if (and (symbol? x) (= (get x 0) 58)) | ||||
|                       x | ||||
|                       (string x))) | ||||
|                      (ast.unwrap args))) | ||||
|   (apply tuple import* '_env upath argm)) | ||||
|                      args)) | ||||
|   (apply tuple import* '_env (string path) argm)) | ||||
|  | ||||
| (defn repl [getchunk onvalue onerr] | ||||
|   "Run a repl. The first parameter is an optional function to call to | ||||
|   | ||||
| @@ -29,13 +29,12 @@ | ||||
| /* This logic needs to be expanded for more types */ | ||||
|  | ||||
| /* Check if a function received only numbers */ | ||||
| static int numbers(DstFopts opts, DstAst *ast, DstSM *args) { | ||||
| static int numbers(DstFopts opts, DstSlot *args) { | ||||
|    int32_t i; | ||||
|    int32_t len = dst_v_count(args); | ||||
|    (void) opts; | ||||
|    (void) ast; | ||||
|    for (i = 0; i < len; i++) { | ||||
|        DstSlot s = args[i].slot; | ||||
|        DstSlot s = args[i]; | ||||
|        if (s.flags & DST_SLOT_CONSTANT) { | ||||
|            Dst c = s.constant; | ||||
|            if (!dst_checktype(c, DST_INTEGER) && | ||||
| @@ -48,34 +47,33 @@ static int numbers(DstFopts opts, DstAst *ast, DstSM *args) { | ||||
|    return 1; | ||||
| } | ||||
|  | ||||
| /* Fold constants in a DstSM */ | ||||
| static DstSM *foldc(DstSM *sms, DstAst *ast, Dst (*fn)(Dst lhs, Dst rhs)) { | ||||
| /* Fold constants in a DstSlot [] */ | ||||
| static DstSlot *foldc(DstSlot *slots, Dst (*fn)(Dst lhs, Dst rhs)) { | ||||
|     int32_t ccount; | ||||
|     int32_t i; | ||||
|     DstSM *ret = NULL; | ||||
|     DstSM sm; | ||||
|     DstSlot *ret = NULL; | ||||
|     DstSlot s; | ||||
|     Dst current; | ||||
|     for (ccount = 0; ccount < dst_v_count(sms); ccount++) { | ||||
|         if (sms[ccount].slot.flags & DST_SLOT_CONSTANT) continue; | ||||
|     for (ccount = 0; ccount < dst_v_count(slots); ccount++) { | ||||
|         if (slots[ccount].flags & DST_SLOT_CONSTANT) continue; | ||||
|         break; | ||||
|     } | ||||
|     if (ccount < 2) return sms; | ||||
|     current = fn(sms[0].slot.constant, sms[1].slot.constant); | ||||
|     if (ccount < 2) return slots; | ||||
|     current = fn(slots[0].constant, slots[1].constant); | ||||
|     for (i = 2; i < ccount; i++) { | ||||
|         Dst nextarg = sms[i].slot.constant; | ||||
|         Dst nextarg = slots[i].constant; | ||||
|         current = fn(current, nextarg); | ||||
|     } | ||||
|     sm.slot = dstc_cslot(current); | ||||
|     sm.map = ast; | ||||
|     dst_v_push(ret, sm); | ||||
|     for (; i < dst_v_count(sms); i++) { | ||||
|         dst_v_push(ret, sms[i]); | ||||
|     s = dstc_cslot(current); | ||||
|     dst_v_push(ret, s); | ||||
|     for (; i < dst_v_count(slots); i++) { | ||||
|         dst_v_push(ret, slots[i]); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /* Emit a series of instructions instead of a function call to a math op */ | ||||
| static DstSlot opreduce(DstFopts opts, DstAst *ast, DstSM *args, int op) { | ||||
| static DstSlot opreduce(DstFopts opts, DstSlot *args, int op) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     int32_t i, len; | ||||
|     int32_t op1, op2; | ||||
| @@ -84,42 +82,41 @@ static DstSlot opreduce(DstFopts opts, DstAst *ast, DstSM *args, int op) { | ||||
|     if (len == 0) { | ||||
|         return dstc_cslot(dst_wrap_integer(0)); | ||||
|     } else if (len == 1) { | ||||
|         return args[0].slot; | ||||
|         return args[0]; | ||||
|     } | ||||
|     t = dstc_gettarget(opts); | ||||
|     /* Compile initial two arguments */ | ||||
|     op1 = dstc_preread(c, args[0].map, 0xFF, 1, args[0].slot); | ||||
|     op2 = dstc_preread(c, args[1].map, 0xFF, 2, args[1].slot); | ||||
|     dstc_emit(c, ast, (t.index << 8) | (op1 << 16) | (op2 << 24) | op); | ||||
|     dstc_postread(c, args[0].slot, op1); | ||||
|     dstc_postread(c, args[1].slot, op2); | ||||
|     op1 = dstc_preread(c, 0xFF, 1, args[0]); | ||||
|     op2 = dstc_preread(c, 0xFF, 2, args[1]); | ||||
|     dstc_emit(c, (t.index << 8) | (op1 << 16) | (op2 << 24) | op); | ||||
|     dstc_postread(c, args[0], op1); | ||||
|     dstc_postread(c, args[1], op2); | ||||
|     for (i = 2; i < len; i++) { | ||||
|         op1 = dstc_preread(c, args[i].map, 0xFF, 1, args[i].slot); | ||||
|         dstc_emit(c, ast, (t.index << 8) | (t.index << 16) | (op1 << 24) | op); | ||||
|         dstc_postread(c, args[i].slot, op1); | ||||
|         op1 = dstc_preread(c, 0xFF, 1, args[i]); | ||||
|         dstc_emit(c, (t.index << 8) | (t.index << 16) | (op1 << 24) | op); | ||||
|         dstc_postread(c, args[i], op1); | ||||
|     } | ||||
|     return t; | ||||
| } | ||||
|  | ||||
| static DstSlot add(DstFopts opts, DstAst *ast, DstSM *args) { | ||||
|     DstSM *newargs = foldc(args, ast, dst_op_add); | ||||
|     DstSlot ret = opreduce(opts, ast, newargs, DOP_ADD); | ||||
| static DstSlot add(DstFopts opts, DstSlot *args) { | ||||
|     DstSlot *newargs = foldc(args, dst_op_add); | ||||
|     DstSlot ret = opreduce(opts, newargs, DOP_ADD); | ||||
|     if (newargs != args) dstc_freeslots(opts.compiler, newargs); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static DstSlot sub(DstFopts opts, DstAst *ast, DstSM *args) { | ||||
|     DstSM *newargs; | ||||
| static DstSlot sub(DstFopts opts, DstSlot *args) { | ||||
|     DstSlot *newargs; | ||||
|     if (dst_v_count(args) == 1) { | ||||
|         newargs = NULL; | ||||
|         dst_v_push(newargs, args[0]); | ||||
|         dst_v_push(newargs, args[0]); | ||||
|         newargs[0].slot = dstc_cslot(dst_wrap_integer(0)); | ||||
|         newargs[0].map = ast; | ||||
|         newargs[0] = dstc_cslot(dst_wrap_integer(0)); | ||||
|     } else { | ||||
|         newargs = foldc(args, ast, dst_op_subtract); | ||||
|         newargs = foldc(args, dst_op_subtract); | ||||
|     } | ||||
|     DstSlot ret = opreduce(opts, ast, newargs, DOP_SUBTRACT); | ||||
|     DstSlot ret = opreduce(opts, newargs, DOP_SUBTRACT); | ||||
|     if (newargs != args) dstc_freeslots(opts.compiler, newargs); | ||||
|     return ret; | ||||
| } | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstparse.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include "compile.h" | ||||
|  | ||||
| @@ -31,6 +30,34 @@ | ||||
| #undef DST_V_DEF_COPYMEM | ||||
| #undef DST_V_DEF_FLATTENMEM | ||||
|  | ||||
| void dstc_ast_push(DstCompiler *c, Dst x) { | ||||
|     DstSourceMapping mapping; | ||||
|     if (c->parser) { | ||||
|         int found = dst_parser_lookup(c->parser, x, &mapping); | ||||
|         if (!found) { | ||||
|             /* Duplicate last value */ | ||||
|             if (dst_v_count(c->ast_stack)) { | ||||
|                 mapping = dst_v_last(c->ast_stack); | ||||
|             } else { | ||||
|                 mapping.start = -1; | ||||
|                 mapping.end = -1; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         mapping.start = -1; | ||||
|         mapping.end = -1; | ||||
|     } | ||||
|     dst_v_push(c->ast_stack, mapping); | ||||
| } | ||||
|  | ||||
| void dstc_ast_pop(DstCompiler *c) { | ||||
|     dst_v_pop(c->ast_stack); | ||||
| } | ||||
|  | ||||
| DstSourceMapping dstc_ast(DstCompiler *c) { | ||||
|     return dst_v_last(c->ast_stack); | ||||
| } | ||||
|  | ||||
| DstFopts dstc_fopts_default(DstCompiler *c) { | ||||
|     DstFopts ret; | ||||
|     ret.compiler = c; | ||||
| @@ -40,25 +67,18 @@ DstFopts dstc_fopts_default(DstCompiler *c) { | ||||
| } | ||||
|  | ||||
| /* Throw an error with a dst string. */ | ||||
| void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m) { | ||||
| void dstc_error(DstCompiler *c, const uint8_t *m) { | ||||
|     /* Don't override first error */ | ||||
|     if (c->result.status == DST_COMPILE_ERROR) { | ||||
|         return; | ||||
|     } | ||||
|     if (NULL != ast) { | ||||
|         c->result.error_start = ast->source_start; | ||||
|         c->result.error_end = ast->source_end; | ||||
|     } else { | ||||
|         c->result.error_start = -1; | ||||
|         c->result.error_end = -1; | ||||
|     } | ||||
|     c->result.status = DST_COMPILE_ERROR; | ||||
|     c->result.error = m; | ||||
| } | ||||
|  | ||||
| /* Throw an error with a message in a cstring */ | ||||
| void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m) { | ||||
|     dstc_error(c, ast, dst_cstring(m)); | ||||
| void dstc_cerror(DstCompiler *c, const char *m) { | ||||
|     dstc_error(c, dst_cstring(m)); | ||||
| } | ||||
|  | ||||
| /* Check error */ | ||||
| @@ -239,7 +259,6 @@ DstSlot dstc_cslot(Dst x) { | ||||
| /* Allow searching for symbols. Return information about the symbol */ | ||||
| DstSlot dstc_resolve( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         const uint8_t *sym) { | ||||
|  | ||||
|     DstSlot ret = dstc_cslot(dst_wrap_nil()); | ||||
| @@ -275,7 +294,7 @@ DstSlot dstc_resolve( | ||||
|         switch (btype) { | ||||
|             default: | ||||
|             case DST_BINDING_NONE: | ||||
|                 dstc_error(c, ast, dst_formatc("unknown symbol %q", sym)); | ||||
|                 dstc_error(c, dst_formatc("unknown symbol %q", sym)); | ||||
|                 return dstc_cslot(dst_wrap_nil()); | ||||
|             case DST_BINDING_DEF: | ||||
|             case DST_BINDING_MACRO: /* Macro should function like defs when not in calling pos */ | ||||
| @@ -341,13 +360,13 @@ DstSlot dstc_resolve( | ||||
| } | ||||
|  | ||||
| /* Emit a raw instruction with source mapping. */ | ||||
| void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr) { | ||||
| void dstc_emit(DstCompiler *c, uint32_t instr) { | ||||
|     dst_v_push(c->buffer, instr); | ||||
|     dst_v_push(c->mapbuffer, ast); | ||||
|     dst_v_push(c->mapbuffer, dstc_ast(c)); | ||||
| } | ||||
|  | ||||
| /* Add a constant to the current scope. Return the index of the constant. */ | ||||
| static int32_t dstc_const(DstCompiler *c, DstAst *ast, Dst x) { | ||||
| static int32_t dstc_const(DstCompiler *c, Dst x) { | ||||
|     DstScope *scope = &dst_v_last(c->scopes); | ||||
|     int32_t i, len; | ||||
|     /* Get the topmost function scope */ | ||||
| @@ -364,7 +383,7 @@ static int32_t dstc_const(DstCompiler *c, DstAst *ast, Dst x) { | ||||
|     } | ||||
|     /* Ensure not too many constsants. */ | ||||
|     if (len >= 0xFFFF) { | ||||
|         dstc_cerror(c, ast, "too many constants"); | ||||
|         dstc_cerror(c, "too many constants"); | ||||
|         return 0; | ||||
|     } | ||||
|     dst_v_push(scope->consts, x); | ||||
| @@ -372,22 +391,22 @@ static int32_t dstc_const(DstCompiler *c, DstAst *ast, Dst x) { | ||||
| } | ||||
|  | ||||
| /* Load a constant into a local slot */ | ||||
| static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) { | ||||
| static void dstc_loadconst(DstCompiler *c, Dst k, int32_t dest) { | ||||
|     switch (dst_type(k)) { | ||||
|         case DST_NIL: | ||||
|             dstc_emit(c, ast, (dest << 8) | DOP_LOAD_NIL); | ||||
|             dstc_emit(c, (dest << 8) | DOP_LOAD_NIL); | ||||
|             break; | ||||
|         case DST_TRUE: | ||||
|             dstc_emit(c, ast, (dest << 8) | DOP_LOAD_TRUE); | ||||
|             dstc_emit(c, (dest << 8) | DOP_LOAD_TRUE); | ||||
|             break; | ||||
|         case DST_FALSE: | ||||
|             dstc_emit(c, ast, (dest << 8) | DOP_LOAD_FALSE); | ||||
|             dstc_emit(c, (dest << 8) | DOP_LOAD_FALSE); | ||||
|             break; | ||||
|         case DST_INTEGER: | ||||
|             { | ||||
|                 int32_t i = dst_unwrap_integer(k); | ||||
|                 if (i <= INT16_MAX && i >= INT16_MIN) { | ||||
|                     dstc_emit(c, ast, | ||||
|                     dstc_emit(c, | ||||
|                             (i << 16) | | ||||
|                             (dest << 8) | | ||||
|                             DOP_LOAD_INTEGER); | ||||
| @@ -398,8 +417,8 @@ static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) { | ||||
|         default: | ||||
|         do_constant: | ||||
|             { | ||||
|                 int32_t cindex = dstc_const(c, ast, k); | ||||
|                 dstc_emit(c, ast, | ||||
|                 int32_t cindex = dstc_const(c, k); | ||||
|                 dstc_emit(c, | ||||
|                         (cindex << 16) | | ||||
|                         (dest << 8) | | ||||
|                         DOP_LOAD_CONSTANT); | ||||
| @@ -412,7 +431,6 @@ static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) { | ||||
|  * that can be used in an instruction. */ | ||||
| int32_t dstc_preread( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         int32_t max, | ||||
|         int nth, | ||||
|         DstSlot s) { | ||||
| @@ -424,24 +442,24 @@ int32_t dstc_preread( | ||||
|  | ||||
|     if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { | ||||
|         ret = dstc_lslotn(c, 0xFF, nth); | ||||
|         dstc_loadconst(c, ast, s.constant, ret); | ||||
|         dstc_loadconst(c, s.constant, ret); | ||||
|         /* If we also are a reference, deref the one element array */ | ||||
|         if (s.flags & DST_SLOT_REF) { | ||||
|             dstc_emit(c, ast, | ||||
|             dstc_emit(c, | ||||
|                     (ret << 16) | | ||||
|                     (ret << 8) | | ||||
|                     DOP_GET_INDEX); | ||||
|         } | ||||
|     } else if (s.envindex >= 0 || s.index > max) { | ||||
|         ret = dstc_lslotn(c, max, nth); | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(s.index) << 24) | | ||||
|                 ((uint32_t)(s.envindex) << 16) | | ||||
|                 ((uint32_t)(ret) << 8) | | ||||
|                 DOP_LOAD_UPVALUE); | ||||
|     } else if (s.index > max) { | ||||
|         ret = dstc_lslotn(c, max, nth); | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(s.index) << 16) | | ||||
|                 ((uint32_t)(ret) << 8) | | ||||
|                     DOP_MOVE_NEAR); | ||||
| @@ -478,7 +496,6 @@ int dstc_sequal(DstSlot lhs, DstSlot rhs) { | ||||
|  * be writeable (not a literal). */ | ||||
| void dstc_copy( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         DstSlot dest, | ||||
|         DstSlot src) { | ||||
|     int writeback = 0; | ||||
| @@ -488,7 +505,7 @@ void dstc_copy( | ||||
|  | ||||
|     /* Can't write to constants */ | ||||
|     if (dest.flags & DST_SLOT_CONSTANT) { | ||||
|         dstc_cerror(c, ast, "cannot write to constant"); | ||||
|         dstc_cerror(c, "cannot write to constant"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -511,21 +528,21 @@ void dstc_copy( | ||||
|     /* If dest is a near index, do some optimization */ | ||||
|     if (dest.envindex < 0 && dest.index >= 0 && dest.index <= 0xFF) { | ||||
|         if (src.flags & DST_SLOT_CONSTANT) { | ||||
|             dstc_loadconst(c, ast, src.constant, dest.index); | ||||
|             dstc_loadconst(c, src.constant, dest.index); | ||||
|         } else if (src.flags & DST_SLOT_REF) { | ||||
|             dstc_loadconst(c, ast, src.constant, dest.index); | ||||
|             dstc_emit(c, ast, | ||||
|             dstc_loadconst(c, src.constant, dest.index); | ||||
|             dstc_emit(c, | ||||
|                     (dest.index << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_GET_INDEX); | ||||
|         } else if (src.envindex >= 0) { | ||||
|             dstc_emit(c, ast, | ||||
|             dstc_emit(c, | ||||
|                     (src.index << 24) | | ||||
|                     (src.envindex << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_LOAD_UPVALUE); | ||||
|         } else { | ||||
|             dstc_emit(c, ast, | ||||
|             dstc_emit(c, | ||||
|                     (src.index << 16) | | ||||
|                     (dest.index << 8) | | ||||
|                     DOP_MOVE_NEAR); | ||||
| @@ -536,15 +553,15 @@ void dstc_copy( | ||||
|     /* Process: src -> srclocal -> destlocal -> dest */ | ||||
|  | ||||
|     /* src -> srclocal */ | ||||
|     srclocal = dstc_preread(c, ast, 0xFF, 1, src); | ||||
|     srclocal = dstc_preread(c, 0xFF, 1, src); | ||||
|  | ||||
|     /* Pull down dest (find destlocal) */ | ||||
|     if (dest.flags & DST_SLOT_REF) { | ||||
|         writeback = 1; | ||||
|         destlocal = srclocal; | ||||
|         reflocal = dstc_lslotn(c, 0xFF, 2); | ||||
|         dstc_emit(c, ast, | ||||
|                 (dstc_const(c, ast, dest.constant) << 16) | | ||||
|         dstc_emit(c, | ||||
|                 (dstc_const(c, dest.constant) << 16) | | ||||
|                 (reflocal << 8) | | ||||
|                 DOP_LOAD_CONSTANT); | ||||
|     } else if (dest.envindex >= 0) { | ||||
| @@ -559,7 +576,7 @@ void dstc_copy( | ||||
|  | ||||
|     /* srclocal -> destlocal */ | ||||
|     if (srclocal != destlocal) { | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(srclocal) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_MOVE_NEAR); | ||||
| @@ -567,18 +584,18 @@ void dstc_copy( | ||||
|  | ||||
|     /* destlocal -> dest */ | ||||
|     if (writeback == 1) { | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 (destlocal << 16) | | ||||
|                 (reflocal << 8) | | ||||
|                 DOP_PUT_INDEX); | ||||
|     } else if (writeback == 2) { | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 24) | | ||||
|                 ((uint32_t)(dest.envindex) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_SET_UPVALUE); | ||||
|     } else if (writeback == 3) { | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 ((uint32_t)(dest.index) << 16) | | ||||
|                 ((uint32_t)(destlocal) << 8) | | ||||
|                 DOP_MOVE_FAR); | ||||
| @@ -592,13 +609,13 @@ void dstc_copy( | ||||
| } | ||||
|  | ||||
| /* Generate the return instruction for a slot. */ | ||||
| DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s) { | ||||
| DstSlot dstc_return(DstCompiler *c, DstSlot s) { | ||||
|     if (!(s.flags & DST_SLOT_RETURNED)) { | ||||
|         if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL)) { | ||||
|             dstc_emit(c, ast, DOP_RETURN_NIL); | ||||
|             dstc_emit(c, DOP_RETURN_NIL); | ||||
|         } else { | ||||
|             int32_t ls = dstc_preread(c, ast, 0xFFFF, 1, s); | ||||
|             dstc_emit(c, ast, DOP_RETURN | (ls << 8)); | ||||
|             int32_t ls = dstc_preread(c, 0xFFFF, 1, s); | ||||
|             dstc_emit(c, DOP_RETURN | (ls << 8)); | ||||
|             dstc_postread(c, s, ls); | ||||
|         } | ||||
|         s.flags |= DST_SLOT_RETURNED; | ||||
| @@ -624,77 +641,69 @@ DstSlot dstc_gettarget(DstFopts opts) { | ||||
| } | ||||
|  | ||||
| /* Get a bunch of slots for function arguments */ | ||||
| DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) { | ||||
| DstSlot *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) { | ||||
|     int32_t i; | ||||
|     DstSM *ret = NULL; | ||||
|     DstSlot *ret = NULL; | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
|     for (i = 0; i < len; i++) { | ||||
|         DstSM sm; | ||||
|         sm.slot = dstc_value(subopts, vals[i]); | ||||
|         sm.map = dst_ast_node(vals[i]); | ||||
|         dst_v_push(ret, sm); | ||||
|         dst_v_push(ret, dstc_value(subopts, vals[i])); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /* Get a bunch of slots for function arguments */ | ||||
| DstSM *dstc_toslotskv(DstCompiler *c, Dst ds) { | ||||
|     DstSM *ret = NULL; | ||||
| DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds) { | ||||
|     DstSlot *ret = NULL; | ||||
|     const DstKV *kv = NULL; | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
|     while ((kv = dstc_next(ds, kv))) { | ||||
|         DstSM km, vm; | ||||
|         km.slot = dstc_value(subopts, kv->key); | ||||
|         km.map = dst_ast_node(kv->key); | ||||
|         vm.slot = dstc_value(subopts, kv->value); | ||||
|         vm.map = dst_ast_node(kv->value); | ||||
|         dst_v_push(ret, km); | ||||
|         dst_v_push(ret, vm); | ||||
|         dst_v_push(ret, dstc_value(subopts, kv->key)); | ||||
|         dst_v_push(ret, dstc_value(subopts, kv->value)); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /* Push slots load via dstc_toslots. */ | ||||
| void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms) { | ||||
| void dstc_pushslots(DstCompiler *c, DstSlot *slots) { | ||||
|     int32_t i; | ||||
|     for (i = 0; i < dst_v_count(sms) - 2; i += 3) { | ||||
|         int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot); | ||||
|         int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFF, 2, sms[i + 1].slot); | ||||
|         int32_t ls3 = dstc_preread(c, sms[i + 2].map, 0xFF, 3, sms[i + 2].slot); | ||||
|         dstc_emit(c, ast, | ||||
|     for (i = 0; i < dst_v_count(slots) - 2; i += 3) { | ||||
|         int32_t ls1 = dstc_preread(c, 0xFF, 1, slots[i]); | ||||
|         int32_t ls2 = dstc_preread(c, 0xFF, 2, slots[i + 1]); | ||||
|         int32_t ls3 = dstc_preread(c, 0xFF, 3, slots[i + 2]); | ||||
|         dstc_emit(c, | ||||
|                 (ls3 << 24) | | ||||
|                 (ls2 << 16) | | ||||
|                 (ls1 << 8) | | ||||
|                 DOP_PUSH_3); | ||||
|         dstc_postread(c, sms[i].slot, ls1); | ||||
|         dstc_postread(c, sms[i + 1].slot, ls2); | ||||
|         dstc_postread(c, sms[i + 2].slot, ls3); | ||||
|         dstc_postread(c, slots[i], ls1); | ||||
|         dstc_postread(c, slots[i + 1], ls2); | ||||
|         dstc_postread(c, slots[i + 2], ls3); | ||||
|     } | ||||
|     if (i == dst_v_count(sms) - 2) { | ||||
|         int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot); | ||||
|         int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFFFF, 2, sms[i + 1].slot); | ||||
|         dstc_emit(c, ast, | ||||
|     if (i == dst_v_count(slots) - 2) { | ||||
|         int32_t ls1 = dstc_preread(c, 0xFF, 1, slots[i]); | ||||
|         int32_t ls2 = dstc_preread(c, 0xFFFF, 2, slots[i + 1]); | ||||
|         dstc_emit(c, | ||||
|                 (ls2 << 16) | | ||||
|                 (ls1 << 8) | | ||||
|                 DOP_PUSH_2); | ||||
|         dstc_postread(c, sms[i].slot, ls1); | ||||
|         dstc_postread(c, sms[i + 1].slot, ls2); | ||||
|     } else if (i == dst_v_count(sms) - 1) { | ||||
|         int32_t ls1 = dstc_preread(c, sms[i].map, 0xFFFFFF, 1, sms[i].slot); | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_postread(c, slots[i], ls1); | ||||
|         dstc_postread(c, slots[i + 1], ls2); | ||||
|     } else if (i == dst_v_count(slots) - 1) { | ||||
|         int32_t ls1 = dstc_preread(c, 0xFFFFFF, 1, slots[i]); | ||||
|         dstc_emit(c, | ||||
|                 (ls1 << 8) | | ||||
|                 DOP_PUSH); | ||||
|         dstc_postread(c, sms[i].slot, ls1); | ||||
|         dstc_postread(c, slots[i], ls1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Free slots loaded via dstc_toslots */ | ||||
| void dstc_freeslots(DstCompiler *c, DstSM *sms) { | ||||
| void dstc_freeslots(DstCompiler *c, DstSlot *slots) { | ||||
|     int32_t i; | ||||
|     for (i = 0; i < dst_v_count(sms); i++) { | ||||
|         dstc_freeslot(c, sms[i].slot); | ||||
|     for (i = 0; i < dst_v_count(slots); i++) { | ||||
|         dstc_freeslot(c, slots[i]); | ||||
|     } | ||||
|     dst_v_free(sms); | ||||
|     dst_v_free(slots); | ||||
| } | ||||
|  | ||||
| /* Compile some code that will be thrown away. Used to ensure | ||||
| @@ -715,7 +724,7 @@ void dstc_throwaway(DstFopts opts, Dst x) { | ||||
| } | ||||
|  | ||||
| /* Compile a call or tailcall instruction */ | ||||
| static DstSlot dstc_call(DstFopts opts, DstAst *ast, DstSM *sms, DstSlot fun) { | ||||
| static DstSlot dstc_call(DstFopts opts, DstSlot *slots, DstSlot fun) { | ||||
|     DstSlot retslot; | ||||
|     int32_t localindex; | ||||
|     DstCompiler *c = opts.compiler; | ||||
| @@ -723,57 +732,57 @@ static DstSlot dstc_call(DstFopts opts, DstAst *ast, DstSM *sms, DstSlot fun) { | ||||
|     if (fun.flags & DST_SLOT_CONSTANT) { | ||||
|         if (dst_checktype(fun.constant, DST_CFUNCTION)) { | ||||
|             const DstCFunOptimizer *o = dstc_cfunopt(dst_unwrap_cfunction(fun.constant)); | ||||
|             if (o && o->can_optimize(opts, ast, sms)) { | ||||
|             if (o && o->can_optimize(opts, slots)) { | ||||
|                 specialized = 1; | ||||
|                 retslot = o->optimize(opts, ast, sms); | ||||
|                 retslot = o->optimize(opts, slots); | ||||
|             } | ||||
|         } | ||||
|         /* TODO dst function inlining (no c functions)*/ | ||||
|     } | ||||
|     if (!specialized) { | ||||
|         dstc_pushslots(c, ast, sms); | ||||
|         localindex = dstc_preread(c, ast, 0xFF, 1, fun); | ||||
|         dstc_pushslots(c, slots); | ||||
|         localindex = dstc_preread(c, 0xFF, 1, fun); | ||||
|         if (opts.flags & DST_FOPTS_TAIL) { | ||||
|             dstc_emit(c, ast, (localindex << 8) | DOP_TAILCALL); | ||||
|             dstc_emit(c, (localindex << 8) | DOP_TAILCALL); | ||||
|             retslot = dstc_cslot(dst_wrap_nil()); | ||||
|             retslot.flags = DST_SLOT_RETURNED; | ||||
|         } else { | ||||
|             retslot = dstc_gettarget(opts); | ||||
|             dstc_emit(c, ast, (localindex << 16) | (retslot.index << 8) | DOP_CALL); | ||||
|             dstc_emit(c, (localindex << 16) | (retslot.index << 8) | DOP_CALL); | ||||
|         } | ||||
|         dstc_postread(c, fun, localindex); | ||||
|     } | ||||
|     dstc_freeslots(c, sms); | ||||
|     dstc_freeslots(c, slots); | ||||
|     return retslot; | ||||
| } | ||||
|  | ||||
| static DstSlot dstc_array(DstFopts opts, DstAst *ast, Dst x) { | ||||
| static DstSlot dstc_array(DstFopts opts, Dst x) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstArray *a = dst_unwrap_array(x); | ||||
|     return dstc_call(opts, ast, | ||||
|     return dstc_call(opts, | ||||
|             dstc_toslots(c, a->data, a->count), | ||||
|             dstc_cslot(dst_wrap_cfunction(dst_core_array))); | ||||
| } | ||||
|  | ||||
| static DstSlot dstc_tablector(DstFopts opts, DstAst *ast, Dst x, DstCFunction cfun) { | ||||
| static DstSlot dstc_tablector(DstFopts opts, Dst x, DstCFunction cfun) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     return dstc_call(opts, ast, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun))); | ||||
|     return dstc_call(opts, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun))); | ||||
| } | ||||
|  | ||||
| static DstSlot dstc_bufferctor(DstFopts opts, DstAst *ast, Dst x) { | ||||
| static DstSlot dstc_bufferctor(DstFopts opts, Dst x) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstBuffer *b = dst_unwrap_buffer(x); | ||||
|     Dst onearg = dst_stringv(b->data, b->count); | ||||
|     return dstc_call(opts, ast, | ||||
|     return dstc_call(opts, | ||||
|             dstc_toslots(c, &onearg, 1), | ||||
|             dstc_cslot(dst_wrap_cfunction(dst_core_buffer))); | ||||
| } | ||||
|  | ||||
| /* Compile a symbol */ | ||||
| DstSlot dstc_symbol(DstFopts opts, DstAst *ast, const uint8_t *sym) { | ||||
| DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) { | ||||
|     if (dst_string_length(sym) && sym[0] != ':') { | ||||
|         /* Non keyword */ | ||||
|         return dstc_resolve(opts.compiler, ast, sym); | ||||
|         return dstc_resolve(opts.compiler, sym); | ||||
|     } else { | ||||
|         /* Keyword */ | ||||
|         return dstc_cslot(dst_wrap_symbol(sym)); | ||||
| @@ -783,18 +792,16 @@ DstSlot dstc_symbol(DstFopts opts, DstAst *ast, const uint8_t *sym) { | ||||
| /* Compile a single value */ | ||||
| DstSlot dstc_value(DstFopts opts, Dst x) { | ||||
|     DstSlot ret; | ||||
|     DstAst *ast; | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     int macrorecur = 0; | ||||
|     opts.compiler->recursion_guard--; | ||||
|     ast = dst_ast_node(x); | ||||
|     x = dst_ast_unwrap1(x); | ||||
|     dstc_ast_push(c, x); | ||||
| recur: | ||||
|     if (dstc_iserr(&opts)) { | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     if (opts.compiler->recursion_guard <= 0) { | ||||
|         dstc_cerror(opts.compiler, ast, "recursed too deeply"); | ||||
|         dstc_cerror(opts.compiler, "recursed too deeply"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     switch (dst_type(x)) { | ||||
| @@ -804,7 +811,7 @@ recur: | ||||
|         case DST_SYMBOL: | ||||
|             { | ||||
|                 const uint8_t *sym = dst_unwrap_symbol(x); | ||||
|                 ret = dstc_symbol(opts, ast, sym); | ||||
|                 ret = dstc_symbol(opts, sym); | ||||
|                 break; | ||||
|             } | ||||
|         case DST_TUPLE: | ||||
| @@ -820,12 +827,12 @@ recur: | ||||
|                     ret = dstc_cslot(x); | ||||
|                 } else { | ||||
|                     /* Symbols could be specials */ | ||||
|                     headval = dst_ast_unwrap1(tup[0]); | ||||
|                     headval = tup[0]; | ||||
|                     if (dst_checktype(headval, DST_SYMBOL)) { | ||||
|                         const uint8_t *headsym = dst_unwrap_symbol(headval); | ||||
|                         const DstSpecial *s = dstc_special(headsym); | ||||
|                         if (NULL != s) { | ||||
|                             ret = s->compile(opts, ast, dst_tuple_length(tup) - 1, tup + 1); | ||||
|                             ret = s->compile(opts, dst_tuple_length(tup) - 1, tup + 1); | ||||
|                             compiled = 1; | ||||
|                         } else { | ||||
|                             /* Check macro */ | ||||
| @@ -834,7 +841,7 @@ recur: | ||||
|                             if (btype == DST_BINDING_MACRO && | ||||
|                                     dst_checktype(macVal, DST_FUNCTION)) { | ||||
|                                 if (macrorecur++ > DST_RECURSION_GUARD) { | ||||
|                                     dstc_cerror(c, ast, "macro expansion recursed too deeply"); | ||||
|                                     dstc_cerror(c, "macro expansion recursed too deeply"); | ||||
|                                     return dstc_cslot(dst_wrap_nil()); | ||||
|                                 } else { | ||||
|                                     DstFunction *f = dst_unwrap_function(macVal); | ||||
| @@ -843,7 +850,7 @@ recur: | ||||
|                                     dst_gcunlock(lock); | ||||
|                                     if (status != DST_SIGNAL_OK) { | ||||
|                                         const uint8_t *es = dst_formatc("error in macro expansion: %V", x); | ||||
|                                         dstc_error(c, ast, es); | ||||
|                                         dstc_error(c, es); | ||||
|                                     } | ||||
|                                     /* Tail recur on the value */ | ||||
|                                     goto recur; | ||||
| @@ -856,35 +863,37 @@ recur: | ||||
|                         subopts.flags = DST_FUNCTION | DST_CFUNCTION; | ||||
|                         head = dstc_value(subopts, tup[0]); | ||||
|                         /* Add compile function call */ | ||||
|                         ret = dstc_call(opts, ast, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head); | ||||
|                         ret = dstc_call(opts, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|         case DST_ARRAY: | ||||
|             ret = dstc_array(opts, ast, x); | ||||
|             ret = dstc_array(opts, x); | ||||
|             break; | ||||
|         case DST_STRUCT: | ||||
|             ret = dstc_tablector(opts, ast, x, dst_core_struct); | ||||
|             ret = dstc_tablector(opts, x, dst_core_struct); | ||||
|             break; | ||||
|         case DST_TABLE: | ||||
|             ret = dstc_tablector(opts, ast, x, dst_core_table); | ||||
|             ret = dstc_tablector(opts, x, dst_core_table); | ||||
|             break; | ||||
|         case DST_BUFFER: | ||||
|             ret = dstc_bufferctor(opts, ast, x); | ||||
|             ret = dstc_bufferctor(opts, x); | ||||
|             break; | ||||
|     } | ||||
|     if (dstc_iserr(&opts)) { | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     if (opts.flags & DST_FOPTS_TAIL) { | ||||
|         ret = dstc_return(opts.compiler, ast, ret); | ||||
|         ret = dstc_return(opts.compiler, ret); | ||||
|     } | ||||
|     if (opts.flags & DST_FOPTS_HINT && !dstc_sequal(opts.hint, ret)) { | ||||
|         dstc_copy(opts.compiler, ast, opts.hint, ret); | ||||
|         dstc_copy(opts.compiler, opts.hint, ret); | ||||
|         ret = opts.hint; | ||||
|     } | ||||
|     opts.compiler->recursion_guard++; | ||||
|     /* Only pop on good path in case of error. */ | ||||
|     dstc_ast_pop(c); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @@ -906,7 +915,7 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) { | ||||
|     def->defs_length = dst_v_count(scope.defs); | ||||
|     def->defs = dst_v_flatten(scope.defs); | ||||
|  | ||||
|     /* Copy bytecode */ | ||||
|     /* Copy bytecode (only last chunk) */ | ||||
|     def->bytecode_length = dst_v_count(c->buffer) - scope.bytecode_start; | ||||
|     if (def->bytecode_length) { | ||||
|         size_t s = sizeof(int32_t) * def->bytecode_length; | ||||
| @@ -924,21 +933,17 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) { | ||||
|                 DST_OUT_OF_MEMORY; | ||||
|             } | ||||
|             for (i = 0; i < dst_v_count(c->mapbuffer); i++) { | ||||
|                 DstAst *a = c->mapbuffer[i]; | ||||
|                 DstSourceMapping mapping; | ||||
|                 if (a) { | ||||
|                     mapping.start = a->source_start; | ||||
|                     mapping.end = a->source_end; | ||||
|                 } else { | ||||
|                     mapping.start = -1; | ||||
|                     mapping.end = -1; | ||||
|                 } | ||||
|                 def->sourcemap[i] = mapping; | ||||
|                 def->sourcemap[i] = c->mapbuffer[i]; | ||||
|             } | ||||
|             dst_v__cnt(c->mapbuffer) = scope.bytecode_start; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Get source from parser */ | ||||
|     if (c->parser && (c->parser->flags & DST_PARSEFLAG_SOURCEMAP)) { | ||||
|         def->source = dst_to_string(c->parser->source); | ||||
|     } | ||||
|  | ||||
|     def->arity = 0; | ||||
|     def->flags = 0; | ||||
|     if (scope.flags & DST_SCOPE_ENV) { | ||||
| @@ -952,12 +957,14 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) { | ||||
| } | ||||
|  | ||||
| /* Initialize a compiler */ | ||||
| static void dstc_init(DstCompiler *c, DstTable *env) { | ||||
| static void dstc_init(DstCompiler *c, DstTable *env, DstParser *p) { | ||||
|     c->scopes = NULL; | ||||
|     c->buffer = NULL; | ||||
|     c->mapbuffer = NULL; | ||||
|     c->recursion_guard = DST_RECURSION_GUARD; | ||||
|     c->env = env; | ||||
|     c->parser = p; | ||||
|     c->ast_stack = NULL; | ||||
|     /* Init result */ | ||||
|     c->result.error = NULL; | ||||
|     c->result.status = DST_COMPILE_OK; | ||||
| @@ -972,16 +979,17 @@ static void dstc_deinit(DstCompiler *c) { | ||||
|     dst_v_free(c->scopes); | ||||
|     dst_v_free(c->buffer); | ||||
|     dst_v_free(c->mapbuffer); | ||||
|     dst_v_free(c->ast_stack); | ||||
|     c->env = NULL; | ||||
| } | ||||
|  | ||||
| /* Compile a form. */ | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, int flags) { | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, int flags, DstParser *p) { | ||||
|     DstCompiler c; | ||||
|     DstFopts fopts; | ||||
|     (void) flags; | ||||
|  | ||||
|     dstc_init(&c, env); | ||||
|     dstc_init(&c, env, p); | ||||
|  | ||||
|     /* Push a function scope */ | ||||
|     dstc_scope(&c, DST_SCOPE_FUNCTION | DST_SCOPE_TOP); | ||||
| @@ -1010,9 +1018,15 @@ int dst_compile_cfun(DstArgs args) { | ||||
|     DstCompileResult res; | ||||
|     DstTable *t; | ||||
|     DstTable *env; | ||||
|     DST_FIXARITY(args, 2); | ||||
|     DST_MINARITY(args, 2); | ||||
|     DST_MAXARITY(args, 3); | ||||
|     DST_ARG_TABLE(env, args, 1); | ||||
|     res = dst_compile(args.v[0], env, 0); | ||||
|     DstParser *p = NULL; | ||||
|     if (args.n == 3) { | ||||
|         p = dst_check_parser(args.v[2]); | ||||
|         if (!p) DST_THROW(args, "expected parser for second argument"); | ||||
|     } | ||||
|     res = dst_compile(args.v[0], env, 0, p); | ||||
|     if (res.status == DST_COMPILE_OK) { | ||||
|         DST_RETURN_FUNCTION(args, dst_thunk(res.funcdef)); | ||||
|     } else { | ||||
|   | ||||
| @@ -54,12 +54,6 @@ struct DstSlot { | ||||
|     Dst constant; /* If the slot has a constant value */ | ||||
| }; | ||||
|  | ||||
| /* Slot and map pairing */ | ||||
| typedef struct DstSM { | ||||
|     DstSlot slot; | ||||
|     DstAst *map; | ||||
| } DstSM; | ||||
|  | ||||
| #define DST_SCOPE_FUNCTION 1 | ||||
| #define DST_SCOPE_ENV 2 | ||||
| #define DST_SCOPE_TOP 4 | ||||
| @@ -106,11 +100,17 @@ struct DstCompiler { | ||||
|     DstScope *scopes; | ||||
|  | ||||
|     uint32_t *buffer; | ||||
|     DstAst **mapbuffer; | ||||
|     DstSourceMapping *mapbuffer; | ||||
|  | ||||
|     /* Keep track of where we are in the source */ | ||||
|     DstSourceMapping *ast_stack; | ||||
|  | ||||
|     /* Hold the environment */ | ||||
|     DstTable *env; | ||||
|  | ||||
|     /* Hold a reference to a parser if we need it */ | ||||
|     DstParser *parser; | ||||
|  | ||||
|     DstCompileResult result; | ||||
| }; | ||||
|  | ||||
| @@ -133,18 +133,23 @@ DstFopts dstc_fopts_default(DstCompiler *c); | ||||
|  * optimizations should be tried before compiling a normal function call. */ | ||||
| struct DstCFunOptimizer { | ||||
|     DstCFunction cfun; | ||||
|     int (*can_optimize)(DstFopts opts, DstAst *ast, DstSM *args); | ||||
|     DstSlot (*optimize)(DstFopts opts, DstAst *ast, DstSM *args); | ||||
|     int (*can_optimize)(DstFopts opts, DstSlot *args); | ||||
|     DstSlot (*optimize)(DstFopts opts, DstSlot *args); | ||||
| }; | ||||
|  | ||||
| /* A grouping of a named special and the corresponding compiler fragment */ | ||||
| struct DstSpecial { | ||||
|     const char *name; | ||||
|     DstSlot (*compile)(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv); | ||||
|     DstSlot (*compile)(DstFopts opts, int32_t argn, const Dst *argv); | ||||
| }; | ||||
|  | ||||
| /****************************************************/ | ||||
|  | ||||
| /* Manipulate the ast stack for source mapping reasons. */ | ||||
| void dstc_ast_push(DstCompiler *c, Dst x); | ||||
| void dstc_ast_pop(DstCompiler *c); | ||||
| DstSourceMapping dstc_ast(DstCompiler *c); | ||||
|  | ||||
| /* Get a cfunction optimizer. Return NULL if none exists.  */ | ||||
| const DstCFunOptimizer *dstc_cfunopt(DstCFunction cfun); | ||||
|  | ||||
| @@ -178,7 +183,6 @@ void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s); | ||||
|  * that can be used in an instruction. */ | ||||
| int32_t dstc_preread( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         int32_t max, | ||||
|         int nth, | ||||
|         DstSlot s); | ||||
| @@ -189,7 +193,6 @@ void dstc_postread(DstCompiler *c, DstSlot s, int32_t index); | ||||
| /* Move value from one slot to another. Cannot copy to constant slots. */ | ||||
| void dstc_copy( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         DstSlot dest, | ||||
|         DstSlot src); | ||||
|  | ||||
| @@ -197,27 +200,27 @@ void dstc_copy( | ||||
| void dstc_throwaway(DstFopts opts, Dst x); | ||||
|  | ||||
| /* Generate the return instruction for a slot. */ | ||||
| DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s); | ||||
| DstSlot dstc_return(DstCompiler *c, DstSlot s); | ||||
|  | ||||
| /* Get a target slot for emitting an instruction. Will always return | ||||
|  * a local slot. */ | ||||
| DstSlot dstc_gettarget(DstFopts opts); | ||||
|  | ||||
| /* Get a bunch of slots for function arguments */ | ||||
| DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len); | ||||
| DstSlot *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len); | ||||
|  | ||||
| /* Get a bunch of slots for function arguments */ | ||||
| DstSM *dstc_toslotskv(DstCompiler *c, Dst ds); | ||||
| DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds); | ||||
|  | ||||
| /* Push slots load via dstc_toslots. */ | ||||
| void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms); | ||||
| void dstc_pushslots(DstCompiler *c, DstSlot *slots); | ||||
|  | ||||
| /* Free slots loaded via dstc_toslots */ | ||||
| void dstc_freeslots(DstCompiler *c, DstSM *sms); | ||||
| void dstc_freeslots(DstCompiler *c, DstSlot *slots); | ||||
|  | ||||
| /* Store an error */ | ||||
| void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m); | ||||
| void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m); | ||||
| void dstc_error(DstCompiler *c, const uint8_t *m); | ||||
| void dstc_cerror(DstCompiler *c, const char *m); | ||||
|  | ||||
| /* Dispatch to correct form compiler */ | ||||
| DstSlot dstc_value(DstFopts opts, Dst x); | ||||
| @@ -234,13 +237,10 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c); | ||||
| /* Create a destory slots */ | ||||
| DstSlot dstc_cslot(Dst x); | ||||
|  | ||||
| /* Free a slot */ | ||||
| void dstc_freeslot(DstCompiler *c, DstSlot slot); | ||||
|  | ||||
| /* Search for a symbol */ | ||||
| DstSlot dstc_resolve(DstCompiler *c, DstAst *ast, const uint8_t *sym); | ||||
| DstSlot dstc_resolve(DstCompiler *c, const uint8_t *sym); | ||||
|  | ||||
| /* Emit instructions. */ | ||||
| void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr); | ||||
| void dstc_emit(DstCompiler *c, uint32_t instr); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -23,23 +23,24 @@ | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include <dst/dstparse.h> | ||||
|  | ||||
| /* Run a string */ | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len) { | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath) { | ||||
|     DstParser parser; | ||||
|     int errflags = 0; | ||||
|     int32_t index = 0; | ||||
|     int dudeol = 0; | ||||
|     int done = 0; | ||||
|     Dst source = sourcePath ? dst_cstringv(sourcePath) : dst_wrap_nil(); | ||||
|  | ||||
|     dst_parser_init(&parser, DST_PARSEFLAG_SOURCEMAP); | ||||
|     dst_parser_init(&parser, sourcePath ? DST_PARSEFLAG_SOURCEMAP : 0); | ||||
|     parser.source = source; | ||||
|     while (!errflags && !done) { | ||||
|         switch (dst_parser_status(&parser)) { | ||||
|             case DST_PARSE_FULL: | ||||
|                 { | ||||
|                     Dst form = dst_parser_produce(&parser); | ||||
|                     DstCompileResult cres = dst_compile(form, env, 0); | ||||
|                     DstCompileResult cres = dst_compile(form, env, 0, &parser); | ||||
|                     if (cres.status == DST_COMPILE_OK) { | ||||
|                         DstFunction *f = dst_thunk(cres.funcdef); | ||||
|                         DstFiber *fiber = dst_fiber(f, 64); | ||||
| @@ -85,9 +86,9 @@ int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len) { | ||||
|     return errflags; | ||||
| } | ||||
|  | ||||
| int dst_dostring(DstTable *env, const char *str) { | ||||
| int dst_dostring(DstTable *env, const char *str, const char *sourcePath) { | ||||
|     int32_t len = 0; | ||||
|     while (str[len]) ++len; | ||||
|     return dst_dobytes(env, (const uint8_t *)str, len); | ||||
|     return dst_dobytes(env, (const uint8_t *)str, len, sourcePath); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,22 +23,13 @@ | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstcompile.h> | ||||
| #include <dst/dstparse.h> | ||||
| #include "compile.h" | ||||
| #include <headerlibs/strbinsearch.h> | ||||
| #include <headerlibs/vector.h> | ||||
|  | ||||
| DstSlot dstc_quote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     if (argn != 1) { | ||||
|         dstc_cerror(opts.compiler, ast, "expected 1 argument"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     return dstc_cslot(dst_ast_unwrap(argv[0])); | ||||
| } | ||||
|  | ||||
| DstSlot dstc_astquote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     if (argn != 1) { | ||||
|         dstc_cerror(opts.compiler, ast, "expected 1 argument"); | ||||
|         dstc_cerror(opts.compiler, "expected 1 argument"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     return dstc_cslot(argv[0]); | ||||
| @@ -46,20 +37,17 @@ DstSlot dstc_astquote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) | ||||
|  | ||||
| static void destructure(DstCompiler *c, Dst left, DstSlot right, | ||||
|         void (*leaf)(DstCompiler *c, | ||||
|             DstAst *ast, | ||||
|             const uint8_t *sym, | ||||
|             DstSlot s, | ||||
|             DstTable *attr), | ||||
|         DstTable *attr) { | ||||
|     DstAst *ast = dst_ast_node(left); | ||||
|     left = dst_ast_unwrap1(left); | ||||
|     switch (dst_type(left)) { | ||||
|         default: | ||||
|             dstc_cerror(c, ast, "unexpected type in destructuring"); | ||||
|             dstc_cerror(c, "unexpected type in destructuring"); | ||||
|             break; | ||||
|         case DST_SYMBOL: | ||||
|             /* Leaf, assign right to left */ | ||||
|             leaf(c, ast, dst_unwrap_symbol(left), right, attr); | ||||
|             leaf(c, dst_unwrap_symbol(left), right, attr); | ||||
|             break; | ||||
|         case DST_TUPLE: | ||||
|         case DST_ARRAY: | ||||
| @@ -70,18 +58,18 @@ static void destructure(DstCompiler *c, Dst left, DstSlot right, | ||||
|                 for (i = 0; i < len; i++) { | ||||
|                     DstSlot newright; | ||||
|                     Dst subval = values[i]; | ||||
|                     localright = dstc_preread(c, ast, 0xFF, 1, right); | ||||
|                     localright = dstc_preread(c, 0xFF, 1, right); | ||||
|                     localsub = dstc_lslotn(c, 0xFF, 3); | ||||
|                     if (i < 0x100) { | ||||
|                         dstc_emit(c, ast, | ||||
|                         dstc_emit(c, | ||||
|                                 (i << 24) | | ||||
|                                 (localright << 16) | | ||||
|                                 (localsub << 8) | | ||||
|                                 DOP_GET_INDEX); | ||||
|                     } else { | ||||
|                         DstSlot islot = dstc_cslot(dst_wrap_integer(i)); | ||||
|                         int32_t locali = dstc_preread(c, ast, 0xFF, 2, islot); | ||||
|                         dstc_emit(c, ast, | ||||
|                         int32_t locali = dstc_preread(c, 0xFF, 2, islot); | ||||
|                         dstc_emit(c, | ||||
|                                 (locali << 24) | | ||||
|                                 (localright << 16) | | ||||
|                                 (localsub << 8) | | ||||
| @@ -109,10 +97,10 @@ static void destructure(DstCompiler *c, Dst left, DstSlot right, | ||||
|                     DstSlot newright; | ||||
|                     DstSlot kslot = dstc_value(dstc_fopts_default(c), kv->key); | ||||
|                     Dst subval = kv->value; | ||||
|                     localright = dstc_preread(c, ast, 0xFF, 1, right); | ||||
|                     localright = dstc_preread(c, 0xFF, 1, right); | ||||
|                     localsub = dstc_lslotn(c, 0xFF, 3); | ||||
|                     int32_t localk = dstc_preread(c, ast, 0xFF, 2, kslot); | ||||
|                     dstc_emit(c, ast, | ||||
|                     int32_t localk = dstc_preread(c, 0xFF, 2, kslot); | ||||
|                     dstc_emit(c, | ||||
|                             (localk << 24) | | ||||
|                             (localright << 16) | | ||||
|                             (localsub << 8) | | ||||
| @@ -134,28 +122,28 @@ static void destructure(DstCompiler *c, Dst left, DstSlot right, | ||||
|  | ||||
| } | ||||
|  | ||||
| DstSlot dstc_varset(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_varset(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstFopts subopts = dstc_fopts_default(opts.compiler); | ||||
|     DstSlot ret, dest; | ||||
|     Dst head; | ||||
|     if (argn != 2) { | ||||
|         dstc_cerror(opts.compiler, ast, "expected 2 arguments"); | ||||
|         dstc_cerror(opts.compiler, "expected 2 arguments"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     head = dst_ast_unwrap(argv[0]); | ||||
|     head = argv[0]; | ||||
|     if (!dst_checktype(head, DST_SYMBOL)) { | ||||
|         dstc_cerror(opts.compiler, ast, "expected symbol"); | ||||
|         dstc_cerror(opts.compiler, "expected symbol"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     dest = dstc_resolve(opts.compiler, ast, dst_unwrap_symbol(head)); | ||||
|     dest = dstc_resolve(opts.compiler, dst_unwrap_symbol(head)); | ||||
|     if (!(dest.flags & DST_SLOT_MUTABLE)) { | ||||
|         dstc_cerror(opts.compiler, ast, "cannot set constant"); | ||||
|         dstc_cerror(opts.compiler, "cannot set constant"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     subopts.flags = DST_FOPTS_HINT; | ||||
|     subopts.hint = dest; | ||||
|     ret = dstc_value(subopts, argv[1]); | ||||
|     dstc_copy(opts.compiler, ast, dest, ret); | ||||
|     dstc_copy(opts.compiler, dest, ret); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| @@ -164,10 +152,10 @@ static DstTable *handleattr(DstCompiler *c, int32_t argn, const Dst *argv) { | ||||
|     int32_t i; | ||||
|     DstTable *tab = dst_table(2); | ||||
|     for (i = 1; i < argn - 1; i++) { | ||||
|         Dst attr = dst_ast_unwrap1(argv[i]); | ||||
|         Dst attr = argv[i]; | ||||
|         switch (dst_type(attr)) { | ||||
|             default: | ||||
|                 dstc_cerror(c, dst_ast_node(argv[i]), "could not add metadata to binding"); | ||||
|                 dstc_cerror(c, "could not add metadata to binding"); | ||||
|                 break; | ||||
|             case DST_SYMBOL: | ||||
|                 dst_table_put(tab, attr, dst_wrap_true()); | ||||
| @@ -180,14 +168,14 @@ static DstTable *handleattr(DstCompiler *c, int32_t argn, const Dst *argv) { | ||||
|     return tab; | ||||
| } | ||||
|  | ||||
| static DstSlot dohead(DstCompiler *c, DstFopts opts, DstAst *ast, Dst *head, int32_t argn, const Dst *argv) { | ||||
| static DstSlot dohead(DstCompiler *c, DstFopts opts, Dst *head, int32_t argn, const Dst *argv) { | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
|     DstSlot ret; | ||||
|     if (argn < 2) { | ||||
|         dstc_cerror(c, ast, "expected at least 2 arguments"); | ||||
|         dstc_cerror(c, "expected at least 2 arguments"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     *head = dst_ast_unwrap1(argv[0]); | ||||
|     *head = argv[0]; | ||||
|     subopts.flags = opts.flags & ~(DST_FOPTS_TAIL | DST_FOPTS_DROP); | ||||
|     subopts.hint = opts.hint; | ||||
|     ret = dstc_value(subopts, argv[argn - 1]); | ||||
| @@ -195,7 +183,7 @@ static DstSlot dohead(DstCompiler *c, DstFopts opts, DstAst *ast, Dst *head, int | ||||
| } | ||||
|  | ||||
| /* Def or var a symbol in a local scope */ | ||||
| static DstSlot namelocal(DstCompiler *c, DstAst *ast, Dst head, int32_t flags, DstSlot ret) { | ||||
| static DstSlot namelocal(DstCompiler *c, Dst head, int32_t flags, DstSlot ret) { | ||||
|     /* Non root scope, bring to local slot */ | ||||
|     if (ret.flags & DST_SLOT_NAMED || | ||||
|             ret.envindex >= 0 || | ||||
| @@ -208,7 +196,7 @@ static DstSlot namelocal(DstCompiler *c, DstAst *ast, Dst head, int32_t flags, D | ||||
|         localslot.flags = flags; | ||||
|         localslot.envindex = -1; | ||||
|         localslot.constant = dst_wrap_nil(); | ||||
|         dstc_copy(c, ast, localslot, ret); | ||||
|         dstc_copy(c, localslot, ret); | ||||
|         ret = localslot; | ||||
|     } | ||||
|     ret.flags |= flags; | ||||
| @@ -218,7 +206,6 @@ static DstSlot namelocal(DstCompiler *c, DstAst *ast, Dst head, int32_t flags, D | ||||
|  | ||||
| static void varleaf( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         const uint8_t *sym, | ||||
|         DstSlot s, | ||||
|         DstTable *attr) { | ||||
| @@ -235,23 +222,23 @@ static void varleaf( | ||||
|         refarrayslot = refslot; | ||||
|         refslot.flags |= DST_SLOT_REF | DST_SLOT_NAMED | DST_SLOT_MUTABLE; | ||||
|         /* Generate code to set ref */ | ||||
|         int32_t refarrayindex = dstc_preread(c, ast, 0xFF, 1, refarrayslot); | ||||
|         int32_t retindex = dstc_preread(c, ast, 0xFF, 2, s); | ||||
|         dstc_emit(c, ast, | ||||
|         int32_t refarrayindex = dstc_preread(c, 0xFF, 1, refarrayslot); | ||||
|         int32_t retindex = dstc_preread(c, 0xFF, 2, s); | ||||
|         dstc_emit(c, | ||||
|                 (retindex << 16) | | ||||
|                 (refarrayindex << 8) | | ||||
|                 DOP_PUT_INDEX); | ||||
|         dstc_postread(c, refarrayslot, refarrayindex); | ||||
|         dstc_postread(c, s, retindex); | ||||
|     } else { | ||||
|         namelocal(c, ast, dst_wrap_symbol(sym), DST_SLOT_NAMED | DST_SLOT_MUTABLE, s) ; | ||||
|         namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED | DST_SLOT_MUTABLE, s) ; | ||||
|     } | ||||
| } | ||||
|  | ||||
| DstSlot dstc_var(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     Dst head; | ||||
|     DstSlot ret = dohead(c, opts, ast, &head, argn, argv); | ||||
|     DstSlot ret = dohead(c, opts, &head, argn, argv); | ||||
|     if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); | ||||
|     destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv)); | ||||
|     return dstc_cslot(dst_wrap_nil()); | ||||
| @@ -259,7 +246,6 @@ DstSlot dstc_var(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  | ||||
| static void defleaf( | ||||
|         DstCompiler *c, | ||||
|         DstAst *ast, | ||||
|         const uint8_t *sym, | ||||
|         DstSlot s, | ||||
|         DstTable *attr) { | ||||
| @@ -274,10 +260,10 @@ static void defleaf( | ||||
|         dst_table_put(c->env, dst_wrap_symbol(sym), dst_wrap_table(tab)); | ||||
|  | ||||
|         /* Put value in table when evaulated */ | ||||
|         tableindex = dstc_preread(c, ast, 0xFF, 1, tabslot); | ||||
|         valsymindex = dstc_preread(c, ast, 0xFF, 2, valsym); | ||||
|         valueindex = dstc_preread(c, ast, 0xFF, 3, s); | ||||
|         dstc_emit(c, ast, | ||||
|         tableindex = dstc_preread(c, 0xFF, 1, tabslot); | ||||
|         valsymindex = dstc_preread(c, 0xFF, 2, valsym); | ||||
|         valueindex = dstc_preread(c, 0xFF, 3, s); | ||||
|         dstc_emit(c, | ||||
|                 (valueindex << 24) | | ||||
|                 (valsymindex << 16) | | ||||
|                 (tableindex << 8) | | ||||
| @@ -286,15 +272,15 @@ static void defleaf( | ||||
|         dstc_postread(c, valsym, valsymindex); | ||||
|         dstc_postread(c, s, valueindex); | ||||
|     } else { | ||||
|         namelocal(c, ast, dst_wrap_symbol(sym), DST_SLOT_NAMED, s); | ||||
|         namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED, s); | ||||
|     } | ||||
| } | ||||
|  | ||||
| DstSlot dstc_def(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     Dst head; | ||||
|     opts.flags &= ~DST_FOPTS_HINT; | ||||
|     DstSlot ret = dohead(c, opts, ast, &head, argn, argv); | ||||
|     DstSlot ret = dohead(c, opts, &head, argn, argv); | ||||
|     if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); | ||||
|     destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv)); | ||||
|     return dstc_cslot(dst_wrap_nil()); | ||||
| @@ -311,7 +297,7 @@ DstSlot dstc_def(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  * ... | ||||
|  * :done | ||||
|  */ | ||||
| DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     int32_t labelr, labeljr, labeld, labeljd, condlocal; | ||||
|     DstFopts condopts, bodyopts; | ||||
| @@ -321,7 +307,7 @@ DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     const int drop = opts.flags & DST_FOPTS_DROP; | ||||
|  | ||||
|     if (argn < 2 || argn > 3) { | ||||
|         dstc_cerror(c, ast, "expected 2 or 3 arguments to if"); | ||||
|         dstc_cerror(c, "expected 2 or 3 arguments to if"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|  | ||||
| @@ -358,27 +344,27 @@ DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|         : dstc_gettarget(opts); | ||||
|  | ||||
|     /* Compile jump to right */ | ||||
|     condlocal = dstc_preread(c, ast, 0xFF, 1, cond); | ||||
|     condlocal = dstc_preread(c, 0xFF, 1, cond); | ||||
|     labeljr = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8)); | ||||
|     dstc_emit(c, DOP_JUMP_IF_NOT | (condlocal << 8)); | ||||
|     dstc_postread(c, cond, condlocal); | ||||
|     dstc_freeslot(c, cond); | ||||
|  | ||||
|     /* Condition left body */ | ||||
|     dstc_scope(c, 0); | ||||
|     left = dstc_value(bodyopts, truebody); | ||||
|     if (!drop && !tail) dstc_copy(c, ast, target, left); | ||||
|     if (!drop && !tail) dstc_copy(c, target, left); | ||||
|     dstc_popscope(c); | ||||
|  | ||||
|     /* Compile jump to done */ | ||||
|     labeljd = dst_v_count(c->buffer); | ||||
|     if (!tail) dstc_emit(c, ast, DOP_JUMP); | ||||
|     if (!tail) dstc_emit(c, DOP_JUMP); | ||||
|  | ||||
|     /* Compile right body */ | ||||
|     labelr = dst_v_count(c->buffer); | ||||
|     dstc_scope(c, 0); | ||||
|     right = dstc_value(bodyopts, falsebody); | ||||
|     if (!drop && !tail) dstc_copy(c, ast, target, right); | ||||
|     if (!drop && !tail) dstc_copy(c, target, right); | ||||
|     dstc_popscope(c); | ||||
|  | ||||
|     /* Write jumps - only add jump lengths if jump actually emitted */ | ||||
| @@ -392,12 +378,11 @@ DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  | ||||
| /* Compile a do form. Do forms execute their body sequentially and | ||||
|  * evaluate to the last expression in the body. */ | ||||
| DstSlot dstc_do(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_do(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     int32_t i; | ||||
|     DstSlot ret = dstc_cslot(dst_wrap_nil()); | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
|     (void) ast; | ||||
|     dstc_scope(c, 0); | ||||
|     for (i = 0; i < argn; i++) { | ||||
|         if (i != argn - 1) { | ||||
| @@ -423,7 +408,7 @@ DstSlot dstc_do(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  * jump :whiletop | ||||
|  * :done | ||||
|  */ | ||||
| DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstSlot cond; | ||||
|     DstFopts subopts = dstc_fopts_default(c); | ||||
| @@ -431,7 +416,7 @@ DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     int infinite = 0; | ||||
|  | ||||
|     if (argn < 2) { | ||||
|         dstc_cerror(c, ast, "expected at least 2 arguments"); | ||||
|         dstc_cerror(c, "expected at least 2 arguments"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|  | ||||
| @@ -454,9 +439,9 @@ DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  | ||||
|     /* Infinite loop does not need to check condition */ | ||||
|     if (!infinite) { | ||||
|         condlocal = dstc_preread(c, ast, 0xFF, 1, cond); | ||||
|         condlocal = dstc_preread(c, 0xFF, 1, cond); | ||||
|         labelc = dst_v_count(c->buffer); | ||||
|         dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8)); | ||||
|         dstc_emit(c, DOP_JUMP_IF_NOT | (condlocal << 8)); | ||||
|         dstc_postread(c, cond, condlocal); | ||||
|     } else { | ||||
|         labelc = 0; | ||||
| @@ -470,7 +455,7 @@ DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|  | ||||
|     /* Compile jump to whiletop */ | ||||
|     labeljt = dst_v_count(c->buffer); | ||||
|     dstc_emit(c, ast, DOP_JUMP); | ||||
|     dstc_emit(c, DOP_JUMP); | ||||
|  | ||||
|     /* Calculate jumps */ | ||||
|     labeld = dst_v_count(c->buffer); | ||||
| @@ -496,7 +481,7 @@ static int32_t dstc_addfuncdef(DstCompiler *c, DstFuncDef *def) { | ||||
|     return dst_v_count(scope->defs) - 1; | ||||
| } | ||||
|  | ||||
| DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { | ||||
|     DstCompiler *c = opts.compiler; | ||||
|     DstFuncDef *def; | ||||
|     DstSlot ret; | ||||
| @@ -508,7 +493,7 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     int selfref = 0; | ||||
|  | ||||
|     if (argn < 2) { | ||||
|         dstc_cerror(c, ast, "expected at least 2 arguments to function literal"); | ||||
|         dstc_cerror(c, "expected at least 2 arguments to function literal"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|  | ||||
| @@ -518,26 +503,26 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     /* Read function parameters */ | ||||
|     parami = 0; | ||||
|     arity = 0; | ||||
|     head = dst_ast_unwrap1(argv[0]); | ||||
|     head = argv[0]; | ||||
|     if (dst_checktype(head, DST_SYMBOL)) { | ||||
|         selfref = 1; | ||||
|         parami = 1; | ||||
|     } | ||||
|     if (parami >= argn) { | ||||
|         dstc_cerror(c, dst_ast_node(argv[0]), "expected function parameters"); | ||||
|         dstc_cerror(c, "expected function parameters"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|     paramv = dst_ast_unwrap(argv[parami]); | ||||
|     paramv = argv[parami]; | ||||
|     if (dst_seq_view(paramv, ¶ms, ¶mcount)) { | ||||
|         int32_t i; | ||||
|         for (i = 0; i < paramcount; i++) { | ||||
|             Dst param = dst_ast_unwrap1(params[i]); | ||||
|             Dst param = params[i]; | ||||
|             if (dst_checktype(param, DST_SYMBOL)) { | ||||
|                 DstSlot slot; | ||||
|                 /* Check for varargs */ | ||||
|                 if (0 == dst_cstrcmp(dst_unwrap_symbol(param), "&")) { | ||||
|                     if (i != paramcount - 2) { | ||||
|                         dstc_cerror(c, dst_ast_node(params[i]), "variable argument symbol in unexpected location"); | ||||
|                         dstc_cerror(c, "variable argument symbol in unexpected location"); | ||||
|                         return dstc_cslot(dst_wrap_nil()); | ||||
|                     } | ||||
|                     varargs = 1; | ||||
| @@ -560,7 +545,7 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|             arity++; | ||||
|         } | ||||
|     } else { | ||||
|         dstc_cerror(c, ast, "expected function parameters"); | ||||
|         dstc_cerror(c, "expected function parameters"); | ||||
|         return dstc_cslot(dst_wrap_nil()); | ||||
|     } | ||||
|  | ||||
| @@ -571,13 +556,13 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|         slot.flags = DST_SLOT_NAMED | DST_FUNCTION; | ||||
|         slot.constant = dst_wrap_nil(); | ||||
|         slot.index = dstc_lsloti(c); | ||||
|         dstc_emit(c, ast, (slot.index << 8) | DOP_LOAD_SELF); | ||||
|         dstc_emit(c, (slot.index << 8) | DOP_LOAD_SELF); | ||||
|         dstc_nameslot(c, dst_unwrap_symbol(head), slot); | ||||
|     } | ||||
|  | ||||
|     /* Compile function body */ | ||||
|     if (parami + 1 == argn) { | ||||
|         dstc_emit(c, ast, DOP_RETURN_NIL); | ||||
|         dstc_emit(c, DOP_RETURN_NIL); | ||||
|     } else for (argi = parami + 1; argi < argn; argi++) { | ||||
|         DstSlot s; | ||||
|         subopts.flags = argi == (argn - 1) ? DST_FOPTS_TAIL : DST_FOPTS_DROP; | ||||
| @@ -600,13 +585,13 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
|     ret = dstc_gettarget(opts); | ||||
|  | ||||
|     localslot = ret.index > 0xF0 ? 0xF1 : ret.index; | ||||
|     dstc_emit(c, ast, | ||||
|     dstc_emit(c, | ||||
|             (defindex << 16) | | ||||
|             (localslot << 8) | | ||||
|             DOP_CLOSURE); | ||||
|  | ||||
|     if (ret.index != localslot) { | ||||
|         dstc_emit(c, ast, | ||||
|         dstc_emit(c, | ||||
|                 (ret.index << 16) | | ||||
|                 (localslot << 8) | | ||||
|                 DOP_MOVE_FAR); | ||||
| @@ -618,7 +603,6 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { | ||||
| /* Keep in lexicographic order */ | ||||
| static const DstSpecial dstc_specials[] = { | ||||
|     {":=", dstc_varset}, | ||||
|     {"ast-quote", dstc_astquote}, | ||||
|     {"def", dstc_def}, | ||||
|     {"do", dstc_do}, | ||||
|     {"fn", dstc_fn}, | ||||
|   | ||||
| @@ -24,7 +24,6 @@ | ||||
| #include <dst/dstopcodes.h> | ||||
| #include <dst/dstcorelib.h> | ||||
| #include <dst/dstasm.h> | ||||
| #include <dst/dstparse.h> | ||||
| #include <dst/dstcompile.h> | ||||
|  | ||||
| /* Generated header */ | ||||
| @@ -155,7 +154,7 @@ DstTable *dst_stl_env(int flags) { | ||||
|     dst_env_def(env, "_env", ret); | ||||
|  | ||||
|     /* Run bootstrap source */ | ||||
|     dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen)); | ||||
|     dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen), "boot.dst"); | ||||
|  | ||||
|     if (flags & DST_STL_NOGCROOT) | ||||
|         dst_gcunroot(dst_wrap_table(env)); | ||||
|   | ||||
| @@ -223,7 +223,6 @@ DstFuncDef *dst_funcdef_alloc() { | ||||
|     def->slotcount = 0; | ||||
|     def->arity = 0; | ||||
|     def->source = NULL; | ||||
|     def->sourcepath = NULL; | ||||
|     def->sourcemap = NULL; | ||||
|     def->name = NULL; | ||||
|     def->defs = NULL; | ||||
|   | ||||
| @@ -370,8 +370,6 @@ static Dst doframe(DstStackFrame *frame) { | ||||
|         } | ||||
|         if (def->source) { | ||||
|             dst_table_put(t, dst_csymbolv(":source"), dst_wrap_string(def->source)); | ||||
|         } else if (def->sourcepath) { | ||||
|             dst_table_put(t, dst_csymbolv(":sourcepath"), dst_wrap_string(def->sourcepath)); | ||||
|         } | ||||
|     } | ||||
|     return dst_wrap_table(t); | ||||
|   | ||||
| @@ -161,8 +161,6 @@ static void dst_mark_funcdef(DstFuncDef *def) { | ||||
|     } | ||||
|     if (def->source) | ||||
|         dst_mark_string(def->source); | ||||
|     if (def->sourcepath) | ||||
|         dst_mark_string(def->sourcepath); | ||||
|     if (def->name) | ||||
|         dst_mark_string(def->name); | ||||
| } | ||||
|   | ||||
| @@ -21,7 +21,121 @@ | ||||
| */ | ||||
| 
 | ||||
| #include <dst/dst.h> | ||||
| #include <dst/dstparse.h> | ||||
| 
 | ||||
| /* custom equals and hash for parse map */ | ||||
| static int32_t identity_hash(Dst x) { | ||||
|     int32_t hash; | ||||
|     if (sizeof(double) == sizeof(void *)) { | ||||
|         /* Assuming 8 byte pointer */ | ||||
|         uint64_t i = dst_u64(x); | ||||
|         hash = (int32_t)(i & 0xFFFFFFFF); | ||||
|         /* Get a bit more entropy by shifting the low bits out */ | ||||
|         hash >>= 3; | ||||
|         hash ^= (int32_t) (i >> 32); | ||||
|     } else { | ||||
|         /* Assuming 4 byte pointer (or smaller) */ | ||||
|         hash = (int32_t) ((char *)dst_unwrap_pointer(x) - (char *)0); | ||||
|         hash >>= 2; | ||||
|     } | ||||
|     return hash; | ||||
| } | ||||
| 
 | ||||
| static int identity_equals(Dst lhs, Dst rhs) { | ||||
|     DstType lhs_type = dst_type(lhs); | ||||
|     DstType rhs_type = dst_type(rhs); | ||||
|     if (lhs_type != rhs_type) { | ||||
|         return 0; | ||||
|     } | ||||
|     switch (lhs_type) { | ||||
|         default: | ||||
|             return 0; | ||||
|         case DST_ARRAY: | ||||
|         case DST_TUPLE: | ||||
|         case DST_BUFFER: | ||||
|         case DST_TABLE: | ||||
|         case DST_STRUCT: | ||||
|             return dst_unwrap_pointer(lhs) == dst_unwrap_pointer(rhs); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int32_t pm_hashmapping(int32_t hash, int32_t cap) { | ||||
|     return (int32_t)((uint32_t)hash % (uint32_t)cap); | ||||
| } | ||||
| 
 | ||||
| /* Find an empty slot in the parse map's hash table for the key */ | ||||
| static DstParseKV *pm_findslot(DstParser *p, Dst key) { | ||||
|     if (!p->pm_capacity) | ||||
|         return NULL; | ||||
|     int32_t hash = identity_hash(key); | ||||
|     int32_t index = pm_hashmapping(hash, p->pm_capacity); | ||||
|     for (int32_t j = index; j < p->pm_capacity; j++) { | ||||
|         if (dst_checktype(p->pm_kvs[j].key, DST_NIL)) { | ||||
|             return p->pm_kvs + j; | ||||
|         } | ||||
|     } | ||||
|     for (int32_t j = 0; j < index; j++) { | ||||
|         if (dst_checktype(p->pm_kvs[j].key, DST_NIL)) { | ||||
|             return p->pm_kvs + j; | ||||
|         } | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Rehash a parse map */ | ||||
| static void pm_rehash(DstParser *p, int32_t newCapacity) { | ||||
|     int32_t oldCapacity = p->pm_capacity; | ||||
|     DstParseKV *oldKvs = p->pm_kvs; | ||||
|     p->pm_kvs = malloc(sizeof(DstParseKV) * newCapacity); | ||||
|     p->pm_capacity = newCapacity; | ||||
|     if (!p->pm_kvs) { | ||||
|         DST_OUT_OF_MEMORY; | ||||
|     } | ||||
|     for (int32_t i = 0; i < newCapacity; i++) { | ||||
|         p->pm_kvs[i].key = dst_wrap_nil(); | ||||
|     } | ||||
|     for (int32_t i = 0; i < oldCapacity; i++) { | ||||
|         DstParseKV source_kv = oldKvs[i]; | ||||
|         if (!dst_checktype(source_kv.key, DST_NIL)) { | ||||
|             DstParseKV *dest_kv = pm_findslot(p, source_kv.key); | ||||
|             *dest_kv = source_kv; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Add a value to the parsemap */ | ||||
| static void pm_put(DstParser *p, Dst key, int32_t start, int32_t end) { | ||||
|     /* guard against unsupported key types (noop) */ | ||||
|     if (!identity_equals(key, key)) return; | ||||
|     int32_t newcount = p->pm_count + 1; | ||||
|     if (newcount * 2 >= p->pm_capacity) { | ||||
|         pm_rehash(p, 4 * newcount); | ||||
|     } | ||||
|     DstParseKV *dest = pm_findslot(p, key); | ||||
|     dest->key = key; | ||||
|     dest->start = start; | ||||
|     dest->end = end; | ||||
|     p->pm_count = newcount; | ||||
| } | ||||
| 
 | ||||
| /* Get a value from the parse map. The returned pointer
 | ||||
|  * should be read and discarded immediately. */ | ||||
| static DstParseKV *pm_get(DstParser *p, Dst ast) { | ||||
|     if (!p->pm_capacity) | ||||
|         return NULL; | ||||
|     int32_t hash = identity_hash(ast); | ||||
|     int32_t index = pm_hashmapping(hash, p->pm_capacity); | ||||
|     for (int32_t j = index; j < p->pm_capacity; j++) { | ||||
|         if (identity_equals(p->pm_kvs[j].key, ast)) { | ||||
|             return p->pm_kvs + j; | ||||
|         } | ||||
|     } | ||||
|     for (int32_t j = 0; j < index; j++) { | ||||
|         if (identity_equals(p->pm_kvs[j].key, ast)) { | ||||
|             return p->pm_kvs + j; | ||||
|         } | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Quote a value */ | ||||
| static Dst quote(Dst x) { | ||||
| @@ -169,14 +283,14 @@ static void popstate(DstParser *p, Dst val) { | ||||
|         /* Quote the returned value qcount times */ | ||||
|         for (i = 0; i < len; i++) { | ||||
|             if (p->flags & DST_PARSEFLAG_SOURCEMAP) | ||||
|                 val = dst_ast_wrap(val, (int32_t) top.start, (int32_t) p->index); | ||||
|                 pm_put(p, val, (int32_t) top.start, (int32_t) p->index); | ||||
|             val = quote(val); | ||||
|         } | ||||
|         newtop->qcount = 0; | ||||
| 
 | ||||
|         /* Ast wrap */ | ||||
|         if (p->flags & DST_PARSEFLAG_SOURCEMAP) | ||||
|             val = dst_ast_wrap(val, (int32_t) top.start, (int32_t) p->index); | ||||
|             pm_put(p, val, (int32_t) top.start, (int32_t) p->index); | ||||
| 
 | ||||
|         newtop->argn++; | ||||
|         push_arg(p, val); | ||||
| @@ -561,6 +675,16 @@ Dst dst_parser_produce(DstParser *parser) { | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int dst_parser_lookup(DstParser *parser, Dst key, DstSourceMapping *out) { | ||||
|     DstParseKV *results = pm_get(parser, key); | ||||
|     if (results) { | ||||
|         out->start = results->start; | ||||
|         out->end = results->end; | ||||
|         return 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void dst_parser_init(DstParser *parser, int flags) { | ||||
|     parser->args = NULL; | ||||
|     parser->states = NULL; | ||||
| @@ -575,6 +699,12 @@ void dst_parser_init(DstParser *parser, int flags) { | ||||
|     parser->index = 0; | ||||
|     parser->lookback = -1; | ||||
|     parser->flags = flags; | ||||
|     parser->source = dst_wrap_nil(); | ||||
| 
 | ||||
|     parser->pm_kvs = NULL; | ||||
|     parser->pm_count = 0; | ||||
|     parser->pm_capacity = 0; | ||||
| 
 | ||||
|     pushstate(parser, root, PFLAG_CONTAINER); | ||||
| } | ||||
| 
 | ||||
| @@ -582,6 +712,7 @@ void dst_parser_deinit(DstParser *parser) { | ||||
|     free(parser->args); | ||||
|     free(parser->buf); | ||||
|     free(parser->states); | ||||
|     free(parser->pm_kvs); | ||||
| } | ||||
| 
 | ||||
| /* C functions */ | ||||
| @@ -590,9 +721,16 @@ static int parsermark(void *p, size_t size) { | ||||
|     size_t i; | ||||
|     DstParser *parser = (DstParser *)p; | ||||
|     (void) size; | ||||
|     dst_mark(parser->source); | ||||
|     for (i = 0; i < parser->argcount; i++) { | ||||
|         dst_mark(parser->args[i]); | ||||
|     } | ||||
|     /* Mark parser map */ | ||||
|     for (int32_t i = 0; i < parser->pm_capacity; i++) { | ||||
|         if (!dst_checktype(parser->pm_kvs[i].key, DST_NIL)) { | ||||
|             dst_mark(parser->pm_kvs[i].key); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @@ -603,12 +741,21 @@ static int parsergc(void *p, size_t size) { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| DstAbstractType dst_parse_parsertype = { | ||||
|     ":parser.parser", | ||||
| static DstAbstractType dst_parse_parsertype = { | ||||
|     ":core.parser", | ||||
|     parsergc, | ||||
|     parsermark | ||||
| }; | ||||
| 
 | ||||
| DstParser *dst_check_parser(Dst x) { | ||||
|     if (!dst_checktype(x, DST_ABSTRACT)) | ||||
|         return NULL; | ||||
|     void *abstract = dst_unwrap_abstract(x); | ||||
|     if (dst_abstract_type(abstract) != &dst_parse_parsertype) | ||||
|         return NULL; | ||||
|     return (DstParser *)abstract; | ||||
| } | ||||
| 
 | ||||
| /* C Function parser */ | ||||
| static int cfun_parser(DstArgs args) { | ||||
|     int flags = 0; | ||||
| @@ -745,39 +892,19 @@ static int cfun_state(DstArgs args) { | ||||
|     DST_RETURN_STRING(args, str); | ||||
| } | ||||
| 
 | ||||
| /* AST */ | ||||
| static int cfun_unwrap1(DstArgs args) { | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_RETURN(args, dst_ast_unwrap1(args.v[0])); | ||||
| static int cfun_lookup(DstArgs args) { | ||||
|     DstParser *p; | ||||
|     DST_FIXARITY(args, 2); | ||||
|     DST_CHECKABSTRACT(args, 0, &dst_parse_parsertype); | ||||
|     p = (DstParser *) dst_unwrap_abstract(args.v[0]); | ||||
|     DstParseKV *results = pm_get(p, args.v[1]); | ||||
|     if (results) { | ||||
|         Dst t[2]; | ||||
|         t[0] = dst_wrap_integer(results->start); | ||||
|         t[1] = dst_wrap_integer(results->end); | ||||
|         DST_RETURN_TUPLE(args, dst_tuple_n(t, 2)); | ||||
|     } | ||||
| 
 | ||||
| static int cfun_unwrap(DstArgs args) { | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_RETURN(args, dst_ast_unwrap(args.v[0])); | ||||
| } | ||||
| 
 | ||||
| static int cfun_wrap(DstArgs args) { | ||||
|     DST_FIXARITY(args, 1); | ||||
|     DST_RETURN(args, dst_ast_wrap(args.v[0], -1, -1)); | ||||
| } | ||||
| 
 | ||||
| static int cfun_node(DstArgs args) { | ||||
|     DstAst *ast; | ||||
|     Dst *tup; | ||||
|     int32_t start, end; | ||||
|     DST_FIXARITY(args, 1); | ||||
|     ast = dst_ast_node(args.v[0]); | ||||
|     if (ast) { | ||||
|         start = ast->source_start; | ||||
|         end = ast->source_end; | ||||
|     } else { | ||||
|         start = -1; | ||||
|         end = -1; | ||||
|     } | ||||
|     tup = dst_tuple_begin(2); | ||||
|     tup[0] = dst_wrap_integer(start); | ||||
|     tup[1] = dst_wrap_integer(end); | ||||
|     DST_RETURN_TUPLE(args, dst_tuple_end(tup)); | ||||
|     DST_RETURN_NIL(args); | ||||
| } | ||||
| 
 | ||||
| static const DstReg cfuns[] = { | ||||
| @@ -789,10 +916,7 @@ static const DstReg cfuns[] = { | ||||
|     {"parser.status", cfun_status}, | ||||
|     {"parser.flush", cfun_flush}, | ||||
|     {"parser.state", cfun_state}, | ||||
|     {"ast.unwrap", cfun_unwrap}, | ||||
|     {"ast.unwrap1", cfun_unwrap1}, | ||||
|     {"ast.wrap", cfun_wrap}, | ||||
|     {"ast.node", cfun_node}, | ||||
|     {"parser.lookup", cfun_lookup}, | ||||
|     {NULL, NULL} | ||||
| }; | ||||
| 
 | ||||
| @@ -36,6 +36,17 @@ extern "C" { | ||||
|  | ||||
| #include "dsttypes.h" | ||||
|  | ||||
| /* Parsing */ | ||||
| void dst_parser_init(DstParser *parser, int flags); | ||||
| void dst_parser_deinit(DstParser *parser); | ||||
| int dst_parser_consume(DstParser *parser, uint8_t c); | ||||
| enum DstParserStatus dst_parser_status(DstParser *parser); | ||||
| Dst dst_parser_produce(DstParser *parser); | ||||
| const char *dst_parser_error(DstParser *parser); | ||||
| void dst_parser_flush(DstParser *parser); | ||||
| int dst_parser_lookup(DstParser *parser, Dst key, DstSourceMapping *out); | ||||
| DstParser *dst_check_parser(Dst x); | ||||
|  | ||||
| /* Number scanning */ | ||||
| Dst dst_scan_number(const uint8_t *src, int32_t len); | ||||
| int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err); | ||||
|   | ||||
| @@ -42,15 +42,15 @@ struct DstCompileResult { | ||||
|     int32_t error_start; | ||||
|     int32_t error_end; | ||||
| }; | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, int flags); | ||||
| DstCompileResult dst_compile(Dst source, DstTable *env, int flags, DstParser *parser); | ||||
| int dst_compile_cfun(DstArgs args); | ||||
| int dst_lib_compile(DstArgs args); | ||||
|  | ||||
| /* Get the default environment for dst */ | ||||
| DstTable *dst_stl_env(); | ||||
|  | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len); | ||||
| int dst_dostring(DstTable *env, const char *str); | ||||
| int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath); | ||||
| int dst_dostring(DstTable *env, const char *str, const char *sourcePath); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -100,6 +100,8 @@ int dst_lib_fiber(DstArgs args); | ||||
| int dst_lib_os(DstArgs args); | ||||
| int dst_lib_string(DstArgs args); | ||||
| int dst_lib_marsh(DstArgs args); | ||||
| int dst_lib_parse(DstArgs args); | ||||
|  | ||||
|  | ||||
| /* Useful for compiler */ | ||||
| Dst dst_op_add(Dst lhs, Dst rhs); | ||||
|   | ||||
| @@ -1,82 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #ifndef DST_PARSE_H_defined | ||||
| #define DST_PARSE_H_defined | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "dsttypes.h" | ||||
|  | ||||
| /* AST */ | ||||
| Dst dst_ast_wrap(Dst x, int32_t start, int32_t end); | ||||
| DstAst *dst_ast_node(Dst x); | ||||
| Dst dst_ast_unwrap1(Dst x); | ||||
| Dst dst_ast_unwrap(Dst x); | ||||
|  | ||||
| typedef struct DstParseState DstParseState; | ||||
| typedef struct DstParser DstParser; | ||||
|  | ||||
| enum DstParserStatus { | ||||
|     DST_PARSE_ROOT, | ||||
|     DST_PARSE_ERROR, | ||||
|     DST_PARSE_FULL, | ||||
|     DST_PARSE_PENDING | ||||
| }; | ||||
|  | ||||
| struct DstParser { | ||||
|     Dst* args; | ||||
|     size_t argcount; | ||||
|     size_t argcap; | ||||
|     DstParseState *states; | ||||
|     size_t statecount; | ||||
|     size_t statecap; | ||||
|     uint8_t *buf; | ||||
|     size_t bufcount; | ||||
|     size_t bufcap; | ||||
|     const char *error; | ||||
|     size_t index; | ||||
|     int lookback; | ||||
|     int flags; | ||||
| }; | ||||
|  | ||||
| /* Parsing */ | ||||
| #define DST_PARSEFLAG_SOURCEMAP 1 | ||||
| void dst_parser_init(DstParser *parser, int flags); | ||||
| void dst_parser_deinit(DstParser *parser); | ||||
| int dst_parser_consume(DstParser *parser, uint8_t c); | ||||
| enum DstParserStatus dst_parser_status(DstParser *parser); | ||||
| Dst dst_parser_produce(DstParser *parser); | ||||
| const char *dst_parser_error(DstParser *parser); | ||||
| void dst_parser_flush(DstParser *parser); | ||||
|  | ||||
| int dst_parse_cfun(DstArgs args); | ||||
|  | ||||
| int dst_lib_parse(DstArgs args); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* DST_PARSE_H_defined */ | ||||
| @@ -91,7 +91,6 @@ typedef struct DstKV DstKV; | ||||
| typedef struct DstStackFrame DstStackFrame; | ||||
| typedef struct DstAbstractType DstAbstractType; | ||||
| typedef struct DstArgs DstArgs; | ||||
| typedef struct DstAst DstAst; | ||||
| typedef struct DstReg DstReg; | ||||
| typedef struct DstSourceMapping DstSourceMapping; | ||||
| typedef int (*DstCFunction)(DstArgs args); | ||||
| @@ -478,7 +477,6 @@ struct DstFuncDef { | ||||
|     /* Various debug information */ | ||||
|     DstSourceMapping *sourcemap; | ||||
|     const uint8_t *source; | ||||
|     const uint8_t *sourcepath; | ||||
|     const uint8_t *name; | ||||
|  | ||||
|     uint32_t flags; | ||||
| @@ -490,6 +488,8 @@ struct DstFuncDef { | ||||
|     int32_t defs_length;  | ||||
| }; | ||||
|  | ||||
| #define DST_PARSEFLAG_SOURCEMAP 1 | ||||
|  | ||||
| /* A fuction environment */ | ||||
| struct DstFuncEnv { | ||||
|     union { | ||||
| @@ -507,6 +507,44 @@ struct DstFunction { | ||||
|     DstFuncEnv *envs[]; | ||||
| }; | ||||
|  | ||||
| /* Parser types */ | ||||
| typedef struct { | ||||
|     Dst key; | ||||
|     int32_t start; | ||||
|     int32_t end; | ||||
| } DstParseKV;  | ||||
|  | ||||
| typedef struct DstParseState DstParseState; | ||||
| typedef struct DstParser DstParser; | ||||
|  | ||||
| enum DstParserStatus { | ||||
|     DST_PARSE_ROOT, | ||||
|     DST_PARSE_ERROR, | ||||
|     DST_PARSE_FULL, | ||||
|     DST_PARSE_PENDING | ||||
| }; | ||||
|  | ||||
| /* A dst parser */ | ||||
| struct DstParser { | ||||
|     Dst* args; | ||||
|     const char *error; | ||||
|     DstParseState *states; | ||||
|     uint8_t *buf; | ||||
|     DstParseKV *pm_kvs; | ||||
|     int32_t pm_capacity; | ||||
|     int32_t pm_count; | ||||
|     Dst source; /* optional source path/string */ | ||||
|     size_t argcount; | ||||
|     size_t argcap; | ||||
|     size_t statecount; | ||||
|     size_t statecap; | ||||
|     size_t bufcount; | ||||
|     size_t bufcap; | ||||
|     size_t index; | ||||
|     int lookback; | ||||
|     int flags; | ||||
| }; | ||||
|  | ||||
| /* Defines an abstract type */ | ||||
| struct DstAbstractType { | ||||
|     const char *name; | ||||
| @@ -525,15 +563,6 @@ struct DstReg { | ||||
|     DstCFunction cfun; | ||||
| }; | ||||
|  | ||||
| /* ASTs are simple wrappers around values. They contain information about sourcemapping | ||||
|  * and other meta data. Possibly types? They are used mainly during compilation and parsing */ | ||||
| struct DstAst { | ||||
|     Dst value; | ||||
|     int32_t source_start; | ||||
|     int32_t source_end; | ||||
|     int flags; | ||||
| }; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| # Copyright 2017-2018 (C) Calvin Rose | ||||
|  | ||||
| (do | ||||
|  | ||||
| (var *should-repl* :private false) | ||||
|   | ||||
| @@ -47,7 +47,7 @@ int main(int argc, char **argv) { | ||||
|     dst_line_init(); | ||||
|  | ||||
|     /* Run startup script */ | ||||
|     status = dst_dobytes(env, dst_mainclient_init, sizeof(dst_mainclient_init)); | ||||
|     status = dst_dobytes(env, dst_mainclient_init, sizeof(dst_mainclient_init), "init.dst"); | ||||
|  | ||||
|     /* Deinitialize vm */ | ||||
|     dst_deinit(); | ||||
|   | ||||
							
								
								
									
										186
									
								
								src/parser/ast.c
									
									
									
									
									
								
							
							
						
						
									
										186
									
								
								src/parser/ast.c
									
									
									
									
									
								
							| @@ -1,186 +0,0 @@ | ||||
| /* | ||||
| * Copyright (c) 2018 Calvin Rose | ||||
| * | ||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| * of this software and associated documentation files (the "Software"), to | ||||
| * deal in the Software without restriction, including without limitation the | ||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| * sell copies of the Software, and to permit persons to whom the Software is | ||||
| * furnished to do so, subject to the following conditions: | ||||
| * | ||||
| * The above copyright notice and this permission notice shall be included in | ||||
| * all copies or substantial portions of the Software. | ||||
| * | ||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| * IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| #include <dst/dst.h> | ||||
|  | ||||
| /* Mark an ast node */ | ||||
| static int dst_ast_gcmark(void *p, size_t size) { | ||||
|     DstAst *ast = (DstAst *)p; | ||||
|     (void) size; | ||||
|     dst_mark(ast->value); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* AST type */ | ||||
| static DstAbstractType dst_ast_type = { | ||||
|     ":parser.ast", | ||||
|     NULL, | ||||
|     dst_ast_gcmark | ||||
| }; | ||||
|  | ||||
| /* Create an ast type */ | ||||
| Dst dst_ast_wrap(Dst x, int32_t start, int32_t end) { | ||||
|     DstAst *ast = dst_abstract(&dst_ast_type, sizeof(DstAst)); | ||||
|     ast->value = x; | ||||
|     ast->source_start = start; | ||||
|     ast->source_end = end; | ||||
|     ast->flags = 1 << dst_type(x); | ||||
|     return dst_wrap_abstract(ast); | ||||
| } | ||||
|  | ||||
| /* Get the node associated with a value */ | ||||
| DstAst *dst_ast_node(Dst x) { | ||||
|     if (dst_checktype(x, DST_ABSTRACT) && | ||||
|             dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) { | ||||
|         DstAst *ast = (DstAst *)dst_unwrap_abstract(x); | ||||
|         return ast; | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| /* Unwrap an ast value one level deep */ | ||||
| Dst dst_ast_unwrap1(Dst x) { | ||||
|     if (dst_checktype(x, DST_ABSTRACT) && | ||||
|             dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) { | ||||
|         DstAst *ast = (DstAst *)dst_unwrap_abstract(x); | ||||
|         return ast->value; | ||||
|     } | ||||
|     return x; | ||||
| } | ||||
|  | ||||
| Dst dst_ast_unwrap(Dst x); | ||||
|  | ||||
| static Dst astunwrap_array(DstArray *other) { | ||||
|     DstArray *array; | ||||
|     Dst diffval; | ||||
|     int32_t i, prescan; | ||||
|     for (prescan = 0; prescan < other->count; prescan++) { | ||||
|         diffval = dst_ast_unwrap(other->data[prescan]); | ||||
|         if (!dst_equals(diffval, other->data[prescan])) break; | ||||
|     } | ||||
|     if (prescan == other->count) return dst_wrap_array(other); | ||||
|     array = dst_array(other->count); | ||||
|     for (i = 0; i < prescan; i++) { | ||||
|         array->data[i] = other->data[i]; | ||||
|     } | ||||
|     array->data[prescan] = diffval; | ||||
|     for (i = prescan + 1; i < other->count; i++) { | ||||
|         array->data[i] = dst_ast_unwrap(other->data[i]); | ||||
|     } | ||||
|     array->count = other->count; | ||||
|     return dst_wrap_array(array); | ||||
| } | ||||
|  | ||||
| static Dst astunwrap_tuple(const Dst *other) { | ||||
|     Dst *tuple; | ||||
|     int32_t i, prescan; | ||||
|     Dst diffval; | ||||
|     for (prescan = 0; prescan < dst_tuple_length(other); prescan++) { | ||||
|         diffval = dst_ast_unwrap(other[prescan]); | ||||
|         if (!dst_equals(diffval, other[prescan])) break; | ||||
|     } | ||||
|     if (prescan == dst_tuple_length(other)) return dst_wrap_tuple(other); | ||||
|     tuple = dst_tuple_begin(dst_tuple_length(other)); | ||||
|     for (i = 0; i < prescan; i++) { | ||||
|         tuple[i] = other[i]; | ||||
|     } | ||||
|     tuple[prescan] = diffval; | ||||
|     for (i = prescan + 1; i < dst_tuple_length(other); i++) { | ||||
|         tuple[i] = dst_ast_unwrap(other[i]); | ||||
|     } | ||||
|     return dst_wrap_tuple(dst_tuple_end(tuple)); | ||||
| } | ||||
|  | ||||
| static Dst astunwrap_struct(const DstKV *other) { | ||||
|     DstKV *st; | ||||
|     const DstKV *prescan, *iter; | ||||
|     Dst diffval, diffkey; | ||||
|     prescan = NULL; | ||||
|     while ((prescan = dst_struct_next(other, prescan))) { | ||||
|         diffkey = dst_ast_unwrap(prescan->key); | ||||
|         diffval = dst_ast_unwrap(prescan->value); | ||||
|         if (!dst_equals(diffkey, prescan->key) || | ||||
|             !dst_equals(diffval, prescan->value)) | ||||
|             break; | ||||
|     } | ||||
|     if (!prescan) return dst_wrap_struct(other); | ||||
|     st = dst_struct_begin(dst_struct_length(other)); | ||||
|     iter = NULL; | ||||
|     while ((iter = dst_struct_next(other, iter))) { | ||||
|         if (iter == prescan) break; | ||||
|         dst_struct_put(st, iter->key, iter->value); | ||||
|     } | ||||
|     dst_struct_put(st, diffkey, diffval); | ||||
|     while ((iter = dst_struct_next(other, iter))) { | ||||
|         dst_struct_put(st,  | ||||
|                 dst_ast_unwrap(iter->key), | ||||
|                 dst_ast_unwrap(iter->value)); | ||||
|     } | ||||
|     return dst_wrap_struct(dst_struct_end(st)); | ||||
| } | ||||
|  | ||||
| static Dst astunwrap_table(DstTable *other) { | ||||
|     DstTable *table; | ||||
|     const DstKV *prescan, *iter; | ||||
|     Dst diffval, diffkey; | ||||
|     prescan = NULL; | ||||
|     while ((prescan = dst_table_next(other, prescan))) { | ||||
|         diffkey = dst_ast_unwrap(prescan->key); | ||||
|         diffval = dst_ast_unwrap(prescan->value); | ||||
|         if (!dst_equals(diffkey, prescan->key) || | ||||
|             !dst_equals(diffval, prescan->value)) | ||||
|             break; | ||||
|     } | ||||
|     if (!prescan) return dst_wrap_table(other); | ||||
|     table = dst_table(other->capacity); | ||||
|     table->proto = other->proto; | ||||
|     iter = NULL; | ||||
|     while ((iter = dst_table_next(other, iter))) { | ||||
|         if (iter == prescan) break; | ||||
|         dst_table_put(table, iter->key, iter->value); | ||||
|     } | ||||
|     dst_table_put(table, diffkey, diffval); | ||||
|     while ((iter = dst_table_next(other, iter))) { | ||||
|         dst_table_put(table,  | ||||
|                 dst_ast_unwrap(iter->key), | ||||
|                 dst_ast_unwrap(iter->value)); | ||||
|     } | ||||
|     return dst_wrap_table(table); | ||||
| } | ||||
|  | ||||
| /* Unwrap an ast value recursively. Preserve as much structure as possible | ||||
|  * to avoid unecessary allocation. */ | ||||
| Dst dst_ast_unwrap(Dst x) { | ||||
|     x = dst_ast_unwrap1(x); | ||||
|     switch (dst_type(x)) { | ||||
|         default: | ||||
|             return x; | ||||
|         case DST_ARRAY: | ||||
|             return astunwrap_array(dst_unwrap_array(x)); | ||||
|         case DST_TUPLE: | ||||
|             return astunwrap_tuple(dst_unwrap_tuple(x)); | ||||
|         case DST_STRUCT: | ||||
|             return astunwrap_struct(dst_unwrap_struct(x)); | ||||
|         case DST_TABLE: | ||||
|             return astunwrap_table(dst_unwrap_table(x)); | ||||
|     } | ||||
| } | ||||
| @@ -18,7 +18,6 @@ | ||||
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| # IN THE SOFTWARE. | ||||
|  | ||||
| (print "Current working directory is: " (os.cwd)) | ||||
| (import test.helper :prefix "" :exit true) | ||||
| (start-suite 0) | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ | ||||
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| # IN THE SOFTWARE. | ||||
|  | ||||
| (print "Current working directory is: " (os.cwd)) | ||||
| (import test.helper :prefix "" :exit true) | ||||
| (start-suite 1) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose