janet/src/include/dst/dst.h

1186 lines
39 KiB
C

/*
* 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_H_defined
#define DST_H_defined
#ifdef __cplusplus
extern "C" {
#endif
/***** START SECTION CONFIG *****/
#define DST_VERSION "0.0.0 alpha"
/*
* Detect OS and endianess.
* From webkit source. There is likely some extreneous
* detection for unsupported platforms
*/
/* Check Unix */
#if defined(_AIX) \
|| defined(__APPLE__) /* Darwin */ \
|| defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__GNU__) /* GNU/Hurd */ \
|| defined(__linux__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__QNXNTO__) \
|| defined(sun) || defined(__sun) /* Solaris */ \
|| defined(unix) || defined(__unix) || defined(__unix__)
#define DST_UNIX 1
/* Enable certain posix features */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#endif
#elif defined(__EMSCRIPTEN__)
#define DST_WEB 1
#elif defined(WIN32) || defined(_WIN32)
#define DST_WINDOWS 1
#endif
/* Check 64-bit vs 32-bit */
#if ((defined(__x86_64__) || defined(_M_X64)) \
&& (defined(DST_UNIX) || defined(DST_WINDOWS))) \
|| (defined(_WIN64)) /* Windows 64 bit */ \
|| (defined(__ia64__) && defined(__LP64__)) /* Itanium in LP64 mode */ \
|| defined(__alpha__) /* DEC Alpha */ \
|| (defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)) /* BE */ \
|| defined(__s390x__) /* S390 64-bit (BE) */ \
|| (defined(__ppc64__) || defined(__PPC64__)) \
|| defined(__aarch64__) /* ARM 64-bit */
#define DST_64 1
#else
#define DST_32 1
#endif
/* Check big endian */
#if defined(__MIPSEB__) /* MIPS 32-bit */ \
|| defined(__ppc__) || defined(__PPC__) /* CPU(PPC) - PowerPC 32-bit */ \
|| defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) \
|| defined(_M_PPC) || defined(__PPC) \
|| defined(__ppc64__) || defined(__PPC64__) /* PowerPC 64-bit */ \
|| defined(__sparc) /* Sparc 32bit */ \
|| defined(__sparc__) /* Sparc 64-bit */ \
|| defined(__s390x__) /* S390 64-bit */ \
|| defined(__s390__) /* S390 32-bit */ \
|| defined(__ARMEB__) /* ARM big endian */ \
|| ((defined(__CC_ARM) || defined(__ARMCC__)) /* ARM RealView compiler */ \
&& defined(__BIG_ENDIAN))
#define DST_BIG_ENDIAN 1
#else
#define DST_LITTLE_ENDIAN 1
#endif
/* Define how global dst state is declared */
#ifdef DST_SINGLE_THREADED
#define DST_THREAD_LOCAL
#elif defined(__GNUC__)
#define DST_THREAD_LOCAL __thread
#elif defined(_MSC_BUILD)
#define DST_THREAD_LOCAL __declspec(thread)
#else
#define DST_THREAD_LOCAL
#endif
/* Enable or disbale dynamic module loading. Enabled by default. */
#ifndef DST_NO_DYNAMIC_MODULES
#define DST_DYNAMIC_MODULES
#endif
/* How to export symbols */
#ifndef DST_API
#ifdef DST_WINDOWS
#define DST_API __declspec(dllexport)
#else
#define DST_API __attribute__((visibility ("default")))
#endif
#endif
/* Handle runtime errors */
#ifndef dst_exit
#include <stdio.h>
#define dst_exit(m) do { \
printf("C runtime error at line %d in file %s: %s\n",\
__LINE__,\
__FILE__,\
(m));\
exit(1);\
} while (0)
#endif
#define dst_assert(c, m) do { \
if (!(c)) dst_exit((m)); \
} while (0)
/* What to do when out of memory */
#ifndef DST_OUT_OF_MEMORY
#include <stdio.h>
#define DST_OUT_OF_MEMORY do { printf("dst out of memory\n"); exit(1); } while (0)
#endif
/* Helper for debugging */
#define dst_trace(x) dst_puts(dst_formatc("DST TRACE %s, %d: %v\n", __FILE__, __LINE__, x))
/* Prevent some recursive functions from recursing too deeply
* ands crashing (the parser). Instead, error out. */
#define DST_RECURSION_GUARD 1024
/* Maximum depth to follow table prototypes before giving up and returning nil. */
#define DST_MAX_PROTO_DEPTH 200
/* Maximum depth to follow table prototypes before giving up and returning nil. */
#define DST_MAX_MACRO_EXPAND 200
/* Define max stack size for stacks before raising a stack overflow error.
* If this is not defined, fiber stacks can grow without limit (until memory
* runs out) */
#define DST_STACK_MAX 8192
/* Use nanboxed values - uses 8 bytes per value instead of 12 or 16.
* To turn of nanboxing, for debugging purposes or for certain
* architectures (Nanboxing only tested on x86 and x64), comment out
* the DST_NANBOX define.*/
#define DST_NANBOX
/* Further refines the type of nanboxing to use. */
#define DST_NANBOX_47
/* Alignment for pointers */
#ifdef DST_32
#define DST_WALIGN 4
#else
#define DST_WALIGN 8
#endif
/***** END SECTION CONFIG *****/
/***** START SECTION TYPES *****/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
/* Names of all of the types */
extern const char *const dst_type_names[16];
/* Fiber signals */
typedef enum {
DST_SIGNAL_OK,
DST_SIGNAL_ERROR,
DST_SIGNAL_DEBUG,
DST_SIGNAL_YIELD,
DST_SIGNAL_USER0,
DST_SIGNAL_USER1,
DST_SIGNAL_USER2,
DST_SIGNAL_USER3,
DST_SIGNAL_USER4,
DST_SIGNAL_USER5,
DST_SIGNAL_USER6,
DST_SIGNAL_USER7,
DST_SIGNAL_USER8,
DST_SIGNAL_USER9
} DstSignal;
/* Fiber statuses - mostly corresponds to signals. */
typedef enum {
DST_STATUS_DEAD,
DST_STATUS_ERROR,
DST_STATUS_DEBUG,
DST_STATUS_PENDING,
DST_STATUS_USER0,
DST_STATUS_USER1,
DST_STATUS_USER2,
DST_STATUS_USER3,
DST_STATUS_USER4,
DST_STATUS_USER5,
DST_STATUS_USER6,
DST_STATUS_USER7,
DST_STATUS_USER8,
DST_STATUS_USER9,
DST_STATUS_NEW,
DST_STATUS_ALIVE
} DstFiberStatus;
#ifdef DST_NANBOX
typedef union Dst Dst;
#else
typedef struct Dst Dst;
#endif
/* All of the dst types */
typedef struct DstFunction DstFunction;
typedef struct DstArray DstArray;
typedef struct DstBuffer DstBuffer;
typedef struct DstTable DstTable;
typedef struct DstFiber DstFiber;
/* Other structs */
typedef struct DstAbstractHeader DstAbstractHeader;
typedef struct DstFuncDef DstFuncDef;
typedef struct DstFuncEnv DstFuncEnv;
typedef struct DstKV DstKV;
typedef struct DstStackFrame DstStackFrame;
typedef struct DstAbstractType DstAbstractType;
typedef struct DstArgs DstArgs;
typedef struct DstReg DstReg;
typedef struct DstSourceMapping DstSourceMapping;
typedef int (*DstCFunction)(DstArgs args);
/* Basic types for all Dst Values */
typedef enum DstType {
DST_NIL,
DST_FALSE,
DST_TRUE,
DST_FIBER,
DST_INTEGER,
DST_REAL,
DST_STRING,
DST_SYMBOL,
DST_ARRAY,
DST_TUPLE,
DST_TABLE,
DST_STRUCT,
DST_BUFFER,
DST_FUNCTION,
DST_CFUNCTION,
DST_ABSTRACT
} DstType;
#define DST_COUNT_TYPES (DST_ABSTRACT + 1)
/* Type flags */
#define DST_TFLAG_NIL (1 << DST_NIL)
#define DST_TFLAG_FALSE (1 << DST_FALSE)
#define DST_TFLAG_TRUE (1 << DST_TRUE)
#define DST_TFLAG_FIBER (1 << DST_FIBER)
#define DST_TFLAG_INTEGER (1 << DST_INTEGER)
#define DST_TFLAG_REAL (1 << DST_REAL)
#define DST_TFLAG_STRING (1 << DST_STRING)
#define DST_TFLAG_SYMBOL (1 << DST_SYMBOL)
#define DST_TFLAG_ARRAY (1 << DST_ARRAY)
#define DST_TFLAG_TUPLE (1 << DST_TUPLE)
#define DST_TFLAG_TABLE (1 << DST_TABLE)
#define DST_TFLAG_STRUCT (1 << DST_STRUCT)
#define DST_TFLAG_BUFFER (1 << DST_BUFFER)
#define DST_TFLAG_FUNCTION (1 << DST_FUNCTION)
#define DST_TFLAG_CFUNCTION (1 << DST_CFUNCTION)
#define DST_TFLAG_ABSTRACT (1 << DST_ABSTRACT)
/* Some abstractions */
#define DST_TFLAG_BOOLEAN (DST_TFLAG_TRUE | DST_TFLAG_FALSE)
#define DST_TFLAG_NUMBER (DST_TFLAG_REAL | DST_TFLAG_INTEGER)
#define DST_TFLAG_CALLABLE (DST_TFLAG_FUNCTION | DST_TFLAG_CFUNCTION)
#define DST_TFLAG_BYTES (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER)
#define DST_TFLAG_INDEXED (DST_TFLAG_ARRAY | DST_TFLAG_TUPLE)
#define DST_TFLAG_DICTIONARY (DST_TFLAG_TABLE | DST_TFLAG_STRUCT)
#define DST_TFLAG_LENGTHABLE (DST_TFLAG_BYTES | DST_TFLAG_INDEXED | DST_TFLAG_DICTIONARY)
/* We provide two possible implemenations of Dsts. The preferred
* nanboxing approach, and the standard C version. Code in the rest of the
* application must interact through exposed interface. */
/* Required interface for Dst */
/* wrap and unwrap for all types */
/* Get type quickly */
/* Check against type quickly */
/* Small footprint */
/* 32 bit integer support */
/* dst_type(x)
* dst_checktype(x, t)
* dst_wrap_##TYPE(x)
* dst_unwrap_##TYPE(x)
* dst_truthy(x)
* dst_memclear(p, n) - clear memory for hash tables to nils
* dst_u64(x) - get 64 bits of payload for hashing
*/
#ifdef DST_NANBOX
#include <math.h>
union Dst {
uint64_t u64;
int64_t i64;
double real;
};
#define dst_u64(x) ((x).u64)
/* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style
* 47 bit payload representaion is that the type bits are no long contiguous. Type
* checking can still be fast, but typewise polymorphism takes a bit longer. However,
* hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers
* in a 48 bit address space (Linux on ARM). If DST_NANBOX_47 is set, use 47 bit tagged pointers. */
/* |.......Tag.......|.......................Payload..................| */
/* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */
/* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
#if defined (DST_NANBOX_47) || defined (DST_32)
#define DST_NANBOX_TAGBITS 0xFFFF800000000000llu
#define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu
#define dst_nanbox_lowtag(type) \
((uint64_t)(type) | 0x1FFF0)
#define dst_nanbox_tag(type) \
(dst_nanbox_lowtag(type) << 47)
#define dst_type(x) \
(isnan((x).real) \
? (((x).u64 >> 47) & 0xF) \
: DST_REAL)
#else /* defined (DST_NANBOX_47) || defined (DST_32) */
#define DST_NANBOX_TAGBITS 0xFFFF000000000000llu
#define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFllu
#define dst_nanbox_lowtag(type) \
((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1))
#define dst_nanbox_tag(type) \
(dst_nanbox_lowtag(type) << 48)
#define dst_type(x) \
(isnan((x).real) \
? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \
: DST_REAL)
#endif /* defined (DST_NANBOX_47) || defined (DST_32) */
/* 32 bit mode will not use the full payload for pointers. */
#ifdef DST_32
#define DST_NANBOX_POINTERBITS 0xFFFFFFFFllu
#else
#define DST_NANBOX_POINTERBITS DST_NANBOX_PAYLOADBITS
#endif
#define dst_nanbox_checkauxtype(x, type) \
(((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type)))
#define dst_nanbox_isreal(x) \
(!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL))
#define dst_checktype(x, t) \
(((t) == DST_REAL) \
? dst_nanbox_isreal(x) \
: dst_nanbox_checkauxtype((x), (t)))
DST_API void *dst_nanbox_to_pointer(Dst x);
DST_API void dst_nanbox_memempty(DstKV *mem, int32_t count);
DST_API void *dst_nanbox_memalloc_empty(int32_t count);
DST_API Dst dst_nanbox_from_pointer(void *p, uint64_t tagmask);
DST_API Dst dst_nanbox_from_cpointer(const void *p, uint64_t tagmask);
DST_API Dst dst_nanbox_from_double(double d);
DST_API 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_API Dst dst_wrap_nil(void);
DST_API Dst dst_wrap_real(double x);
DST_API Dst dst_wrap_integer(int32_t x);
DST_API Dst dst_wrap_true(void);
DST_API Dst dst_wrap_false(void);
DST_API Dst dst_wrap_boolean(int x);
DST_API Dst dst_wrap_string(const uint8_t *x);
DST_API Dst dst_wrap_symbol(const uint8_t *x);
DST_API Dst dst_wrap_array(DstArray *x);
DST_API Dst dst_wrap_tuple(const Dst *x);
DST_API Dst dst_wrap_struct(const DstKV *x);
DST_API Dst dst_wrap_fiber(DstFiber *x);
DST_API Dst dst_wrap_buffer(DstBuffer *x);
DST_API Dst dst_wrap_function(DstFunction *x);
DST_API Dst dst_wrap_cfunction(DstCFunction x);
DST_API Dst dst_wrap_table(DstTable *x);
DST_API Dst dst_wrap_abstract(void *x);
/* End of tagged union implementation */
#endif
/* Hold components of arguments passed to DstCFunction. */
struct DstArgs {
Dst *v;
Dst *ret;
int32_t n;
};
/* 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 */
int32_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;
int32_t flags;
};
/* Number of Dsts a frame takes up in the stack */
#define DST_FRAME_SIZE ((sizeof(DstStackFrame) + sizeof(Dst) - 1) / sizeof(Dst))
/* A dynamic array type. */
struct DstArray {
Dst *data;
int32_t count;
int32_t capacity;
};
/* A bytebuffer type. Used as a mutable string or string builder. */
struct DstBuffer {
uint8_t *data;
int32_t count;
int32_t capacity;
};
/* A mutable associative data type. Backed by a hashtable. */
struct DstTable {
DstKV *data;
DstTable *proto;
int32_t count;
int32_t capacity;
int32_t deleted;
};
/* A key value pair in a struct or table */
struct DstKV {
Dst key;
Dst value;
};
/* Some function defintion flags */
#define DST_FUNCDEF_FLAG_VARARG 0x10000
#define DST_FUNCDEF_FLAG_NEEDSENV 0x20000
#define DST_FUNCDEF_FLAG_FIXARITY 0x40000
#define DST_FUNCDEF_FLAG_HASNAME 0x80000
#define DST_FUNCDEF_FLAG_HASSOURCE 0x100000
#define DST_FUNCDEF_FLAG_HASDEFS 0x200000
#define DST_FUNCDEF_FLAG_HASENVS 0x400000
#define DST_FUNCDEF_FLAG_HASSOURCEMAP 0x800000
#define DST_FUNCDEF_FLAG_TAG 0xFFFF
/* Source mapping structure for a bytecode instruction */
struct DstSourceMapping {
int32_t line;
int32_t column;
};
/* A function definition. Contains information needed to instantiate closures. */
struct DstFuncDef {
int32_t *environments; /* Which environments to capture from parent. */
Dst *constants;
DstFuncDef **defs;
uint32_t *bytecode;
/* Various debug information */
DstSourceMapping *sourcemap;
const uint8_t *source;
const uint8_t *name;
int32_t flags;
int32_t slotcount; /* The amount of stack space required for the function */
int32_t arity; /* Not including varargs */
int32_t constants_length;
int32_t bytecode_length;
int32_t environments_length;
int32_t defs_length;
};
/* A fuction environment */
struct DstFuncEnv {
union {
DstFiber *fiber;
Dst *values;
} as;
int32_t length; /* Size of environment */
int32_t offset; /* Stack offset when values still on stack. If offset is <= 0, then
environment is no longer on the stack. */
};
/* A function */
struct DstFunction {
DstFuncDef *def;
DstFuncEnv *envs[];
};
typedef struct DstParseState DstParseState;
typedef struct DstParser DstParser;
enum DstParserStatus {
DST_PARSE_ROOT,
DST_PARSE_ERROR,
DST_PARSE_FULL,
DST_PARSE_PENDING
};
/* A dst parser */
struct DstParser {
Dst* args;
const char *error;
DstParseState *states;
uint8_t *buf;
size_t argcount;
size_t argcap;
size_t statecount;
size_t statecap;
size_t bufcount;
size_t bufcap;
size_t line;
size_t col;
int lookback;
};
/* Defines an abstract type */
struct DstAbstractType {
const char *name;
int (*gc)(void *data, size_t len);
int (*gcmark)(void *data, size_t len);
};
/* Contains information about userdata */
struct DstAbstractHeader {
const DstAbstractType *type;
size_t size;
};
struct DstReg {
const char *name;
DstCFunction cfun;
};
/***** END SECTION TYPES *****/
/***** START SECTION OPCODES *****/
/* Bytecode op argument types */
enum DstOpArgType {
DST_OAT_SLOT,
DST_OAT_ENVIRONMENT,
DST_OAT_CONSTANT,
DST_OAT_INTEGER,
DST_OAT_TYPE,
DST_OAT_SIMPLETYPE,
DST_OAT_LABEL,
DST_OAT_FUNCDEF
};
/* Various types of instructions */
enum DstInstructionType {
DIT_0, /* No args */
DIT_S, /* Slot(3) */
DIT_L, /* Label(3) */
DIT_SS, /* Slot(1), Slot(2) */
DIT_SL, /* Slot(1), Label(2) */
DIT_ST, /* Slot(1), Slot(2) */
DIT_SI, /* Slot(1), Immediate(2) */
DIT_SD, /* Slot(1), Closure(2) */
DIT_SU, /* Slot(1), Unsigned Immediate(2) */
DIT_SSS, /* Slot(1), Slot(1), Slot(1) */
DIT_SSI, /* Slot(1), Slot(1), Immediate(1) */
DIT_SSU, /* Slot(1), Slot(1), Unsigned Immediate(1) */
DIT_SES, /* Slot(1), Environment(1), Far Slot(1) */
DIT_SC /* Slot(1), Constant(2) */
};
enum DstOpCode {
DOP_NOOP,
DOP_ERROR,
DOP_TYPECHECK,
DOP_RETURN,
DOP_RETURN_NIL,
DOP_ADD_INTEGER,
DOP_ADD_IMMEDIATE,
DOP_ADD_REAL,
DOP_ADD,
DOP_SUBTRACT_INTEGER,
DOP_SUBTRACT_REAL,
DOP_SUBTRACT,
DOP_MULTIPLY_INTEGER,
DOP_MULTIPLY_IMMEDIATE,
DOP_MULTIPLY_REAL,
DOP_MULTIPLY,
DOP_DIVIDE_INTEGER,
DOP_DIVIDE_IMMEDIATE,
DOP_DIVIDE_REAL,
DOP_DIVIDE,
DOP_BAND,
DOP_BOR,
DOP_BXOR,
DOP_BNOT,
DOP_SHIFT_LEFT,
DOP_SHIFT_LEFT_IMMEDIATE,
DOP_SHIFT_RIGHT,
DOP_SHIFT_RIGHT_IMMEDIATE,
DOP_SHIFT_RIGHT_UNSIGNED,
DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE,
DOP_MOVE_FAR,
DOP_MOVE_NEAR,
DOP_JUMP,
DOP_JUMP_IF,
DOP_JUMP_IF_NOT,
DOP_GREATER_THAN,
DOP_GREATER_THAN_INTEGER,
DOP_GREATER_THAN_IMMEDIATE,
DOP_GREATER_THAN_REAL,
DOP_GREATER_THAN_EQUAL_REAL,
DOP_LESS_THAN,
DOP_LESS_THAN_INTEGER,
DOP_LESS_THAN_IMMEDIATE,
DOP_LESS_THAN_REAL,
DOP_LESS_THAN_EQUAL_REAL,
DOP_EQUALS,
DOP_EQUALS_INTEGER,
DOP_EQUALS_IMMEDIATE,
DOP_EQUALS_REAL,
DOP_COMPARE,
DOP_LOAD_NIL,
DOP_LOAD_TRUE,
DOP_LOAD_FALSE,
DOP_LOAD_INTEGER,
DOP_LOAD_CONSTANT,
DOP_LOAD_UPVALUE,
DOP_LOAD_SELF,
DOP_SET_UPVALUE,
DOP_CLOSURE,
DOP_PUSH,
DOP_PUSH_2,
DOP_PUSH_3,
DOP_PUSH_ARRAY,
DOP_CALL,
DOP_TAILCALL,
DOP_RESUME,
DOP_SIGNAL,
DOP_GET,
DOP_PUT,
DOP_GET_INDEX,
DOP_PUT_INDEX,
DOP_LENGTH,
DOP_MAKE_ARRAY,
DOP_MAKE_BUFFER,
DOP_MAKE_STRING,
DOP_MAKE_STRUCT,
DOP_MAKE_TABLE,
DOP_MAKE_TUPLE,
DOP_NUMERIC_LESS_THAN,
DOP_NUMERIC_LESS_THAN_EQUAL,
DOP_NUMERIC_GREATER_THAN,
DOP_NUMERIC_GREATER_THAN_EQUAL,
DOP_NUMERIC_EQUAL,
DOP_INSTRUCTION_COUNT
};
/* Info about all instructions */
extern enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT];
/***** END SECTION OPCODES *****/
/***** START SECTION MAIN *****/
/* Parsing */
DST_API void dst_parser_init(DstParser *parser);
DST_API void dst_parser_deinit(DstParser *parser);
DST_API int dst_parser_consume(DstParser *parser, uint8_t c);
DST_API enum DstParserStatus dst_parser_status(DstParser *parser);
DST_API Dst dst_parser_produce(DstParser *parser);
DST_API const char *dst_parser_error(DstParser *parser);
DST_API void dst_parser_flush(DstParser *parser);
DST_API DstParser *dst_check_parser(Dst x);
/* Assembly */
typedef struct DstAssembleResult DstAssembleResult;
typedef struct DstAssembleOptions DstAssembleOptions;
enum DstAssembleStatus {
DST_ASSEMBLE_OK,
DST_ASSEMBLE_ERROR
};
struct DstAssembleResult {
DstFuncDef *funcdef;
const uint8_t *error;
enum DstAssembleStatus status;
};
DST_API DstAssembleResult dst_asm(Dst source, int flags);
DST_API Dst dst_disasm(DstFuncDef *def);
DST_API Dst dst_asm_decode_instruction(uint32_t instr);
/* Compilation */
typedef struct DstCompileOptions DstCompileOptions;
typedef struct DstCompileResult DstCompileResult;
enum DstCompileStatus {
DST_COMPILE_OK,
DST_COMPILE_ERROR
};
struct DstCompileResult {
DstFuncDef *funcdef;
const uint8_t *error;
DstFiber *macrofiber;
DstSourceMapping error_mapping;
enum DstCompileStatus status;
};
DST_API DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where);
/* Get the default environment for dst */
DST_API DstTable *dst_core_env(void);
DST_API int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath);
DST_API int dst_dostring(DstTable *env, const char *str, const char *sourcePath);
/* Number scanning */
DST_API Dst dst_scan_number(const uint8_t *src, int32_t len);
DST_API int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err);
DST_API double dst_scan_real(const uint8_t *str, int32_t len, int *err);
/* Array functions */
DST_API DstArray *dst_array(int32_t capacity);
DST_API DstArray *dst_array_n(const Dst *elements, int32_t n);
DST_API DstArray *dst_array_init(DstArray *array, int32_t capacity);
DST_API void dst_array_deinit(DstArray *array);
DST_API void dst_array_ensure(DstArray *array, int32_t capacity);
DST_API void dst_array_setcount(DstArray *array, int32_t count);
DST_API void dst_array_push(DstArray *array, Dst x);
DST_API Dst dst_array_pop(DstArray *array);
DST_API Dst dst_array_peek(DstArray *array);
/* Buffer functions */
DST_API DstBuffer *dst_buffer(int32_t capacity);
DST_API DstBuffer *dst_buffer_init(DstBuffer *buffer, int32_t capacity);
DST_API void dst_buffer_deinit(DstBuffer *buffer);
DST_API void dst_buffer_ensure(DstBuffer *buffer, int32_t capacity);
DST_API void dst_buffer_setcount(DstBuffer *buffer, int32_t count);
DST_API int dst_buffer_extra(DstBuffer *buffer, int32_t n);
DST_API int dst_buffer_push_bytes(DstBuffer *buffer, const uint8_t *string, int32_t len);
DST_API int dst_buffer_push_string(DstBuffer *buffer, const uint8_t *string);
DST_API int dst_buffer_push_cstring(DstBuffer *buffer, const char *cstring);
DST_API int dst_buffer_push_u8(DstBuffer *buffer, uint8_t x);
DST_API int dst_buffer_push_u16(DstBuffer *buffer, uint16_t x);
DST_API int dst_buffer_push_u32(DstBuffer *buffer, uint32_t x);
DST_API int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x);
/* Tuple */
#define dst_tuple_raw(t) ((int32_t *)(t) - 4)
#define dst_tuple_length(t) (dst_tuple_raw(t)[0])
#define dst_tuple_hash(t) ((dst_tuple_raw(t)[1]))
#define dst_tuple_sm_line(t) ((dst_tuple_raw(t)[2]))
#define dst_tuple_sm_col(t) ((dst_tuple_raw(t)[3]))
DST_API Dst *dst_tuple_begin(int32_t length);
DST_API const Dst *dst_tuple_end(Dst *tuple);
DST_API const Dst *dst_tuple_n(const Dst *values, int32_t n);
DST_API int dst_tuple_equal(const Dst *lhs, const Dst *rhs);
DST_API int dst_tuple_compare(const Dst *lhs, const Dst *rhs);
/* String/Symbol functions */
#define dst_string_raw(s) ((int32_t *)(s) - 2)
#define dst_string_length(s) (dst_string_raw(s)[0])
#define dst_string_hash(s) ((dst_string_raw(s)[1]))
DST_API uint8_t *dst_string_begin(int32_t length);
DST_API const uint8_t *dst_string_end(uint8_t *str);
DST_API const uint8_t *dst_string(const uint8_t *buf, int32_t len);
DST_API const uint8_t *dst_cstring(const char *cstring);
DST_API int dst_string_compare(const uint8_t *lhs, const uint8_t *rhs);
DST_API int dst_string_equal(const uint8_t *lhs, const uint8_t *rhs);
DST_API int dst_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen, int32_t rhash);
DST_API const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len);
DST_API const uint8_t *dst_cstring_unique(const char *s);
DST_API const uint8_t *dst_description(Dst x);
DST_API const uint8_t *dst_to_string(Dst x);
DST_API void dst_to_string_b(DstBuffer *buffer, Dst x);
DST_API void dst_to_description_b(DstBuffer *buffer, Dst x);
DST_API const char *dst_to_zerostring(Dst x);
#define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr))
#define dst_stringv(str, len) dst_wrap_string(dst_string((str), (len)))
DST_API const uint8_t *dst_formatc(const char *format, ...);
DST_API void dst_puts(const uint8_t *str);
/* Symbol functions */
DST_API const uint8_t *dst_symbol(const uint8_t *str, int32_t len);
DST_API const uint8_t *dst_symbol_from_string(const uint8_t *str);
DST_API const uint8_t *dst_csymbol(const char *str);
DST_API const uint8_t *dst_symbol_gen(void);
#define dst_symbolv(str, len) dst_wrap_symbol(dst_symbol((str), (len)))
#define dst_csymbolv(cstr) dst_wrap_symbol(dst_csymbol(cstr))
/* Structs */
#define dst_struct_raw(t) ((int32_t *)(t) - 4)
#define dst_struct_length(t) (dst_struct_raw(t)[0])
#define dst_struct_capacity(t) (dst_struct_raw(t)[1])
#define dst_struct_hash(t) (dst_struct_raw(t)[2])
/* Do something with the 4th header slot - flags? */
DST_API DstKV *dst_struct_begin(int32_t count);
DST_API void dst_struct_put(DstKV *st, Dst key, Dst value);
DST_API const DstKV *dst_struct_end(DstKV *st);
DST_API Dst dst_struct_get(const DstKV *st, Dst key);
DST_API const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv);
DST_API DstTable *dst_struct_to_table(const DstKV *st);
DST_API int dst_struct_equal(const DstKV *lhs, const DstKV *rhs);
DST_API int dst_struct_compare(const DstKV *lhs, const DstKV *rhs);
DST_API const DstKV *dst_struct_find(const DstKV *st, Dst key);
/* Table functions */
DST_API DstTable *dst_table(int32_t capacity);
DST_API DstTable *dst_table_init(DstTable *table, int32_t capacity);
DST_API void dst_table_deinit(DstTable *table);
DST_API Dst dst_table_get(DstTable *t, Dst key);
DST_API Dst dst_table_rawget(DstTable *t, Dst key);
DST_API Dst dst_table_remove(DstTable *t, Dst key);
DST_API void dst_table_put(DstTable *t, Dst key, Dst value);
DST_API const DstKV *dst_table_next(DstTable *t, const DstKV *kv);
DST_API const DstKV *dst_table_to_struct(DstTable *t);
DST_API void dst_table_merge_table(DstTable *table, DstTable *other);
DST_API void dst_table_merge_struct(DstTable *table, const DstKV *other);
DST_API DstKV *dst_table_find(DstTable *t, Dst key);
/* Fiber */
DST_API DstFiber *dst_fiber(DstFunction *callee, int32_t capacity);
#define dst_fiber_status(f) (((f)->flags & DST_FIBER_STATUS_MASK) >> DST_FIBER_STATUS_OFFSET)
/* Treat similar types through uniform interfaces for iteration */
DST_API int dst_indexed_view(Dst seq, const Dst **data, int32_t *len);
DST_API int dst_bytes_view(Dst str, const uint8_t **data, int32_t *len);
DST_API int dst_dictionary_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap);
/* Abstract */
#define dst_abstract_header(u) ((DstAbstractHeader *)(u) - 1)
#define dst_abstract_type(u) (dst_abstract_header(u)->type)
#define dst_abstract_size(u) (dst_abstract_header(u)->size)
DST_API void *dst_abstract(const DstAbstractType *type, size_t size);
/* Native */
DST_API DstCFunction dst_native(const char *name, const uint8_t **error);
/* GC */
DST_API void dst_mark(Dst x);
DST_API void dst_sweep(void);
DST_API void dst_collect(void);
DST_API void dst_clear_memory(void);
DST_API void dst_gcroot(Dst root);
DST_API int dst_gcunroot(Dst root);
DST_API int dst_gcunrootall(Dst root);
DST_API int dst_gclock(void);
DST_API void dst_gcunlock(int handle);
/* Functions */
DST_API DstFuncDef *dst_funcdef_alloc(void);
DST_API DstFunction *dst_thunk(DstFuncDef *def);
DST_API int dst_verify(DstFuncDef *def);
/* Misc */
DST_API int dst_equals(Dst x, Dst y);
DST_API int32_t dst_hash(Dst x);
DST_API int dst_compare(Dst x, Dst y);
DST_API int dst_cstrcmp(const uint8_t *str, const char *other);
/* VM functions */
DST_API int dst_init(void);
DST_API void dst_deinit(void);
DST_API DstSignal dst_continue(DstFiber *fiber, Dst in, Dst *out);
#define dst_run(F,O) dst_continue(F, dst_wrap_nil(), O)
DST_API DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out, DstFiber **f);
/* C Library helpers */
typedef enum {
DST_BINDING_NONE,
DST_BINDING_DEF,
DST_BINDING_VAR,
DST_BINDING_MACRO
} DstBindingType;
DST_API void dst_def(DstTable *env, const char *name, Dst val);
DST_API void dst_var(DstTable *env, const char *name, Dst val);
DST_API void dst_cfuns(DstTable *env, const char *regprefix, const DstReg *cfuns);
DST_API DstBindingType dst_resolve(DstTable *env, const uint8_t *sym, Dst *out);
DST_API DstTable *dst_env(DstArgs args);
DST_API void dst_register(const char *name, Dst value);
/* C Function helpers */
DST_API int dst_arity_err(DstArgs args, int32_t n, const char *prefix);
DST_API int dst_type_err(DstArgs args, int32_t n, DstType expected);
DST_API int dst_typemany_err(DstArgs args, int32_t n, int expected);
DST_API int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at);
/* Helpers for writing modules */
#define DST_MODULE_ENTRY DST_API int _dst_init
/***** END SECTION MAIN *****/
/***** START SECTION MACROS *****/
/* Macros */
#define DST_THROW(a, e) return (*((a).ret) = dst_cstringv(e), DST_SIGNAL_ERROR)
#define DST_THROWV(a, v) return (*((a).ret) = (v), DST_SIGNAL_ERROR)
#define DST_RETURN(a, v) return (*((a).ret) = (v), DST_SIGNAL_OK)
/* Early exit macros */
#define DST_MAXARITY(A, N) do { if ((A).n > (N))\
return dst_arity_err(A, N, "at most "); } while (0)
#define DST_MINARITY(A, N) do { if ((A).n < (N))\
return dst_arity_err(A, N, "at least "); } while (0)
#define DST_FIXARITY(A, N) do { if ((A).n != (N))\
return dst_arity_err(A, N, ""); } while (0)
#define DST_CHECK(A, N, T) do {\
if ((A).n > (N)) {\
if (!dst_checktype((A).v[(N)], (T))) return dst_type_err(A, N, T);\
} else {\
if ((T) != DST_NIL) return dst_type_err(A, N, T);\
}\
} while (0)
#define DST_CHECKMANY(A, N, TS) do {\
if ((A).n > (N)) {\
DstType t = dst_type((A).v[(N)]);\
if (!((1 << t) & (TS))) return dst_typemany_err(A, N, TS);\
} else {\
if (!((TS) & DST_NIL)) return dst_typemany_err(A, N, TS);\
}\
} while (0)
#define DST_CHECKABSTRACT(A, N, AT) do {\
if ((A).n > (N)) {\
Dst x = (A).v[(N)];\
if (!dst_checktype(x, DST_ABSTRACT) ||\
dst_abstract_type(dst_unwrap_abstract(x)) != (AT))\
return dst_typeabstract_err(A, N, AT);\
} else {\
return dst_typeabstract_err(A, N, AT);\
}\
} while (0)
#define DST_ARG_NUMBER(DEST, A, N) do { \
if ((A).n <= (N)) \
return dst_typemany_err(A, N, DST_TFLAG_NUMBER);\
Dst val = (A).v[(N)];\
if (dst_checktype(val, DST_REAL)) { \
DEST = dst_unwrap_real(val); \
} else if (dst_checktype(val, DST_INTEGER)) {\
DEST = (double) dst_unwrap_integer(val);\
}\
else return dst_typemany_err(A, N, DST_TFLAG_NUMBER); \
} while (0)
#define DST_ARG_BOOLEAN(DEST, A, N) do { \
DST_CHECKMANY(A, N, DST_TFLAG_TRUE | DST_TFLAG_FALSE);\
DEST = dst_unwrap_boolean((A).v[(N)]); \
} while (0)
#define DST_ARG_BYTES(DESTBYTES, DESTLEN, A, N) do {\
if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_BYTES);\
if (!dst_bytes_view((A).v[(N)], &(DESTBYTES), &(DESTLEN))) {\
return dst_typemany_err(A, N, DST_TFLAG_BYTES);\
}\
} while (0)
#define DST_ARG_INDEXED(DESTVALS, DESTLEN, A, N) do {\
if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\
if (!dst_indexed_view((A).v[(N)], &(DESTVALS), &(DESTLEN))) {\
return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\
}\
} while (0)
#define _DST_ARG(TYPE, NAME, DEST, A, N) do { \
DST_CHECK(A, N, TYPE);\
DEST = dst_unwrap_##NAME((A).v[(N)]); \
} while (0)
#define DST_ARG_FIBER(DEST, A, N) _DST_ARG(DST_FIBER, fiber, DEST, A, N)
#define DST_ARG_INTEGER(DEST, A, N) _DST_ARG(DST_INTEGER, integer, DEST, A, N)
#define DST_ARG_REAL(DEST, A, N) _DST_ARG(DST_REAL, real, DEST, A, N)
#define DST_ARG_STRING(DEST, A, N) _DST_ARG(DST_STRING, string, DEST, A, N)
#define DST_ARG_SYMBOL(DEST, A, N) _DST_ARG(DST_SYMBOL, symbol, DEST, A, N)
#define DST_ARG_ARRAY(DEST, A, N) _DST_ARG(DST_ARRAY, array, DEST, A, N)
#define DST_ARG_TUPLE(DEST, A, N) _DST_ARG(DST_TUPLE, tuple, DEST, A, N)
#define DST_ARG_TABLE(DEST, A, N) _DST_ARG(DST_TABLE, table, DEST, A, N)
#define DST_ARG_STRUCT(DEST, A, N) _DST_ARG(DST_STRUCT, st, DEST, A, N)
#define DST_ARG_BUFFER(DEST, A, N) _DST_ARG(DST_BUFFER, buffer, DEST, A, N)
#define DST_ARG_FUNCTION(DEST, A, N) _DST_ARG(DST_FUNCTION, function, DEST, A, N)
#define DST_ARG_CFUNCTION(DEST, A, N) _DST_ARG(DST_CFUNCTION, cfunction, DEST, A, N)
#define DST_ARG_ABSTRACT(DEST, A, N) _DST_ARG(DST_ABSTRACT, abstract, DEST, A, N)
#define DST_RETURN_NIL(A) do { return DST_SIGNAL_OK; } while (0)
#define DST_RETURN_FALSE(A) DST_RETURN(A, dst_wrap_false())
#define DST_RETURN_TRUE(A) DST_RETURN(A, dst_wrap_true())
#define DST_RETURN_BOOLEAN(A, X) DST_RETURN(A, dst_wrap_boolean(X))
#define DST_RETURN_FIBER(A, X) DST_RETURN(A, dst_wrap_fiber(X))
#define DST_RETURN_INTEGER(A, X) DST_RETURN(A, dst_wrap_integer(X))
#define DST_RETURN_REAL(A, X) DST_RETURN(A, dst_wrap_real(X))
#define DST_RETURN_STRING(A, X) DST_RETURN(A, dst_wrap_string(X))
#define DST_RETURN_SYMBOL(A, X) DST_RETURN(A, dst_wrap_symbol(X))
#define DST_RETURN_ARRAY(A, X) DST_RETURN(A, dst_wrap_array(X))
#define DST_RETURN_TUPLE(A, X) DST_RETURN(A, dst_wrap_tuple(X))
#define DST_RETURN_TABLE(A, X) DST_RETURN(A, dst_wrap_table(X))
#define DST_RETURN_STRUCT(A, X) DST_RETURN(A, dst_wrap_struct(X))
#define DST_RETURN_BUFFER(A, X) DST_RETURN(A, dst_wrap_buffer(X))
#define DST_RETURN_FUNCTION(A, X) DST_RETURN(A, dst_wrap_function(X))
#define DST_RETURN_CFUNCTION(A, X) DST_RETURN(A, dst_wrap_cfunction(X))
#define DST_RETURN_ABSTRACT(A, X) DST_RETURN(A, dst_wrap_abstract(X))
#define DST_RETURN_CSTRING(A, X) DST_RETURN(A, dst_cstringv(X))
#define DST_RETURN_CSYMBOL(A, X) DST_RETURN(A, dst_csymbolv(X))
/**** END SECTION MACROS *****/
#ifdef __cplusplus
}
#endif
#endif /* DST_H_defined */