1
0
mirror of https://github.com/janet-lang/janet synced 2025-01-10 23:50:26 +00:00

Major refactor. Move files around, merge compiler into

core and other changes, work on inlining many c functions.
This commit is contained in:
Calvin Rose 2018-07-03 23:07:35 -04:00
parent 17685bd789
commit a018f9f54a
44 changed files with 5721 additions and 2053 deletions

View File

@ -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 -Os -s
CLIBS=-lm -ldl
PREFIX=/usr/local
DST_TARGET=dst
@ -49,18 +49,11 @@ else
endif
# Source headers
DST_GENERATED_HEADERS=$(sort $(wildcard src/include/generated/*.h))
DST_HEADERS=$(sort $(wildcard src/include/dst/*.h))
DST_LOCAL_HEADERS=$(sort $(wildcard src/*/*.h))
DST_LIBHEADERS=$(sort $(wildcard src/include/headerlibs/*.h))
DST_GENERATED_HEADERS=src/mainclient/clientinit.gen.h \
src/compiler/dststlbootstrap.gen.h
DST_ALL_HEADERS=$(DST_LOCAL_HEADERS) \
$(DST_HEADERS) \
$(DST_LIB_HEADERS) \
$(DST_GENERATED_HEADERS)
# Source files
DST_COMPILER_SOURCES=$(sort $(wildcard src/compiler/*.c))
DST_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
DST_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
@ -77,33 +70,33 @@ xxd: src/tools/xxd.c
##### Generated Headers #####
#############################
src/mainclient/clientinit.gen.h: src/mainclient/init.dst xxd
src/include/generated/init.h: src/mainclient/init.dst xxd
./xxd $< $@ dst_mainclient_init
src/compiler/dststlbootstrap.gen.h: src/compiler/boot.dst xxd
src/include/generated/boot.h: src/core/boot.dst xxd
./xxd $< $@ dst_stl_bootstrap_gen
# Only a few files depend on the generated headers
src/core/corelib.o: src/include/generated/boot.h
src/mainclient/main.o: src/include/generated/init.h
##########################################################
##### The main interpreter program and shared object #####
##########################################################
DST_LIB_SOURCES=$(DST_COMPILER_SOURCES) \
$(DST_CONTEXT_SOURCES) \
$(DST_CORE_SOURCES)
DST_ALL_SOURCES=$(DST_LIB_SOURCES) \
DST_ALL_SOURCES=$(DST_CORE_SOURCES) \
$(DST_MAINCLIENT_SOURCES)
DST_LIB_OBJECTS=$(patsubst %.c,%.o,$(DST_LIB_SOURCES))
DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES))
DST_ALL_OBJECTS=$(patsubst %.c,%.o,$(DST_ALL_SOURCES))
%.o: %.c $(DST_ALL_HEADERS)
%.o: %.c $(DST_HEADERS) $(DST_LOCAL_HEADERS)
$(CC) $(CFLAGS) -o $@ -c $<
$(DST_TARGET): $(DST_ALL_OBJECTS)
$(CC) $(CFLAGS) -o $(DST_TARGET) $^ $(CLIBS)
$(DST_LIBRARY): $(DST_LIB_OBJECTS)
$(DST_LIBRARY): $(DST_CORE_OBJECTS)
$(CC) $(CFLAGS) -shared -o $(DST_LIBRARY) $^ $(CLIBS)
###################

View File

@ -1,246 +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>
#include <dst/dstopcodes.h>
#include <dst/dstcorelib.h>
#include <dst/dstcompile.h>
#include "compile.h"
/* Generated header */
#include "dststlbootstrap.gen.h"
static const DstReg cfuns[] = {
{"native", dst_core_native},
{"print", dst_core_print},
{"describe", dst_core_describe},
{"string", dst_core_string},
{"symbol", dst_core_symbol},
{"buffer", dst_core_buffer},
{"table", dst_core_table},
{"array", dst_core_array},
{"scan-number", dst_core_scannumber},
{"scan-integer", dst_core_scaninteger},
{"scan-real", dst_core_scanreal},
{"tuple", dst_core_tuple},
{"struct", dst_core_struct},
{"buffer", dst_core_buffer},
{"gensym", dst_core_gensym},
{"gccollect", dst_core_gccollect},
{"gcsetinterval", dst_core_gcsetinterval},
{"gcinterval", dst_core_gcinterval},
{"type", dst_core_type},
{"next", dst_core_next},
{"hash", dst_core_hash},
{NULL, NULL}
};
/* Utility for inline assembly */
static void dst_quick_asm(
DstTable *env,
int32_t flags,
const char *name,
int32_t arity,
int32_t slots,
const uint32_t *bytecode,
size_t bytecode_size) {
DstFuncDef *def = dst_funcdef_alloc();
def->arity = arity;
def->flags = flags;
def->slotcount = slots;
def->bytecode = malloc(bytecode_size);
def->bytecode_length = bytecode_size / sizeof(uint32_t);
def->name = dst_cstring(name);
if (!def->bytecode) {
DST_OUT_OF_MEMORY;
}
memcpy(def->bytecode, bytecode, bytecode_size);
dst_env_def(env, name, dst_wrap_function(dst_thunk(def)));
}
#define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24))
#define SS(op, a, b) SSS(op, a, b, 0)
#define S(op, a) SSS(op, a, 0, 0)
/* Variadic operator assembly. Must be templatized for each different opcode. */
/* Reg 0: Argument tuple (args) */
/* Reg 1: Argument count (argn) */
/* Reg 2: Jump flag (jump?) */
/* Reg 3: Accumulator (accum) */
/* Reg 4: Next operand (operand) */
/* Reg 5: Loop iterator (i) */
static DST_THREAD_LOCAL uint32_t varop_asm[] = {
DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */
/* Cheack nullary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */
DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */
/* Nullary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = nullary value */
DOP_RETURN | (3 << 8), /* return accum */
/* Check unary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */
DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */
/* Unary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */
DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
DOP_RETURN | (3 << 8), /* return accum */
/* Mutli (2 or more) arity */
/* Prime loop */
DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */
DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */
/* Main loop */
DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */
DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */
DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */
/* Done, do last and return accumulator */
DOP_RETURN | (3 << 8) /* return accum */
};
#define VAROP_NULLARY_LOC 3
#define VAROP_UNARY_LOC 7
#define VAROP_OP_LOC1 9
#define VAROP_OP_LOC2 14
/* Templatize a varop */
static void templatize_varop(
DstTable *env,
int32_t flags,
const char *name,
int32_t nullary,
int32_t unary,
uint32_t op) {
varop_asm[VAROP_NULLARY_LOC] = SS(DOP_LOAD_INTEGER, 3, nullary);
varop_asm[VAROP_UNARY_LOC] = SS(DOP_LOAD_INTEGER, 3, unary);
varop_asm[VAROP_OP_LOC1] = SSS(op, 3, 3, 4);
varop_asm[VAROP_OP_LOC2] = SSS(op, 3, 3, 4);
dst_quick_asm(
env,
flags | DST_FUNCDEF_FLAG_VARARG,
name,
0,
6,
varop_asm,
sizeof(varop_asm));
}
DstTable *dst_stl_env(int flags) {
static uint32_t error_asm[] = {
DOP_ERROR
};
static uint32_t apply_asm[] = {
DOP_PUSH_ARRAY | (1 << 8),
DOP_TAILCALL
};
static uint32_t debug_asm[] = {
DOP_SIGNAL | (2 << 24),
DOP_RETURN_NIL
};
static uint32_t yield_asm[] = {
DOP_SIGNAL | (3 << 24),
DOP_RETURN
};
static uint32_t resume_asm[] = {
DOP_RESUME | (1 << 24),
DOP_RETURN
};
static uint32_t get_asm[] = {
DOP_GET | (1 << 24),
DOP_RETURN
};
static uint32_t put_asm[] = {
DOP_PUT | (1 << 16) | (2 << 24),
DOP_RETURN
};
static uint32_t length_asm[] = {
DOP_LENGTH,
DOP_RETURN
};
DstTable *env = dst_table(0);
Dst ret = dst_wrap_table(env);
/* Load main functions */
dst_env_cfuns(env, cfuns);
dst_quick_asm(env, DST_FUN_YIELD, "debug", 0, 1, debug_asm, sizeof(debug_asm));
dst_quick_asm(env, DST_FUN_ERROR, "error", 1, 1, error_asm, sizeof(error_asm));
dst_quick_asm(env, DST_FUN_APPLY1, "apply1", 2, 2, apply_asm, sizeof(apply_asm));
dst_quick_asm(env, DST_FUN_YIELD, "yield", 1, 2, yield_asm, sizeof(yield_asm));
dst_quick_asm(env, DST_FUN_RESUME, "resume", 2, 2, resume_asm, sizeof(resume_asm));
dst_quick_asm(env, DST_FUN_GET, "get", 2, 2, get_asm, sizeof(get_asm));
dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm));
dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm));
/* Variadic ops */
templatize_varop(env, DST_FUN_ADD, "+", 0, 0, DOP_ADD);
templatize_varop(env, DST_FUN_SUBTRACT, "-", 0, 0, DOP_SUBTRACT);
templatize_varop(env, DST_FUN_MULTIPLY, "*", 1, 1, DOP_MULTIPLY);
templatize_varop(env, DST_FUN_DIVIDE, "/", 1, 1, DOP_DIVIDE);
templatize_varop(env, DST_FUN_BAND, "&", -1, -1, DOP_BAND);
templatize_varop(env, DST_FUN_BOR, "|", 0, 0, DOP_BOR);
templatize_varop(env, DST_FUN_BXOR, "^", 0, 0, DOP_BXOR);
templatize_varop(env, DST_FUN_LSHIFT, "<<", 1, 1, DOP_SHIFT_LEFT);
templatize_varop(env, DST_FUN_RSHIFT, ">>", 1, 1, DOP_SHIFT_RIGHT);
templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED);
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
/* Set as gc root */
dst_gcroot(dst_wrap_table(env));
/* Load auxiliary envs */
{
DstArgs args;
args.n = 1;
args.v = &ret;
args.ret = &ret;
dst_lib_io(args);
dst_lib_math(args);
dst_lib_array(args);
dst_lib_tuple(args);
dst_lib_buffer(args);
dst_lib_table(args);
dst_lib_fiber(args);
dst_lib_os(args);
dst_lib_parse(args);
dst_lib_compile(args);
dst_lib_asm(args);
dst_lib_string(args);
dst_lib_marsh(args);
}
/* Allow references to the environment */
dst_env_def(env, "_env", ret);
/* Run bootstrap source */
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));
return env;
}

View File

