mirror of
https://github.com/janet-lang/janet
synced 2024-11-17 14:14:49 +00:00
New sourcemaps v1.
This commit is contained in:
parent
23dcfb986e
commit
bb406133de
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_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;
|
||||
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));
|
||||
}
|
||||
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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user