mirror of
https://github.com/janet-lang/janet
synced 2024-07-03 02:23:15 +00:00
453 lines
14 KiB
C
453 lines
14 KiB
C
/*
|
|
* Copyright (c) 2017 Calvin Rose
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef DST_TYPES_H_defined
|
|
#define DST_TYPES_H_defined
|
|
|
|
#include <stdint.h>
|
|
#include "dstconfig.h"
|
|
|
|
#ifdef DST_NANBOX
|
|
typedef union DstValue DstValue;
|
|
#else
|
|
typedef struct DstValue DstValue;
|
|
#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 DstReg DstReg;
|
|
typedef struct DstAbstractHeader DstAbstractHeader;
|
|
typedef struct DstFuncDef DstFuncDef;
|
|
typedef struct DstFuncEnv DstFuncEnv;
|
|
typedef struct DstStackFrame DstStackFrame;
|
|
typedef struct DstAbstractType DstAbstractType;
|
|
typedef int (*DstCFunction)(int32_t argn, DstValue *argv, DstValue *ret);
|
|
|
|
typedef enum DstAssembleStatus DstAssembleStatus;
|
|
typedef struct DstAssembleResult DstAssembleResult;
|
|
typedef struct DstAssembleOptions DstAssembleOptions;
|
|
typedef enum DstCompileStatus DstCompileStatus;
|
|
typedef struct DstCompileOptions DstCompileOptions;
|
|
typedef struct DstCompileResult DstCompileResult;
|
|
typedef struct DstParseResult DstParseResult;
|
|
typedef enum DstParseStatus DstParseStatus;
|
|
|
|
/* 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;
|
|
|
|
/* We provide two possible implemenations of DstValues. The preferred
|
|
* nanboxing approach, and the standard C version. Code in the rest of the
|
|
* application must interact through exposed interface. */
|
|
|
|
/* Required interface for DstValue */
|
|
/* 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 DstValue {
|
|
uint64_t u64;
|
|
int64_t i64;
|
|
void *pointer;
|
|
const void *cpointer;
|
|
double real;
|
|
};
|
|
|
|
/* 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) */
|
|
|
|
/* |.......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 */
|
|
|
|
/* A simple scheme for nan boxed values */
|
|
/* normal doubles, denormalized doubles, and infinities are doubles */
|
|
/* Quiet nan is nil. Sign bit should be 0. */
|
|
|
|
#define DST_NANBOX_TYPEBITS 0x0007000000000000lu
|
|
#define DST_NANBOX_TAGBITS 0xFFFF000000000000lu
|
|
#define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFlu
|
|
#ifdef DST_64
|
|
#define DST_NANBOX_POINTERBITS 0x0000FFFFFFFFFFFFlu
|
|
#else
|
|
#define DST_NANBOX_POINTERBITS 0x00000000FFFFFFFFlu
|
|
#endif
|
|
|
|
#define dst_u64(x) ((x).u64)
|
|
#define dst_nanbox_lowtag(type) \
|
|
((((uint64_t)(type) & 0x8) << 12) | 0x7FF8 | (type))
|
|
#define dst_nanbox_tag(type) \
|
|
(dst_nanbox_lowtag(type) << 48)
|
|
|
|
#define dst_nanbox_checkauxtype(x, type) \
|
|
(((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type)))
|
|
|
|
/* Check if number is nan or if number is real double */
|
|
#define dst_nanbox_isreal(x) \
|
|
(!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL))
|
|
|
|
#define dst_type(x) \
|
|
(isnan((x).real) \
|
|
? (((x).u64 & DST_NANBOX_TYPEBITS) >> 48) | (((x).u64 >> 60) & 0x8) \
|
|
: DST_REAL)
|
|
|
|
#define dst_checktype(x, t) \
|
|
(((t) == DST_REAL) \
|
|
? dst_nanbox_isreal(x) \
|
|
: dst_nanbox_checkauxtype((x), (t)))
|
|
|
|
void *dst_nanbox_to_pointer(DstValue x);
|
|
void dst_nanbox_memempty(DstValue *mem, int32_t count);
|
|
void *dst_nanbox_memalloc_empty(int32_t count);
|
|
DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask);
|
|
DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask);
|
|
DstValue dst_nanbox_from_double(double d);
|
|
DstValue 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) | 0x7FF8000000000000lu)
|
|
|
|
#define dst_nanbox_wrap_c(p, t) \
|
|
dst_nanbox_from_cpointer((p), dst_nanbox_tag(t) | 0x7FF8000000000000lu)
|
|
|
|
/* 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) \
|
|
(((x).u64 >> 48) == dst_nanbox_lowtag(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 DstValue *)dst_nanbox_to_pointer(x))
|
|
#define dst_unwrap_tuple(x) ((const DstValue *)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 DstValue {
|
|
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(DstValue) * (count))
|
|
#define dst_memalloc_empty(count) calloc((count), sizeof(DstValue))
|
|
#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 DstValue *)(x).as.pointer)
|
|
#define dst_unwrap_tuple(x) ((const DstValue *)(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)
|
|
|
|
DstValue dst_wrap_nil();
|
|
DstValue dst_wrap_real(double x);
|
|
DstValue dst_wrap_integer(int32_t x);
|
|
DstValue dst_wrap_true();
|
|
DstValue dst_wrap_false();
|
|
DstValue dst_wrap_boolean(int x);
|
|
DstValue dst_wrap_string(const uint8_t *x);
|
|
DstValue dst_wrap_symbol(const uint8_t *x);
|
|
DstValue dst_wrap_array(DstArray *x);
|
|
DstValue dst_wrap_tuple(const DstValue *x);
|
|
DstValue dst_wrap_struct(const DstValue *x);
|
|
DstValue dst_wrap_fiber(DstFiber *x);
|
|
DstValue dst_wrap_buffer(DstBuffer *x);
|
|
DstValue dst_wrap_function(DstFunction *x);
|
|
DstValue dst_wrap_cfunction(DstCFunction x);
|
|
DstValue dst_wrap_table(DstTable *x);
|
|
DstValue dst_wrap_abstract(void *x);
|
|
|
|
/* End of tagged union implementation */
|
|
#endif
|
|
|
|
/* Used for creating libraries of cfunctions. */
|
|
struct DstReg {
|
|
const char *name;
|
|
DstCFunction function;
|
|
};
|
|
|
|
/* A lightweight green thread in dst. Does not correspond to
|
|
* operating system threads. */
|
|
struct DstFiber {
|
|
DstValue *data;
|
|
DstFiber *parent;
|
|
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;
|
|
enum {
|
|
DST_FIBER_PENDING = 0,
|
|
DST_FIBER_ALIVE,
|
|
DST_FIBER_DEAD,
|
|
DST_FIBER_ERROR
|
|
} status;
|
|
};
|
|
|
|
/* A stack frame on the fiber. Is stored along with the stack values. */
|
|
struct DstStackFrame {
|
|
DstFunction *func;
|
|
uint32_t *pc;
|
|
int32_t prevframe;
|
|
};
|
|
|
|
/* Number of DstValues a frame takes up in the stack */
|
|
#define DST_FRAME_SIZE ((sizeof(DstStackFrame) + sizeof(DstValue) - 1)/ sizeof(DstValue))
|
|
|
|
/* A dynamic array type. */
|
|
struct DstArray {
|
|
DstValue *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 {
|
|
DstValue *data;
|
|
int32_t count;
|
|
int32_t capacity;
|
|
int32_t deleted;
|
|
};
|
|
|
|
/* Some function defintion flags */
|
|
#define DST_FUNCDEF_FLAG_VARARG 1
|
|
#define DST_FUNCDEF_FLAG_NEEDSENV 4
|
|
|
|
/* A function definition. Contains information needed to instantiate closures. */
|
|
struct DstFuncDef {
|
|
int32_t *environments; /* Which environments to capture from parent. */
|
|
DstValue *constants;
|
|
DstFuncDef **defs;
|
|
uint32_t *bytecode;
|
|
|
|
/* Various debug information */
|
|
int32_t *sourcemap;
|
|
const uint8_t *source;
|
|
const uint8_t *sourcepath;
|
|
|
|
uint32_t flags;
|
|
int32_t slotcount; /* The amount of stack space required for the function */
|
|
int32_t arity; /* Not including varargs */
|
|
int32_t constants_length;
|
|
int32_t bytecode_length;
|
|
int32_t environments_length;
|
|
int32_t defs_length;
|
|
};
|
|
|
|
/* A fuction environment */
|
|
struct DstFuncEnv {
|
|
union {
|
|
DstFiber *fiber;
|
|
DstValue *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;
|
|
/* Consider allocating envs with entire function struct */
|
|
DstFuncEnv **envs;
|
|
};
|
|
|
|
/* Defines an abstract type */
|
|
struct DstAbstractType {
|
|
const char *name;
|
|
int (*serialize)(void *data, size_t len);
|
|
int (*deserialize)();
|
|
void (*finalize)(void *data, size_t len);
|
|
};
|
|
|
|
/* Contains information about userdata */
|
|
struct DstAbstractHeader {
|
|
const DstAbstractType *type;
|
|
size_t size;
|
|
};
|
|
|
|
/* Assemble structs */
|
|
enum DstAssembleStatus {
|
|
DST_ASSEMBLE_OK,
|
|
DST_ASSEMBLE_ERROR
|
|
};
|
|
|
|
struct DstAssembleOptions {
|
|
DstValue source;
|
|
uint32_t flags;
|
|
};
|
|
|
|
struct DstAssembleResult {
|
|
DstFuncDef *funcdef;
|
|
const uint8_t *error;
|
|
DstAssembleStatus status;
|
|
};
|
|
|
|
/* Compile structs */
|
|
enum DstCompileStatus {
|
|
DST_COMPILE_OK,
|
|
DST_COMPILE_ERROR
|
|
};
|
|
|
|
struct DstCompileResult {
|
|
DstCompileStatus status;
|
|
DstFuncDef *funcdef;
|
|
const uint8_t *error;
|
|
int32_t error_start;
|
|
int32_t error_end;
|
|
};
|
|
|
|
struct DstCompileOptions {
|
|
uint32_t flags;
|
|
const DstValue *sourcemap;
|
|
DstValue source;
|
|
DstValue env;
|
|
};
|
|
|
|
/* Parse structs */
|
|
enum DstParseStatus {
|
|
DST_PARSE_OK,
|
|
DST_PARSE_ERROR,
|
|
DST_PARSE_UNEXPECTED_EOS,
|
|
DST_PARSE_NODATA
|
|
};
|
|
|
|
struct DstParseResult {
|
|
DstValue value;
|
|
const uint8_t *error;
|
|
const DstValue *map;
|
|
int32_t bytes_read;
|
|
DstParseStatus status;
|
|
};
|
|
|
|
#endif /* DST_TYPES_H_defined */
|