@ -21,8 +21,8 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "gc.h"
#include <string.h>
/* Initializes an array */
DstArray *dst_array_init(DstArray *array, int32_t capacity) {
@ -49,6 +49,19 @@ DstArray *dst_array(int32_t capacity) {
return dst_array_init(array, capacity);
}
/* Creates a new array from n elements. */
DstArray *dst_array_n(const Dst *elements, int32_t n) {
DstArray *array = dst_gcalloc(DST_MEMORY_ARRAY, sizeof(DstArray));
array->capacity = n;
array->count = n;
array->data = malloc(sizeof(Dst) * n);
if (!array->data) {
DST_OUT_OF_MEMORY;
}
memcpy(array->data, elements, sizeof(Dst) * n);
return array;
}
/* Ensure the array has enough capacity for elements */
void dst_array_ensure(DstArray *array, int32_t capacity) {
Dst *newData;

View File

@ -21,10 +21,8 @@
*/
#include <setjmp.h>
#include <dst/dst.h>
#include <dst/dstopcodes.h>
#include <headerlibs/strbinsearch.h>
#include "util.h"
/* Convert a slot to to an integer for bytecode */
@ -118,6 +116,12 @@ static const DstInstructionDef dst_ops[] = {
{"ltim", DOP_LESS_THAN_IMMEDIATE},
{"ltr", DOP_LESS_THAN_REAL},
{"lter", DOP_LESS_THAN_EQUAL_REAL},
{"mkarr", DOP_MAKE_ARRAY},
{"mkbuf", DOP_MAKE_BUFFER},
{"mktab", DOP_MAKE_TABLE},
{"mktup", DOP_MAKE_TUPLE},
{"mkstr", DOP_MAKE_STRING},
{"mkstu", DOP_MAKE_STRUCT},
{"movf", DOP_MOVE_FAR},
{"movn", DOP_MOVE_NEAR},
{"mul", DOP_MULTIPLY},
@ -376,7 +380,7 @@ static uint32_t read_instruction(
{
if (dst_tuple_length(argt) != 2)
dst_asm_error(a, "expected 1 argument: (op, slot)");
instr |= doarg(a, DST_OAT_SLOT, 1, 3, 0, argt[1]);
instr |= doarg(a, DST_OAT_SLOT, 1, 2, 0, argt[1]);
break;
}
case DIT_L:

View File

@ -15,7 +15,7 @@
"Define a function. Equivalent to (def name (fn name [args] ...))."
(fn defn [name & more]
(def len (length more))
(def fstart
(def fstart
(fn recur [i]
(def {i ith} more)
(def t (type ith))
@ -88,9 +88,9 @@
(defn true? [x] (= x true))
(defn false? [x] (= x false))
(defn nil? [x] (= x nil))
(def atomic?
(def atomic?
(do
(def non-atomic-types
(def non-atomic-types
{:array true
:tuple true
:table true
@ -301,8 +301,8 @@
evaluates to false."
[& forms]
(def len (length forms))
(if (= len 0)
true
(if (= len 0)
true
((fn aux [i]
(cond
(>= (inc i) len) (get forms i)
@ -313,8 +313,8 @@
evaluates to true."
[& forms]
(def len (length forms))
(if (= len 0)
false
(if (= len 0)
false
((fn aux [i]
(def fi (get forms i))
(if
@ -971,7 +971,7 @@
(def p (parser.new))
# Fiber stream of characters
(def chars
(def chars
(coro
(def buf @"")
(var len 1)
@ -984,7 +984,7 @@
0))
# Fiber stream of values
(def vals
(def vals
(coro
(while going
(switch (parser.status p)
@ -1002,21 +1002,22 @@
# Evaluate 1 source form
(defn eval1 [source]
(var good true)
(def f
(fiber.new
(def f
(fiber.new
(fn []
(def res (compile source env where))
(if (= (type res) :function)
(res)
(do
(:= good false)
(def {:error err :error-line errl :error-column errc} res)
(onerr
where
(def {:error err :line errl :column errc :fiber errf} res)
(onerr
where
"compile"
(if (< 0 errl)
(string err " in form at line " errl ", column " errc)
err)))))
(string err "\n in a form at line " errl ", column " errc)
err)
errf))))
:a))
(def res (resume f))
(when good
@ -1043,7 +1044,7 @@
(pp x))
(when f
(def st (fiber.stack f))
(loop
(loop
[{
:function func
:tail tail
@ -1051,20 +1052,26 @@
:c c
:name name
:source source
:source-line source-line
:source-column source-col
:line source-line
:column source-col
} :in st]
(file.write stdout " in")
(when c (file.write stdout " cfunction"))
(if name
(file.write stdout " " name)
(when func (file.write stdout " " (string func))))
(if source
(if source
(do
(file.write stdout " [" source "]")
(if source-line (file.write stdout " on line "
(string source-line) ", column " (string source-col)))))
(if pc (file.write stdout " (pc=" (string pc) ")"))
(if source-line
(file.write
stdout
" on line "
(string source-line)
", column "
(string source-col)))))
(if (and (not source-line) pc)
(file.write stdout " (pc=" (string pc) ")"))
(when tail (file.write stdout " (tailcall)"))
(file.write stdout "\n"))))
@ -1082,7 +1089,7 @@
(run-context *env* chunks (fn [x] (:= returnval x)) default-error-handler "eval")
returnval)
(def module.paths
(def module.paths
@["./?.dst"
"./?/init.dst"
"./dst_modules/?.dst"
@ -1090,7 +1097,7 @@
"/usr/local/dst/0.0.0/?.dst"
"/usr/local/dst/0.0.0/?/init.dst"])
(def module.native-paths
(def module.native-paths
@["./?.so"
"./?/??.so"
"./dst_modules/?.so"
@ -1143,8 +1150,8 @@
(error (string "circular dependency: module " path " is loading")))
(def {:exit exit-on-error} (or args {}))
(def check (get cache path))
(if check
check
(if check
check
(do
(def newenv (make-env))
(put cache path newenv)

View File

@ -21,7 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "gc.h"
/* Initialize a buffer */

View File

@ -20,8 +20,7 @@
* IN THE SOFTWARE.
*/
#include <dst/dsttypes.h>
#include <dst/dstopcodes.h>
#include <dst/dst.h>
#include "gc.h"
/* Look up table for instructions */
@ -97,7 +96,13 @@ enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT] = {
DIT_SSS, /* DOP_PUT, */
DIT_SSU, /* DOP_GET_INDEX, */
DIT_SSU, /* DOP_PUT_INDEX, */
DIT_SS /* DOP_LENGTH */
DIT_SS, /* DOP_LENGTH */
DIT_S, /* DOP_MAKE_ARRAY */
DIT_S, /* DOP_MAKE_BUFFER */
DIT_S, /* DOP_MAKE_TUPLE */
DIT_S, /* DOP_MAKE_STRUCT */
DIT_S, /* DOP_MAKE_TABLE */
DIT_S /* DOP_MAKE_STRING */
};
/* Verify some bytecode */

View File

@ -21,12 +21,9 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "compile.h"
#define DST_V_NODEF_GROW
#include <headerlibs/vector.h>
#undef DST_V_NODEF_GROW
#include "emit.h"
#include "vector.h"
static int fixarity0(DstFopts opts, DstSlot *args) {
(void) opts;
@ -41,41 +38,17 @@ static int fixarity2(DstFopts opts, DstSlot *args) {
return dst_v_count(args) == 2;
}
/* Generic hanldling for $A = B op $C */
static DstSlot genericSSS(DstFopts opts, int op, Dst leftval, DstSlot s) {
DstSlot target = dstc_gettarget(opts);
DstSlot zero = dstc_cslot(leftval);
int32_t lhs = dstc_regnear(opts.compiler, zero, DSTC_REGTEMP_0);
int32_t rhs = dstc_regnear(opts.compiler, s, DSTC_REGTEMP_1);
dstc_emit(opts.compiler, op |
(target.index << 8) |
(lhs << 16) |
(rhs << 24));
dstc_free_reg(opts.compiler, zero, lhs);
dstc_free_reg(opts.compiler, s, rhs);
return target;
}
/* Generic hanldling for $A = op $B */
static DstSlot genericSS(DstFopts opts, int op, DstSlot s) {
DstSlot target = dstc_gettarget(opts);
int32_t rhs = dstc_regfar(opts.compiler, s, DSTC_REGTEMP_0);
dstc_emit(opts.compiler, op |
(target.index << 8) |
(rhs << 16));
dstc_free_reg(opts.compiler, s, rhs);
dstc_emit_ss(opts.compiler, op, target, s, 1);
return target;
}
/* Generic hanldling for $A = $B op I */
static DstSlot genericSSI(DstFopts opts, int op, DstSlot s, int32_t imm) {
DstSlot target = dstc_gettarget(opts);
int32_t rhs = dstc_regnear(opts.compiler, s, DSTC_REGTEMP_0);
dstc_emit(opts.compiler, op |
(target.index << 8) |
(rhs << 16) |
(imm << 24));
dstc_free_reg(opts.compiler, s, rhs);
dstc_emit_ssi(opts.compiler, op, target, s, imm, 1);
return target;
}
@ -92,29 +65,21 @@ static DstSlot opreduce(
if (len == 0) {
return dstc_cslot(nullary);
} else if (len == 1) {
return genericSSS(opts, op, nullary, args[0]);
t = dstc_gettarget(opts);
dstc_emit_sss(c, op, t, dstc_cslot(nullary), args[0], 1);
return t;
}
t = dstc_gettarget(opts);
/* Compile initial two arguments */
int32_t lhs = dstc_regnear(c, args[0], DSTC_REGTEMP_0);
int32_t rhs = dstc_regnear(c, args[1], DSTC_REGTEMP_1);
dstc_emit(c, op | (t.index << 8) | (lhs << 16) | (rhs << 24));
dstc_free_reg(c, args[0], lhs);
dstc_free_reg(c, args[1], rhs);
/* Don't release t */
/* Compile the rest of the arguments */
for (i = 2; i < len; i++) {
rhs = dstc_regnear(c, args[i], DSTC_REGTEMP_0);
dstc_emit(c, op | (t.index << 8) | (t.index << 16) | (rhs << 24));
dstc_free_reg(c, args[i], rhs);
}
dstc_emit_sss(c, op, t, args[0], args[1], 1);
for (i = 2; i < len; i++)
dstc_emit_sss(c, op, t, t, args[i], 1);
return t;
}
/* Function optimizers */
static DstSlot do_error(DstFopts opts, DstSlot *args) {
dstc_emit_s(opts.compiler, DOP_ERROR, args[0]);
dstc_emit_s(opts.compiler, DOP_ERROR, args[0], 0);
return dstc_cslot(dst_wrap_nil());
}
static DstSlot do_debug(DstFopts opts, DstSlot *args) {
@ -139,23 +104,17 @@ static DstSlot do_resume(DstFopts opts, DstSlot *args) {
}
static DstSlot do_apply1(DstFopts opts, DstSlot *args) {
/* Push phase */
int32_t array_reg = dstc_regfar(opts.compiler, args[1], DSTC_REGTEMP_1);
dstc_emit(opts.compiler, DOP_PUSH_ARRAY | (array_reg << 8));
dstc_free_reg(opts.compiler, args[1], array_reg);
dstc_emit_s(opts.compiler, DOP_PUSH_ARRAY, args[1], 0);
/* Call phase */
int32_t fun_reg = dstc_regnear(opts.compiler, args[0], DSTC_REGTEMP_0);
DstSlot target;
if (opts.flags & DST_FOPTS_TAIL) {
dstc_emit(opts.compiler, DOP_TAILCALL | (fun_reg << 8));
dstc_emit_s(opts.compiler, DOP_TAILCALL, args[0], 0);
target = dstc_cslot(dst_wrap_nil());
target.flags |= DST_SLOT_RETURNED;
} else {
target = dstc_gettarget(opts);
dstc_emit(opts.compiler, DOP_CALL |
(target.index << 8) |
(fun_reg << 16));
dstc_emit_ss(opts.compiler, DOP_CALL, target, args[0], 1);
}
dstc_free_reg(opts.compiler, args[0], fun_reg);
return target;
}

View File

@ -21,13 +21,9 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "compile.h"
#include "emit.h"
#define DST_V_DEF_FLATTENMEM
#include <headerlibs/vector.h>
#undef DST_V_DEF_FLATTENMEM
#include "vector.h"
DstFopts dstc_fopts_default(DstCompiler *c) {
DstFopts ret;
@ -97,17 +93,7 @@ DstSlot dstc_cslot(Dst x) {
return ret;
}
/* Get a temp near slot */
DstSlot dstc_nearslot(DstCompiler *c, DstcRegisterTemp tag) {
DstSlot ret;
ret.flags = DST_SLOTTYPE_ANY;
ret.index = dstc_allocnear(c, tag);
ret.constant = dst_wrap_nil();
ret.envindex = -1;
return ret;
}
/* Get a temp near slot */
/* Get a local slot */
DstSlot dstc_farslot(DstCompiler *c) {
DstSlot ret;
ret.flags = DST_SLOTTYPE_ANY;
@ -296,14 +282,13 @@ DstSlot dstc_return(DstCompiler *c, DstSlot s) {
if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL))
dstc_emit(c, DOP_RETURN_NIL);
else
dstc_emit_s(c, DOP_RETURN, s);
dstc_emit_s(c, DOP_RETURN, s, 0);
s.flags |= DST_SLOT_RETURNED;
}
return s;
}
/* Get a target slot for emitting an instruction. Will always return
* a local slot. */
/* Get a target slot for emitting an instruction. */
DstSlot dstc_gettarget(DstFopts opts) {
DstSlot slot;
if ((opts.flags & DST_FOPTS_HINT) &&
@ -314,7 +299,7 @@ DstSlot dstc_gettarget(DstFopts opts) {
slot.envindex = -1;
slot.constant = dst_wrap_nil();
slot.flags = 0;
slot.index = dstc_allocnear(opts.compiler, DSTC_REGTEMP_TARGET);
slot.index = dstc_allocfar(opts.compiler);
}
return slot;
}
@ -346,11 +331,11 @@ DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds) {
void dstc_pushslots(DstCompiler *c, DstSlot *slots) {
int32_t i;
for (i = 0; i < dst_v_count(slots) - 2; i += 3)
dstc_emit_sss(c, DOP_PUSH_3, slots[i], slots[i+1], slots[i+2]);
dstc_emit_sss(c, DOP_PUSH_3, slots[i], slots[i+1], slots[i+2], 0);
if (i == dst_v_count(slots) - 2)
dstc_emit_ss(c, DOP_PUSH_2, slots[i], slots[i+1]);
dstc_emit_ss(c, DOP_PUSH_2, slots[i], slots[i+1], 0);
else if (i == dst_v_count(slots) - 1)
dstc_emit_s(c, DOP_PUSH, slots[i]);
dstc_emit_s(c, DOP_PUSH, slots[i], 0);
}
/* Free slots loaded via dstc_toslots */
@ -399,159 +384,185 @@ static DstSlot dstc_call(DstFopts opts, DstSlot *slots, DstSlot fun) {
if (!specialized) {
dstc_pushslots(c, slots);
if (opts.flags & DST_FOPTS_TAIL) {
dstc_emit_s(c, DOP_TAILCALL, fun);
dstc_emit_s(c, DOP_TAILCALL, fun, 0);
retslot = dstc_cslot(dst_wrap_nil());
retslot.flags = DST_SLOT_RETURNED;
} else {
retslot = dstc_gettarget(opts);
int32_t fun_register = dstc_regnear(c, fun, DSTC_REGTEMP_0);
dstc_emit(c, DOP_CALL |
(retslot.index << 8) |
(fun_register << 16));
/* Don't free ret register */
dstc_free_reg(c, fun, fun_register);
dstc_emit_ss(c, DOP_CALL, retslot, fun, 1);
}
}
dstc_freeslots(c, slots);
return retslot;
}
static DstSlot dstc_maker(DstFopts opts, DstSlot *slots, int op) {
DstCompiler *c = opts.compiler;
DstSlot retslot;
dstc_pushslots(c, slots);
dstc_freeslots(c, slots);
retslot = dstc_gettarget(opts);
dstc_emit_s(c, op, retslot, 1);
return retslot;
}
static DstSlot dstc_array(DstFopts opts, Dst x) {
DstCompiler *c = opts.compiler;
DstArray *a = dst_unwrap_array(x);
return dstc_call(opts,
return dstc_maker(opts,
dstc_toslots(c, a->data, a->count),
dstc_cslot(dst_wrap_cfunction(dst_core_array)));
DOP_MAKE_ARRAY);
}
static DstSlot dstc_tablector(DstFopts opts, Dst x, DstCFunction cfun) {
static DstSlot dstc_tablector(DstFopts opts, Dst x, int op) {
DstCompiler *c = opts.compiler;
return dstc_call(opts, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun)));
return dstc_maker(opts,
dstc_toslotskv(c, x),
op);
}
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,
return dstc_maker(opts,
dstc_toslots(c, &onearg, 1),
dstc_cslot(dst_wrap_cfunction(dst_core_buffer)));
DOP_MAKE_BUFFER);
}
/* Compile a symbol */
DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) {
static DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) {
if (dst_string_length(sym) && sym[0] != ':') {
/* Non keyword */
return dstc_resolve(opts.compiler, sym);
} else {
/* Keyword */
return dstc_cslot(dst_wrap_symbol(sym));
}
}
/* Expand a macro one time. Also get the special form compiler if we
* find that instead. */
static int macroexpand1(
DstCompiler *c,
Dst x,
Dst *out,
const DstSpecial **spec) {
if (!dst_checktype(x, DST_TUPLE))
return 0;
const Dst *form = dst_unwrap_tuple(x);
if (dst_tuple_length(form) == 0)
return 0;
/* Source map - only set when we get a tuple */
if (dst_tuple_sm_line(form) > 0) {
c->current_mapping.line = dst_tuple_sm_line(form);
c->current_mapping.column = dst_tuple_sm_col(form);
}
if (!dst_checktype(form[0], DST_SYMBOL))
return 0;
const uint8_t *name = dst_unwrap_symbol(form[0]);
const DstSpecial *s = dstc_special(name);
if (s) {
*spec = s;
return 0;
}
Dst macroval;
DstBindingType btype = dst_env_resolve(c->env, name, &macroval);
if (btype != DST_BINDING_MACRO ||
!dst_checktype(macroval, DST_FUNCTION))
return 0;
/* Evaluate macro */
DstFiber *fiberp;
DstFunction *macro = dst_unwrap_function(macroval);
int lock = dst_gclock();
DstSignal status = dst_call(
macro,
dst_tuple_length(form) - 1,
form + 1,
&x,
&fiberp);
dst_gcunlock(lock);
if (status != DST_SIGNAL_OK) {
const uint8_t *es = dst_formatc("(macro) %V", x);
c->result.macrofiber = fiberp;
dstc_error(c, es);
} else {
*out = x;
}
return 1;
}
/* Compile a single value */
DstSlot dstc_value(DstFopts opts, Dst x) {
DstSlot ret;
DstCompiler *c = opts.compiler;
int macrorecur = 0;
DstSourceMapping last_mapping = c->current_mapping;
opts.compiler->recursion_guard--;
recur:
if (dstc_iserr(&opts)) {
c->recursion_guard--;
/* Guard against previous errors and unbounded recursion */
if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil());
if (c->recursion_guard <= 0) {
dstc_cerror(c, "recursed too deeply");
return dstc_cslot(dst_wrap_nil());
}
if (opts.compiler->recursion_guard <= 0) {
dstc_cerror(opts.compiler, "recursed too deeply");
/* Macro expand. Also gets possible special form and
* refines source mapping cursor if possible. */
const DstSpecial *spec = NULL;
int macroi = DST_RECURSION_GUARD;
while (macroi && !dstc_iserr(&opts) && macroexpand1(c, x, &x, &spec))
macroi--;
if (macroi == 0) {
dstc_cerror(c, "recursed too deeply in macro expansion");
return dstc_cslot(dst_wrap_nil());
}
switch (dst_type(x)) {
default:
ret = dstc_cslot(x);
break;
case DST_SYMBOL:
{
const uint8_t *sym = dst_unwrap_symbol(x);
ret = dstc_symbol(opts, sym);
break;
}
case DST_TUPLE:
{
int compiled = 0;
Dst headval;
DstSlot head;
DstFopts subopts = dstc_fopts_default(c);
const Dst *tup = dst_unwrap_tuple(x);
/* Get ast mapping */
if (dst_tuple_sm_line(tup) > 0) {
c->current_mapping.line = dst_tuple_sm_line(tup);
c->current_mapping.column = dst_tuple_sm_col(tup);
}
/* Empty tuple is tuple literal */
if (dst_tuple_length(tup) == 0) {
compiled = 1;
ret = dstc_cslot(x);
} else {
/* Symbols could be specials */
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, dst_tuple_length(tup) - 1, tup + 1);
compiled = 1;
} else {
/* Check macro */
Dst macVal;
DstBindingType btype = dst_env_resolve(c->env, headsym, &macVal);
if (btype == DST_BINDING_MACRO &&
dst_checktype(macVal, DST_FUNCTION)) {
if (macrorecur++ > DST_RECURSION_GUARD) {
dstc_cerror(c, "macro expansion recursed too deeply");
return dstc_cslot(dst_wrap_nil());
} else {
DstFunction *f = dst_unwrap_function(macVal);
int lock = dst_gclock();
DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x);
dst_gcunlock(lock);
if (status != DST_SIGNAL_OK) {
const uint8_t *es = dst_formatc("error in macro expansion: %V", x);
dstc_error(c, es);
}
/* Tail recur on the value */
goto recur;
}
}
}
}
if (!compiled) {
/* Compile the head of the tuple */
/* Special forms */
if (spec) {
const Dst *tup = dst_unwrap_tuple(x);
ret = spec->compile(opts, dst_tuple_length(tup) - 1, tup + 1);
} else {
switch (dst_type(x)) {
case DST_TUPLE:
{
DstFopts subopts = dstc_fopts_default(c);
const Dst *tup = dst_unwrap_tuple(x);
/* Empty tuple is tuple literal */
if (dst_tuple_length(tup) == 0) {
ret = dstc_cslot(x);
} else {
DstSlot head = dstc_value(subopts, tup[0]);
subopts.flags = DST_FUNCTION | DST_CFUNCTION;
head = dstc_value(subopts, tup[0]);
/* Add compile function call */
ret = dstc_call(opts, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head);
dstc_freeslot(c, head);
}
}
/* Pop source mapping */
if (c->result.status != DST_COMPILE_ERROR)
c->current_mapping = last_mapping;
}
break;
case DST_ARRAY:
ret = dstc_array(opts, x);
break;
case DST_STRUCT:
ret = dstc_tablector(opts, x, dst_core_struct);
break;
case DST_TABLE:
ret = dstc_tablector(opts, x, dst_core_table);
break;
case DST_BUFFER:
ret = dstc_bufferctor(opts, x);
break;
break;
case DST_SYMBOL:
ret = dstc_symbol(opts, dst_unwrap_symbol(x));
break;
case DST_ARRAY:
ret = dstc_array(opts, x);
break;
case DST_STRUCT:
ret = dstc_tablector(opts, x, DOP_MAKE_STRUCT);
break;
case DST_TABLE:
ret = dstc_tablector(opts, x, DOP_MAKE_TABLE);
break;
case DST_BUFFER:
ret = dstc_bufferctor(opts, x);
break;
default:
ret = dstc_cslot(x);
break;
}
}
if (dstc_iserr(&opts)) {
return dstc_cslot(dst_wrap_nil());
}
c->current_mapping = last_mapping;
if (opts.flags & DST_FOPTS_TAIL) {
ret = dstc_return(opts.compiler, ret);
}
@ -631,6 +642,7 @@ static void dstc_init(DstCompiler *c, DstTable *env, const uint8_t *where) {
c->result.error = NULL;
c->result.status = DST_COMPILE_OK;
c->result.funcdef = NULL;
c->result.macrofiber = NULL;
c->result.error_mapping.line = 0;
c->result.error_mapping.column = 0;
}
@ -691,10 +703,13 @@ static int cfun(DstArgs args) {
if (res.status == DST_COMPILE_OK) {
DST_RETURN_FUNCTION(args, dst_thunk(res.funcdef));
} else {
t = dst_table(2);
t = dst_table(4);
dst_table_put(t, dst_csymbolv(":error"), dst_wrap_string(res.error));
dst_table_put(t, dst_csymbolv(":error-line"), dst_wrap_integer(res.error_mapping.line));
dst_table_put(t, dst_csymbolv(":error-column"), dst_wrap_integer(res.error_mapping.column));
dst_table_put(t, dst_csymbolv(":line"), dst_wrap_integer(res.error_mapping.line));
dst_table_put(t, dst_csymbolv(":column"), dst_wrap_integer(res.error_mapping.column));
if (res.macrofiber) {
dst_table_put(t, dst_csymbolv(":fiber"), dst_wrap_fiber(res.macrofiber));
}
DST_RETURN_TABLE(args, t);
}
}

View File

@ -24,8 +24,6 @@
#define DST_COMPILE_H
#include <dst/dst.h>
#include <dst/dstcompile.h>
#include <dst/dstopcodes.h>
#include "regalloc.h"
/* Tags for some functions for the prepared inliner */
@ -185,7 +183,6 @@ const DstKV *dstc_next(Dst ds, const DstKV *kv);
void dstc_freeslot(DstCompiler *c, DstSlot s);
void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s);
DstSlot dstc_nearslot(DstCompiler *c, DstcRegisterTemp tag);
DstSlot dstc_farslot(DstCompiler *c);
/* Throw away some code after checking that it is well formed. */

View File

@ -21,9 +21,64 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "corelib.h"
#include "compile.h"
#include "state.h"
/* Generated header */
#include <generated/boot.h>
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
* with native code. */
#ifdef DST_WINDOWS
#include <windows.h>
typedef HINSTANCE Clib;
#define load_clib(name) LoadLibrary((name))
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
#define error_clib() "could not load dynamic library"
#elif defined(DST_WEB)
#include <emscripten.h>
/* TODO - figure out how loading modules will work in JS */
typedef int Clib;
#define load_clib(name) 0
#define symbol_clib(lib, sym) 0
#define error_clib() "dynamic libraries not supported"
#else
#include <dlfcn.h>
typedef void *Clib;
#define load_clib(name) dlopen((name), RTLD_NOW)
#define symbol_clib(lib, sym) dlsym((lib), (sym))
#define error_clib() dlerror()
#endif
DstCFunction dst_native(const char *name, const uint8_t **error) {
Clib lib = load_clib(name);
DstCFunction init;
if (!lib) {
*error = dst_cstring(error_clib());
return NULL;
}
init = (DstCFunction) symbol_clib(lib, "_dst_init");
if (!init) {
*error = dst_cstring("could not find _dst_init symbol");
return NULL;
}
return init;
}
int dst_core_native(DstArgs args) {
DstCFunction init;
const uint8_t *error = NULL;
const uint8_t *path = NULL;
DST_FIXARITY(args, 1);
DST_ARG_STRING(path, args, 0);
init = dst_native((const char *)path, &error);
if (!init) {
DST_THROWV(args, dst_wrap_string(error));
}
DST_RETURN_CFUNCTION(args, init);
}
int dst_core_print(DstArgs args) {
int32_t i;
for (i = 0; i < args.n; ++i) {
@ -232,3 +287,219 @@ int dst_core_hash(DstArgs args) {
DST_FIXARITY(args, 1);
DST_RETURN_INTEGER(args, dst_hash(args.v[0]));
}
static const DstReg cfuns[] = {
{"native", dst_core_native},
{"print", dst_core_print},
{"describe", dst_core_describe},
{"string", dst_core_string},
{"symbol", dst_core_symbol},
{"buffer", dst_core_buffer},
{"table", dst_core_table},
{"array", dst_core_array},
{"scan-number", dst_core_scannumber},
{"scan-integer", dst_core_scaninteger},
{"scan-real", dst_core_scanreal},
{"tuple", dst_core_tuple},
{"struct", dst_core_struct},
{"buffer", dst_core_buffer},
{"gensym", dst_core_gensym},
{"gccollect", dst_core_gccollect},
{"gcsetinterval", dst_core_gcsetinterval},
{"gcinterval", dst_core_gcinterval},
{"type", dst_core_type},
{"next", dst_core_next},
{"hash", dst_core_hash},
{NULL, NULL}
};
/* Utility for inline assembly */
static void dst_quick_asm(
DstTable *env,
int32_t flags,
const char *name,
int32_t arity,
int32_t slots,
const uint32_t *bytecode,
size_t bytecode_size) {
DstFuncDef *def = dst_funcdef_alloc();
def->arity = arity;
def->flags = flags;
def->slotcount = slots;
def->bytecode = malloc(bytecode_size);
def->bytecode_length = bytecode_size / sizeof(uint32_t);
def->name = dst_cstring(name);
if (!def->bytecode) {
DST_OUT_OF_MEMORY;
}
memcpy(def->bytecode, bytecode, bytecode_size);
dst_env_def(env, name, dst_wrap_function(dst_thunk(def)));
}
#define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24))
#define SS(op, a, b) SSS(op, a, b, 0)
#define S(op, a) SSS(op, a, 0, 0)
/* Variadic operator assembly. Must be templatized for each different opcode. */
/* Reg 0: Argument tuple (args) */
/* Reg 1: Argument count (argn) */
/* Reg 2: Jump flag (jump?) */
/* Reg 3: Accumulator (accum) */
/* Reg 4: Next operand (operand) */
/* Reg 5: Loop iterator (i) */
static DST_THREAD_LOCAL uint32_t varop_asm[] = {
DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */
/* Cheack nullary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */
DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */
/* Nullary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = nullary value */
DOP_RETURN | (3 << 8), /* return accum */
/* Check unary */
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */
DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */
/* Unary */
DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */
DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
DOP_RETURN | (3 << 8), /* return accum */
/* Mutli (2 or more) arity */
/* Prime loop */
DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */
DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */
/* Main loop */
DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */
DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */
DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */
/* Done, do last and return accumulator */
DOP_RETURN | (3 << 8) /* return accum */
};
#define VAROP_NULLARY_LOC 3
#define VAROP_UNARY_LOC 7
#define VAROP_OP_LOC1 9
#define VAROP_OP_LOC2 14
/* Templatize a varop */
static void templatize_varop(
DstTable *env,
int32_t flags,
const char *name,
int32_t nullary,
int32_t unary,
uint32_t op) {
varop_asm[VAROP_NULLARY_LOC] = SS(DOP_LOAD_INTEGER, 3, nullary);
varop_asm[VAROP_UNARY_LOC] = SS(DOP_LOAD_INTEGER, 3, unary);
varop_asm[VAROP_OP_LOC1] = SSS(op, 3, 3, 4);
varop_asm[VAROP_OP_LOC2] = SSS(op, 3, 3, 4);
dst_quick_asm(
env,
flags | DST_FUNCDEF_FLAG_VARARG,
name,
0,
6,
varop_asm,
sizeof(varop_asm));
}
DstTable *dst_stl_env(int flags) {
static uint32_t error_asm[] = {
DOP_ERROR
};
static uint32_t apply_asm[] = {
DOP_PUSH_ARRAY | (1 << 8),
DOP_TAILCALL
};
static uint32_t debug_asm[] = {
DOP_SIGNAL | (2 << 24),
DOP_RETURN_NIL
};
static uint32_t yield_asm[] = {
DOP_SIGNAL | (3 << 24),
DOP_RETURN
};
static uint32_t resume_asm[] = {
DOP_RESUME | (1 << 24),
DOP_RETURN
};
static uint32_t get_asm[] = {
DOP_GET | (1 << 24),
DOP_RETURN
};
static uint32_t put_asm[] = {
DOP_PUT | (1 << 16) | (2 << 24),
DOP_RETURN
};
static uint32_t length_asm[] = {
DOP_LENGTH,
DOP_RETURN
};
DstTable *env = dst_table(0);
Dst ret = dst_wrap_table(env);
/* Load main functions */
dst_env_cfuns(env, cfuns);
dst_quick_asm(env, DST_FUN_YIELD, "debug", 0, 1, debug_asm, sizeof(debug_asm));
dst_quick_asm(env, DST_FUN_ERROR, "error", 1, 1, error_asm, sizeof(error_asm));
dst_quick_asm(env, DST_FUN_APPLY1, "apply1", 2, 2, apply_asm, sizeof(apply_asm));
dst_quick_asm(env, DST_FUN_YIELD, "yield", 1, 2, yield_asm, sizeof(yield_asm));
dst_quick_asm(env, DST_FUN_RESUME, "resume", 2, 2, resume_asm, sizeof(resume_asm));
dst_quick_asm(env, DST_FUN_GET, "get", 2, 2, get_asm, sizeof(get_asm));
dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm));
dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm));
/* Variadic ops */
templatize_varop(env, DST_FUN_ADD, "+", 0, 0, DOP_ADD);
templatize_varop(env, DST_FUN_SUBTRACT, "-", 0, 0, DOP_SUBTRACT);
templatize_varop(env, DST_FUN_MULTIPLY, "*", 1, 1, DOP_MULTIPLY);
templatize_varop(env, DST_FUN_DIVIDE, "/", 1, 1, DOP_DIVIDE);
templatize_varop(env, DST_FUN_BAND, "&", -1, -1, DOP_BAND);
templatize_varop(env, DST_FUN_BOR, "|", 0, 0, DOP_BOR);
templatize_varop(env, DST_FUN_BXOR, "^", 0, 0, DOP_BXOR);
templatize_varop(env, DST_FUN_LSHIFT, "<<", 1, 1, DOP_SHIFT_LEFT);
templatize_varop(env, DST_FUN_RSHIFT, ">>", 1, 1, DOP_SHIFT_RIGHT);
templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED);
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
/* Set as gc root */
dst_gcroot(dst_wrap_table(env));
/* Load auxiliary envs */
{
DstArgs args;
args.n = 1;
args.v = &ret;
args.ret = &ret;
dst_lib_io(args);
dst_lib_math(args);
dst_lib_array(args);
dst_lib_tuple(args);
dst_lib_buffer(args);
dst_lib_table(args);
dst_lib_fiber(args);
dst_lib_os(args);
dst_lib_parse(args);
dst_lib_compile(args);
dst_lib_asm(args);
dst_lib_string(args);
dst_lib_marsh(args);
}
/* Allow references to the environment */
dst_env_def(env, "_env", ret);
/* Run bootstrap source */
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));
return env;
}

View File

@ -20,39 +20,7 @@
* IN THE SOFTWARE.
*/
#ifndef DST_COMPILE_H_defined
#define DST_COMPILE_H_defined
#ifndef DST_CORELIB_H
#define DST_CORELIB_H
#ifdef __cplusplus
extern "C" {
#endif
#include "dsttypes.h"
typedef struct DstCompileOptions DstCompileOptions;
typedef struct DstCompileResult DstCompileResult;
enum DstCompileStatus {
DST_COMPILE_OK,
DST_COMPILE_ERROR
};
struct DstCompileResult {
enum DstCompileStatus status;
DstFuncDef *funcdef;
const uint8_t *error;
DstSourceMapping error_mapping;
};
DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where);
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, const char *sourcePath);
int dst_dostring(DstTable *env, const char *str, const char *sourcePath);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -20,9 +20,10 @@
* IN THE SOFTWARE.
*/
#include <dst/dstcompile.h>
#include <headerlibs/vector.h>
#include <dst/dst.h>
#include "emit.h"
#include "vector.h"
#include "regalloc.h"
/* Get a register */
int32_t dstc_allocfar(DstCompiler *c) {
@ -106,77 +107,104 @@ static void dstc_loadconst(DstCompiler *c, Dst k, int32_t reg) {
}
}
/* Convert a slot to a two byte register */
int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) {
int32_t reg;
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) {
reg = dstc_allocnear(c, tag);
dstc_loadconst(c, s.constant, reg);
/* Move a slot to a near register */
static void dstc_movenear(DstCompiler *c,
int32_t dest,
DstSlot src) {
if (src.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) {
dstc_loadconst(c, src.constant, dest);
/* If we also are a reference, deref the one element array */
if (s.flags & DST_SLOT_REF) {
if (src.flags & DST_SLOT_REF) {
dstc_emit(c,
(reg << 16) |
(reg << 8) |
(dest << 16) |
(dest << 8) |
DOP_GET_INDEX);
}
} else if (s.envindex >= 0) {
reg = dstc_allocnear(c, tag);
} else if (src.envindex >= 0) {
dstc_emit(c,
((uint32_t)(s.index) << 24) |
((uint32_t)(s.envindex) << 16) |
((uint32_t)(reg) << 8) |
((uint32_t)(src.index) << 24) |
((uint32_t)(src.envindex) << 16) |
((uint32_t)(dest) << 8) |
DOP_LOAD_UPVALUE);
} else if (src.index > 0xFF || src.index != dest) {
dstc_emit(c,
((uint32_t)(src.index) << 16) |
((uint32_t)(dest) << 8) |
DOP_MOVE_NEAR);
}
}
/* Move a near register to a Slot. */
static void dstc_moveback(DstCompiler *c,
DstSlot dest,
int32_t src) {
if (dest.flags & DST_SLOT_REF) {
int32_t refreg = dstc_regalloc_temp(&c->scope->ra, DSTC_REGTEMP_5);
dstc_loadconst(c, dest.constant, refreg);
dstc_emit(c,
(src << 16) |
(refreg << 8) |
DOP_PUT_INDEX);
dstc_regalloc_freetemp(&c->scope->ra, refreg, DSTC_REGTEMP_5);
} else if (dest.envindex >= 0) {
dstc_emit(c,
((uint32_t)(dest.index) << 24) |
((uint32_t)(dest.envindex) << 16) |
((uint32_t)(src) << 8) |
DOP_SET_UPVALUE);
} else if (dest.index != src) {
dstc_emit(c,
((uint32_t)(dest.index) << 16) |
((uint32_t)(src) << 8) |
DOP_MOVE_FAR);
}
}
/* Call this to release a register after emitting the instruction. */
static void dstc_free_regnear(DstCompiler *c, DstSlot s, int32_t reg, DstcRegisterTemp tag) {
if (reg != s.index ||
s.envindex >= 0 ||
s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) {
/* We need to free the temporary slot */
dstc_regalloc_freetemp(&c->scope->ra, reg, tag);
}
}
/* Convert a slot to a two byte register */
static int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) {
/* check if already near register */
if (s.envindex < 0 && s.index >= 0) {
return s.index;
}
int32_t reg;
int32_t nearreg = dstc_regalloc_temp(&c->scope->ra, tag);
dstc_movenear(c, nearreg, s);
if (nearreg >= 0xF0) {
reg = dstc_allocfar(c);
dstc_emit(c, DOP_MOVE_FAR | (nearreg << 8) | (reg << 16));
dstc_regalloc_freetemp(&c->scope->ra, nearreg, tag);
} else {
/* We have a normal slot that fits in the required bit width */
reg = s.index;
reg = nearreg;
dstc_regalloc_freetemp(&c->scope->ra, nearreg, tag);
dstc_regalloc_touch(&c->scope->ra, reg);
}
return reg;
}
/* Convert a slot to a temporary 1 byte register */
int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) {
int32_t reg;
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) {
reg = dstc_allocnear(c, tag);
dstc_loadconst(c, s.constant, reg);
/* If we also are a reference, deref the one element array */
if (s.flags & DST_SLOT_REF) {
dstc_emit(c,
(reg << 16) |
(reg << 8) |
DOP_GET_INDEX);
}
} else if (s.envindex >= 0) {
reg = dstc_allocnear(c, tag);
dstc_emit(c,
((uint32_t)(s.index) << 24) |
((uint32_t)(s.envindex) << 16) |
((uint32_t)(reg) << 8) |
DOP_LOAD_UPVALUE);
} else if (s.index > 0xFF) {
reg = dstc_allocnear(c, tag);
dstc_emit(c,
((uint32_t)(s.index) << 16) |
((uint32_t)(reg) << 8) |
DOP_MOVE_NEAR);
} else {
/* We have a normal slot that fits in the required bit width */
reg = s.index;
static int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag) {
/* check if already near register */
if (s.envindex < 0 && s.index >= 0 && s.index <= 0xFF) {
return s.index;
}
int32_t reg = dstc_regalloc_temp(&c->scope->ra, tag);
dstc_movenear(c, reg, s);
return reg;
}
/* Call this to release a register after emitting the instruction. */
void dstc_free_reg(DstCompiler *c, DstSlot s, int32_t reg) {
if (reg != s.index || s.envindex >= 0 || s.flags & DST_SLOT_CONSTANT) {
/* We need to free the temporary slot */
dstc_regalloc_free(&c->scope->ra, reg);
}
}
/* Check if two slots are equal */
static int dstc_sequal(DstSlot lhs, DstSlot rhs) {
if (lhs.flags == rhs.flags &&
if ((lhs.flags & ~DST_SLOTTYPE_ANY) == (rhs.flags & ~DST_SLOTTYPE_ANY) &&
lhs.index == rhs.index &&
lhs.envindex == rhs.envindex) {
if (lhs.flags & (DST_SLOT_REF | DST_SLOT_CONSTANT)) {
@ -194,131 +222,48 @@ void dstc_copy(
DstCompiler *c,
DstSlot dest,
DstSlot src) {
int writeback = 0;
int32_t destlocal = -1;
int32_t srclocal = -1;
int32_t reflocal = -1;
/* Can't write to constants */
if (dest.flags & DST_SLOT_CONSTANT) {
dstc_cerror(c, "cannot write to constant");
return;
}
/* Short circuit if dest and source are equal */
if (dstc_sequal(dest, src)) return;
/* Types of slots - src */
/* constants */
/* upvalues */
/* refs */
/* near index */
/* far index */
/* Types of slots - dest */
/* upvalues */
/* refs */
/* near index */
/* far index */
/* If dest is a near index, do some optimization */
/* If dest is a near register */
if (dest.envindex < 0 && dest.index >= 0 && dest.index <= 0xFF) {
if (src.flags & DST_SLOT_CONSTANT) {
dstc_loadconst(c, src.constant, dest.index);
} else if (src.flags & DST_SLOT_REF) {
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,
(src.index << 24) |
(src.envindex << 16) |
(dest.index << 8) |
DOP_LOAD_UPVALUE);
} else {
dstc_emit(c,
(src.index << 16) |
(dest.index << 8) |
DOP_MOVE_NEAR);
}
dstc_movenear(c, dest.index, src);
return;
}
/* Process: src -> srclocal -> destlocal -> dest */
/* src -> srclocal */
srclocal = dstc_regnear(c, src, DSTC_REGTEMP_0);
/* Pull down dest (find destlocal) */
if (dest.flags & DST_SLOT_REF) {
writeback = 1;
destlocal = srclocal;
reflocal = dstc_allocnear(c, DSTC_REGTEMP_1);
dstc_emit(c,
(dstc_const(c, dest.constant) << 16) |
(reflocal << 8) |
DOP_LOAD_CONSTANT);
} else if (dest.envindex >= 0) {
writeback = 2;
destlocal = srclocal;
} else if (dest.index > 0xFF) {
writeback = 3;
destlocal = srclocal;
} else {
destlocal = dest.index;
/* If src is a near register */
if (src.envindex < 0 && src.index >= 0 && src.index <= 0xFF) {
dstc_moveback(c, dest, src.index);
return;
}
/* srclocal -> destlocal */
if (srclocal != destlocal) {
dstc_emit(c,
((uint32_t)(srclocal) << 16) |
((uint32_t)(destlocal) << 8) |
DOP_MOVE_NEAR);
}
/* destlocal -> dest */
if (writeback == 1) {
dstc_emit(c,
(destlocal << 16) |
(reflocal << 8) |
DOP_PUT_INDEX);
} else if (writeback == 2) {
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,
((uint32_t)(dest.index) << 16) |
((uint32_t)(destlocal) << 8) |
DOP_MOVE_FAR);
}
/* Process: src -> near -> dest */
int32_t near = dstc_allocnear(c, DSTC_REGTEMP_3);
dstc_movenear(c, near, src);
dstc_moveback(c, dest, near);
/* Cleanup */
if (reflocal >= 0) {
dstc_regalloc_free(&c->scope->ra, reflocal);
}
dstc_free_reg(c, src, srclocal);
}
dstc_regalloc_freetemp(&c->scope->ra, near, DSTC_REGTEMP_3);
}
/* Instruction templated emitters */
static int32_t emit1s(DstCompiler *c, uint8_t op, DstSlot s, int32_t rest) {
static int32_t emit1s(DstCompiler *c, uint8_t op, DstSlot s, int32_t rest, int wr) {
int32_t reg = dstc_regnear(c, s, DSTC_REGTEMP_0);
int32_t label = dst_v_count(c->buffer);
dstc_emit(c, op | (reg << 8) | (rest << 16));
dstc_free_reg(c, s, reg);
if (wr)
dstc_moveback(c, s, reg);
dstc_free_regnear(c, s, reg, DSTC_REGTEMP_0);
return label;
}
int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s) {
int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s, int wr) {
int32_t reg = dstc_regfar(c, s, DSTC_REGTEMP_0);
int32_t label = dst_v_count(c->buffer);
dstc_emit(c, op | (reg << 8));
dstc_free_reg(c, s, reg);
if (wr)
dstc_moveback(c, s, reg);
dstc_free_regnear(c, s, reg, DSTC_REGTEMP_0);
return label;
}
@ -328,57 +273,63 @@ int32_t dstc_emit_sl(DstCompiler *c, uint8_t op, DstSlot s, int32_t label) {
if (jump < INT16_MIN || jump > INT16_MAX) {
dstc_cerror(c, "jump is too far");
}
return emit1s(c, op, s, jump);
return emit1s(c, op, s, jump, 0);
}
int32_t dstc_emit_st(DstCompiler *c, uint8_t op, DstSlot s, int32_t tflags) {
return emit1s(c, op, s, tflags);
return emit1s(c, op, s, tflags, 0);
}
int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate) {
return emit1s(c, op, s, immediate);
int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate, int wr) {
return emit1s(c, op, s, immediate, wr);
}
int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate) {
return emit1s(c, op, s, (int32_t) immediate);
int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate, int wr) {
return emit1s(c, op, s, (int32_t) immediate, wr);
}
static int32_t emit2s(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int32_t rest) {
static int32_t emit2s(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int32_t rest, int wr) {
int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0);
int32_t reg2 = dstc_regnear(c, s2, DSTC_REGTEMP_1);
int32_t label = dst_v_count(c->buffer);
dstc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (rest << 24));
dstc_free_reg(c, s1, reg1);
dstc_free_reg(c, s2, reg2);
dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1);
if (wr)
dstc_moveback(c, s1, reg1);
dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0);
return label;
}
int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2) {
int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int wr) {
int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0);
int32_t reg2 = dstc_regfar(c, s2, DSTC_REGTEMP_1);
int32_t label = dst_v_count(c->buffer);
dstc_emit(c, op | (reg1 << 8) | (reg2 << 16));
dstc_free_reg(c, s1, reg1);
dstc_free_reg(c, s2, reg2);
dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1);
if (wr)
dstc_moveback(c, s1, reg1);
dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0);
return label;
}
int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate) {
return emit2s(c, op, s1, s2, immediate);
int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate, int wr) {
return emit2s(c, op, s1, s2, immediate, wr);
}
int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate) {
return emit2s(c, op, s1, s2, (int32_t) immediate);
int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate, int wr) {
return emit2s(c, op, s1, s2, (int32_t) immediate, wr);
}
int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3) {
int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3, int wr) {
int32_t reg1 = dstc_regnear(c, s1, DSTC_REGTEMP_0);
int32_t reg2 = dstc_regnear(c, s2, DSTC_REGTEMP_1);
int32_t reg3 = dstc_regnear(c, s3, DSTC_REGTEMP_2);
int32_t label = dst_v_count(c->buffer);
dstc_emit(c, op | (reg1 << 8) | (reg2 << 16) | (reg3 << 24));
dstc_free_reg(c, s1, reg1);
dstc_free_reg(c, s2, reg2);
dstc_free_reg(c, s3, reg3);
dstc_free_regnear(c, s2, reg2, DSTC_REGTEMP_1);
dstc_free_regnear(c, s3, reg3, DSTC_REGTEMP_2);
if (wr)
dstc_moveback(c, s1, reg1);
dstc_free_regnear(c, s1, reg1, DSTC_REGTEMP_0);
return label;
}

View File

@ -30,19 +30,15 @@ void dstc_emit(DstCompiler *c, uint32_t instr);
int32_t dstc_allocfar(DstCompiler *c);
int32_t dstc_allocnear(DstCompiler *c, DstcRegisterTemp);
int32_t dstc_regfar(DstCompiler *c, DstSlot s, DstcRegisterTemp tag);
int32_t dstc_regnear(DstCompiler *c, DstSlot s, DstcRegisterTemp tag);
void dstc_free_reg(DstCompiler *c, DstSlot s, int32_t reg);
int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s);
int32_t dstc_emit_s(DstCompiler *c, uint8_t op, DstSlot s, int wr);
int32_t dstc_emit_sl(DstCompiler *c, uint8_t op, DstSlot s, int32_t label);
int32_t dstc_emit_st(DstCompiler *c, uint8_t op, DstSlot s, int32_t tflags);
int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate);
int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate);
int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2);
int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate);
int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate);
int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3);
int32_t dstc_emit_si(DstCompiler *c, uint8_t op, DstSlot s, int16_t immediate, int wr);
int32_t dstc_emit_su(DstCompiler *c, uint8_t op, DstSlot s, uint16_t immediate, int wr);
int32_t dstc_emit_ss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int wr);
int32_t dstc_emit_ssi(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, int8_t immediate, int wr);
int32_t dstc_emit_ssu(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, uint8_t immediate, int wr);
int32_t dstc_emit_sss(DstCompiler *c, uint8_t op, DstSlot s1, DstSlot s2, DstSlot s3, int wr);
/* Move value from one slot to another. Cannot copy to constant slots. */
void dstc_copy(DstCompiler *c, DstSlot dest, DstSlot src);

View File

@ -21,8 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstopcodes.h>
#include <dst/dstcorelib.h>
#include "fiber.h"
#include "state.h"
#include "gc.h"
@ -365,8 +363,8 @@ static Dst doframe(DstStackFrame *frame) {
dst_table_put(t, dst_csymbolv(":pc"), dst_wrap_integer(off));
if (def->sourcemap) {
DstSourceMapping mapping = def->sourcemap[off];
dst_table_put(t, dst_csymbolv(":source-line"), dst_wrap_integer(mapping.line));
dst_table_put(t, dst_csymbolv(":source-column"), dst_wrap_integer(mapping.column));
dst_table_put(t, dst_csymbolv(":line"), dst_wrap_integer(mapping.line));
dst_table_put(t, dst_csymbolv(":column"), dst_wrap_integer(mapping.column));
}
if (def->source) {
dst_table_put(t, dst_csymbolv(":source"), dst_wrap_string(def->source));

View File

@ -20,8 +20,9 @@
* IN THE SOFTWARE.
*/
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include <errno.h>
#define IO_WRITE 1

View File

@ -21,7 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include <math.h>
/* Get a random number */

View File

@ -1,75 +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>
#include <dst/dstcorelib.h>
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
* with native code. */
#ifdef DST_WINDOWS
#include <windows.h>
typedef HINSTANCE Clib;
#define load_clib(name) LoadLibrary((name))
#define symbol_clib(lib, sym) GetProcAddress((lib), (sym))
#define error_clib() "could not load dynamic library"
#elif defined(DST_WEB)
#include <emscripten.h>
/* TODO - figure out how loading modules will work in JS */
typedef int Clib;
#define load_clib(name) 0
#define symbol_clib(lib, sym) 0
#define error_clib() "dynamic libraries not supported"
#else
#include <dlfcn.h>
typedef void *Clib;
#define load_clib(name) dlopen((name), RTLD_NOW)
#define symbol_clib(lib, sym) dlsym((lib), (sym))
#define error_clib() dlerror()
#endif
DstCFunction dst_native(const char *name, const uint8_t **error) {
Clib lib = load_clib(name);
DstCFunction init;
if (!lib) {
*error = dst_cstring(error_clib());
return NULL;
}
init = (DstCFunction) symbol_clib(lib, "_dst_init");
if (!init) {
*error = dst_cstring("could not find _dst_init symbol");
return NULL;
}
return init;
}
int dst_core_native(DstArgs args) {
DstCFunction init;
const uint8_t *error = NULL;
const uint8_t *path = NULL;
DST_FIXARITY(args, 1);
DST_ARG_STRING(path, args, 0);
init = dst_native((const char *)path, &error);
if (!init) {
DST_THROWV(args, dst_wrap_string(error));
}
DST_RETURN_CFUNCTION(args, init);
}

View File

@ -21,8 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include <stdlib.h>
#include <time.h>

View File

@ -20,9 +20,8 @@
* IN THE SOFTWARE.
*/
#include "regalloc.h"
#include <stdlib.h>
#include <dst/dst.h>
#include "regalloc.h"
void dstc_regalloc_init(DstcRegisterAllocator *ra) {
ra->chunks = NULL;
@ -66,6 +65,7 @@ void dstc_regalloc_clone(DstcRegisterAllocator *dest, DstcRegisterAllocator *src
dest->max = src->max;
size = sizeof(uint32_t) * dest->capacity;
dest->chunks = malloc(size);
dest->regtemps = 0;
if (!dest->chunks) {
DST_OUT_OF_MEMORY;
}
@ -126,17 +126,7 @@ int32_t dstc_regalloc_1(DstcRegisterAllocator *ra) {
/* Free a register. The register must have been previously allocated
* without being freed. */
void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg) {
/* We cannot free reserved slots */
if (reg < 0)
return;
if (reg >= 0xF0 && reg <= 0xFF) {
ra->regtemps &= ~(1 << (reg - 0xF0));
return;
}
int32_t chunk = reg >> 5;
/* Outside normal chunk range */
if (chunk >= ra->count)
return;
int32_t bit = reg & 0x1F;
ra->chunks[chunk] &= ~ithbit(bit);
}
@ -146,9 +136,11 @@ void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg) {
* on the returned register before. */
int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth) {
int32_t oldmax = ra->max;
int32_t reg = dstc_regalloc_1(ra);
dst_assert(~(ra->regtemps & (1 << nth)), "regtemp already allocated");
if (ra->regtemps & (1 << nth)) {
dst_exit("regtemp already allocated");
}
ra->regtemps |= 1 << nth;
int32_t reg = dstc_regalloc_1(ra);
if (reg > 0xFF) {
reg = 0xF0 + nth;
ra->max = (reg > oldmax) ? reg : oldmax;
@ -156,6 +148,12 @@ int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth) {
return reg;
}
void dstc_regalloc_freetemp(DstcRegisterAllocator *ra, int32_t reg, DstcRegisterTemp nth) {
ra->regtemps &= ~(1 << nth);
if (reg < 0xF0)
dstc_regalloc_free(ra, reg);
}
/* Disable multi-slot allocation for now. */
/*

View File

@ -36,7 +36,7 @@ typedef enum {
DSTC_REGTEMP_4,
DSTC_REGTEMP_5,
DSTC_REGTEMP_6,
DSTC_REGTEMP_TARGET
DSTC_REGTEMP_7
} DstcRegisterTemp;
typedef struct {
@ -53,6 +53,7 @@ void dstc_regalloc_deinit(DstcRegisterAllocator *ra);
int32_t dstc_regalloc_1(DstcRegisterAllocator *ra);
void dstc_regalloc_free(DstcRegisterAllocator *ra, int32_t reg);
int32_t dstc_regalloc_temp(DstcRegisterAllocator *ra, DstcRegisterTemp nth);
void dstc_regalloc_freetemp(DstcRegisterAllocator *ra, int32_t reg, DstcRegisterTemp nth);
void dstc_regalloc_clone(DstcRegisterAllocator *dest, DstcRegisterAllocator *src);
void dstc_regalloc_touch(DstcRegisterAllocator *ra, int32_t reg);

View File

@ -21,8 +21,49 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include <dst/dstcompile.h>
#include "state.h"
/* Error reporting */
static void print_error_report(DstFiber *fiber, const char *errtype, Dst err) {
const char *errstr = (const char *)dst_to_string(err);
printf("%s error: %s\n", errtype, errstr);
if (!fiber) return;
int32_t i = fiber->frame;
while (i > 0) {
DstStackFrame *frame = (DstStackFrame *)(fiber->data + i - DST_FRAME_SIZE);
DstFuncDef *def = NULL;
i = frame->prevframe;
printf(" at");
if (frame->func) {
def = frame->func->def;
printf(" %s", def->name ? (const char *)def->name : "<anonymous>");
if (def->source) {
printf(" %s", (const char *)def->source);
}
} else {
DstCFunction cfun = (DstCFunction)(frame->pc);
if (cfun) {
Dst name = dst_table_get(dst_vm_registry, dst_wrap_cfunction(cfun));
if (!dst_checktype(name, DST_NIL))
printf(" [%s]", (const char *)dst_to_string(name));
}
}
if (frame->flags & DST_STACKFRAME_TAILCALL)
printf(" (tailcall)");
if (frame->func && frame->pc) {
int32_t off = (int32_t) (frame->pc - def->bytecode);
if (def->sourcemap) {
DstSourceMapping mapping = def->sourcemap[off];
printf(" on line %d, column %d", mapping.line, mapping.column);
} else {
printf(" pc=%d", off);
}
}
printf("\n");
}
}
/* Run a string */
int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath) {
@ -47,18 +88,19 @@ int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len, const char *so
Dst ret = dst_wrap_nil();
DstSignal status = dst_run(fiber, &ret);
if (status != DST_SIGNAL_OK) {
printf("internal runtime error: %s\n", (const char *) dst_to_string(ret));
print_error_report(fiber, "runtime", ret);
errflags |= 0x01;
}
} else {
printf("internal compile error: %s\n", (const char *) cres.error);
print_error_report(cres.macrofiber, "compile",
dst_wrap_string(cres.error));
errflags |= 0x02;
}
}
break;
case DST_PARSE_ERROR:
errflags |= 0x04;
printf("internal parse error: %s\n", dst_parser_error(&parser));
printf("parse error: %s\n", dst_parser_error(&parser));
break;
case DST_PARSE_PENDING:
if (index >= len) {

View File

@ -21,11 +21,9 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include <dst/dstcompile.h>
#include "compile.h"
#include <headerlibs/strbinsearch.h>
#include <headerlibs/vector.h>
#include "util.h"
#include "vector.h"
#include "emit.h"
DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) {
@ -37,11 +35,12 @@ DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) {
}
/* Preform destructuring. Be careful to
* keep the order registers are freed. */
static void destructure(DstCompiler *c,
* keep the order registers are freed.
* Returns if the slot 'right' can be freed. */
static int destructure(DstCompiler *c,
Dst left,
DstSlot right,
void (*leaf)(DstCompiler *c,
int (*leaf)(DstCompiler *c,
const uint8_t *sym,
DstSlot s,
DstTable *attr),
@ -49,73 +48,43 @@ static void destructure(DstCompiler *c,
switch (dst_type(left)) {
default:
dstc_cerror(c, "unexpected type in destructuring");
break;
return 1;
case DST_SYMBOL:
/* Leaf, assign right to left */
leaf(c, dst_unwrap_symbol(left), right, attr);
break;
return leaf(c, dst_unwrap_symbol(left), right, attr);
case DST_TUPLE:
case DST_ARRAY:
{
int32_t i, len, right_register, subval_register;
int32_t i, len;
const Dst *values;
dst_seq_view(left, &values, &len);
for (i = 0; i < len; i++) {
DstSlot nextright;
DstSlot nextright = dstc_farslot(c);
Dst subval = values[i];
right_register = dstc_regnear(c, right, DSTC_REGTEMP_0);
subval_register = dstc_allocnear(c, DSTC_REGTEMP_1);
if (i < 0x100) {
dstc_emit(c, DOP_GET_INDEX |
(subval_register << 8) |
(right_register << 16) |
(i << 24));
dstc_emit_ssu(c, DOP_GET_INDEX, nextright, right, (uint8_t) i, 1);
} else {
DstSlot islot = dstc_cslot(dst_wrap_integer(i));
int32_t i_register = dstc_regnear(c, islot, DSTC_REGTEMP_2);
dstc_emit(c, DOP_GET_INDEX |
(subval_register << 8) |
(right_register << 16) |
(i_register << 24));
dstc_free_reg(c, islot, i_register);
DstSlot k = dstc_cslot(dst_wrap_integer(i));
dstc_emit_sss(c, DOP_GET, nextright, right, k, 1);
}
nextright.index = subval_register;
nextright.envindex = -1;
nextright.constant = dst_wrap_nil();
nextright.flags = DST_SLOTTYPE_ANY;
destructure(c, subval, nextright, leaf, attr);
/* Free right_register AFTER sub destructuring */
dstc_free_reg(c, right, right_register);
if (destructure(c, subval, nextright, leaf, attr))
dstc_freeslot(c, nextright);
}
}
break;
return 1;
case DST_TABLE:
case DST_STRUCT:
{
int32_t right_register, subval_register, k_register;
const DstKV *kv = NULL;
while ((kv = dstc_next(left, kv))) {
DstSlot nextright;
DstSlot kslot = dstc_value(dstc_fopts_default(c), kv->key);
right_register = dstc_regnear(c, right, DSTC_REGTEMP_0);
subval_register = dstc_allocnear(c, DSTC_REGTEMP_1);
k_register = dstc_regnear(c, kslot, DSTC_REGTEMP_2);
dstc_emit(c, DOP_GET |
(subval_register << 8) |
(right_register << 16) |
(k_register << 24));
dstc_free_reg(c, kslot, k_register);
nextright.index = subval_register;
nextright.envindex = -1;
nextright.constant = dst_wrap_nil();
nextright.flags = DST_SLOTTYPE_ANY;
destructure(c, kv->value, nextright, leaf, attr);
/* Free right_register AFTER sub destructuring */
dstc_free_reg(c, right, right_register);
DstSlot nextright = dstc_farslot(c);
DstSlot k = dstc_value(dstc_fopts_default(c), kv->key);
dstc_emit_sss(c, DOP_GET, nextright, right, k, 1);
if (destructure(c, kv->value, nextright, leaf, attr))
dstc_freeslot(c, nextright);
}
}
break;
return 1;
}
}
@ -180,28 +149,22 @@ static DstSlot dohead(DstCompiler *c, DstFopts opts, Dst *head, int32_t argn, co
}
/* Def or var a symbol in a local scope */
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 ||
ret.index < 0 ||
ret.index > 0xFF) {
static int namelocal(DstCompiler *c, const uint8_t *head, int32_t flags, DstSlot ret) {
int isUnnamedRegister = !(ret.flags & DST_SLOT_NAMED) &&
ret.index > 0 &&
ret.envindex >= 0;
if (!isUnnamedRegister) {
/* Slot is not able to be named */
DstSlot localslot;
localslot.index = dstc_allocfar(c);
/* infer type? */
localslot.flags = flags;
localslot.envindex = -1;
localslot.constant = dst_wrap_nil();
DstSlot localslot = dstc_farslot(c);
dstc_copy(c, localslot, ret);
ret = localslot;
}
ret.flags |= flags;
dstc_nameslot(c, dst_unwrap_symbol(head), ret);
return ret;
dstc_nameslot(c, head, ret);
return !isUnnamedRegister;
}
static void varleaf(
static int varleaf(
DstCompiler *c,
const uint8_t *sym,
DstSlot s,
@ -216,9 +179,10 @@ static void varleaf(
dst_table_put(reftab, dst_csymbolv(":ref"), dst_wrap_array(ref));
dst_table_put(c->env, dst_wrap_symbol(sym), dst_wrap_table(reftab));
refslot = dstc_cslot(dst_wrap_array(ref));
dstc_emit_ssu(c, DOP_PUT_INDEX, refslot, s, 0);
dstc_emit_ssu(c, DOP_PUT_INDEX, refslot, s, 0, 0);
return 1;
} else {
namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED | DST_SLOT_MUTABLE, s) ;
return namelocal(c, sym, DST_SLOT_MUTABLE, s);
}
}
@ -227,11 +191,12 @@ DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) {
Dst head;
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));
if (destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv)))
dstc_freeslot(c, ret);
return dstc_cslot(dst_wrap_nil());
}
static void defleaf(
static int defleaf(
DstCompiler *c,
const uint8_t *sym,
DstSlot s,
@ -246,9 +211,10 @@ static void defleaf(
dst_table_put(c->env, dst_wrap_symbol(sym), dst_wrap_table(tab));
/* Put value in table when evaulated */
dstc_emit_sss(c, DOP_PUT, tabslot, valsym, s);
dstc_emit_sss(c, DOP_PUT, tabslot, valsym, s, 0);
return 1;
} else {
namelocal(c, dst_wrap_symbol(sym), DST_SLOT_NAMED, s);
return namelocal(c, sym, 0, s);
}
}
@ -258,7 +224,8 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) {
opts.flags &= ~DST_FOPTS_HINT;
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));
if (destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv)))
dstc_freeslot(c, ret);
return dstc_cslot(dst_wrap_nil());
}
@ -321,7 +288,7 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) {
: dstc_gettarget(opts);
/* Compile jump to right */
labeljr = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0);
labeljr = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0, 0);
/* Condition left body */
dstc_scope(&tempscope, c, 0, "if-true");
@ -414,7 +381,7 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) {
/* Infinite loop does not need to check condition */
if (!infinite) {
labelc = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0);
labelc = dstc_emit_si(c, DOP_JUMP_IF_NOT, cond, 0, 0);
} else {
labelc = 0;
}
@ -459,7 +426,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot ret;
Dst head, paramv;
DstScope fnscope;
int32_t paramcount, argi, parami, arity, localslot, defindex;
int32_t paramcount, argi, parami, arity, defindex;
DstFopts subopts = dstc_fopts_default(c);
const Dst *params;
const char *errmsg = NULL;
@ -517,7 +484,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
if (selfref) {
DstSlot slot = dstc_farslot(c);
slot.flags = DST_SLOT_NAMED | DST_FUNCTION;
dstc_emit_s(c, DOP_LOAD_SELF, slot);
dstc_emit_s(c, DOP_LOAD_SELF, slot, 1);
dstc_nameslot(c, dst_unwrap_symbol(head), slot);
}
@ -525,10 +492,8 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
if (parami + 1 == argn) {
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;
s = dstc_value(subopts, argv[argi]);
dstc_freeslot(c, s);
dstc_value(subopts, argv[argi]);
if (dstc_iserr(&opts))
goto error2;
}
@ -545,20 +510,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
/* Instantiate closure */
ret = dstc_gettarget(opts);
localslot = ret.index > 0xF0 ? 0xF1 : ret.index;
dstc_emit(c,
(defindex << 16) |
(localslot << 8) |
DOP_CLOSURE);
if (ret.index != localslot) {
dstc_emit(c,
(ret.index << 16) |
(localslot << 8) |
DOP_MOVE_FAR);
}
dstc_emit_su(c, DOP_CLOSURE, ret, defindex, 1);
return ret;
error:

View File

@ -23,13 +23,7 @@
#ifndef DST_STATE_H_defined
#define DST_STATE_H_defined
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <dst/dstconfig.h>
#include <dst/dsttypes.h>
/* The VM state. Rather than a struct that is passed
* around, the vm state is global for simplicity. If
@ -66,8 +60,4 @@ extern DST_THREAD_LOCAL Dst *dst_vm_roots;
extern DST_THREAD_LOCAL uint32_t dst_vm_root_count;
extern DST_THREAD_LOCAL uint32_t dst_vm_root_capacity;
#ifdef __cplusplus
}
#endif
#endif /* DST_STATE_H_defined */

View File

@ -21,7 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "gc.h"
#include "util.h"
#include "state.h"

View File

@ -21,7 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "gc.h"
#include "util.h"

View File

@ -21,7 +21,6 @@
*/
#include <dst/dst.h>
#include <dst/dstcorelib.h>
#include "symcache.h"
#include "gc.h"
#include "util.h"

View File

@ -110,6 +110,33 @@ int dst_cstrcmp(const uint8_t *str, const char *other) {
return (other[index] == '\0') ? 0 : -1;
}
/* Do a binary search on a static array of structs. Each struct must
* have a string as its first element, and the struct must be sorted
* lexogrpahically by that element. */
const void *dst_strbinsearch(
const void *tab,
size_t tabcount,
size_t itemsize,
const uint8_t *key) {
size_t low = 0;
size_t hi = tabcount;
const char *t = (const char *)tab;
while (low < hi) {
size_t mid = low + ((hi - low) / 2);
const char **item = (const char **)(t + mid * itemsize);
const char *name = *item;
int comp = dst_cstrcmp(key, name);
if (comp < 0) {
hi = mid;
} else if (comp > 0) {
low = mid + 1;
} else {
return (const void *)item;
}
}
return NULL;
}
/* Add a module definition */
void dst_env_def(DstTable *env, const char *name, Dst val) {
DstTable *subt = dst_table(1);
@ -238,26 +265,29 @@ int dst_type_err(DstArgs args, int32_t n, DstType expected) {
DST_THROWV(args, dst_wrap_string(message));
}
int dst_typemany_err(DstArgs args, int32_t n, int expected) {
int i;
void dst_buffer_push_types(DstBuffer *buffer, int types) {
int first = 1;
int i = 0;
while (types) {
if (1 & types) {
if (first) {
first = 0;
} else {
dst_buffer_push_u8(buffer, '|');
}
dst_buffer_push_cstring(buffer, dst_type_names[i] + 1);
}
i++;
types >>= 1;
}
}
int dst_typemany_err(DstArgs args, int32_t n, int expected) {
const uint8_t *message;
DstBuffer buf;
dst_buffer_init(&buf, 20);
dst_buffer_push_string(&buf, dst_formatc("bad slot #%d, expected ", n));
i = 0;
while (expected) {
if (1 & expected) {
if (first) {
first = 0;
} else {
dst_buffer_push_u8(&buf, '|');
}
dst_buffer_push_cstring(&buf, dst_type_names[i] + 1);
}
i++;
expected >>= 1;
}
dst_buffer_push_types(&buf, expected);
dst_buffer_push_cstring(&buf, ", got ");
dst_buffer_push_cstring(&buf, typestr(args, n));
message = dst_string(buf.data, buf.count);

View File

@ -31,5 +31,11 @@ int32_t dst_array_calchash(const Dst *array, int32_t len);
int32_t dst_kv_calchash(const DstKV *kvs, int32_t len);
int32_t dst_string_calchash(const uint8_t *str, int32_t len);
int32_t dst_tablen(int32_t n);
void dst_buffer_push_types(DstBuffer *buffer, int types);
const void *dst_strbinsearch(
const void *tab,
size_t tabcount,
size_t itemsize,
const uint8_t *key);
#endif

76
src/core/vector.c Normal file
View File

@ -0,0 +1,76 @@
/*
* 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 "vector.h"
/* Grow the buffer dynamically. Used for push operations. */
void *dst_v_grow(void *v, int32_t increment, int32_t itemsize) {
int32_t dbl_cur = (NULL != v) ? 2 * dst_v__cap(v) : 0;
int32_t min_needed = dst_v_count(v) + increment;
int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed;
int32_t *p = (int32_t *) realloc(v ? dst_v__raw(v) : 0, itemsize * m + sizeof(int32_t)*2);
if (NULL != p) {
if (!v) p[1] = 0;
p[0] = m;
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t));
}
}
/* Clone a buffer. */
void *dst_v_copymem(void *v, int32_t itemsize) {
int32_t *p;
if (NULL == v) return NULL;
p = malloc(2 * sizeof(int32_t) + itemsize * dst_v__cap(v));
if (NULL != p) {
memcpy(p, dst_v__raw(v), 2 * sizeof(int32_t) + itemsize * dst_v__cnt(v));
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t));
}
}
/* Convert a buffer to normal allocated memory (forget capacity) */
void *dst_v_flattenmem(void *v, int32_t itemsize) {
int32_t *p;
int32_t sizen;
if (NULL == v) return NULL;
sizen = itemsize * dst_v__cnt(v);
p = malloc(sizen);
if (NULL != p) {
memcpy(p, v, sizen);
return p;
} else {
{
DST_OUT_OF_MEMORY;
}
return NULL;
}
}

View File

@ -23,6 +23,8 @@
#ifndef DST_VECTOR_H_defined
#define DST_VECTOR_H_defined
#include <dst/dst.h>
/*
* vector code modified from
* https://github.com/nothings/stb/blob/master/stretchy_buffer.h
@ -50,65 +52,9 @@
#define dst_v__maybegrow(v, n) (dst_v__needgrow((v), (n)) ? dst_v__grow((v), (n)) : 0)
#define dst_v__grow(v, n) ((v) = dst_v_grow((v), (n), sizeof(*(v))))
/* Vector code */
/* Grow the buffer dynamically. Used for push operations. */
#ifndef DST_V_NODEF_GROW
static void *dst_v_grow(void *v, int32_t increment, int32_t itemsize) {
int32_t dbl_cur = (NULL != v) ? 2 * dst_v__cap(v) : 0;
int32_t min_needed = dst_v_count(v) + increment;
int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed;
int32_t *p = (int32_t *) realloc(v ? dst_v__raw(v) : 0, itemsize * m + sizeof(int32_t)*2);
if (NULL != p) {
if (!v) p[1] = 0;
p[0] = m;
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
}
}
#endif
/* Clone a buffer. */
#ifdef DST_V_DEF_COPYMEM
static void *dst_v_copymem(void *v, int32_t itemsize) {
int32_t *p;
if (NULL == v) return NULL;
p = malloc(2 * sizeof(int32_t) + itemsize * dst_v__cap(v));
if (NULL != p) {
memcpy(p, dst_v__raw(v), 2 * sizeof(int32_t) + itemsize * dst_v__cnt(v));
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
}
}
#endif
/* Convert a buffer to normal allocated memory (forget capacity) */
#ifdef DST_V_DEF_FLATTENMEM
static void *dst_v_flattenmem(void *v, int32_t itemsize) {
int32_t *p;
int32_t sizen;
if (NULL == v) return NULL;
sizen = itemsize * dst_v__cnt(v);
p = malloc(sizen);
if (NULL != p) {
memcpy(p, v, sizen);
return p;
} else {
{
DST_OUT_OF_MEMORY;
}
return NULL;
}
}
#endif
/* Actual functions defined in vector.c */
void *dst_v_grow(void *v, int32_t increment, int32_t itemsize);
void *dst_v_copymem(void *v, int32_t itemsize);
void *dst_v_flattenmem(void *v, int32_t itemsize);
#endif

View File

@ -21,11 +21,11 @@
*/
#include <dst/dst.h>
#include <dst/dstopcodes.h>
#include "state.h"
#include "fiber.h"
#include "gc.h"
#include "symcache.h"
#include "util.h"
/* VM state */
DST_THREAD_LOCAL DstTable *dst_vm_registry;
@ -51,6 +51,9 @@ DstSignal dst_continue(DstFiber *fiber, Dst in, Dst *out) {
* Values stored here should be used immediately */
Dst retreg;
/* Expected types on type error */
uint16_t expected_types;
/* Signal to return when done */
DstSignal signal = DST_SIGNAL_OK;
@ -181,6 +184,12 @@ static void *op_lookup[255] = {
&&label_DOP_GET_INDEX,
&&label_DOP_PUT_INDEX,
&&label_DOP_LENGTH,
&&label_DOP_MAKE_ARRAY,
&&label_DOP_MAKE_BUFFER,
&&label_DOP_MAKE_STRING,
&&label_DOP_MAKE_STRUCT,
&&label_DOP_MAKE_TABLE,
&&label_DOP_MAKE_TUPLE,
&&label_unknown_op
};
#else
@ -195,6 +204,20 @@ static void *op_lookup[255] = {
#define vm_throw(e) do { retreg = dst_cstringv(e); goto vm_error; } while (0)
#define vm_assert(cond, e) do {if (!(cond)) vm_throw((e)); } while (0)
#define vm_assert_type(X, T) do { \
if (!(dst_checktype((X), (T)))) { \
expected_types = 1 << (T); \
retreg = (X); \
goto vm_type_error; \
} \
} while (0)
#define vm_assert_types(X, TS) do { \
if (!((1 << dst_type(X)) & (TS))) { \
expected_types = (TS); \
retreg = (X); \
goto vm_type_error; \
} \
} while (0)
#define vm_binop_integer(op) \
stack[oparg(1, 0xFF)] = dst_wrap_integer(\
@ -221,8 +244,8 @@ static void *op_lookup[255] = {
{\
Dst op1 = stack[oparg(2, 0xFF)];\
Dst op2 = stack[oparg(3, 0xFF)];\
vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number");\
vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number");\
vm_assert_types(op1, DST_TFLAG_NUMBER);\
vm_assert_types(op2, DST_TFLAG_NUMBER);\
stack[oparg(1, 0xFF)] = dst_checktype(op1, DST_INTEGER)\
? (dst_checktype(op2, DST_INTEGER)\
? dst_wrap_integer(dst_unwrap_integer(op1) op dst_unwrap_integer(op2))\
@ -333,8 +356,8 @@ static void *op_lookup[255] = {
{
Dst op1 = stack[oparg(2, 0xFF)];
Dst op2 = stack[oparg(3, 0xFF)];
vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number");
vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number");
vm_assert_types(op1, DST_TFLAG_NUMBER);
vm_assert_types(op2, DST_TFLAG_NUMBER);
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == 0)
vm_throw("integer divide by zero");
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == -1 &&
@ -688,7 +711,9 @@ static void *op_lookup[255] = {
if (dst_seq_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) {
dst_fiber_pushn(fiber, vals, len);
} else {
vm_throw("expected array/tuple");
retreg = stack[oparg(1, 0xFFFFFF)];
expected_types = DST_TFLAG_INDEXED;
goto vm_type_error;
}
}
pc++;
@ -721,7 +746,9 @@ static void *op_lookup[255] = {
}
goto vm_return_cfunc;
}
vm_throw("expected function");
expected_types = DST_TFLAG_CALLABLE;
retreg = callee;
goto vm_type_error;
}
VM_OP(DOP_TAILCALL)
@ -745,13 +772,15 @@ static void *op_lookup[255] = {
}
goto vm_return_cfunc_tail;
}
vm_throw("expected function");
expected_types = DST_TFLAG_CALLABLE;
retreg = callee;
goto vm_type_error;
}
VM_OP(DOP_RESUME)
{
Dst fiberval = stack[oparg(2, 0xFF)];
vm_assert(dst_checktype(fiberval, DST_FIBER), "expected fiber");
vm_assert_type(fiberval, DST_FIBER);
retreg = stack[oparg(3, 0xFF)];
fiber->child = dst_unwrap_fiber(fiberval);
goto vm_resume_child;
@ -775,12 +804,15 @@ static void *op_lookup[255] = {
Dst value = stack[oparg(3, 0xFF)];
switch (dst_type(ds)) {
default:
vm_throw("expected mutable data structure");
expected_types = DST_TFLAG_ARRAY | DST_TFLAG_BUFFER | DST_TFLAG_TABLE;
retreg = ds;
goto vm_type_error;
case DST_ARRAY:
{
int32_t index;
DstArray *array = dst_unwrap_array(ds);
if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0)
vm_assert_type(key, DST_INTEGER);
if (dst_unwrap_integer(key) < 0)
vm_throw("expected non-negative integer key");
index = dst_unwrap_integer(key);
if (index == INT32_MAX)
@ -795,13 +827,13 @@ static void *op_lookup[255] = {
{
int32_t index;
DstBuffer *buffer = dst_unwrap_buffer(ds);
if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0)
vm_assert_type(key, DST_INTEGER);
if (dst_unwrap_integer(key) < 0)
vm_throw("expected non-negative integer key");
index = dst_unwrap_integer(key);
if (index == INT32_MAX)
vm_throw("key too large");
if (!dst_checktype(value, DST_INTEGER))
vm_throw("expected integer value");
vm_assert_type(value, DST_INTEGER);
if (index >= buffer->count) {
dst_buffer_setcount(buffer, index + 1);
}
@ -823,7 +855,9 @@ static void *op_lookup[255] = {
int32_t index = oparg(3, 0xFF);
switch (dst_type(ds)) {
default:
vm_throw("expected mutable indexed data structure");
expected_types = DST_TFLAG_ARRAY | DST_TFLAG_BUFFER;
retreg = ds;
goto vm_type_error;
case DST_ARRAY:
if (index >= dst_unwrap_array(ds)->count) {
dst_array_ensure(dst_unwrap_array(ds), 2 * index);
@ -832,8 +866,7 @@ static void *op_lookup[255] = {
dst_unwrap_array(ds)->data[index] = value;
break;
case DST_BUFFER:
if (!dst_checktype(value, DST_INTEGER))\
vm_throw("expected integer to set in buffer");
vm_assert_type(value, DST_INTEGER);
if (index >= dst_unwrap_buffer(ds)->count) {
dst_buffer_ensure(dst_unwrap_buffer(ds), 2 * index);
dst_unwrap_buffer(ds)->count = index + 1;
@ -852,7 +885,9 @@ static void *op_lookup[255] = {
Dst value;
switch (dst_type(ds)) {
default:
vm_throw("expected data structure");
expected_types = DST_TFLAG_LENGTHABLE;
retreg = ds;
goto vm_type_error;
case DST_STRUCT:
value = dst_struct_get(dst_unwrap_struct(ds), key);
break;
@ -863,8 +898,7 @@ static void *op_lookup[255] = {
{
DstArray *array = dst_unwrap_array(ds);
int32_t index;
if (!dst_checktype(key, DST_INTEGER))
vm_throw("expected integer key");
vm_assert_type(key, DST_INTEGER);
index = dst_unwrap_integer(key);
if (index < 0 || index >= array->count) {
/*vm_throw("index out of bounds");*/
@ -878,8 +912,7 @@ static void *op_lookup[255] = {
{
const Dst *tuple = dst_unwrap_tuple(ds);
int32_t index;
if (!dst_checktype(key, DST_INTEGER))
vm_throw("expected integer key");
vm_assert_type(key, DST_INTEGER);
index = dst_unwrap_integer(key);
if (index < 0 || index >= dst_tuple_length(tuple)) {
/*vm_throw("index out of bounds");*/
@ -893,8 +926,7 @@ static void *op_lookup[255] = {
{
DstBuffer *buffer = dst_unwrap_buffer(ds);
int32_t index;
if (!dst_checktype(key, DST_INTEGER))
vm_throw("expected integer key");
vm_assert_type(key, DST_INTEGER);
index = dst_unwrap_integer(key);
if (index < 0 || index >= buffer->count) {
/*vm_throw("index out of bounds");*/
@ -909,8 +941,7 @@ static void *op_lookup[255] = {
{
const uint8_t *str = dst_unwrap_string(ds);
int32_t index;
if (!dst_checktype(key, DST_INTEGER))
vm_throw("expected integer key");
vm_assert_type(key, DST_INTEGER);
index = dst_unwrap_integer(key);
if (index < 0 || index >= dst_string_length(str)) {
/*vm_throw("index out of bounds");*/
@ -933,7 +964,9 @@ static void *op_lookup[255] = {
Dst value;
switch (dst_type(ds)) {
default:
vm_throw("expected indexed data structure");
expected_types = DST_TFLAG_LENGTHABLE;
retreg = ds;
goto vm_type_error;
case DST_STRING:
case DST_SYMBOL:
if (index >= dst_string_length(dst_unwrap_string(ds))) {
@ -967,6 +1000,12 @@ static void *op_lookup[255] = {
value = dst_unwrap_tuple(ds)[index];
}
break;
case DST_TABLE:
value = dst_table_get(dst_unwrap_table(ds), dst_wrap_integer(index));
break;
case DST_STRUCT:
value = dst_struct_get(dst_unwrap_struct(ds), dst_wrap_integer(index));
break;
}
stack[oparg(1, 0xFF)] = value;
++pc;
@ -979,7 +1018,9 @@ static void *op_lookup[255] = {
int32_t len;
switch (dst_type(x)) {
default:
vm_throw("expected data structure");
expected_types = DST_TFLAG_LENGTHABLE;
retreg = x;
goto vm_type_error;
case DST_STRING:
case DST_SYMBOL:
len = dst_string_length(dst_unwrap_string(x));
@ -1005,6 +1046,84 @@ static void *op_lookup[255] = {
vm_next();
}
VM_OP(DOP_MAKE_ARRAY)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
stack[oparg(1, 0xFFFFFF)] = dst_wrap_array(dst_array_n(mem, count));
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
VM_OP(DOP_MAKE_TUPLE)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
stack[oparg(1, 0xFFFFFF)] = dst_wrap_tuple(dst_tuple_n(mem, count));
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
VM_OP(DOP_MAKE_TABLE)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
if (count & 1)
vm_throw("expected even number of arguments to table constructor");
DstTable *table = dst_table(count / 2);
for (int32_t i = 0; i < count; i += 2)
dst_table_put(table, mem[i], mem[i + 1]);
stack[oparg(1, 0xFFFFFF)] = dst_wrap_table(table);
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
VM_OP(DOP_MAKE_STRUCT)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
if (count & 1)
vm_throw("expected even number of arguments to struct constructor");
DstKV *st = dst_struct_begin(count / 2);
for (int32_t i = 0; i < count; i += 2)
dst_struct_put(st, mem[i], mem[i + 1]);
stack[oparg(1, 0xFFFFFF)] = dst_wrap_struct(dst_struct_end(st));
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
VM_OP(DOP_MAKE_STRING)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
DstBuffer buffer;
dst_buffer_init(&buffer, 10 * count);
for (int32_t i = 0; i < count; i++)
dst_to_string_b(&buffer, mem[i]);
stack[oparg(1, 0xFFFFFF)] = dst_stringv(buffer.data, buffer.count);
dst_buffer_deinit(&buffer);
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
VM_OP(DOP_MAKE_BUFFER)
{
int32_t count = fiber->stacktop - fiber->stackstart;
Dst *mem = fiber->data + fiber->stackstart;
DstBuffer *buffer = dst_buffer(10 * count);
for (int32_t i = 0; i < count; i++)
dst_to_string_b(buffer, mem[i]);
stack[oparg(1, 0xFFFFFF)] = dst_wrap_buffer(buffer);
fiber->stacktop = fiber->stackstart;
++pc;
vm_checkgc_next();
}
/* Return from c function. Simpler than returning from dst function */
vm_return_cfunc:
{
@ -1059,6 +1178,22 @@ static void *op_lookup[255] = {
vm_checkgc_next();
}
/* Handle type errors. The found type is the type of retreg,
* the expected types are in the expected_types field. */
vm_type_error:
{
DstBuffer errbuf;
dst_buffer_init(&errbuf, 10);
dst_buffer_push_cstring(&errbuf, "expected ");
dst_buffer_push_types(&errbuf, expected_types);
dst_buffer_push_cstring(&errbuf, ", got ");
dst_buffer_push_cstring(&errbuf, dst_type_names[dst_type(retreg)] + 1);
retreg = dst_stringv(errbuf.data, errbuf.count);
dst_buffer_deinit(&errbuf);
signal = DST_SIGNAL_ERROR;
goto vm_exit;
}
/* Handle errors from c functions and vm opcodes */
vm_error:
{
@ -1108,12 +1243,18 @@ static void *op_lookup[255] = {
}
DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out) {
DstSignal dst_call(
DstFunction *fun,
int32_t argn,
const Dst *argv,
Dst *out,
DstFiber **f) {
int32_t i;
DstFiber *fiber = dst_fiber(fun, 64);
for (i = 0; i < argn; i++) {
if (f)
*f = fiber;
for (i = 0; i < argn; i++)
dst_fiber_push(fiber, argv[i]);
}
dst_fiber_funcframe(fiber, fiber->root);
/* Prevent push an extra value on the stack */
dst_fiber_set_status(fiber, DST_STATUS_PENDING);

View File

@ -27,14 +27,786 @@
extern "C" {
#endif
#include "dstconfig.h"
/***** 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
/* 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
/* 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. */
#define DST_NANBOX
#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>
#include "dsttypes.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)))
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 0x10000
#define DST_FUNCDEF_FLAG_NEEDSENV 0x20000
#define DST_FUNCDEF_FLAG_FIXARITY 0x40000
#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;
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[];
};
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_INSTRUCTION_COUNT
};
/* Info about all instructions */
extern enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT];
/***** END SECTION OPCODES *****/
/***** START SECTION MAIN *****/
/* Parsing */
void dst_parser_init(DstParser *parser);
@ -62,6 +834,28 @@ DstAssembleResult dst_asm(Dst source, int flags);
Dst dst_disasm(DstFuncDef *def);
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 {
enum DstCompileStatus status;
DstFuncDef *funcdef;
const uint8_t *error;
DstFiber *macrofiber;
DstSourceMapping error_mapping;
};
DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where);
/* Get the default environment for dst */
DstTable *dst_stl_env();
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);
/* 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);
@ -69,6 +863,7 @@ double dst_scan_real(const uint8_t *str, int32_t len, int *err);
/* Array functions */
DstArray *dst_array(int32_t capacity);
DstArray *dst_array_n(const Dst *elements, int32_t n);
DstArray *dst_array_init(DstArray *array, int32_t capacity);
void dst_array_deinit(DstArray *array);
void dst_array_ensure(DstArray *array, int32_t capacity);
@ -119,6 +914,8 @@ const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len);
const uint8_t *dst_cstring_unique(const char *s);
const uint8_t *dst_description(Dst x);
const uint8_t *dst_to_string(Dst x);
void dst_to_string_b(DstBuffer *buffer, Dst x);
void dst_to_description_b(DstBuffer *buffer, Dst x);
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)))
@ -208,7 +1005,7 @@ int dst_init(void);
void dst_deinit(void);
DstSignal dst_continue(DstFiber *fiber, Dst in, Dst *out);
#define dst_run(F,O) dst_continue(F, dst_wrap_nil(), O)
DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out);
DstSignal dst_call(DstFunction *fun, int32_t argn, const Dst *argv, Dst *out, DstFiber **f);
/* Env helpers */
typedef enum {
@ -233,6 +1030,25 @@ int dst_type_err(DstArgs args, int32_t n, DstType expected);
int dst_typemany_err(DstArgs args, int32_t n, int expected);
int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at);
/* Initialize builtin libraries */
int dst_lib_io(DstArgs args);
int dst_lib_math(DstArgs args);
int dst_lib_array(DstArgs args);
int dst_lib_tuple(DstArgs args);
int dst_lib_buffer(DstArgs args);
int dst_lib_table(DstArgs args);
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);
int dst_lib_asm(DstArgs args);
int dst_lib_compile(DstArgs args);
/***** 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)
@ -343,6 +1159,8 @@ int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at);
#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

View File

@ -1,163 +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_CONFIG_H_defined
#define DST_CONFIG_H_defined
#ifdef __cplusplus
extern "C" {
#endif
#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
#else
#if defined(__GNUC__)
#define DST_THREAD_LOCAL __thread
#elif defined(_MSC_BUILD)
#define DST_THREAD_LOCAL __declspec(thread)
#else
#define DST_THREAD_LOCAL
#endif
#endif
/* Include default headers */
#include <stdint.h>
/* Handle runtime errors */
#ifndef dst_exit
#include <stdlib.h>
#include <stdio.h>
#define dst_exit(m) do { \
printf("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
/* 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. */
#define DST_NANBOX
#define DST_NANBOX_47
/* Alignment for pointers */
#ifdef DST_32
#define DST_WALIGN 4
#else
#define DST_WALIGN 8
#endif
#ifdef __cplusplus
}
#endif
#endif /* DST_CONFIG_H_defined */

View File

@ -1,88 +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_CORELIB_H_defined
#define DST_CORELIB_H_defined
#ifdef __cplusplus
extern "C" {
#endif
#include "dsttypes.h"
/* Native */
int dst_core_native(DstArgs args);
/* Arithmetic */
int dst_int(DstArgs args);
int dst_real(DstArgs args);
int dst_rand(DstArgs args);
int dst_srand(DstArgs args);
int dst_remainder(DstArgs args);
/* Misc core functions */
int dst_core_print(DstArgs args);
int dst_core_describe(DstArgs args);
int dst_core_string(DstArgs args);
int dst_core_symbol(DstArgs args);
int dst_core_buffer(DstArgs args);
int dst_core_scannumber(DstArgs args);
int dst_core_scaninteger(DstArgs args);
int dst_core_scanreal(DstArgs args);
int dst_core_tuple(DstArgs args);
int dst_core_array(DstArgs args);
int dst_core_table(DstArgs args);
int dst_core_struct(DstArgs args);
int dst_core_buffer(DstArgs args);
int dst_core_gensym(DstArgs args);
int dst_core_type(DstArgs args);
int dst_core_next(DstArgs args);
int dst_core_hash(DstArgs args);
/* GC */
int dst_core_gccollect(DstArgs args);
int dst_core_gcsetinterval(DstArgs args);
int dst_core_gcinterval(DstArgs args);
/* Initialize builtin libraries */
int dst_lib_io(DstArgs args);
int dst_lib_math(DstArgs args);
int dst_lib_array(DstArgs args);
int dst_lib_tuple(DstArgs args);
int dst_lib_buffer(DstArgs args);
int dst_lib_table(DstArgs args);
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);
int dst_lib_asm(DstArgs args);
/* Useful for compiler */
Dst dst_op_add(Dst lhs, Dst rhs);
Dst dst_op_subtract(Dst lhs, Dst rhs);
#ifdef __cplusplus
}
#endif
#endif /* DST_CORELIB_H_defined */

View File

@ -1,143 +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_OPCODES_H_defined
#define DST_OPCODES_H_defined
#ifdef __cplusplus
extern "C" {
#endif
/* 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_INSTRUCTION_COUNT
};
/* Info about all instructions */
extern enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT];
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,562 +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_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 0x10000
#define DST_FUNCDEF_FLAG_NEEDSENV 0x20000
#define DST_FUNCDEF_FLAG_FIXARITY 0x40000
#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;
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;
};
#define DST_PARSEFLAG_SOURCEMAP 1
/* 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;
};
#ifdef __cplusplus
}
#endif
#endif /* DST_TYPES_H_defined */

View File

3636
src/include/generated/boot.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
/* Auto generated - DO NOT EDIT */
static const unsigned char dst_mainclient_init[] = {
0x23, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
0x74, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x32, 0x30, 0x31,
0x38, 0x20, 0x28, 0x43, 0x29, 0x20, 0x43, 0x61, 0x6C, 0x76,
0x69, 0x6E, 0x20, 0x52, 0x6F, 0x73, 0x65, 0x0A, 0x28, 0x74,
0x61, 0x62, 0x6C, 0x65, 0x2E, 0x73, 0x65, 0x74, 0x70, 0x72,
0x6F, 0x74, 0x6F, 0x20, 0x40, 0x7B, 0x20, 0x31, 0x20, 0x32,
0x7D, 0x20, 0x40, 0x7B, 0x7D, 0x29, 0x0A, 0x28, 0x64, 0x6F,
0x0A, 0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A,
0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70,
0x6C, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
0x65, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20,
0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x6E, 0x6F, 0x2D,
0x66, 0x69, 0x6C, 0x65, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69,
0x76, 0x61, 0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29,
0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x72,
0x61, 0x77, 0x2D, 0x73, 0x74, 0x64, 0x69, 0x6E, 0x2A, 0x20,
0x3A, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x66,
0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20, 0x20, 0x28, 0x76,
0x61, 0x72, 0x20, 0x2A, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65,
0x6F, 0x70, 0x74, 0x73, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69,
0x76, 0x61, 0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29,
0x0A, 0x20, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x2A, 0x65,
0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E, 0x2D, 0x65, 0x72, 0x72,
0x6F, 0x72, 0x2A, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61,
0x74, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x0A, 0x0A,
0x20, 0x20, 0x23, 0x20, 0x46, 0x6C, 0x61, 0x67, 0x20, 0x68,
0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x73, 0x0A, 0x20, 0x20,
0x28, 0x64, 0x65, 0x66, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x6C,
0x65, 0x72, 0x73, 0x20, 0x3A, 0x70, 0x72, 0x69, 0x76, 0x61,
0x74, 0x65, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x22,
0x68, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x20, 0x22,
0x75, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x20, 0x22, 0x20, 0x28,
0x67, 0x65, 0x74, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x30,
0x29, 0x20, 0x22, 0x20, 0x5B, 0x6F, 0x70, 0x74, 0x69, 0x6F,
0x6E, 0x73, 0x5D, 0x20, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x73, 0x2E, 0x2E, 0x2E, 0x22, 0x29, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x70,
0x72, 0x69, 0x6E, 0x74, 0x20, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60,
0x4F, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x61, 0x72,
0x65, 0x3A, 0x0A, 0x20, 0x20, 0x2D, 0x68, 0x20, 0x53, 0x68,
0x6F, 0x77, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65,
0x6C, 0x70, 0x0A, 0x20, 0x20, 0x2D, 0x76, 0x20, 0x50, 0x72,
0x69, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x74, 0x72, 0x69,
0x6E, 0x67, 0x0A, 0x20, 0x20, 0x2D, 0x73, 0x20, 0x55, 0x73,
0x65, 0x20, 0x72, 0x61, 0x77, 0x20, 0x73, 0x74, 0x64, 0x69,
0x6E, 0x20, 0x69, 0x6E, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20,
0x6F, 0x66, 0x20, 0x67, 0x65, 0x74, 0x6C, 0x69, 0x6E, 0x65,
0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x66, 0x75, 0x6E, 0x63,
0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x69, 0x74, 0x79, 0x0A,
0x20, 0x20, 0x2D, 0x65, 0x20, 0x45, 0x78, 0x65, 0x63, 0x75,
0x74, 0x65, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E,
0x67, 0x20, 0x6F, 0x66, 0x20, 0x64, 0x73, 0x74, 0x0A, 0x20,
0x20, 0x2D, 0x72, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x20,
0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x20, 0x61,
0x66, 0x74, 0x65, 0x72, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69,
0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x73, 0x0A, 0x20, 0x20, 0x2D, 0x70, 0x20,
0x4B, 0x65, 0x65, 0x70, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x78,
0x65, 0x63, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x66,
0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20,
0x61, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6C, 0x65, 0x76, 0x65,
0x6C, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x28, 0x70,
0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x74, 0x29,
0x0A, 0x20, 0x20, 0x2D, 0x2D, 0x20, 0x53, 0x74, 0x6F, 0x70,
0x20, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x69, 0x6E, 0x67, 0x20,
0x6F, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x60, 0x29, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x28, 0x6F, 0x73, 0x2E, 0x65, 0x78, 0x69, 0x74, 0x20,
0x30, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x31, 0x29, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x76, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20,
0x5B, 0x5D, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x20,
0x56, 0x45, 0x52, 0x53, 0x49, 0x4F, 0x4E, 0x29, 0x20, 0x28,
0x6F, 0x73, 0x2E, 0x65, 0x78, 0x69, 0x74, 0x20, 0x30, 0x29,
0x20, 0x31, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x73, 0x22, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20,
0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x72, 0x61, 0x77, 0x2D, 0x73,
0x74, 0x64, 0x69, 0x6E, 0x2A, 0x20, 0x74, 0x72, 0x75, 0x65,
0x29, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x73, 0x68, 0x6F,
0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, 0x6C, 0x2A, 0x20,
0x74, 0x72, 0x75, 0x65, 0x29, 0x20, 0x31, 0x29, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x22, 0x20, 0x28, 0x66,
0x6E, 0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A,
0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70,
0x6C, 0x2A, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x20, 0x31,
0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x22,
0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A,
0x3D, 0x20, 0x2A, 0x65, 0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E,
0x2D, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x2A, 0x20, 0x66, 0x61,
0x6C, 0x73, 0x65, 0x29, 0x20, 0x31, 0x29, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x2D, 0x22, 0x20, 0x28, 0x66, 0x6E,
0x20, 0x5B, 0x5D, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x68,
0x61, 0x6E, 0x64, 0x6C, 0x65, 0x6F, 0x70, 0x74, 0x73, 0x2A,
0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, 0x20, 0x31, 0x29,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x65, 0x22, 0x20,
0x28, 0x66, 0x6E, 0x20, 0x5B, 0x69, 0x5D, 0x20, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x28, 0x3A, 0x3D, 0x20, 0x2A, 0x6E, 0x6F, 0x2D, 0x66, 0x69,
0x6C, 0x65, 0x2A, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29,
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x28, 0x65, 0x76, 0x61, 0x6C, 0x20, 0x28, 0x67,
0x65, 0x74, 0x20, 0x61, 0x72, 0x67, 0x73, 0x20, 0x28, 0x2B,
0x20, 0x69, 0x20, 0x31, 0x29, 0x29, 0x29, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32,
0x29, 0x7D, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x28, 0x64, 0x65,
0x66, 0x6E, 0x2D, 0x20, 0x64, 0x6F, 0x68, 0x61, 0x6E, 0x64,
0x6C, 0x65, 0x72, 0x20, 0x5B, 0x6E, 0x20, 0x69, 0x5D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66, 0x20, 0x68,
0x20, 0x28, 0x67, 0x65, 0x74, 0x20, 0x68, 0x61, 0x6E, 0x64,
0x6C, 0x65, 0x72, 0x73, 0x20, 0x6E, 0x29, 0x29, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20, 0x68, 0x20, 0x28,
0x68, 0x20, 0x69, 0x29, 0x20, 0x28, 0x70, 0x72, 0x69, 0x6E,
0x74, 0x20, 0x22, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E,
0x20, 0x66, 0x6C, 0x61, 0x67, 0x20, 0x2D, 0x22, 0x20, 0x6E,
0x29, 0x29, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x23, 0x20, 0x50,
0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x72, 0x67,
0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x0A, 0x20, 0x20, 0x28,
0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x31, 0x29, 0x0A, 0x20,
0x20, 0x28, 0x64, 0x65, 0x66, 0x20, 0x6C, 0x65, 0x6E, 0x61,
0x72, 0x67, 0x73, 0x20, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74,
0x68, 0x20, 0x61, 0x72, 0x67, 0x73, 0x29, 0x29, 0x0A, 0x20,
0x20, 0x28, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x3C,
0x20, 0x69, 0x20, 0x6C, 0x65, 0x6E, 0x61, 0x72, 0x67, 0x73,
0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66,
0x20, 0x61, 0x72, 0x67, 0x20, 0x28, 0x67, 0x65, 0x74, 0x20,
0x61, 0x72, 0x67, 0x73, 0x20, 0x69, 0x29, 0x29, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20, 0x28, 0x61, 0x6E,
0x64, 0x20, 0x2A, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x6F,
0x70, 0x74, 0x73, 0x2A, 0x20, 0x28, 0x3D, 0x20, 0x22, 0x2D,
0x22, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E,
0x73, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x72, 0x67, 0x20,
0x30, 0x20, 0x31, 0x29, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x28, 0x2B, 0x3D, 0x20, 0x69, 0x20, 0x28,
0x64, 0x6F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x20,
0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x73, 0x6C,
0x69, 0x63, 0x65, 0x20, 0x61, 0x72, 0x67, 0x20, 0x31, 0x20,
0x32, 0x29, 0x20, 0x69, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x28, 0x64, 0x6F, 0x0A, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x3A, 0x3D, 0x20, 0x2A,
0x6E, 0x6F, 0x2D, 0x66, 0x69, 0x6C, 0x65, 0x2A, 0x20, 0x66,
0x61, 0x6C, 0x73, 0x65, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x28, 0x69, 0x6D, 0x70, 0x6F, 0x72,
0x74, 0x2A, 0x20, 0x5F, 0x65, 0x6E, 0x76, 0x20, 0x61, 0x72,
0x67, 0x20, 0x3A, 0x65, 0x78, 0x69, 0x74, 0x20, 0x2A, 0x65,
0x78, 0x69, 0x74, 0x2D, 0x6F, 0x6E, 0x2D, 0x65, 0x72, 0x72,
0x6F, 0x72, 0x2A, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x28, 0x2B, 0x2B, 0x20, 0x69, 0x29, 0x29,
0x29, 0x29, 0x0A, 0x0A, 0x20, 0x20, 0x28, 0x77, 0x68, 0x65,
0x6E, 0x20, 0x28, 0x6F, 0x72, 0x20, 0x2A, 0x73, 0x68, 0x6F,
0x75, 0x6C, 0x64, 0x2D, 0x72, 0x65, 0x70, 0x6C, 0x2A, 0x20,
0x2A, 0x6E, 0x6F, 0x2D, 0x66, 0x69, 0x6C, 0x65, 0x2A, 0x29,
0x20, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x28, 0x69, 0x66, 0x20,
0x2A, 0x72, 0x61, 0x77, 0x2D, 0x73, 0x74, 0x64, 0x69, 0x6E,
0x2A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72,
0x65, 0x70, 0x6C, 0x20, 0x6E, 0x69, 0x6C, 0x20, 0x69, 0x64,
0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x29, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x6F, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x70, 0x72, 0x69,
0x6E, 0x74, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x20, 0x22, 0x44, 0x73, 0x74, 0x20, 0x22, 0x20, 0x56, 0x45,
0x52, 0x53, 0x49, 0x4F, 0x4E, 0x20, 0x22, 0x20, 0x20, 0x43,
0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28,
0x43, 0x29, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2D, 0x32, 0x30,
0x31, 0x38, 0x20, 0x43, 0x61, 0x6C, 0x76, 0x69, 0x6E, 0x20,
0x52, 0x6F, 0x73, 0x65, 0x22, 0x29, 0x29, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72, 0x65, 0x70,
0x6C, 0x20, 0x28, 0x66, 0x6E, 0x20, 0x5B, 0x62, 0x75, 0x66,
0x20, 0x70, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x28, 0x64, 0x65, 0x66, 0x20, 0x5B, 0x6C, 0x69, 0x6E, 0x65,
0x5D, 0x20, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x2E,
0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x70, 0x29, 0x29, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x65, 0x66,
0x20, 0x70, 0x72, 0x6F, 0x6D, 0x70, 0x74, 0x20, 0x28, 0x73,
0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x22, 0x64, 0x73, 0x74,
0x3A, 0x22, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x22, 0x3A,
0x22, 0x20, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x2E,
0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x70, 0x29, 0x20, 0x22,
0x3E, 0x20, 0x22, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x28, 0x67, 0x65, 0x74, 0x6C, 0x69, 0x6E, 0x65,
0x20, 0x70, 0x72, 0x6F, 0x6D, 0x70, 0x74, 0x20, 0x62, 0x75,
0x66, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x0A
};

View File

@ -1,53 +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_STRBINSEARCH_H_defined
#define DST_STRBINSEARCH_H_defined
/* Do a binary search on a static array of structs. Each struct must
* have a string as its first element, and the struct must be sorted
* lexogrpahically by that element. */
static const void *dst_strbinsearch(
const void *tab,
size_t tabcount,
size_t itemsize,
const uint8_t *key) {
size_t low = 0;
size_t hi = tabcount;
const char *t = (const char *)tab;
while (low < hi) {
size_t mid = low + ((hi - low) / 2);
const char **item = (const char **)(t + mid * itemsize);
const char *name = *item;
int comp = dst_cstrcmp(key, name);
if (comp < 0) {
hi = mid;
} else if (comp > 0) {
low = mid + 1;
} else {
return (const void *)item;
}
}
return NULL;
}
#endif

View File

@ -1,4 +1,5 @@
# Copyright 2017-2018 (C) Calvin Rose
(table.setproto @{ 1 2} @{})
(do
(var *should-repl* :private false)

View File

@ -83,8 +83,6 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c
#include <string.h>
#include <signal.h>
#include <headerlibs/vector.h>
/* static state */
#define DST_LINE_MAX 1024
#define DST_HISTORY_MAX 100
@ -95,7 +93,8 @@ static char buf[DST_LINE_MAX];
static int len = 0;
static int pos = 0;
static int cols = 80;
static char **history = NULL;
static char *history[DST_HISTORY_MAX];
static int history_count = 0;
static int historyi = 0;
static struct termios termios_start;
@ -238,7 +237,7 @@ static int insert(char c) {
}
static void historymove(int delta) {
if (dst_v_count(history) > 1) {
if (history_count > 1) {
free(history[historyi]);
history[historyi] = sdup(buf);
@ -246,8 +245,8 @@ static void historymove(int delta) {
if (historyi < 0) {
historyi = 0;
return;
} else if (historyi >= dst_v_count(history)) {
historyi = dst_v_count(history) - 1;
} else if (historyi >= history_count) {
historyi = history_count - 1;
return;
}
strncpy(buf, history[historyi], DST_LINE_MAX);
@ -262,9 +261,9 @@ static void addhistory() {
int i, len;
char *newline = sdup(buf);
if (!newline) return;
len = dst_v_count(history);
len = history_count;
if (len < DST_HISTORY_MAX) {
dst_v_push(history, newline);
history[history_count++] = newline;
len++;
} else {
free(history[DST_HISTORY_MAX - 1]);
@ -429,9 +428,8 @@ void dst_line_init() {
void dst_line_deinit() {
int i;
norawmode();
for (i = 0; i < dst_v_count(history); i++)
for (i = 0; i < history_count; i++)
free(history[i]);
dst_v_free(history);
historyi = 0;
}

View File

@ -21,9 +21,8 @@
*/
#include <dst/dst.h>
#include <dst/dstcompile.h>
#include "clientinit.gen.h"
#include <generated/init.h>
#include "line.h"
int main(int argc, char **argv) {