mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 17:27:18 +00:00
Major refactor and restructure. Add CMake for anticipated windows
support.
This commit is contained in:
parent
acb706ca3a
commit
30f62ca454
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
# Target
|
||||
/client/dst
|
||||
dst
|
||||
build
|
||||
|
||||
# Generated files
|
||||
*.gen.h
|
||||
|
104
CMakeLists.txt
Normal file
104
CMakeLists.txt
Normal file
@ -0,0 +1,104 @@
|
||||
# Copyright (c) 2017 Calvin Rose
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(dst)
|
||||
|
||||
# Set Some Variables
|
||||
set(TARGET_NAME ${PROJECT_NAME})
|
||||
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
set (CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}")
|
||||
endif ()
|
||||
else ()
|
||||
set (CMAKE_C_STANDARD 99)
|
||||
endif ()
|
||||
|
||||
include_directories(src/include)
|
||||
|
||||
set(ASSEMBLER_SOURCES
|
||||
src/assembler/asm.c
|
||||
)
|
||||
|
||||
set(COMPILER_SOURCES
|
||||
src/compiler/compile.c
|
||||
src/compiler/compile_specials.c
|
||||
src/compiler/context.c
|
||||
|
||||
src/compiler/compile.h
|
||||
)
|
||||
|
||||
set(CORE_SOURCES
|
||||
src/core/abstract.c
|
||||
src/core/array.c
|
||||
src/core/buffer.c
|
||||
src/core/fiber.c
|
||||
src/core/gc.c
|
||||
src/core/io.c
|
||||
src/core/math.c
|
||||
src/core/native.c
|
||||
src/core/stl.c
|
||||
src/core/string.c
|
||||
src/core/struct.c
|
||||
src/core/symcache.c
|
||||
src/core/table.c
|
||||
src/core/tuple.c
|
||||
src/core/util.c
|
||||
src/core/value.c
|
||||
src/core/vm.c
|
||||
src/core/wrap.c
|
||||
|
||||
src/core/gc.h
|
||||
src/core/symcache.h
|
||||
src/core/util.h
|
||||
)
|
||||
|
||||
set(MAINCLIENT_SOURCES
|
||||
src/mainclient/main.c
|
||||
)
|
||||
|
||||
set(PARSER_SOURCES
|
||||
src/parser/ast.c
|
||||
src/parser/parse.c
|
||||
src/parser/strtod.c
|
||||
)
|
||||
|
||||
set(TESTLIB_SOURCES
|
||||
src/testlib/testlib.c
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
${ASSEMBLER_SOURCES}
|
||||
${COMPILER_SOURCES}
|
||||
${CORE_SOURCES}
|
||||
${MAINCLIENT_SOURCES}
|
||||
${PARSER_SOURCES}
|
||||
)
|
||||
|
||||
# Build the executable
|
||||
add_executable(${TARGET_NAME} ${SOURCES})
|
||||
target_link_libraries(${TARGET_NAME} m)
|
||||
|
||||
# Build some modules
|
||||
add_library(testlib MODULE ${TESTLIB_SOURCES})
|
||||
|
||||
# TODO dont do this on windows
|
||||
target_link_libraries(${TARGET_NAME} dl)
|
||||
|
53
Makefile
53
Makefile
@ -24,40 +24,41 @@
|
||||
|
||||
PREFIX?=/usr/local
|
||||
BINDIR=$(PREFIX)/bin
|
||||
VERSION=0.0.0-beta
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -I./include -I./libs -g -DDST_VERSION=\"$(VERSION)\"
|
||||
CFLAGS=-std=c99 -Wall -Wextra -I./src/include -g
|
||||
CLIBS=-lm -ldl
|
||||
PREFIX=/usr/local
|
||||
DST_TARGET=dst
|
||||
DEBUGGER=lldb
|
||||
DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h compile.h gc.h util.h)
|
||||
DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dstcontext.h dsttypes.h dststate.h dststl.h)
|
||||
|
||||
DST_C_LIBS=$(addprefix libs/,testlib.so)
|
||||
|
||||
#############################
|
||||
##### Generated headers #####
|
||||
#############################
|
||||
DST_HEADERS=$(sort $(wildcard src/include/dst/*.h))
|
||||
DST_LIBHEADERS=$(sort $(wildcard src/include/headerlibs/*.h))
|
||||
DST_ALL_HEADERS=$(DST_HEADERS) $(DST_LIB_HEADERS)
|
||||
|
||||
DST_ALL_HEADERS=$(DST_HEADERS) $(DST_INTERNAL_HEADERS)
|
||||
DST_ASM_SOURCES=$(sort $(wildcard src/assembler/*.c))
|
||||
DST_COMPILER_SOURCES=$(sort $(wildcard src/compiler/*.c))
|
||||
DST_CONTEXT_SOURCES=$(sort $(wildcard src/context/*.c))
|
||||
DST_CORE_SOURCES=$(sort $(wildcard src/core/*.c))
|
||||
DST_MAINCLIENT_SOURCES=$(sort $(wildcard src/mainclient/*.c))
|
||||
DST_PARSER_SOURCES=$(sort $(wildcard src/parser/*.c))
|
||||
|
||||
all: $(DST_TARGET)
|
||||
|
||||
###################################
|
||||
##### The core vm and runtime #####
|
||||
###################################
|
||||
########################################
|
||||
##### The main interpreter program #####
|
||||
########################################
|
||||
|
||||
DST_CORE_SOURCES=$(addprefix core/,\
|
||||
abstract.c array.c asm.c ast.c buffer.c compile.c compile_specials.c\
|
||||
context.c fiber.c gc.c io.c math.c native.c parse.c string.c\
|
||||
stl.c strtod.c struct.c symcache.c table.c tuple.c util.c\
|
||||
value.c vm.c wrap.c)
|
||||
DST_ALL_SOURCES=$(DST_ASM_SOURCES) \
|
||||
$(DST_COMPILER_SOURCES) \
|
||||
$(DST_CONTEXT_SOURCES) \
|
||||
$(DST_CORE_SOURCES) \
|
||||
$(DST_MAINCLIENT_SOURCES) \
|
||||
$(DST_PARSER_SOURCES)
|
||||
|
||||
DST_CLIENT_SOURCES=$(addprefix client/,\
|
||||
main.c)
|
||||
|
||||
$(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $(DST_TARGET) $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(CLIBS)
|
||||
$(DST_TARGET): $(DST_ALL_SOURCES) $(DST_ALL_HEADERS)
|
||||
$(CC) $(CFLAGS) -o $(DST_TARGET) $(DST_ALL_SOURCES) $(CLIBS)
|
||||
|
||||
#######################
|
||||
##### C Libraries #####
|
||||
@ -66,7 +67,6 @@ $(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS)
|
||||
%.so: %.c $(DST_HEADERS)
|
||||
$(CC) $(CFLAGS) -DDST_LIB -shared -undefined dynamic_lookup -o $@ $<
|
||||
|
||||
|
||||
###################
|
||||
##### Testing #####
|
||||
###################
|
||||
@ -81,7 +81,7 @@ valgrind: $(DST_TARGET)
|
||||
@ valgrind --leak-check=full -v ./$(DST_TARGET)
|
||||
|
||||
test: $(DST_TARGET)
|
||||
@ ./$(DST_TARGET) --gcinterval=0x10000 dsttest/suite0.dst
|
||||
@ ./$(DST_TARGET) --gcinterval=0x10000 test/suite0.dst
|
||||
|
||||
valtest: $(DST_TARGET)
|
||||
valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst
|
||||
@ -92,13 +92,8 @@ valtest: $(DST_TARGET)
|
||||
|
||||
clean:
|
||||
rm $(DST_TARGET) || true
|
||||
rm *.o || true
|
||||
rm client/*.o || true
|
||||
rm core/*.o || true
|
||||
rm $(DST_LANG_HEADERS) || true
|
||||
rm src/**/*.o || true
|
||||
rm vgcore.* || true
|
||||
rm unittests/*.out || true
|
||||
rm $(DST_XXD) || true
|
||||
|
||||
install: $(DST_TARGET)
|
||||
cp $(DST_TARGET) $(BINDIR)/dst
|
||||
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_OPCODES_H_defined
|
||||
#define DST_OPCODES_H_defined
|
||||
|
||||
typedef enum DstOpCode DstOpCode;
|
||||
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_LESS_THAN,
|
||||
DOP_EQUALS,
|
||||
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_TRANSFER,
|
||||
DOP_GET,
|
||||
DOP_PUT,
|
||||
DOP_GET_INDEX,
|
||||
DOP_PUT_INDEX,
|
||||
DOP_LENGTH
|
||||
};
|
||||
|
||||
#endif
|
@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_H_defined
|
||||
#define DST_H_defined
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "dstconfig.h"
|
||||
#include "dsttypes.h"
|
||||
#include "dststate.h"
|
||||
|
||||
/* Array functions */
|
||||
DstArray *dst_array(int32_t capacity);
|
||||
DstArray *dst_array_init(DstArray *array, int32_t capacity);
|
||||
void dst_array_deinit(DstArray *array);
|
||||
void dst_array_ensure(DstArray *array, int32_t capacity);
|
||||
void dst_array_setcount(DstArray *array, int32_t count);
|
||||
void dst_array_push(DstArray *array, Dst x);
|
||||
Dst dst_array_pop(DstArray *array);
|
||||
Dst dst_array_peek(DstArray *array);
|
||||
|
||||
/* Buffer functions */
|
||||
DstBuffer *dst_buffer(int32_t capacity);
|
||||
DstBuffer *dst_buffer_init(DstBuffer *buffer, int32_t capacity);
|
||||
void dst_buffer_deinit(DstBuffer *buffer);
|
||||
void dst_buffer_ensure(DstBuffer *buffer, int32_t capacity);
|
||||
int dst_buffer_extra(DstBuffer *buffer, int32_t n);
|
||||
int dst_buffer_push_bytes(DstBuffer *buffer, const uint8_t *string, int32_t len);
|
||||
int dst_buffer_push_cstring(DstBuffer *buffer, const char *cstring);
|
||||
int dst_buffer_push_u8(DstBuffer *buffer, uint8_t x);
|
||||
int dst_buffer_push_u16(DstBuffer *buffer, uint16_t x);
|
||||
int dst_buffer_push_u32(DstBuffer *buffer, uint32_t x);
|
||||
int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x);
|
||||
|
||||
/* Tuple */
|
||||
#define dst_tuple_raw(t) ((int32_t *)(t) - 2)
|
||||
#define dst_tuple_length(t) (dst_tuple_raw(t)[0])
|
||||
#define dst_tuple_hash(t) ((dst_tuple_raw(t)[1]))
|
||||
Dst *dst_tuple_begin(int32_t length);
|
||||
const Dst *dst_tuple_end(Dst *tuple);
|
||||
const Dst *dst_tuple_n(Dst *values, int32_t n);
|
||||
int dst_tuple_equal(const Dst *lhs, const Dst *rhs);
|
||||
int dst_tuple_compare(const Dst *lhs, const Dst *rhs);
|
||||
|
||||
/* String/Symbol functions */
|
||||
#define dst_string_raw(s) ((int32_t *)(s) - 2)
|
||||
#define dst_string_length(s) (dst_string_raw(s)[0])
|
||||
#define dst_string_hash(s) ((dst_string_raw(s)[1]))
|
||||
uint8_t *dst_string_begin(int32_t length);
|
||||
const uint8_t *dst_string_end(uint8_t *str);
|
||||
const uint8_t *dst_string(const uint8_t *buf, int32_t len);
|
||||
const uint8_t *dst_cstring(const char *cstring);
|
||||
int dst_string_compare(const uint8_t *lhs, const uint8_t *rhs);
|
||||
int dst_string_equal(const uint8_t *lhs, const uint8_t *rhs);
|
||||
int dst_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen, int32_t rhash);
|
||||
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_short_description(Dst x);
|
||||
const uint8_t *dst_to_string(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)))
|
||||
const uint8_t *dst_formatc(const char *format, ...);
|
||||
void dst_puts(const uint8_t *str);
|
||||
|
||||
/* Symbol functions */
|
||||
const uint8_t *dst_symbol(const uint8_t *str, int32_t len);
|
||||
const uint8_t *dst_symbol_from_string(const uint8_t *str);
|
||||
const uint8_t *dst_csymbol(const char *str);
|
||||
const uint8_t *dst_symbol_gen(const uint8_t *buf, int32_t len);
|
||||
#define dst_symbolv(str, len) dst_wrap_symbol(dst_symbol((str), (len)))
|
||||
#define dst_csymbolv(cstr) dst_wrap_symbol(dst_csymbol(cstr))
|
||||
|
||||
/* Structs */
|
||||
#define dst_struct_raw(t) ((int32_t *)(t) - 4)
|
||||
#define dst_struct_length(t) (dst_struct_raw(t)[0])
|
||||
#define dst_struct_capacity(t) (dst_struct_raw(t)[1])
|
||||
#define dst_struct_hash(t) (dst_struct_raw(t)[2])
|
||||
/* Do something with the 4th header slot - flags? */
|
||||
DstKV *dst_struct_begin(int32_t count);
|
||||
void dst_struct_put(DstKV *st, Dst key, Dst value);
|
||||
const DstKV *dst_struct_end(DstKV *st);
|
||||
Dst dst_struct_get(const DstKV *st, Dst key);
|
||||
const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv);
|
||||
DstTable *dst_struct_to_table(const DstKV *st);
|
||||
int dst_struct_equal(const DstKV *lhs, const DstKV *rhs);
|
||||
int dst_struct_compare(const DstKV *lhs, const DstKV *rhs);
|
||||
const DstKV *dst_struct_find(const DstKV *st, Dst key);
|
||||
|
||||
/* Table functions */
|
||||
DstTable *dst_table(int32_t capacity);
|
||||
DstTable *dst_table_init(DstTable *table, int32_t capacity);
|
||||
void dst_table_deinit(DstTable *table);
|
||||
Dst dst_table_get(DstTable *t, Dst key);
|
||||
Dst dst_table_remove(DstTable *t, Dst key);
|
||||
void dst_table_put(DstTable *t, Dst key, Dst value);
|
||||
const DstKV *dst_table_next(DstTable *t, const DstKV *kv);
|
||||
const DstKV *dst_table_to_struct(DstTable *t);
|
||||
void dst_table_merge_table(DstTable *table, DstTable *other);
|
||||
void dst_table_merge_struct(DstTable *table, const DstKV *other);
|
||||
DstKV *dst_table_find(DstTable *t, Dst key);
|
||||
|
||||
/* Fiber */
|
||||
DstFiber *dst_fiber(int32_t capacity);
|
||||
#define dst_stack_frame(s) ((DstStackFrame *)((s) - DST_FRAME_SIZE))
|
||||
#define dst_fiber_frame(f) dst_stack_frame((f)->data + (f)->frame)
|
||||
DstFiber *dst_fiber_reset(DstFiber *fiber);
|
||||
void dst_fiber_setcapacity(DstFiber *fiber, int32_t n);
|
||||
void dst_fiber_push(DstFiber *fiber, Dst x);
|
||||
void dst_fiber_push2(DstFiber *fiber, Dst x, Dst y);
|
||||
void dst_fiber_push3(DstFiber *fiber, Dst x, Dst y, Dst z);
|
||||
void dst_fiber_pushn(DstFiber *fiber, const Dst *arr, int32_t n);
|
||||
void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func);
|
||||
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func);
|
||||
void dst_fiber_cframe(DstFiber *fiber);
|
||||
void dst_fiber_popframe(DstFiber *fiber);
|
||||
|
||||
/* Treat similar types through uniform interfaces for iteration */
|
||||
int dst_seq_view(Dst seq, const Dst **data, int32_t *len);
|
||||
int dst_chararray_view(Dst str, const uint8_t **data, int32_t *len);
|
||||
int dst_hashtable_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap);
|
||||
|
||||
/* Abstract */
|
||||
#define dst_abstract_header(u) ((DstAbstractHeader *)(u) - 1)
|
||||
#define dst_abstract_type(u) (dst_abstract_header(u)->type)
|
||||
#define dst_abstract_size(u) (dst_abstract_header(u)->size)
|
||||
void *dst_abstract(const DstAbstractType *type, size_t size);
|
||||
|
||||
/* Value functions */
|
||||
int dst_equals(Dst x, Dst y);
|
||||
int32_t dst_hash(Dst x);
|
||||
int dst_compare(Dst x, Dst y);
|
||||
|
||||
/* GC */
|
||||
void dst_mark(Dst x);
|
||||
void dst_sweep();
|
||||
void dst_collect();
|
||||
void dst_clear_memory();
|
||||
void dst_gcroot(Dst root);
|
||||
int dst_gcunroot(Dst root);
|
||||
int dst_gcunrootall(Dst root);
|
||||
#define dst_maybe_collect() do {\
|
||||
if (dst_vm_next_collection >= dst_vm_gc_interval) dst_collect(); } while (0)
|
||||
|
||||
/* Data structure functions */
|
||||
Dst dst_get(Dst ds, Dst key);
|
||||
void dst_put(Dst ds, Dst key, Dst value);
|
||||
const DstKV *dst_next(Dst ds, const DstKV *kv);
|
||||
int32_t dst_length(Dst x);
|
||||
int32_t dst_capacity(Dst x);
|
||||
Dst dst_getindex(Dst ds, int32_t index);
|
||||
void dst_setindex(Dst ds, Dst value, int32_t index);
|
||||
|
||||
/* AST */
|
||||
Dst dst_ast_wrap(Dst x, int32_t start, int32_t end);
|
||||
DstAst *dst_ast_node(Dst x);
|
||||
Dst dst_ast_unwrap1(Dst x);
|
||||
Dst dst_ast_unwrap(Dst x);
|
||||
|
||||
/* Native */
|
||||
DstCFunction dst_native(const char *name, const uint8_t **error);
|
||||
int dst_load_native(DstArgs args);
|
||||
|
||||
/* VM functions */
|
||||
int dst_init();
|
||||
void dst_deinit();
|
||||
int dst_run(Dst callee, Dst *returnreg);
|
||||
|
||||
/* 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);
|
||||
double dst_scan_real(const uint8_t *str, int32_t len, int *err);
|
||||
|
||||
/* Module helpers */
|
||||
void dst_env_def(DstTable *env, const char *name, Dst val);
|
||||
void dst_env_var(DstTable *env, const char *name, Dst val);
|
||||
Dst dst_env_resolve(DstTable *env, const char *name);
|
||||
DstTable *dst_env_arg(DstArgs args);
|
||||
|
||||
/* C Function helpers */
|
||||
#define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1)
|
||||
#define dst_throwv(a, v) (*((a).ret) = (v), 1)
|
||||
#define dst_return(a, v) (*((a).ret) = (v), 0)
|
||||
|
||||
/* Parsing */
|
||||
typedef enum DstParserStatus DstParserStatus;
|
||||
typedef struct DstParseState DstParseState;
|
||||
typedef struct DstParser DstParser;
|
||||
enum DstParserStatus {
|
||||
DST_PARSE_ROOT,
|
||||
DST_PARSE_ERROR,
|
||||
DST_PARSE_FULL,
|
||||
DST_PARSE_PENDING
|
||||
};
|
||||
struct DstParser {
|
||||
Dst* argstack;
|
||||
DstParseState *states;
|
||||
uint8_t *buf;
|
||||
const char *error;
|
||||
size_t index;
|
||||
int lookback;
|
||||
int flags;
|
||||
};
|
||||
#define DST_PARSEFLAG_SOURCEMAP 1
|
||||
void dst_parser_init(DstParser *parser, int flags);
|
||||
void dst_parser_deinit(DstParser *parser);
|
||||
int dst_parser_consume(DstParser *parser, uint8_t c);
|
||||
DstParserStatus dst_parser_status(DstParser *parser);
|
||||
Dst dst_parser_produce(DstParser *parser);
|
||||
const char *dst_parser_error(DstParser *parser);
|
||||
int dst_parse_cfun(DstArgs args);
|
||||
|
||||
/* Compile */
|
||||
typedef enum DstCompileStatus DstCompileStatus;
|
||||
typedef struct DstCompileOptions DstCompileOptions;
|
||||
typedef struct DstCompileResult DstCompileResult;
|
||||
enum DstCompileStatus {
|
||||
DST_COMPILE_OK,
|
||||
DST_COMPILE_ERROR
|
||||
};
|
||||
struct DstCompileResult {
|
||||
DstCompileStatus status;
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
int32_t error_start;
|
||||
int32_t error_end;
|
||||
};
|
||||
DstCompileResult dst_compile(Dst source, DstTable *env, int flags);
|
||||
DstFunction *dst_compile_func(DstCompileResult result);
|
||||
int dst_compile_cfun(DstArgs args);
|
||||
|
||||
/* Assembly */
|
||||
typedef enum DstAssembleStatus DstAssembleStatus;
|
||||
typedef struct DstAssembleResult DstAssembleResult;
|
||||
typedef struct DstAssembleOptions DstAssembleOptions;
|
||||
enum DstAssembleStatus {
|
||||
DST_ASSEMBLE_OK,
|
||||
DST_ASSEMBLE_ERROR
|
||||
};
|
||||
struct DstAssembleResult {
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
DstAssembleStatus status;
|
||||
};
|
||||
DstAssembleResult dst_asm(Dst source, int flags);
|
||||
DstFunction *dst_asm_func(DstAssembleResult result);
|
||||
Dst dst_disasm(DstFuncDef *def);
|
||||
Dst dst_asm_decode_instruction(uint32_t instr);
|
||||
int dst_asm_cfun(DstArgs args);
|
||||
int dst_disasm_cfun(DstArgs args);
|
||||
|
||||
/* STL */
|
||||
DstTable *dst_stl_env();
|
||||
int dst_lib_io(DstArgs args);
|
||||
int dst_lib_math(DstArgs args);
|
||||
int dst_lib_array(DstArgs args);
|
||||
int dst_lib_buffer(DstArgs args);
|
||||
int dst_lib_parse(DstArgs args);
|
||||
|
||||
#endif /* DST_H_defined */
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_CONFIG_H_defined
|
||||
#define DST_CONFIG_H_defined
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* 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
|
||||
#endif
|
||||
|
||||
/* Check Windows */
|
||||
#if 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(__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
|
||||
|
||||
/* 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
|
||||
|
||||
#ifndef DST_NOASSERT
|
||||
#define dst_assert(c, m) do { \
|
||||
if (!(c)) dst_exit((m)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* What to do when out of memory */
|
||||
#ifndef DST_OUT_OF_MEMORY
|
||||
#include <stdio.h>
|
||||
#define DST_OUT_OF_MEMORY do { printf("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 1000
|
||||
|
||||
/* 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
|
||||
|
||||
#endif /* DST_CONFIG_H_defined */
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_MATH_H_defined
|
||||
#define DST_MATH_H_defined
|
||||
|
||||
#include "dsttypes.h"
|
||||
|
||||
/* Basic C Functions. These are good
|
||||
* candidates for optimizations like bytecode
|
||||
* inlining and costant folding */
|
||||
int dst_int(DstArgs args);
|
||||
int dst_real(DstArgs args);
|
||||
int dst_add(DstArgs args);
|
||||
int dst_subtract(DstArgs args);
|
||||
int dst_multiply(DstArgs args);
|
||||
int dst_divide(DstArgs args);
|
||||
int dst_modulo(DstArgs args);
|
||||
int dst_band(DstArgs args);
|
||||
int dst_bor(DstArgs args);
|
||||
int dst_bxor(DstArgs args);
|
||||
int dst_lshift(DstArgs arsg);
|
||||
int dst_rshift(DstArgs args);
|
||||
int dst_lshiftu(DstArgs args);
|
||||
|
||||
/* Native type constructors */
|
||||
int dst_cfun_table(DstArgs args);
|
||||
int dst_cfun_array(DstArgs args);
|
||||
int dst_cfun_struct(DstArgs args);
|
||||
int dst_cfun_tuple(DstArgs args);
|
||||
|
||||
/* Initialize builtin libraries */
|
||||
int dst_io_init(DstArgs args);
|
||||
int dst_cmath_init(DstArgs args);
|
||||
|
||||
#endif /* DST_MATH_H_defined */
|
@ -1,427 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_TYPES_H_defined
|
||||
#define DST_TYPES_H_defined
|
||||
|
||||
#include "dstconfig.h"
|
||||
|
||||
#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 DstAst DstAst;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
void *pointer;
|
||||
const void *cpointer;
|
||||
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 0xFFFF800000000000lu
|
||||
#define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFlu
|
||||
|
||||
|
||||
#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 0xFFFF000000000000lu
|
||||
#define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFlu
|
||||
|
||||
#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 0xFFFFFFFFlu
|
||||
#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();
|
||||
Dst dst_wrap_real(double x);
|
||||
Dst dst_wrap_integer(int32_t x);
|
||||
Dst dst_wrap_true();
|
||||
Dst dst_wrap_false();
|
||||
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;
|
||||
};
|
||||
|
||||
/* A lightweight green thread in dst. Does not correspond to
|
||||
* operating system threads. */
|
||||
struct DstFiber {
|
||||
Dst *data;
|
||||
DstFiber *parent;
|
||||
int32_t frame; /* Index of the stack frame */
|
||||
int32_t stackstart; /* Beginning of next args */
|
||||
int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */
|
||||
int32_t capacity;
|
||||
enum {
|
||||
DST_FIBER_PENDING,
|
||||
DST_FIBER_NEW,
|
||||
DST_FIBER_ALIVE,
|
||||
DST_FIBER_DEAD,
|
||||
DST_FIBER_ERROR
|
||||
} status;
|
||||
};
|
||||
|
||||
/* A stack frame on the fiber. Is stored along with the stack values. */
|
||||
struct DstStackFrame {
|
||||
DstFunction *func;
|
||||
uint32_t *pc;
|
||||
int32_t prevframe;
|
||||
};
|
||||
|
||||
/* Number of 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;
|
||||
int32_t count;
|
||||
int32_t capacity;
|
||||
int32_t deleted;
|
||||
};
|
||||
|
||||
/* A key value pair in a struct or table */
|
||||
struct DstKV {
|
||||
Dst key;
|
||||
Dst value;
|
||||
};
|
||||
|
||||
/* Some function defintion flags */
|
||||
#define DST_FUNCDEF_FLAG_VARARG 1
|
||||
#define DST_FUNCDEF_FLAG_NEEDSENV 4
|
||||
|
||||
/* 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 */
|
||||
int32_t *sourcemap;
|
||||
const uint8_t *source;
|
||||
const uint8_t *sourcepath;
|
||||
|
||||
uint32_t flags;
|
||||
int32_t slotcount; /* The amount of stack space required for the function */
|
||||
int32_t arity; /* Not including varargs */
|
||||
int32_t constants_length;
|
||||
int32_t bytecode_length;
|
||||
int32_t environments_length;
|
||||
int32_t defs_length;
|
||||
};
|
||||
|
||||
/* A fuction environment */
|
||||
struct DstFuncEnv {
|
||||
union {
|
||||
DstFiber *fiber;
|
||||
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;
|
||||
/* Consider allocating envs with entire function struct */
|
||||
DstFuncEnv **envs;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Compile structs */
|
||||
|
||||
/* ASTs are simple wrappers around values. They contain information about sourcemapping
|
||||
* and other meta data. Possibly types? They are used mainly during compilation and parsing */
|
||||
struct DstAst {
|
||||
Dst value;
|
||||
int32_t source_start;
|
||||
int32_t source_end;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#endif /* DST_TYPES_H_defined */
|
@ -1,20 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
|
||||
|
||||
int main() {
|
||||
int32_t i;
|
||||
dst_init();
|
||||
DstArray *array = dst_array(10);
|
||||
assert(array->capacity == 10);
|
||||
assert(array->count == 0);
|
||||
for (i = 0; i < 500; ++i)
|
||||
dst_array_push(array, dst_wrap_integer(i));
|
||||
for (i = 0; i < 500; ++i)
|
||||
assert(dst_checktype(array->data[i], DST_INTEGER) &&
|
||||
dst_unwrap_integer(array->data[i]) == i);
|
||||
for (i = 0; i < 200; ++i)
|
||||
dst_array_pop(array);
|
||||
assert(array->count == 300);
|
||||
return 0;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
|
||||
int main() {
|
||||
DstParseResult pres;
|
||||
DstAssembleOptions opts;
|
||||
DstAssembleResult ares;
|
||||
DstFunction *func;
|
||||
|
||||
FILE *f = fopen("./dsttest/minimal.dsts", "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||
|
||||
char *string = malloc(fsize + 1);
|
||||
fread(string, fsize, 1, f);
|
||||
fclose(f);
|
||||
|
||||
string[fsize] = 0;
|
||||
|
||||
dst_init();
|
||||
|
||||
pres = dst_parsec(string);
|
||||
free(string);
|
||||
|
||||
if (pres.status == DST_PARSE_ERROR) {
|
||||
dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error));
|
||||
return 1;
|
||||
}
|
||||
assert(pres.status == DST_PARSE_OK);
|
||||
dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value));
|
||||
|
||||
opts.flags = 0;
|
||||
opts.source = pres.value;
|
||||
opts.sourcemap = pres.map;
|
||||
|
||||
ares = dst_asm(opts);
|
||||
if (ares.status == DST_ASSEMBLE_ERROR) {
|
||||
dst_puts(dst_formatc("assembly error: %S\n", ares.error));
|
||||
dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end));
|
||||
return 1;
|
||||
}
|
||||
assert(ares.status == DST_ASSEMBLE_OK);
|
||||
|
||||
func = dst_asm_func(ares);
|
||||
|
||||
dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(ares.funcdef)));
|
||||
|
||||
dst_run(dst_wrap_function(func));
|
||||
dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret));
|
||||
|
||||
dst_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
|
||||
# This file is executed without any macro expansion (macros are not
|
||||
# yet defined). Cannot use macros or anything outside the stl.
|
||||
|
||||
# Helper for macro expansion
|
||||
(def macroexpander (fn [x env f]
|
||||
(if (= (type x) :tuple)
|
||||
(if (> (length x) 0)
|
||||
(do
|
||||
(def first (get x 0))
|
||||
(def macros (get env :macros))
|
||||
(if macros
|
||||
(do
|
||||
(def macro (get macros first))
|
||||
(if macro
|
||||
(f (apply macro (slice x 1)))
|
||||
x))
|
||||
x)
|
||||
x)
|
||||
x)
|
||||
x)))
|
||||
|
||||
# Macro expansion
|
||||
(def macroexpand (fn [x env]
|
||||
(macroexpander x (if env env (getenv)) macroexpander)))
|
||||
|
||||
# Function to create macros
|
||||
(def global-macro (fn [name f]
|
||||
(def env (getenv))
|
||||
(def env-macros (get env :macros))
|
||||
(def macros (if env-macros env-macros {}))
|
||||
(set! env :macros macros)
|
||||
(set! macros (symbol name) f)
|
||||
f))
|
||||
|
||||
# Make defn
|
||||
(global-macro "defn" (fn [name &]
|
||||
(tuple 'def name (apply tuple 'fn &))))
|
||||
|
||||
# Make defmacro
|
||||
(global-macro "defmacro" (fn [name &]
|
||||
(tuple global-macro (string name) (apply tuple 'fn &))))
|
||||
|
||||
# Comment returns nil
|
||||
(global-macro "comment" (fn [] nil))
|
||||
|
||||
# The source file to read from
|
||||
(var *sourcefile* stdin)
|
||||
|
||||
# The *read* macro gets the next form from the source file, and
|
||||
# returns it. It is a var and therefor can be overwritten.
|
||||
(var *read* (fn []
|
||||
(def b (buffer))
|
||||
(def p (parser))
|
||||
(while (not (parse-hasvalue p))
|
||||
(read *sourcefile* 1 b)
|
||||
(if (= (length b) 0)
|
||||
(error "parse error: unexpected end of source"))
|
||||
(parse-charseq p b)
|
||||
(if (= (parse-status p) :error)
|
||||
(error (string "parse error: " (parse-consume p))))
|
||||
(clear b))
|
||||
(parse-consume p)))
|
||||
|
||||
# Evaluates a form by macro-expanding it, compiling it, and
|
||||
# then executing it.
|
||||
(def eval (fn [x]
|
||||
(def func (compile (macroexpand x)))
|
||||
(if (= :function (type func))
|
||||
(func)
|
||||
(error (string "compiler error: " func)))))
|
||||
|
||||
# A simple repl for testing.
|
||||
(while true
|
||||
(def t (thread (fn []
|
||||
(while true
|
||||
(print (eval (*read*)))))))
|
||||
(print (tran t)))
|
@ -1,20 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
|
||||
int main() {
|
||||
dst_init();
|
||||
DstBuffer *buffer = dst_buffer(100);
|
||||
assert(buffer->count == 0);
|
||||
assert(buffer->capacity == 100);
|
||||
dst_buffer_push_u8(buffer, 'h');
|
||||
dst_buffer_push_u8(buffer, 'e');
|
||||
dst_buffer_push_u8(buffer, 'l');
|
||||
dst_buffer_push_u8(buffer, 'l');
|
||||
dst_buffer_push_u8(buffer, 'o');
|
||||
dst_buffer_push_cstring(buffer, " world!");
|
||||
assert(dst_equals(
|
||||
dst_wrap_string(dst_cstring("hello world!")),
|
||||
dst_wrap_string(dst_string(buffer->data, buffer->count))
|
||||
));
|
||||
return 0;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dst/dst.h>
|
||||
#include "bootstrap.h"
|
||||
|
||||
void teststr(Dst *vm, const char *src) {
|
||||
uint32_t len = 0;
|
||||
const uint8_t *bytes;
|
||||
const char *ns = NULL;
|
||||
int status = dst_parsec(vm, src, &ns);
|
||||
if (status) {
|
||||
printf("Parse failed: ");
|
||||
bytes = dst_bytes(vm, -1, &len);
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
putc(bytes[i], stdout);
|
||||
putc('\n', stdout);
|
||||
printf("%s\n", src);
|
||||
for (const char *scan = src + 1; scan < ns; ++scan)
|
||||
putc(' ', stdout);
|
||||
putc('^', stdout);
|
||||
putc('\n', stdout);
|
||||
return;
|
||||
}
|
||||
dst_description(vm);
|
||||
bytes = dst_bytes(vm, -1, &len);
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
putc(bytes[i], stdout);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
Dst *vm = dst_init();
|
||||
|
||||
teststr(vm, "[+ 1 2 3 \"porkpie\" ]");
|
||||
teststr(vm, "(+ 1 2 \t asdajs 1035.89 3)");
|
||||
teststr(vm, "[+ 1 2 :bokr]");
|
||||
teststr(vm, "{+ 1 2 3}");
|
||||
|
||||
dst_deinit(vm);
|
||||
|
||||
return 0;
|
||||
}
|
1343
junkyard/compile.c
1343
junkyard/compile.c
File diff suppressed because it is too large
Load Diff
@ -1,77 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
|
||||
int testprint(DstValue *argv, int32_t argn) {
|
||||
int32_t i;
|
||||
for (i = 0; i < argn; i++) {
|
||||
dst_puts(dst_formatc("%v\n", argv[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DstReg testreg[] = {
|
||||
{"print", testprint},
|
||||
{"+", dst_add},
|
||||
{"-", dst_subtract},
|
||||
{"*", dst_multiply},
|
||||
{"/", dst_divide},
|
||||
{"%", dst_modulo},
|
||||
{"acos", dst_acos},
|
||||
{"asin", dst_asin}
|
||||
};
|
||||
|
||||
int main() {
|
||||
DstParseResult pres;
|
||||
DstCompileOptions opts;
|
||||
DstCompileResult cres;
|
||||
DstFunction *func;
|
||||
|
||||
FILE *f = fopen("./dsttest/basic.dst", "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||
|
||||
char *string = malloc(fsize + 1);
|
||||
fread(string, fsize, 1, f);
|
||||
fclose(f);
|
||||
|
||||
string[fsize] = 0;
|
||||
|
||||
dst_init();
|
||||
|
||||
pres = dst_parsec(string);
|
||||
free(string);
|
||||
|
||||
if (pres.status == DST_PARSE_ERROR) {
|
||||
dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error));
|
||||
return 1;
|
||||
}
|
||||
assert(pres.status == DST_PARSE_OK);
|
||||
dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value));
|
||||
|
||||
opts.flags = 0;
|
||||
opts.source = pres.value;
|
||||
opts.sourcemap = pres.map;
|
||||
opts.env = dst_loadreg(testreg, sizeof(testreg)/sizeof(DstReg));
|
||||
dst_puts(dst_formatc("initial compile env: %v\n", opts.env));
|
||||
|
||||
cres = dst_compile(opts);
|
||||
if (cres.status == DST_COMPILE_ERROR) {
|
||||
dst_puts(dst_formatc("compilation error: %S\n", cres.error));
|
||||
dst_puts(dst_formatc("error location: %d, %d\n", cres.error_start, cres.error_end));
|
||||
return 1;
|
||||
}
|
||||
assert(cres.status == DST_COMPILE_OK);
|
||||
|
||||
dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(cres.funcdef)));
|
||||
|
||||
func = dst_compile_func(cres);
|
||||
|
||||
dst_run(dst_wrap_function(func));
|
||||
dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret));
|
||||
|
||||
dst_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include "../core/gc.h"
|
||||
#include <dst/dst.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Create dud funcdef and function */
|
||||
static DstFunction *dud_func(uint32_t slotcount, uint32_t arity, int varargs) {
|
||||
DstFuncDef *def = dst_gcalloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||
def->environments_length = 0;
|
||||
def->constants_length = 0;
|
||||
def->bytecode_length = 0;
|
||||
def->environments = NULL;
|
||||
def->constants = NULL;
|
||||
def->bytecode = NULL;
|
||||
def->flags = varargs ? DST_FUNCDEF_FLAG_VARARG : 0;
|
||||
def->arity = arity;
|
||||
def->slotcount = slotcount;
|
||||
DstFunction *f = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||
f->envs = NULL;
|
||||
f->def = def;
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Print debug information for a fiber */
|
||||
static void debug_print_fiber(DstFiber *fiber, int showslots) {
|
||||
uint32_t frameindex = fiber->frame;
|
||||
uint32_t frametopindex = fiber->frametop;
|
||||
const char *statusname =
|
||||
fiber->status == DST_FIBER_ALIVE ? "alive" :
|
||||
fiber->status == DST_FIBER_PENDING ? "pending" :
|
||||
fiber->status == DST_FIBER_ERROR ? "error" :
|
||||
"dead";
|
||||
|
||||
printf("fiber at %p\n", fiber);
|
||||
printf(" frame = %d\n", fiber->frame);
|
||||
printf(" frametop = %d\n", fiber->frametop);
|
||||
printf(" stacktop = %d\n", fiber->stacktop);
|
||||
printf(" capacity = %d\n", fiber->capacity);
|
||||
printf(" status = %s\n -----\n", statusname);
|
||||
|
||||
while (frameindex > 0) {
|
||||
DstValue *stack = fiber->data + frameindex;
|
||||
DstStackFrame *frame = dst_stack_frame(stack);
|
||||
uint32_t slots = frametopindex - frameindex;
|
||||
const uint8_t *str;
|
||||
/* Print the stack frame */
|
||||
if (frame->func != NULL)
|
||||
str = dst_to_string(dst_wrap_function(frame->func));
|
||||
else
|
||||
str = dst_cstring("<anonymous>");
|
||||
printf(" at %.*s (slots: %d)\n",
|
||||
dst_string_length(str),
|
||||
(const char *)str,
|
||||
slots);
|
||||
/* Optionally print all values in the stack */
|
||||
if (showslots) {
|
||||
for (uint32_t j = 0; j < slots; j++) {
|
||||
const uint8_t *vstr = dst_to_string(stack[j]);
|
||||
printf(" [%d]: %.*s\n",
|
||||
j,
|
||||
dst_string_length(vstr),
|
||||
(const char *)vstr);
|
||||
}
|
||||
}
|
||||
frametopindex = frameindex - DST_FRAME_SIZE;
|
||||
frameindex = frame->prevframe;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
dst_init();
|
||||
|
||||
DstFunction *f1 = dud_func(5, 0, 1);
|
||||
DstFiber *fiber1 = dst_fiber(10);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
dst_fiber_funcframe(fiber1, f1);
|
||||
}
|
||||
for (int i = 0; i < 13; i++) {
|
||||
dst_fiber_push(fiber1, dst_wrap_integer(i));
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
dst_fiber_popvalue(fiber1);
|
||||
}
|
||||
dst_fiber_funcframe_tail(fiber1, dud_func(20, 0, 0));
|
||||
debug_print_fiber(fiber1, 1);
|
||||
|
||||
//dst_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,265 +0,0 @@
|
||||
#include <dst/dst.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include "unit.h"
|
||||
|
||||
/* Required interface for DstValue */
|
||||
/* wrap and unwrap for all types */
|
||||
/* Get type quickly */
|
||||
/* Check against type quickly */
|
||||
/* Small footprint */
|
||||
/* 64 bit integer support undecided */
|
||||
|
||||
/* 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_isnan(x) - check if value is nan
|
||||
*/
|
||||
|
||||
typedef union dst_t dst_t;
|
||||
union dst_t {
|
||||
uint64_t u64;
|
||||
int64_t i64;
|
||||
void *pointer;
|
||||
double real;
|
||||
};
|
||||
|
||||
/* dst_t */
|
||||
|
||||
/* 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), or when generating Signaling NaNs. */
|
||||
|
||||
/* |.......Tag.......|.......................Payload..................| */
|
||||
/* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
/* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */
|
||||
|
||||
/* Other possible representations: */
|
||||
|
||||
/* Common Style */
|
||||
/* Non-double: 1|11111111111|tttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
|
||||
/* LuaJIT style */
|
||||
/* Non-double: 1|11111111111|1ttt|txxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
|
||||
/* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
|
||||
/* A simple scheme for nan boxed values */
|
||||
/* normal doubles, denormalized doubles, and infinities are doubles */
|
||||
/* Quiet nan is nil. Sign bit should be 0. */
|
||||
|
||||
#define DST_NANBOX_TYPEBITS 0x0007000000000000lu
|
||||
#define DST_NANBOX_TAGBITS 0xFFFF000000000000lu
|
||||
|
||||
#ifdef DST_64
|
||||
#define DST_NANBOX_POINTERBITS 0x0000FFFFFFFFFFFFlu
|
||||
#else
|
||||
#define DST_NANBOX_POINTERBITS 0x00000000FFFFFFFFlu
|
||||
#endif
|
||||
|
||||
#define DST_NANBOX_QUIET_BIT 0x0008000000000000lu
|
||||
|
||||
#define dst_nanbox_tag(type) \
|
||||
((((uint64_t)(type) & 0x8) << 12) | 0x7FF8 | (type))
|
||||
|
||||
#define dst_nanbox_checkauxtype(x, type) \
|
||||
(((x).u64 & DST_NANBOX_TAGBITS) == (dst_nanbox_tag((type)) << 48))
|
||||
|
||||
/* Check if number is nan or if number is real double */
|
||||
#define dst_nanbox_isreal(x) \
|
||||
(!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL))
|
||||
|
||||
#define dst_nanbox_tagbits(x) \
|
||||
((x).u64 & 0xFFFF000000000000lu)
|
||||
|
||||
#define dst_nanbox_payloadbits(x) \
|
||||
((x).u64 & 0x0000FFFFFFFFFFFFlu)
|
||||
|
||||
#define dst_nanbox_type(x) \
|
||||
(isnan((x).real) \
|
||||
? (((x).u64 & DST_NANBOX_TYPEBITS) >> 48) | (((x).u64 >> 60) & 0x8) \
|
||||
: DST_REAL)
|
||||
|
||||
#define dst_nanbox_checktype(x, t) \
|
||||
(((t) == DST_REAL) \
|
||||
? dst_nanbox_isreal(x) \
|
||||
: dst_nanbox_checkauxtype((x), (t)))
|
||||
|
||||
static inline void *dst_nanbox_to_pointer(dst_t x) {
|
||||
/* We need to do this shift to keep the higher bits of the pointer
|
||||
* the same as bit 47 as required by the x86 architecture. We may save
|
||||
* an instruction if we do x.u64 & DST_NANBOX_POINTERBITS, but this 0s
|
||||
* th high bits. */
|
||||
x.i64 = (x.i64 << 16) >> 16;
|
||||
return x.pointer;
|
||||
}
|
||||
|
||||
static inline dst_t dst_nanbox_from_pointer(void *p, uint64_t tagmask) {
|
||||
dst_t ret;
|
||||
ret.pointer = p;
|
||||
ret.u64 &= DST_NANBOX_POINTERBITS;
|
||||
ret.u64 |= tagmask;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline dst_t dst_nanbox_from_double(double d) {
|
||||
dst_t ret;
|
||||
ret.real = d;
|
||||
/* Normalize NaNs */
|
||||
if (d != d)
|
||||
ret.u64 = dst_nanbox_tag(DST_REAL) << 48;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline dst_t dst_nanbox_from_bits(uint64_t bits) {
|
||||
dst_t ret;
|
||||
ret.u64 = bits;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define dst_nanbox_truthy(x) \
|
||||
(~(dst_nanbox_checktype((x), DST_NIL) || dst_nanbox_checktype((x), DST_FALSE)))
|
||||
|
||||
#define dst_nanbox_from_payload(t, p) \
|
||||
dst_nanbox_from_bits((dst_nanbox_tag(t) << 48) | (p))
|
||||
|
||||
#define dst_nanbox_wrap_(p, t) \
|
||||
dst_nanbox_from_pointer((p), (dst_nanbox_tag(t) << 48) | 0x7FF8000000000000lu)
|
||||
|
||||
/* Wrap the simple types */
|
||||
#define dst_nanbox_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1)
|
||||
#define dst_nanbox_wrap_true() dst_nanbox_from_payload(DST_TRUE, 1)
|
||||
#define dst_nanbox_wrap_false() dst_nanbox_from_payload(DST_FALSE, 1)
|
||||
#define dst_nanbox_wrap_boolean(b) dst_nanbox_from_payload((b) ? DST_TRUE : DST_FALSE, 1)
|
||||
#define dst_nanbox_wrap_integer(i) dst_nanbox_from_payload(DST_INTEGER, (uint32_t)(i))
|
||||
#define dst_nanbox_wrap_real(r) dst_nanbox_from_double(r)
|
||||
|
||||
#define dst_nanbox_unwrap_boolean(x) \
|
||||
(((x).u64 >> 48) == dst_nanbox_tag(DST_TRUE))
|
||||
|
||||
#define dst_nanbox_unwrap_integer(x) \
|
||||
((int32_t)((x).u64 & 0xFFFFFFFFlu))
|
||||
|
||||
#define dst_nanbox_unwrap_real(x) ((x).real)
|
||||
|
||||
/* Wrap the pointer types */
|
||||
#define dst_nanbox_wrap_struct(s) dst_nanbox_wrap_((s), DST_STRUCT)
|
||||
#define dst_nanbox_wrap_tuple(s) dst_nanbox_wrap_((s), DST_TUPLE)
|
||||
#define dst_nanbox_wrap_fiber(s) dst_nanbox_wrap_((s), DST_FIBER)
|
||||
#define dst_nanbox_wrap_array(s) dst_nanbox_wrap_((s), DST_ARRAY)
|
||||
#define dst_nanbox_wrap_table(s) dst_nanbox_wrap_((s), DST_TABLE)
|
||||
#define dst_nanbox_wrap_buffer(s) dst_nanbox_wrap_((s), DST_BUFFER)
|
||||
#define dst_nanbox_wrap_string(s) dst_nanbox_wrap_((s), DST_STRING)
|
||||
#define dst_nanbox_wrap_symbol(s) dst_nanbox_wrap_((s), DST_SYMBOL)
|
||||
#define dst_nanbox_wrap_userdata(s) dst_nanbox_wrap_((s), DST_USERDATA)
|
||||
#define dst_nanbox_wrap_function(s) dst_nanbox_wrap_((s), DST_FUNCTION)
|
||||
#define dst_nanbox_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION)
|
||||
|
||||
/* Unwrap the pointer types */
|
||||
#define dst_nanbox_unwrap_struct(x) ((const DstValue *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_tuple(x) ((const DstValue *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_table(x) ((DstTable *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_buffer(x) ((DstBuffer *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_string(x) ((const uint8_t *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_symbol(x) ((const uint8_t *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_userdata(x) (dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_function(x) ((DstFunction *)dst_nanbox_to_pointer(x))
|
||||
#define dst_nanbox_unwrap_cfunction(x) ((DstCFunction)dst_nanbox_to_pointer(x))
|
||||
|
||||
void dst_nanbox_print(dst_t x) {
|
||||
printf("hex: 0x%lx, "
|
||||
"description: ", x.u64);
|
||||
switch (dst_nanbox_type(x)) {
|
||||
case DST_NIL:
|
||||
printf("nil\n");
|
||||
break;
|
||||
case DST_TRUE:
|
||||
printf("true\n");
|
||||
break;
|
||||
case DST_FALSE:
|
||||
printf("false\n");
|
||||
break;
|
||||
case DST_INTEGER:
|
||||
printf("%dI\n", dst_nanbox_unwrap_integer(x));
|
||||
break;
|
||||
case DST_STRUCT:
|
||||
printf("<struct %p>\n", dst_nanbox_unwrap_struct(x));
|
||||
break;
|
||||
case DST_TUPLE:
|
||||
printf("<tuple %p>\n", dst_nanbox_unwrap_tuple(x));
|
||||
break;
|
||||
case DST_FIBER:
|
||||
printf("<fiber %p>\n", dst_nanbox_unwrap_fiber(x));
|
||||
break;
|
||||
case DST_ARRAY:
|
||||
printf("<array %p>\n", dst_nanbox_unwrap_array(x));
|
||||
break;
|
||||
case DST_TABLE:
|
||||
printf("<table %p>\n", dst_nanbox_unwrap_table(x));
|
||||
break;
|
||||
case DST_STRING:
|
||||
printf("<string %p>\n", dst_nanbox_unwrap_string(x));
|
||||
break;
|
||||
case DST_SYMBOL:
|
||||
printf("<symbol %p>\n", dst_nanbox_unwrap_symbol(x));
|
||||
break;
|
||||
case DST_USERDATA:
|
||||
printf("<userdata %p>\n", dst_nanbox_unwrap_userdata(x));
|
||||
break;
|
||||
case DST_FUNCTION:
|
||||
printf("<function %p>\n", dst_nanbox_unwrap_function(x));
|
||||
break;
|
||||
case DST_CFUNCTION:
|
||||
printf("<cfunction %p>\n", dst_nanbox_unwrap_cfunction(x));
|
||||
break;
|
||||
case DST_BUFFER:
|
||||
printf("<buffer %p>\n", dst_nanbox_unwrap_buffer(x));
|
||||
break;
|
||||
default:
|
||||
printf("unknown type 0x%lu\n", dst_nanbox_type(x));
|
||||
case DST_REAL:
|
||||
printf("%.21g\n", dst_nanbox_unwrap_real(x));
|
||||
break;
|
||||
}
|
||||
assert(dst_nanbox_checktype(x, dst_nanbox_type(x)));
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("--- nan box test ---\n");
|
||||
printf("sizeof(dst_t) = %lu\n", sizeof(dst_t));
|
||||
|
||||
DstArray array;
|
||||
|
||||
dst_t a = dst_nanbox_wrap_real(0.123);
|
||||
dst_t b = dst_nanbox_wrap_nil();
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(dst_nanbox_unwrap_real(a) + dst_nanbox_unwrap_real(b)));
|
||||
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(0.125));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(19236910.125));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(123120.125));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(0.0));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(1.0/0.0));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(1.0/-0.0));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(0.0/-0.0));
|
||||
dst_nanbox_print(dst_nanbox_wrap_real(0.0/0.0));
|
||||
dst_nanbox_print(dst_nanbox_wrap_true());
|
||||
dst_nanbox_print(dst_nanbox_wrap_false());
|
||||
dst_nanbox_print(dst_nanbox_wrap_nil());
|
||||
dst_nanbox_print(dst_nanbox_wrap_integer(123));
|
||||
dst_nanbox_print(dst_nanbox_wrap_integer(-123));
|
||||
dst_nanbox_print(dst_nanbox_wrap_integer(0));
|
||||
|
||||
dst_nanbox_print(dst_nanbox_wrap_array(&array));
|
||||
dst_nanbox_print(dst_nanbox_wrap_table(&array));
|
||||
dst_nanbox_print(dst_nanbox_wrap_string(&array));
|
||||
dst_nanbox_print(dst_nanbox_wrap_buffer(&array));
|
||||
|
||||
printf("--- nan box test end ---\n");
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
|
||||
int main() {
|
||||
DstParseResult pres;
|
||||
const uint8_t *str;
|
||||
|
||||
dst_init();
|
||||
|
||||
pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")");
|
||||
|
||||
assert(pres.status == DST_PARSE_OK);
|
||||
assert(dst_checktype(pres.value, DST_TUPLE));
|
||||
|
||||
str = dst_to_string(pres.value);
|
||||
printf("%.*s\n", dst_string_length(str), (const char *) str);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* Data format v1
|
||||
*
|
||||
* Types:
|
||||
*
|
||||
* Byte 0 to 200: small integer with value (byte - 100)
|
||||
* Byte 201: Nil
|
||||
* Byte 202: True
|
||||
* Byte 203: False
|
||||
* Byte 204: Number - IEEE 754 double format
|
||||
* Byte 205: String - [u32 length]*[u8... characters]
|
||||
* Byte 206: Struct - [u32 length]*2*[value... kvs]
|
||||
* Byte 207: Buffer - [u32 capacity][u32 length]*[u8... characters]
|
||||
* Byte 208: Array - [u32 length]*[value... elements]
|
||||
* Byte 209: Tuple - [u32 length]*[value... elements]
|
||||
* Byte 210: Thread - [value parent][u8 state][u32 frames]*[[value callee][value env]
|
||||
* [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]]
|
||||
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
||||
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
||||
* literals][u32 bytecodelen]*[u16... bytecode]
|
||||
* Byte 213: FuncEnv - [value thread][u32 length]*[value ...upvalues]
|
||||
* (upvalues is not read if thread is a thread object)
|
||||
* Byte 214: Func - [value parent][value def][value env]
|
||||
* (nil values indicate empty)
|
||||
* Byte 215: LUdata - [value meta][u32 length]*[u8... bytes]
|
||||
* Byte 216: CFunc - [u32 length]*[u8... idstring]
|
||||
* Byte 217: Ref - [u32 id]
|
||||
* Byte 218: Integer - [i64 value]
|
||||
* Byte 219: Symbol - [u32 length]*[u8... characters]
|
||||
*
|
||||
* This data format needs both a serialization function and deserialization function
|
||||
* written in C, as this will load embeded and precompiled programs into the VM, including
|
||||
* the self hosted parser abd compiler. It is therefor important that it is correct,
|
||||
* does not leak memory, and is fast.
|
||||
*/
|
981
junkyard/stl.c
981
junkyard/stl.c
@ -1,981 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static const char DST_EXPECTED_INTEGER[] = "expected integer";
|
||||
static const char DST_EXPECTED_STRING[] = "expected string";
|
||||
|
||||
static const char *types[] = {
|
||||
"nil",
|
||||
"real",
|
||||
"integer",
|
||||
"boolean",
|
||||
"string",
|
||||
"symbol",
|
||||
"array",
|
||||
"tuple",
|
||||
"table",
|
||||
"struct",
|
||||
"thread",
|
||||
"buffer",
|
||||
"function",
|
||||
"cfunction",
|
||||
"userdata",
|
||||
"funcenv",
|
||||
"funcdef"
|
||||
};
|
||||
|
||||
static DstValue nil() {
|
||||
DstValue n;
|
||||
n.type = DST_NIL;
|
||||
n.as.integer = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static DstValue integer(DstInteger i) {
|
||||
DstValue n;
|
||||
n.type = DST_INTEGER;
|
||||
n.as.integer = i;
|
||||
return n;
|
||||
}
|
||||
|
||||
static DstValue real(DstReal r) {
|
||||
DstValue n;
|
||||
n.type = DST_REAL;
|
||||
n.as.real = r;
|
||||
return n;
|
||||
}
|
||||
|
||||
static DstValue boolean(int b) {
|
||||
DstValue n;
|
||||
n.type = DST_BOOLEAN;
|
||||
n.as.boolean = b;
|
||||
return n;
|
||||
}
|
||||
|
||||
/***/
|
||||
/* Arithmetic */
|
||||
/***/
|
||||
|
||||
#define MAKE_BINOP(name, op)\
|
||||
static DstValue dst_stl_binop_##name(DstValue lhs, DstValue rhs) {\
|
||||
if (lhs.type == DST_INTEGER)\
|
||||
if (rhs.type == DST_INTEGER)\
|
||||
return integer(lhs.as.integer op rhs.as.integer);\
|
||||
else if (rhs.type == DST_REAL)\
|
||||
return real(lhs.as.integer op rhs.as.real);\
|
||||
else\
|
||||
return nil();\
|
||||
else if (lhs.type == DST_REAL)\
|
||||
if (rhs.type == DST_INTEGER)\
|
||||
return real(lhs.as.real op rhs.as.integer);\
|
||||
else if (rhs.type == DST_REAL)\
|
||||
return real(lhs.as.real op rhs.as.real);\
|
||||
else\
|
||||
return nil();\
|
||||
else\
|
||||
return nil();\
|
||||
}
|
||||
|
||||
#define SIMPLE_ACCUM_FUNCTION(name, op)\
|
||||
MAKE_BINOP(name, op)\
|
||||
int dst_stl_##name(Dst* vm) {\
|
||||
DstValue lhs, rhs;\
|
||||
uint32_t j, count;\
|
||||
count = dst_args(vm);\
|
||||
lhs = dst_arg(vm, 0);\
|
||||
for (j = 1; j < count; ++j) {\
|
||||
rhs = dst_arg(vm, j);\
|
||||
lhs = dst_stl_binop_##name(lhs, rhs);\
|
||||
}\
|
||||
if (lhs.type == DST_NIL)\
|
||||
dst_c_throwc(vm, "expected integer/real");\
|
||||
dst_c_return(vm, lhs);\
|
||||
}
|
||||
|
||||
SIMPLE_ACCUM_FUNCTION(add, +)
|
||||
SIMPLE_ACCUM_FUNCTION(mul, *)
|
||||
SIMPLE_ACCUM_FUNCTION(sub, -)
|
||||
|
||||
/* Detect division by zero */
|
||||
MAKE_BINOP(div, /)
|
||||
int dst_stl_div(Dst *vm) {
|
||||
DstValue lhs, rhs;
|
||||
uint32_t j, count;
|
||||
count = dst_args(vm);
|
||||
lhs = dst_arg(vm, 0);
|
||||
for (j = 1; j < count; ++j) {
|
||||
rhs = dst_arg(vm, j);
|
||||
if (lhs.type == DST_INTEGER && rhs.type == DST_INTEGER && rhs.as.integer == 0)
|
||||
dst_c_throwc(vm, "cannot integer divide by 0");
|
||||
lhs = dst_stl_binop_div(lhs, rhs);
|
||||
}
|
||||
if (lhs.type == DST_NIL)
|
||||
dst_c_throwc(vm, "expected integer/real");
|
||||
dst_c_return(vm, lhs);
|
||||
}
|
||||
|
||||
#undef SIMPLE_ACCUM_FUNCTION
|
||||
|
||||
#define BITWISE_FUNCTION(name, op) \
|
||||
int dst_stl_##name(Dst *vm) {\
|
||||
DstValue ret;\
|
||||
uint32_t i, count;\
|
||||
count = dst_args(vm);\
|
||||
ret = dst_arg(vm, 0);\
|
||||
if (ret.type != DST_INTEGER) {\
|
||||
dst_c_throwc(vm, "expected integer");\
|
||||
}\
|
||||
if (count < 2) {\
|
||||
dst_c_return(vm, ret);\
|
||||
}\
|
||||
for (i = 1; i < count; ++i) {\
|
||||
DstValue next = dst_arg(vm, i);\
|
||||
if (next.type != DST_INTEGER) {\
|
||||
dst_c_throwc(vm, "expected integer");\
|
||||
}\
|
||||
ret.as.integer = ret.as.integer op next.as.integer;\
|
||||
}\
|
||||
dst_c_return(vm, ret);\
|
||||
}
|
||||
|
||||
BITWISE_FUNCTION(band, &)
|
||||
BITWISE_FUNCTION(bor, |)
|
||||
BITWISE_FUNCTION(bxor, ^)
|
||||
BITWISE_FUNCTION(blshift, <<)
|
||||
BITWISE_FUNCTION(brshift, >>)
|
||||
|
||||
#undef BITWISE_FUNCTION
|
||||
|
||||
int dst_stl_bnot(Dst *vm) {
|
||||
DstValue in = dst_arg(vm, 0);
|
||||
uint32_t count = dst_args(vm);
|
||||
if (count != 1 || in.type != DST_INTEGER) {
|
||||
dst_c_throwc(vm, "expected 1 integer argument");
|
||||
}
|
||||
in.as.integer = ~in.as.integer;
|
||||
dst_c_return(vm, in);
|
||||
}
|
||||
|
||||
#define COMPARE_FUNCTION(name, check)\
|
||||
int dst_stl_##name(Dst *vm) {\
|
||||
DstValue ret;\
|
||||
uint32_t i, count;\
|
||||
count = dst_args(vm);\
|
||||
ret.as.boolean = 1;\
|
||||
ret.type = DST_BOOLEAN;\
|
||||
if (count < 2) {\
|
||||
dst_c_return(vm, ret);\
|
||||
}\
|
||||
for (i = 1; i < count; ++i) {\
|
||||
DstValue lhs = dst_arg(vm, i - 1);\
|
||||
DstValue rhs = dst_arg(vm, i);\
|
||||
if (!(check)) {\
|
||||
ret.as.boolean = 0;\
|
||||
break;\
|
||||
}\
|
||||
}\
|
||||
dst_c_return(vm, ret);\
|
||||
}
|
||||
|
||||
COMPARE_FUNCTION(lessthan, dst_compare(lhs, rhs) < 0)
|
||||
COMPARE_FUNCTION(greaterthan, dst_compare(lhs, rhs) > 0)
|
||||
COMPARE_FUNCTION(equal, dst_equals(lhs, rhs))
|
||||
COMPARE_FUNCTION(notequal, !dst_equals(lhs, rhs))
|
||||
COMPARE_FUNCTION(lessthaneq, dst_compare(lhs, rhs) <= 0)
|
||||
COMPARE_FUNCTION(greaterthaneq, dst_compare(lhs, rhs) >= 0)
|
||||
|
||||
#undef COMPARE_FUNCTION
|
||||
|
||||
/* Boolean not */
|
||||
int dst_stl_not(Dst *vm) {
|
||||
dst_c_return(vm, boolean(!dst_truthy(dst_arg(vm, 0))));
|
||||
}
|
||||
|
||||
/****/
|
||||
/* Core */
|
||||
/****/
|
||||
|
||||
/* Empty a mutable datastructure */
|
||||
int dst_stl_clear(Dst *vm) {
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
switch (x.type) {
|
||||
default:
|
||||
dst_c_throwc(vm, "cannot clear");
|
||||
case DST_ARRAY:
|
||||
x.as.array->count = 0;
|
||||
break;
|
||||
case DST_BUFFER:
|
||||
x.as.buffer->count = 0;
|
||||
break;
|
||||
case DST_TABLE:
|
||||
dst_table_clear(x.as.table);
|
||||
break;
|
||||
}
|
||||
dst_c_return(vm, x);
|
||||
}
|
||||
|
||||
/* Get length of object */
|
||||
int dst_stl_length(Dst *vm) {
|
||||
dst_set_integer(vm, 0, dst_length(vm, 0));
|
||||
dst_return(vm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get hash of a value */
|
||||
int dst_stl_hash(Dst *vm) {
|
||||
dst_set_integer(vm, 0, dst_hash(vm, 0););
|
||||
dst_return(vm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert to integer */
|
||||
int dst_stl_to_int(Dst *vm) {
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
if (x.type == DST_INTEGER) dst_c_return(vm, x);
|
||||
if (x.type == DST_REAL)
|
||||
dst_c_return(vm, integer((DstInteger) x.as.real));
|
||||
else
|
||||
dst_c_throwc(vm, "expected number");
|
||||
}
|
||||
|
||||
/* Convert to integer */
|
||||
int dst_stl_to_real(Dst *vm) {
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
if (x.type == DST_REAL) dst_c_return(vm, x);
|
||||
if (x.type == DST_INTEGER)
|
||||
dst_c_return(vm, dst_wrap_real((DstReal) x.as.integer));
|
||||
else
|
||||
dst_c_throwc(vm, "expected number");
|
||||
}
|
||||
|
||||
/* Get a slice of a sequence */
|
||||
int dst_stl_slice(Dst *vm) {
|
||||
uint32_t count = dst_args(vm);
|
||||
int32_t from, to;
|
||||
DstValue x;
|
||||
const DstValue *data;
|
||||
const uint8_t *cdata;
|
||||
uint32_t length;
|
||||
uint32_t newlength;
|
||||
DstInteger num;
|
||||
|
||||
/* Get data */
|
||||
x = dst_arg(vm, 0);
|
||||
if (!dst_seq_view(x, &data, &length) &&
|
||||
!dst_chararray_view(x, &cdata, &length)) {
|
||||
dst_c_throwc(vm, "expected array/tuple/buffer/symbol/string");
|
||||
}
|
||||
|
||||
/* Get from index */
|
||||
if (count < 2) {
|
||||
from = 0;
|
||||
} else {
|
||||
if (!dst_check_integer(vm, 1, &num))
|
||||
dst_c_throwc(vm, DST_EXPECTED_INTEGER);
|
||||
from = dst_startrange(num, length);
|
||||
}
|
||||
|
||||
/* Get to index */
|
||||
if (count < 3) {
|
||||
to = length;
|
||||
} else {
|
||||
if (!dst_check_integer(vm, 2, &num))
|
||||
dst_c_throwc(vm, DST_EXPECTED_INTEGER);
|
||||
to = dst_endrange(num, length);
|
||||
}
|
||||
|
||||
/* Check from bad bounds */
|
||||
if (from < 0 || to < 0 || to < from)
|
||||
dst_c_throwc(vm, "index out of bounds");
|
||||
|
||||
/* Build slice */
|
||||
newlength = to - from;
|
||||
if (x.type == DST_TUPLE) {
|
||||
DstValue *tup = dst_tuple_begin(vm, newlength);
|
||||
dst_memcpy(tup, data + from, newlength * sizeof(DstValue));
|
||||
dst_c_return(vm, dst_wrap_tuple(dst_tuple_end(vm, tup)));
|
||||
} else if (x.type == DST_ARRAY) {
|
||||
DstArray *arr = dst_array(vm, newlength);
|
||||
arr->count = newlength;
|
||||
dst_memcpy(arr->data, data + from, newlength * sizeof(DstValue));
|
||||
dst_c_return(vm, dst_wrap_array(arr));
|
||||
} else if (x.type == DST_STRING) {
|
||||
dst_c_return(vm, dst_wrap_string(dst_string_b(vm, x.as.string + from, newlength)));
|
||||
} else if (x.type == DST_SYMBOL) {
|
||||
dst_c_return(vm, dst_wrap_symbol(dst_string_b(vm, x.as.string + from, newlength)));
|
||||
} else { /* buffer */
|
||||
DstBuffer *b = dst_buffer(vm, newlength);
|
||||
dst_memcpy(b->data, x.as.buffer->data, newlength);
|
||||
b->count = newlength;
|
||||
dst_c_return(vm, dst_wrap_buffer(b));
|
||||
}
|
||||
}
|
||||
|
||||
/* Get type of object */
|
||||
int dst_stl_type(Dst *vm) {
|
||||
DstValue x;
|
||||
const char *typestr = "nil";
|
||||
uint32_t count = dst_args(vm);
|
||||
if (count == 0)
|
||||
dst_c_throwc(vm, "expected at least 1 argument");
|
||||
x = dst_arg(vm, 0);
|
||||
switch (x.type) {
|
||||
default:
|
||||
break;
|
||||
case DST_REAL:
|
||||
typestr = "real";
|
||||
break;
|
||||
case DST_INTEGER:
|
||||
typestr = "integer";
|
||||
break;
|
||||
case DST_BOOLEAN:
|
||||
typestr = "boolean";
|
||||
break;
|
||||
case DST_STRING:
|
||||
typestr = "string";
|
||||
break;
|
||||
case DST_SYMBOL:
|
||||
typestr = "symbol";
|
||||
break;
|
||||
case DST_ARRAY:
|
||||
typestr = "array";
|
||||
break;
|
||||
case DST_TUPLE:
|
||||
typestr = "tuple";
|
||||
break;
|
||||
case DST_THREAD:
|
||||
typestr = "thread";
|
||||
break;
|
||||
case DST_BUFFER:
|
||||
typestr = "buffer";
|
||||
break;
|
||||
case DST_FUNCTION:
|
||||
typestr = "function";
|
||||
break;
|
||||
case DST_CFUNCTION:
|
||||
typestr = "cfunction";
|
||||
break;
|
||||
case DST_TABLE:
|
||||
typestr = "table";
|
||||
break;
|
||||
case DST_USERDATA:
|
||||
typestr = "userdata";
|
||||
break;
|
||||
case DST_FUNCENV:
|
||||
typestr = "funcenv";
|
||||
break;
|
||||
case DST_FUNCDEF:
|
||||
typestr = "funcdef";
|
||||
break;
|
||||
}
|
||||
dst_c_return(vm, dst_string_cv(vm, typestr));
|
||||
}
|
||||
|
||||
/* Create array */
|
||||
int dst_stl_array(Dst *vm) {
|
||||
uint32_t i;
|
||||
uint32_t count = dst_args(vm);
|
||||
DstArray *array = dst_array(vm, count);
|
||||
for (i = 0; i < count; ++i)
|
||||
array->data[i] = dst_arg(vm, i);
|
||||
dst_c_return(vm, dst_wrap_array(array));
|
||||
}
|
||||
|
||||
/* Create tuple */
|
||||
int dst_stl_tuple(Dst *vm) {
|
||||
uint32_t i;
|
||||
uint32_t count = dst_args(vm);
|
||||
DstValue *tuple= dst_tuple_begin(vm, count);
|
||||
for (i = 0; i < count; ++i)
|
||||
tuple[i] = dst_arg(vm, i);
|
||||
dst_c_return(vm, dst_wrap_tuple(dst_tuple_end(vm, tuple)));
|
||||
}
|
||||
|
||||
/* Create object */
|
||||
int dst_stl_table(Dst *vm) {
|
||||
uint32_t i;
|
||||
uint32_t count = dst_args(vm);
|
||||
DstTable *table;
|
||||
if (count % 2 != 0)
|
||||
dst_c_throwc(vm, "expected even number of arguments");
|
||||
table = dst_table(vm, 4 * count);
|
||||
for (i = 0; i < count; i += 2)
|
||||
dst_table_put(vm, table, dst_arg(vm, i), dst_arg(vm, i + 1));
|
||||
dst_c_return(vm, dst_wrap_table(table));
|
||||
}
|
||||
|
||||
/* Create struct */
|
||||
int dst_stl_struct(Dst *vm) {
|
||||
uint32_t i;
|
||||
uint32_t count = dst_args(vm);
|
||||
DstValue *st;
|
||||
if (count % 2 != 0)
|
||||
dst_c_throwc(vm, "expected even number of arguments");
|
||||
st = dst_struct_begin(vm, count / 2);
|
||||
for (i = 0; i < count; i += 2)
|
||||
dst_struct_put(st, dst_arg(vm, i), dst_arg(vm, i + 1));
|
||||
dst_c_return(vm, dst_wrap_struct(dst_struct_end(vm, st)));
|
||||
}
|
||||
|
||||
/* Create a buffer */
|
||||
int dst_stl_buffer(Dst *vm) {
|
||||
uint32_t i, count;
|
||||
const uint8_t *dat;
|
||||
uint32_t slen;
|
||||
DstBuffer *buf = dst_buffer(vm, 10);
|
||||
count = dst_args(vm);
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (dst_chararray_view(dst_arg(vm, i), &dat, &slen))
|
||||
dst_buffer_append(vm, buf, dat, slen);
|
||||
else
|
||||
dst_c_throwc(vm, DST_EXPECTED_STRING);
|
||||
}
|
||||
dst_c_return(vm, dst_wrap_buffer(buf));
|
||||
}
|
||||
|
||||
/* Create a string */
|
||||
int dst_stl_string(Dst *vm) {
|
||||
uint32_t j;
|
||||
uint32_t count = dst_args(vm);
|
||||
uint32_t length = 0;
|
||||
uint32_t index = 0;
|
||||
uint8_t *str;
|
||||
const uint8_t *dat;
|
||||
uint32_t slen;
|
||||
/* Find length and assert string arguments */
|
||||
for (j = 0; j < count; ++j) {
|
||||
if (!dst_chararray_view(dst_arg(vm, j), &dat, &slen)) {
|
||||
DstValue newarg;
|
||||
dat = dst_to_string(vm, dst_arg(vm, j));
|
||||
slen = dst_string_length(dat);
|
||||
newarg.type = DST_STRING;
|
||||
newarg.as.string = dat;
|
||||
dst_set_arg(vm, j, newarg);
|
||||
}
|
||||
length += slen;
|
||||
}
|
||||
/* Make string */
|
||||
str = dst_string_begin(vm, length);
|
||||
for (j = 0; j < count; ++j) {
|
||||
dst_chararray_view(dst_arg(vm, j), &dat, &slen);
|
||||
dst_memcpy(str + index, dat, slen);
|
||||
index += slen;
|
||||
}
|
||||
dst_c_return(vm, dst_wrap_string(dst_string_end(vm, str)));
|
||||
}
|
||||
|
||||
/* Create a symbol */
|
||||
int dst_stl_symbol(Dst *vm) {
|
||||
int ret = dst_stl_string(vm);
|
||||
if (ret == DST_RETURN_OK) {
|
||||
vm->ret.type = DST_SYMBOL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create a thread */
|
||||
int dst_stl_thread(Dst *vm) {
|
||||
DstThread *t;
|
||||
DstValue callee = dst_arg(vm, 0);
|
||||
DstValue parent = dst_arg(vm, 1);
|
||||
DstValue errorParent = dst_arg(vm, 2);
|
||||
t = dst_thread(vm, callee, 10);
|
||||
if (callee.type != DST_FUNCTION && callee.type != DST_CFUNCTION)
|
||||
dst_c_throwc(vm, "expected function in thread constructor");
|
||||
if (parent.type == DST_THREAD) {
|
||||
t->parent = parent.as.thread;
|
||||
} else if (parent.type != DST_NIL) {
|
||||
dst_c_throwc(vm, "expected thread/nil as parent");
|
||||
} else {
|
||||
t->parent = vm->thread;
|
||||
}
|
||||
dst_c_return(vm, dst_wrap_thread(t));
|
||||
}
|
||||
|
||||
/* Get current thread */
|
||||
int dst_stl_current(Dst *vm) {
|
||||
dst_c_return(vm, dst_wrap_thread(vm->thread));
|
||||
}
|
||||
|
||||
/* Get parent of a thread */
|
||||
/* TODO - consider implications of this function
|
||||
* for sandboxing */
|
||||
int dst_stl_parent(Dst *vm) {
|
||||
DstThread *t;
|
||||
if (!dst_check_thread(vm, 0, &t))
|
||||
dst_c_throwc(vm, "expected thread");
|
||||
if (t->parent == NULL)
|
||||
dst_c_return(vm, dst_wrap_nil());
|
||||
dst_c_return(vm, dst_wrap_thread(t->parent));
|
||||
}
|
||||
|
||||
/* Get the status of a thread */
|
||||
int dst_stl_status(Dst *vm) {
|
||||
DstThread *t;
|
||||
const char *cstr;
|
||||
if (!dst_check_thread(vm, 0, &t))
|
||||
dst_c_throwc(vm, "expected thread");
|
||||
switch (t->status) {
|
||||
case DST_THREAD_PENDING:
|
||||
cstr = "pending";
|
||||
break;
|
||||
case DST_THREAD_ALIVE:
|
||||
cstr = "alive";
|
||||
break;
|
||||
case DST_THREAD_DEAD:
|
||||
cstr = "dead";
|
||||
break;
|
||||
case DST_THREAD_ERROR:
|
||||
cstr = "error";
|
||||
break;
|
||||
}
|
||||
dst_c_return(vm, dst_string_cv(vm, cstr));
|
||||
}
|
||||
|
||||
/* Associative get */
|
||||
int dst_stl_get(Dst *vm) {
|
||||
DstValue ret;
|
||||
uint32_t count;
|
||||
const char *err;
|
||||
count = dst_args(vm);
|
||||
if (count != 2)
|
||||
dst_c_throwc(vm, "expects 2 arguments");
|
||||
err = dst_get(dst_arg(vm, 0), dst_arg(vm, 1), &ret);
|
||||
if (err != NULL)
|
||||
dst_c_throwc(vm, err);
|
||||
else
|
||||
dst_c_return(vm, ret);
|
||||
}
|
||||
|
||||
/* Associative set */
|
||||
int dst_stl_set(Dst *vm) {
|
||||
uint32_t count;
|
||||
const char *err;
|
||||
count = dst_args(vm);
|
||||
if (count != 3)
|
||||
dst_c_throwc(vm, "expects 3 arguments");
|
||||
err = dst_set(vm, dst_arg(vm, 0), dst_arg(vm, 1), dst_arg(vm, 2));
|
||||
if (err != NULL)
|
||||
dst_c_throwc(vm, err);
|
||||
else
|
||||
dst_c_return(vm, dst_arg(vm, 0));
|
||||
}
|
||||
|
||||
/* Push to end of array */
|
||||
int dst_stl_push(Dst *vm) {
|
||||
DstValue ds = dst_arg(vm, 0);
|
||||
if (ds.type != DST_ARRAY)
|
||||
dst_c_throwc(vm, "expected array");
|
||||
dst_array_push(vm, ds.as.array, dst_arg(vm, 1));
|
||||
dst_c_return(vm, ds);
|
||||
}
|
||||
|
||||
/* Pop from end of array */
|
||||
int dst_stl_pop(Dst *vm) {
|
||||
DstValue ds = dst_arg(vm, 0);
|
||||
if (ds.type != DST_ARRAY)
|
||||
dst_c_throwc(vm, "expected array");
|
||||
dst_c_return(vm, dst_array_pop(ds.as.array));
|
||||
}
|
||||
|
||||
/* Peek at end of array */
|
||||
int dst_stl_peek(Dst *vm) {
|
||||
DstValue ds = dst_arg(vm, 0);
|
||||
if (ds.type != DST_ARRAY)
|
||||
dst_c_throwc(vm, "expected array");
|
||||
dst_c_return(vm, dst_array_peek(ds.as.array));
|
||||
}
|
||||
|
||||
/* Ensure array capacity */
|
||||
int dst_stl_ensure(Dst *vm) {
|
||||
DstValue ds = dst_arg(vm, 0);
|
||||
DstValue cap = dst_arg(vm, 1);
|
||||
if (ds.type != DST_ARRAY)
|
||||
dst_c_throwc(vm, "expected array");
|
||||
if (cap.type != DST_INTEGER)
|
||||
dst_c_throwc(vm, DST_EXPECTED_INTEGER);
|
||||
dst_array_ensure(vm, ds.as.array, (uint32_t) cap.as.integer);
|
||||
dst_c_return(vm, ds);
|
||||
}
|
||||
|
||||
/* Get next key in struct or table */
|
||||
int dst_stl_next(Dst *vm) {
|
||||
DstValue ds = dst_arg(vm, 0);
|
||||
DstValue key = dst_arg(vm, 1);
|
||||
if (ds.type == DST_TABLE) {
|
||||
dst_c_return(vm, dst_table_next(ds.as.table, key));
|
||||
} else if (ds.type == DST_STRUCT) {
|
||||
dst_c_return(vm, dst_struct_next(ds.as.st, key));
|
||||
} else {
|
||||
dst_c_throwc(vm, "expected table or struct");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print values for inspection */
|
||||
int dst_stl_print(Dst *vm) {
|
||||
uint32_t j, count;
|
||||
count = dst_args(vm);
|
||||
for (j = 0; j < count; ++j) {
|
||||
uint32_t i;
|
||||
const uint8_t *string = dst_to_string(vm, dst_arg(vm, j));
|
||||
uint32_t len = dst_string_length(string);
|
||||
for (i = 0; i < len; ++i)
|
||||
fputc(string[i], stdout);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
/* Long description */
|
||||
int dst_stl_description(Dst *vm) {
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
const uint8_t *buf = dst_description(vm, x);
|
||||
dst_c_return(vm, dst_wrap_string(buf));
|
||||
}
|
||||
|
||||
/* Short description */
|
||||
int dst_stl_short_description(Dst *vm) {
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
const uint8_t *buf = dst_short_description(vm, x);
|
||||
dst_c_return(vm, dst_wrap_string(buf));
|
||||
}
|
||||
|
||||
/* Exit */
|
||||
int dst_stl_exit(Dst *vm) {
|
||||
int ret;
|
||||
DstValue x = dst_arg(vm, 0);
|
||||
ret = x.type == DST_INTEGER ? x.as.integer : (x.type == DST_REAL ? x.as.real : 0);
|
||||
exit(ret);
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
/* Throw error */
|
||||
int dst_stl_error(Dst *vm) {
|
||||
dst_c_throw(vm, dst_arg(vm, 0));
|
||||
}
|
||||
|
||||
/***/
|
||||
/* Function reflection */
|
||||
/***/
|
||||
|
||||
int dst_stl_funcenv(Dst *vm) {
|
||||
DstFunction *fn;
|
||||
if (!dst_check_function(vm, 0, &fn))
|
||||
dst_c_throwc(vm, "expected function");
|
||||
if (fn->env)
|
||||
dst_c_return(vm, dst_wrap_funcenv(fn->env));
|
||||
else
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
int dst_stl_funcdef(Dst *vm) {
|
||||
DstFunction *fn;
|
||||
if (!dst_check_function(vm, 0, &fn))
|
||||
dst_c_throwc(vm, "expected function");
|
||||
dst_c_return(vm, dst_wrap_funcdef(fn->def));
|
||||
}
|
||||
|
||||
int dst_stl_funcparent(Dst *vm) {
|
||||
DstFunction *fn;
|
||||
if (!dst_check_function(vm, 0, &fn))
|
||||
dst_c_throwc(vm, "expected function");
|
||||
if (fn->parent)
|
||||
dst_c_return(vm, dst_wrap_function(fn->parent));
|
||||
else
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
int dst_stl_def(Dst *vm) {
|
||||
DstValue key = dst_arg(vm, 0);
|
||||
if (dst_args(vm) != 2) {
|
||||
dst_c_throwc(vm, "expected 2 arguments to global-def");
|
||||
}
|
||||
if (key.type != DST_STRING && key.type != DST_SYMBOL) {
|
||||
dst_c_throwc(vm, "expected string/symbol as first argument");
|
||||
}
|
||||
key.type = DST_SYMBOL;
|
||||
dst_env_put(vm, vm->env, key, dst_arg(vm, 1));
|
||||
dst_c_return(vm, dst_arg(vm, 1));
|
||||
}
|
||||
|
||||
int dst_stl_var(Dst *vm) {
|
||||
DstValue key = dst_arg(vm, 0);
|
||||
if (dst_args(vm) != 2) {
|
||||
dst_c_throwc(vm, "expected 2 arguments to global-var");
|
||||
}
|
||||
if (key.type != DST_STRING && key.type != DST_SYMBOL) {
|
||||
dst_c_throwc(vm, "expected string as first argument");
|
||||
}
|
||||
key.type = DST_SYMBOL;
|
||||
dst_env_putvar(vm, vm->env, key, dst_arg(vm, 1));
|
||||
dst_c_return(vm, dst_arg(vm, 1));
|
||||
}
|
||||
|
||||
/****/
|
||||
/* IO */
|
||||
/****/
|
||||
|
||||
/* File type definition */
|
||||
static DstUserType dst_stl_filetype = {
|
||||
"std.file",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Open a a file and return a userdata wrapper arounf the C file API. */
|
||||
int dst_stl_open(Dst *vm) {
|
||||
const uint8_t *fname = dst_to_string(vm, dst_arg(vm, 0));
|
||||
const uint8_t *fmode = dst_to_string(vm, dst_arg(vm, 1));
|
||||
FILE *f;
|
||||
FILE **fp;
|
||||
if (dst_args(vm) < 2 || dst_arg(vm, 0).type != DST_STRING
|
||||
|| dst_arg(vm, 1).type != DST_STRING)
|
||||
dst_c_throwc(vm, "expected filename and filemode");
|
||||
f = fopen((const char *)fname, (const char *)fmode);
|
||||
if (!f)
|
||||
dst_c_throwc(vm, "could not open file");
|
||||
fp = dst_userdata(vm, sizeof(FILE *), &dst_stl_filetype);
|
||||
*fp = f;
|
||||
dst_c_return(vm, dst_wrap_userdata(fp));
|
||||
}
|
||||
|
||||
/* Read an entire file into memory */
|
||||
int dst_stl_slurp(Dst *vm) {
|
||||
DstBuffer *b;
|
||||
long fsize;
|
||||
FILE *f;
|
||||
FILE **fp = dst_check_userdata(vm, 0, &dst_stl_filetype);
|
||||
if (fp == NULL) dst_c_throwc(vm, "expected file");
|
||||
if (!dst_check_buffer(vm, 1, &b)) b = dst_buffer(vm, 10);
|
||||
f = *fp;
|
||||
/* Read whole file */
|
||||
fseek(f, 0, SEEK_END);
|
||||
fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
/* Ensure buffer size */
|
||||
dst_buffer_ensure(vm, b, b->count + fsize);
|
||||
fread((char *)(b->data + b->count), fsize, 1, f);
|
||||
b->count += fsize;
|
||||
dst_c_return(vm, dst_wrap_buffer(b));
|
||||
}
|
||||
|
||||
/* Read a certain number of bytes into memory */
|
||||
int dst_stl_read(Dst *vm) {
|
||||
DstBuffer *b;
|
||||
FILE *f;
|
||||
int64_t len;
|
||||
FILE **fp = dst_check_userdata(vm, 0, &dst_stl_filetype);
|
||||
if (fp == NULL) dst_c_throwc(vm, "expected file");
|
||||
if (!(dst_check_integer(vm, 1, &len))) dst_c_throwc(vm, "expected integer");
|
||||
if (!dst_check_buffer(vm, 2, &b)) b = dst_buffer(vm, 10);
|
||||
f = *fp;
|
||||
/* Ensure buffer size */
|
||||
dst_buffer_ensure(vm, b, b->count + len);
|
||||
b->count += fread((char *)(b->data + b->count), len, 1, f) * len;
|
||||
dst_c_return(vm, dst_wrap_buffer(b));
|
||||
}
|
||||
|
||||
/* Write bytes to a file */
|
||||
int dst_stl_write(Dst *vm) {
|
||||
FILE *f;
|
||||
const uint8_t *data;
|
||||
uint32_t len;
|
||||
FILE **fp = dst_check_userdata(vm, 0, &dst_stl_filetype);
|
||||
if (fp == NULL) dst_c_throwc(vm, "expected file");
|
||||
if (!dst_chararray_view(dst_arg(vm, 1), &data, &len)) dst_c_throwc(vm, "expected string|buffer");
|
||||
f = *fp;
|
||||
fwrite(data, len, 1, f);
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
/* Close a file */
|
||||
int dst_stl_close(Dst *vm) {
|
||||
FILE **fp = dst_check_userdata(vm, 0, &dst_stl_filetype);
|
||||
if (fp == NULL) dst_c_throwc(vm, "expected file");
|
||||
fclose(*fp);
|
||||
dst_c_return(vm, dst_wrap_nil());
|
||||
}
|
||||
|
||||
/****/
|
||||
/* Temporary */
|
||||
/****/
|
||||
|
||||
/* Force garbage collection */
|
||||
int dst_stl_gcollect(Dst *vm) {
|
||||
dst_collect(vm);
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
/***/
|
||||
/* Compilation */
|
||||
/***/
|
||||
|
||||
/* Generate a unique symbol */
|
||||
static int dst_stl_gensym(Dst *vm) {
|
||||
DstValue source = dst_arg(vm, 0);
|
||||
const uint8_t *sym = NULL;
|
||||
uint32_t len;
|
||||
const uint8_t *data;
|
||||
if (source.type == DST_NIL) {
|
||||
sym = dst_string_cu(vm, "");
|
||||
} else if (dst_chararray_view(source, &data, &len)) {
|
||||
sym = dst_string_bu(vm, data, len);
|
||||
} else {
|
||||
dst_c_throwc(vm, "exepcted string/buffer/symbol/nil");
|
||||
}
|
||||
dst_c_return(vm, dst_wrap_symbol(sym));
|
||||
}
|
||||
|
||||
/* Compile a value */
|
||||
static int dst_stl_compile(Dst *vm) {
|
||||
DstTable *env = vm->env;
|
||||
if (dst_arg(vm, 1).type == DST_TABLE) {
|
||||
env = dst_arg(vm, 1).as.table;
|
||||
}
|
||||
dst_c_return(vm, dst_compile(vm, env, dst_arg(vm, 0)));
|
||||
}
|
||||
|
||||
/* Get vm->env */
|
||||
static int dst_stl_getenv(Dst *vm) {
|
||||
dst_c_return(vm, dst_wrap_table(vm->env));
|
||||
}
|
||||
|
||||
/* Set vm->env */
|
||||
static int dst_stl_setenv(Dst *vm) {
|
||||
DstValue newEnv = dst_arg(vm, 0);
|
||||
if (newEnv.type != DST_TABLE) {
|
||||
dst_c_throwc(vm, "expected table");
|
||||
}
|
||||
vm->env = newEnv.as.table;
|
||||
return DST_RETURN_OK;
|
||||
}
|
||||
|
||||
/****/
|
||||
/* Bootstraping */
|
||||
/****/
|
||||
|
||||
static const DstModuleItem std_module[] = {
|
||||
/* Arithmetic */
|
||||
{"+", dst_stl_add},
|
||||
{"*", dst_stl_mul},
|
||||
{"-", dst_stl_sub},
|
||||
{"/", dst_stl_div},
|
||||
/* Comparisons */
|
||||
{"<", dst_stl_lessthan},
|
||||
{">", dst_stl_greaterthan},
|
||||
{"=", dst_stl_equal},
|
||||
{"not=", dst_stl_notequal},
|
||||
{"<=", dst_stl_lessthaneq},
|
||||
{">=", dst_stl_greaterthaneq},
|
||||
/* Bitwise arithmetic */
|
||||
{"band", dst_stl_band},
|
||||
{"bor", dst_stl_bor},
|
||||
{"bxor", dst_stl_bxor},
|
||||
{"blshift", dst_stl_blshift},
|
||||
{"brshift", dst_stl_brshift},
|
||||
{"bnot", dst_stl_bnot},
|
||||
/* IO */
|
||||
{"open", dst_stl_open},
|
||||
{"slurp", dst_stl_slurp},
|
||||
{"read", dst_stl_read},
|
||||
{"write", dst_stl_write},
|
||||
/* Compile */
|
||||
{"gensym", dst_stl_gensym},
|
||||
{"getenv", dst_stl_getenv},
|
||||
{"setenv", dst_stl_setenv},
|
||||
{"compile", dst_stl_compile},
|
||||
/* Other */
|
||||
{"not", dst_stl_not},
|
||||
{"clear", dst_stl_clear},
|
||||
{"length", dst_stl_length},
|
||||
{"hash", dst_stl_hash},
|
||||
{"integer", dst_stl_to_int},
|
||||
{"real", dst_stl_to_real},
|
||||
{"type", dst_stl_type},
|
||||
{"slice", dst_stl_slice},
|
||||
{"array", dst_stl_array},
|
||||
{"tuple", dst_stl_tuple},
|
||||
{"table", dst_stl_table},
|
||||
{"struct", dst_stl_struct},
|
||||
{"buffer", dst_stl_buffer},
|
||||
{"string", dst_stl_string},
|
||||
{"symbol", dst_stl_symbol},
|
||||
{"thread", dst_stl_thread},
|
||||
{"status", dst_stl_status},
|
||||
{"current", dst_stl_current},
|
||||
{"parent", dst_stl_parent},
|
||||
{"print", dst_stl_print},
|
||||
{"description", dst_stl_description},
|
||||
{"short-description", dst_stl_short_description},
|
||||
{"exit!", dst_stl_exit},
|
||||
{"get", dst_stl_get},
|
||||
{"set!", dst_stl_set},
|
||||
{"next", dst_stl_next},
|
||||
{"error", dst_stl_error},
|
||||
{"push!", dst_stl_push},
|
||||
{"pop!", dst_stl_pop},
|
||||
{"peek", dst_stl_peek},
|
||||
{"ensure!", dst_stl_ensure},
|
||||
{"open", dst_stl_open},
|
||||
{"slurp", dst_stl_slurp},
|
||||
{"read", dst_stl_read},
|
||||
{"write", dst_stl_write},
|
||||
{"close", dst_stl_close},
|
||||
{"funcenv", dst_stl_funcenv},
|
||||
{"funcdef", dst_stl_funcdef},
|
||||
{"funcparent", dst_stl_funcparent},
|
||||
{"gcollect", dst_stl_gcollect},
|
||||
{"global-def", dst_stl_def},
|
||||
{"global-var", dst_stl_var},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load stl library into the current environment. Create stl module object
|
||||
* only if it is not yet created. */
|
||||
void dst_stl_load(Dst *vm) {
|
||||
DstValue maybeEnv = dst_table_get(vm->modules, dst_string_cvs(vm, "std"));
|
||||
if (maybeEnv.type == DST_TABLE) {
|
||||
/* Module already created, so merge into main vm. */
|
||||
dst_env_merge(vm, vm->env, maybeEnv.as.table);
|
||||
} else {
|
||||
/* Module not yet created */
|
||||
/* Load the normal c functions */
|
||||
dst_module_mutable(vm, "std", std_module);
|
||||
/* Wrap stdin and stdout */
|
||||
FILE **inp = dst_userdata(vm, sizeof(FILE *), &dst_stl_filetype);
|
||||
FILE **outp = dst_userdata(vm, sizeof(FILE *), &dst_stl_filetype);
|
||||
FILE **errp = dst_userdata(vm, sizeof(FILE *), &dst_stl_filetype);
|
||||
*inp = stdin;
|
||||
*outp = stdout;
|
||||
*errp = stderr;
|
||||
dst_module_put(vm, "std", "stdin", dst_wrap_userdata(inp));
|
||||
dst_module_put(vm, "std", "stdout", dst_wrap_userdata(outp));
|
||||
dst_module_put(vm, "std", "stderr", dst_wrap_userdata(outp));
|
||||
/* Now merge */
|
||||
maybeEnv = dst_table_get(vm->modules, dst_string_cvs(vm, "std"));
|
||||
dst_env_merge(vm, vm->env, maybeEnv.as.table);
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Use a custom double parser instead of libc's strtod for better portability
|
||||
* and control. Also, uses a less strict rounding method than ieee to not incur
|
||||
* the cost of 4000 loc and dependence on arbitary precision arithmetic. There
|
||||
* is no plan to use arbitrary precision arithmetic for parsing numbers, and a
|
||||
* formal rounding mode has yet to be chosen (round towards 0 seems
|
||||
* reasonable).
|
||||
*
|
||||
* This version has been modified for much greater flexibility in parsing, such
|
||||
* as choosing the radix, supporting integer output, and returning DstValues
|
||||
* directly.
|
||||
*
|
||||
* Numbers are of the form [-+]R[rR]I.F[eE&][-+]X where R is the radix, I is
|
||||
* the integer part, F is the fractional part, and X is the exponent. All
|
||||
* signs, radix, decimal point, fractional part, and exponent can be ommited.
|
||||
* The number will be considered and integer if the there is no decimal point
|
||||
* and no exponent. Any number greater the 2^32-1 or less than -(2^32) will be
|
||||
* coerced to a double. If there is an error, the function dst_scan_number will
|
||||
* return a dst nil. The radix is assumed to be 10 if omitted, and the E
|
||||
* separator for the exponent can only be used when the radix is 10. This is
|
||||
* because E is a vaid digit in bases 15 or greater. For bases greater than 10,
|
||||
* the letters are used as digitis. A through Z correspond to the digits 10
|
||||
* through 35, and the lowercase letters have the same values. The radix number
|
||||
* is always in base 10. For example, a hexidecimal number could be written
|
||||
* '16rdeadbeef'. dst_scan_number also supports some c style syntax for
|
||||
* hexidecimal literals. The previous number could also be written
|
||||
* '0xdeadbeef'. Note that in this case, the number will actually be a double
|
||||
* as it will not fit in the range for a signed 32 bit integer. The string
|
||||
* '0xbeef' would parse to an integer as it is in the range of an int32_t. */
|
||||
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
#include <math.h>
|
||||
|
||||
DstValue dst_scan_number(const uint8_t *str, int32_t len);
|
||||
|
||||
const char *valid_test_strs[] = {
|
||||
"0",
|
||||
"-0.0",
|
||||
"+0",
|
||||
"123",
|
||||
"-123",
|
||||
"aaaaaa",
|
||||
"+a123",
|
||||
"0.12312",
|
||||
"89.12312",
|
||||
"-123.01231",
|
||||
"123e10",
|
||||
"1203412347981232379183.13013248723478932478923478e12",
|
||||
"120341234798123237918313013248723478932478923478",
|
||||
"999_999_999_999",
|
||||
"8r777",
|
||||
"",
|
||||
"----",
|
||||
" ",
|
||||
"--123",
|
||||
"0xff",
|
||||
"0xff.f",
|
||||
"0xff&-1",
|
||||
"0xfefefe",
|
||||
"1926.4823e11",
|
||||
"0xff_ff_ff_ff",
|
||||
"0xff_ff_ff_ff_ff_ff",
|
||||
"2r1010",
|
||||
"2r10101010001101",
|
||||
"123a",
|
||||
"0.1e510",
|
||||
"4.123123e-308",
|
||||
"4.123123e-320",
|
||||
"1e-308",
|
||||
"1e-309",
|
||||
"9e-308",
|
||||
"9e-309",
|
||||
"919283691283e-309",
|
||||
"9999e302",
|
||||
"123.12312.123",
|
||||
"90.e0.1",
|
||||
"90.e1",
|
||||
".e1"
|
||||
};
|
||||
|
||||
int main() {
|
||||
dst_init();
|
||||
unsigned i;
|
||||
for (i = 0; i < (sizeof(valid_test_strs) / sizeof(void *)); i++) {
|
||||
DstValue out;
|
||||
double refout;
|
||||
const uint8_t *str = (const uint8_t *) valid_test_strs[i];
|
||||
int32_t len = 0; while (str[len]) len++;
|
||||
|
||||
refout = strtod(valid_test_strs[i], NULL);
|
||||
out = dst_scan_number(str, len);
|
||||
dst_puts(dst_formatc("literal: %s, out: %v, refout: %v\n",
|
||||
valid_test_strs[i], out, dst_wrap_real(refout)));
|
||||
|
||||
}
|
||||
uint64_t x = 0x07FFFFFFFFFFFFFF;
|
||||
uint64_t y = 36;
|
||||
|
||||
printf("%llu, %llu\n", x, (x * y) / y);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#include "unit.h"
|
||||
#include <dst/dst.h>
|
||||
|
||||
int main() {
|
||||
dst_init();
|
||||
DstTable *table = dst_table(10);
|
||||
assert(table->count == 0);
|
||||
dst_table_put(table, dst_cstringv("a"), dst_cstringv("b"));
|
||||
dst_table_put(table, dst_cstringv("b"), dst_cstringv("a"));
|
||||
dst_table_put(table, dst_cstringv("a"), dst_cstringv("c"));
|
||||
assert(table->count == 2);
|
||||
dst_table_remove(table, dst_cstringv("a"));
|
||||
assert(table->count == 1);
|
||||
assert(dst_equals(
|
||||
dst_table_get(table, dst_cstringv("b")),
|
||||
dst_cstringv("a")
|
||||
));
|
||||
return 0;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Calvin Rose
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Simple clone of the xxd tool used at build time. Used to
|
||||
* create headers out of source files. Only used for core libraries
|
||||
* like the bootstrapping code and the stl. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BUFSIZE 1024
|
||||
#define PERLINE 10
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
char buf[BUFSIZE];
|
||||
size_t bytesRead = 0;
|
||||
int lineIndex = 0;
|
||||
int line = 0;
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "Usage: %s infile outfile symbol\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open the files */
|
||||
FILE *in = fopen(argv[1], "rb");
|
||||
FILE *out = fopen(argv[2], "wb");
|
||||
|
||||
/* Check if files open successfully */
|
||||
if (in == NULL) {
|
||||
fprintf(stderr, "Could not open input file %s\n", argv[1]);
|
||||
return 1;
|
||||
} else if (out == NULL) {
|
||||
fprintf(stderr, "Could not open output file %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write the header */
|
||||
fprintf(out, "/* Auto generated - DO NOT EDIT */\n\n");
|
||||
fprintf(out, "#include <stdint.h>\n\n");
|
||||
fprintf(out, "const uint8_t dst_gen_%s[] = {", argv[3]);
|
||||
|
||||
/* Read in chunks from buffer */
|
||||
while ((bytesRead = fread(buf, 1, sizeof(buf), in)) > 0) {
|
||||
int i;
|
||||
for (i = 0; i < bytesRead; ++i) {
|
||||
int byte = ((uint8_t *)buf) [i];
|
||||
|
||||
/* Write the byte */
|
||||
if (lineIndex++ == 0) {
|
||||
if (line++)
|
||||
fputc(',', out);
|
||||
fputs("\n\t", out);
|
||||
} else {
|
||||
fputs(", ", out);
|
||||
}
|
||||
fputs("0x", out);
|
||||
fputc(hex[byte & 0xF], out);
|
||||
fputc(hex[byte >> 4], out);
|
||||
|
||||
/* Make line index wrap */
|
||||
if (lineIndex >= PERLINE)
|
||||
lineIndex = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the tail */
|
||||
fputs("\n};\n", out);
|
||||
|
||||
/* Close the file handles */
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#include <dst/dst.h>
|
||||
|
||||
#ifdef DST_LIB
|
||||
#define dst_entry _dst_init
|
||||
#else
|
||||
#define dst_entry dst_testlib_init
|
||||
#endif
|
||||
|
||||
int dst_entry(DstArgs args) {
|
||||
DstTable *module = dst_get_module(args);
|
||||
dst_module_def(module, "pi", dst_wrap_real(M_PI));
|
||||
*args.ret = dst_wrap_table(module);
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include <dst/dst.h>
|
@ -23,9 +23,9 @@
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include "opcodes.h"
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include <dst/dstasm.h>
|
||||
#include <dst/dstopcodes.h>
|
||||
#include <headerlibs/strbinsearch.h>
|
||||
|
||||
/* Bytecode op argument types */
|
||||
|
||||
@ -492,21 +492,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) {
|
||||
(void) flags;
|
||||
|
||||
/* Initialize funcdef */
|
||||
def = dst_gcalloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||
def->environments = NULL;
|
||||
def->constants = NULL;
|
||||
def->bytecode = NULL;
|
||||
def->flags = 0;
|
||||
def->slotcount = 0;
|
||||
def->arity = 0;
|
||||
def->source = NULL;
|
||||
def->sourcepath = NULL;
|
||||
def->sourcemap = NULL;
|
||||
def->defs = NULL;
|
||||
def->defs_length = 0;
|
||||
def->constants_length = 0;
|
||||
def->bytecode_length = 0;
|
||||
def->environments_length = 1;
|
||||
def = dst_funcdef_alloc();
|
||||
|
||||
/* Initialize Assembler */
|
||||
a.def = def;
|
||||
@ -732,17 +718,6 @@ DstAssembleResult dst_asm(Dst source, int flags) {
|
||||
return dst_asm1(NULL, source, flags);
|
||||
}
|
||||
|
||||
/* Build a function from the result */
|
||||
DstFunction *dst_asm_func(DstAssembleResult result) {
|
||||
if (result.status != DST_ASSEMBLE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
DstFunction *func = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||
func->def = result.funcdef;
|
||||
func->envs = NULL;
|
||||
return func;
|
||||
}
|
||||
|
||||
/* Disassembly */
|
||||
|
||||
/* Find the deinfintion of an instruction given the instruction word. Return
|
||||
@ -917,7 +892,7 @@ int dst_asm_cfun(DstArgs args) {
|
||||
if (args.n < 1) return dst_throw(args, "expected assembly source");
|
||||
res = dst_asm(args.v[0], 0);
|
||||
if (res.status == DST_ASSEMBLE_OK) {
|
||||
return dst_return(args, dst_wrap_function(dst_asm_func(res)));
|
||||
return dst_return(args, dst_wrap_function(dst_function(res.funcdef, NULL)));
|
||||
} else {
|
||||
return dst_throwv(args, dst_wrap_string(res.error));
|
||||
}
|
@ -23,8 +23,12 @@
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
#include "compile.h"
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DST_V_DEF_COPYMEM
|
||||
#define DST_V_DEF_FLATTENMEM
|
||||
#include <headerlibs/vector.h>
|
||||
#undef DST_V_DEF_COPYMEM
|
||||
#undef DST_V_DEF_FLATTENMEM
|
||||
|
||||
DstFopts dstc_fopts_default(DstCompiler *c) {
|
||||
DstFopts ret;
|
||||
@ -792,15 +796,11 @@ DstSlot dstc_value(DstFopts opts, Dst x) {
|
||||
/* Compile a funcdef */
|
||||
DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
|
||||
DstScope scope = dst_v_last(c->scopes);
|
||||
DstFuncDef *def = dst_gcalloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||
def->source = NULL;
|
||||
def->sourcepath = NULL;
|
||||
def->sourcemap = NULL;
|
||||
DstFuncDef *def = dst_funcdef_alloc();
|
||||
def->slotcount = scope.smax + 1;
|
||||
|
||||
/* Copy envs */
|
||||
def->environments_length = dst_v_count(scope.envs);
|
||||
def->environments = NULL;
|
||||
if (def->environments_length > 1) def->environments = dst_v_flatten(scope.envs);
|
||||
|
||||
def->constants_length = dst_v_count(scope.consts);
|
||||
@ -897,24 +897,6 @@ DstCompileResult dst_compile(Dst source, DstTable *env, int flags) {
|
||||
return c.result;
|
||||
}
|
||||
|
||||
DstFunction *dst_compile_func(DstCompileResult res) {
|
||||
if (res.status != DST_COMPILE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
DstFunction *func = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||
func->def = res.funcdef;
|
||||
if (res.funcdef->flags & DST_FUNCDEF_FLAG_NEEDSENV) {
|
||||
func->envs = malloc(sizeof(DstFuncEnv *));
|
||||
if (NULL == func->envs) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
func->envs[0] = NULL;
|
||||
} else {
|
||||
func->envs = NULL;
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/* C Function for compiling */
|
||||
int dst_compile_cfun(DstArgs args) {
|
||||
DstCompileResult res;
|
||||
@ -930,7 +912,7 @@ int dst_compile_cfun(DstArgs args) {
|
||||
}
|
||||
res = dst_compile(args.v[0], env, 0);
|
||||
if (res.status == DST_COMPILE_OK) {
|
||||
DstFunction *fun = dst_compile_func(res);
|
||||
DstFunction *fun = dst_function(res.funcdef, NULL);
|
||||
return dst_return(args, dst_wrap_function(fun));
|
||||
} else {
|
||||
t = dst_table(2);
|
@ -25,7 +25,8 @@
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <setjmp.h>
|
||||
#include "opcodes.h"
|
||||
#include <dst/dstcompile.h>
|
||||
#include <dst/dstopcodes.h>
|
||||
|
||||
/* Compiler typedefs */
|
||||
typedef struct DstCompiler DstCompiler;
|
@ -22,9 +22,11 @@
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
#include <dst/dstcompile.h>
|
||||
#include <dst/dstparse.h>
|
||||
#include "compile.h"
|
||||
#include "gc.h"
|
||||
#include "util.h"
|
||||
#include <headerlibs/strbinsearch.h>
|
||||
#include <headerlibs/vector.h>
|
||||
|
||||
DstSlot dstc_quote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
|
||||
if (argn != 1) {
|
@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dstcontext.h>
|
||||
#include <dst/dstcompile.h>
|
||||
#include <dst/dstparse.h>
|
||||
|
||||
#define CHUNKSIZE 1024
|
||||
|
||||
@ -158,7 +159,7 @@ int dst_context_run(DstContext *c, int flags) {
|
||||
{
|
||||
DstCompileResult cres = dst_compile(dst_parser_produce(&parser), c->env, flags);
|
||||
if (cres.status == DST_COMPILE_OK) {
|
||||
DstFunction *f = dst_compile_func(cres);
|
||||
DstFunction *f = dst_function(cres.funcdef, NULL);
|
||||
Dst ret;
|
||||
if (dst_run(dst_wrap_function(f), &ret)) {
|
||||
/* Get location from stacktrace? */
|
@ -230,14 +230,19 @@ static int dst_io_fclose(DstArgs args) {
|
||||
#define dst_lib_io _dst_init
|
||||
#endif
|
||||
|
||||
static const DstReg cfuns[] = {
|
||||
{"fopen", dst_io_fopen},
|
||||
{"fclose", dst_io_fclose},
|
||||
{"fread", dst_io_fread},
|
||||
{"fwrite", dst_io_fwrite},
|
||||
{"fflush", dst_io_fflush},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
int dst_lib_io(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "fopen", dst_wrap_cfunction(dst_io_fopen));
|
||||
dst_env_def(env, "fclose", dst_wrap_cfunction(dst_io_fclose));
|
||||
dst_env_def(env, "fread", dst_wrap_cfunction(dst_io_fread));
|
||||
dst_env_def(env, "fwrite", dst_wrap_cfunction(dst_io_fwrite));
|
||||
dst_env_def(env, "fflush", dst_wrap_cfunction(dst_io_fflush));
|
||||
dst_env_cfuns(env, cfuns);
|
||||
|
||||
/* stdout */
|
||||
dst_env_def(env, "stdout",
|
@ -343,45 +343,50 @@ static int dst_math_not(DstArgs args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const DstReg cfuns[] = {
|
||||
{"int", dst_int},
|
||||
{"real", dst_real},
|
||||
{"+", dst_add},
|
||||
{"-", dst_subtract},
|
||||
{"*", dst_multiply},
|
||||
{"/", dst_divide},
|
||||
{"%", dst_modulo},
|
||||
{"=", dst_math_equal},
|
||||
{"not=", dst_math_notequal},
|
||||
{"<", dst_math_ascending},
|
||||
{">", dst_math_descending},
|
||||
{"<=", dst_math_notdescending},
|
||||
{">=", dst_math_notascending},
|
||||
{"|", dst_bor},
|
||||
{"&", dst_band},
|
||||
{"^", dst_bxor},
|
||||
{"~", dst_bnot},
|
||||
{">>", dst_lshift},
|
||||
{"<<", dst_rshift},
|
||||
{">>>", dst_lshiftu},
|
||||
{"not", dst_math_not},
|
||||
{"cos", dst_cos},
|
||||
{"sin", dst_sin},
|
||||
{"tan", dst_tan},
|
||||
{"acos", dst_acos},
|
||||
{"asin", dst_asin},
|
||||
{"atan", dst_atan},
|
||||
{"exp", dst_exp},
|
||||
{"log", dst_log},
|
||||
{"log10", dst_log10},
|
||||
{"sqrt", dst_sqrt},
|
||||
{"floor", dst_floor},
|
||||
{"ceil", dst_ceil},
|
||||
{"pow", dst_pow},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Module entry point */
|
||||
int dst_lib_math(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "int", dst_wrap_cfunction(dst_int));
|
||||
dst_env_def(env, "real", dst_wrap_cfunction(dst_real));
|
||||
dst_env_def(env, "+", dst_wrap_cfunction(dst_add));
|
||||
dst_env_def(env, "-", dst_wrap_cfunction(dst_subtract));
|
||||
dst_env_def(env, "*", dst_wrap_cfunction(dst_multiply));
|
||||
dst_env_def(env, "/", dst_wrap_cfunction(dst_divide));
|
||||
dst_env_def(env, "%", dst_wrap_cfunction(dst_modulo));
|
||||
dst_env_def(env, "=", dst_wrap_cfunction(dst_math_equal));
|
||||
dst_env_def(env, "not=", dst_wrap_cfunction(dst_math_notequal));
|
||||
dst_env_def(env, "<", dst_wrap_cfunction(dst_math_ascending));
|
||||
dst_env_def(env, ">", dst_wrap_cfunction(dst_math_descending));
|
||||
dst_env_def(env, "<=", dst_wrap_cfunction(dst_math_notdescending));
|
||||
dst_env_def(env, ">=", dst_wrap_cfunction(dst_math_notascending));
|
||||
dst_env_def(env, "|", dst_wrap_cfunction(dst_bor));
|
||||
dst_env_def(env, "&", dst_wrap_cfunction(dst_band));
|
||||
dst_env_def(env, "^", dst_wrap_cfunction(dst_bxor));
|
||||
dst_env_def(env, "~", dst_wrap_cfunction(dst_bnot));
|
||||
dst_env_def(env, ">>", dst_wrap_cfunction(dst_lshift));
|
||||
dst_env_def(env, "<<", dst_wrap_cfunction(dst_rshift));
|
||||
dst_env_def(env, ">>>", dst_wrap_cfunction(dst_lshiftu));
|
||||
dst_env_def(env, "not", dst_wrap_cfunction(dst_math_not));
|
||||
dst_env_def(env, "cos", dst_wrap_cfunction(dst_cos));
|
||||
dst_env_def(env, "sin", dst_wrap_cfunction(dst_sin));
|
||||
dst_env_def(env, "tan", dst_wrap_cfunction(dst_tan));
|
||||
dst_env_def(env, "acos", dst_wrap_cfunction(dst_acos));
|
||||
dst_env_def(env, "asin", dst_wrap_cfunction(dst_asin));
|
||||
dst_env_def(env, "atan", dst_wrap_cfunction(dst_atan));
|
||||
dst_env_def(env, "exp", dst_wrap_cfunction(dst_exp));
|
||||
dst_env_def(env, "log", dst_wrap_cfunction(dst_log));
|
||||
dst_env_def(env, "log10", dst_wrap_cfunction(dst_log10));
|
||||
dst_env_def(env, "sqrt", dst_wrap_cfunction(dst_sqrt));
|
||||
dst_env_def(env, "floor", dst_wrap_cfunction(dst_floor));
|
||||
dst_env_def(env, "ceil", dst_wrap_cfunction(dst_ceil));
|
||||
dst_env_def(env, "pow", dst_wrap_cfunction(dst_pow));
|
||||
dst_env_cfuns(env, cfuns);
|
||||
|
||||
dst_env_def(env, "pi", dst_wrap_real(3.1415926535897931));
|
||||
dst_env_def(env, "\xCF\x80", dst_wrap_real(3.1415926535897931));
|
||||
dst_env_def(env, "e", dst_wrap_real(2.7182818284590451));
|
||||
return 0;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
|
||||
/* Use LoadLibrary on windows or dlopen on posix to load dynamic libaries
|
||||
* with native code. */
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
#include <dst/dstasm.h>
|
||||
|
||||
int dst_stl_exit(DstArgs args) {
|
||||
int32_t exitcode = 0;
|
||||
@ -245,35 +246,39 @@ int dst_stl_hash(DstArgs args) {
|
||||
return dst_return(args, dst_wrap_integer(dst_hash(args.v[0])));
|
||||
}
|
||||
|
||||
static const DstReg cfuns[] = {
|
||||
{"native", dst_load_native},
|
||||
{"print", dst_stl_print},
|
||||
{"describe", dst_stl_describe},
|
||||
{"string", dst_stl_string},
|
||||
{"buffer-string", dst_stl_buffer_to_string},
|
||||
{"table", dst_cfun_table},
|
||||
{"array", dst_cfun_array},
|
||||
{"tuple", dst_cfun_tuple},
|
||||
{"struct", dst_cfun_struct},
|
||||
{"fiber", dst_stl_fiber},
|
||||
{"status", dst_stl_status},
|
||||
{"buffer", dst_stl_buffer},
|
||||
{"gensym", dst_stl_gensym},
|
||||
{"get", dst_stl_get},
|
||||
{"put", dst_stl_put},
|
||||
{"length", dst_stl_length},
|
||||
{"gccollect", dst_stl_gccollect},
|
||||
{"type", dst_stl_type},
|
||||
{"next", dst_stl_next},
|
||||
{"hash", dst_stl_hash},
|
||||
{"exit", dst_stl_exit},
|
||||
{"asm", dst_asm_cfun},
|
||||
{"disasm", dst_disasm_cfun},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DstTable *dst_stl_env() {
|
||||
DstTable *env = dst_table(0);
|
||||
Dst ret = dst_wrap_table(env);
|
||||
|
||||
dst_env_def(env, "native", dst_wrap_cfunction(dst_load_native));
|
||||
dst_env_def(env, "print", dst_wrap_cfunction(dst_stl_print));
|
||||
dst_env_def(env, "describe", dst_wrap_cfunction(dst_stl_describe));
|
||||
dst_env_def(env, "string", dst_wrap_cfunction(dst_stl_string));
|
||||
dst_env_def(env, "buffer-to-string", dst_wrap_cfunction(dst_stl_buffer_to_string));
|
||||
dst_env_def(env, "table", dst_wrap_cfunction(dst_cfun_table));
|
||||
dst_env_def(env, "array", dst_wrap_cfunction(dst_cfun_array));
|
||||
dst_env_def(env, "tuple", dst_wrap_cfunction(dst_cfun_tuple));
|
||||
dst_env_def(env, "struct", dst_wrap_cfunction(dst_cfun_struct));
|
||||
dst_env_def(env, "fiber", dst_wrap_cfunction(dst_stl_fiber));
|
||||
dst_env_def(env, "status", dst_wrap_cfunction(dst_stl_status));
|
||||
dst_env_def(env, "buffer", dst_wrap_cfunction(dst_stl_buffer));
|
||||
dst_env_def(env, "gensym", dst_wrap_cfunction(dst_stl_gensym));
|
||||
dst_env_def(env, "get", dst_wrap_cfunction(dst_stl_get));
|
||||
dst_env_def(env, "put", dst_wrap_cfunction(dst_stl_put));
|
||||
dst_env_def(env, "length", dst_wrap_cfunction(dst_stl_length));
|
||||
dst_env_def(env, "gccollect", dst_wrap_cfunction(dst_stl_gccollect));
|
||||
dst_env_def(env, "type", dst_wrap_cfunction(dst_stl_type));
|
||||
dst_env_def(env, "next", dst_wrap_cfunction(dst_stl_next));
|
||||
dst_env_def(env, "hash", dst_wrap_cfunction(dst_stl_hash));
|
||||
dst_env_def(env, "exit", dst_wrap_cfunction(dst_stl_exit));
|
||||
|
||||
dst_env_def(env, "compile", dst_wrap_cfunction(dst_compile_cfun));
|
||||
dst_env_def(env, "asm", dst_wrap_cfunction(dst_asm_cfun));
|
||||
dst_env_def(env, "disasm", dst_wrap_cfunction(dst_disasm_cfun));
|
||||
/* Load main functions */
|
||||
dst_env_cfuns(env, cfuns);
|
||||
|
||||
/* Allow references to the environment */
|
||||
dst_env_def(env, "_env", ret);
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include "util.h"
|
||||
#include "gc.h"
|
||||
|
||||
/* Base 64 lookup table for digits */
|
||||
const char dst_base64[65] =
|
||||
@ -51,6 +52,16 @@ const char *dst_type_names[16] = {
|
||||
"abstract"
|
||||
};
|
||||
|
||||
/* Calculate hash for string */
|
||||
|
||||
int32_t dst_string_calchash(const uint8_t *str, int32_t len) {
|
||||
const uint8_t *end = str + len;
|
||||
uint32_t hash = 5381;
|
||||
while (str < end)
|
||||
hash = (hash << 5) + hash + *str++;
|
||||
return (int32_t) hash;
|
||||
}
|
||||
|
||||
/* Computes hash of an array of values */
|
||||
int32_t dst_array_calchash(const Dst *array, int32_t len) {
|
||||
const Dst *end = array + len;
|
||||
@ -72,15 +83,6 @@ int32_t dst_kv_calchash(const DstKV *kvs, int32_t len) {
|
||||
return (int32_t) hash;
|
||||
}
|
||||
|
||||
/* Calculate hash for string */
|
||||
int32_t dst_string_calchash(const uint8_t *str, int32_t len) {
|
||||
const uint8_t *end = str + len;
|
||||
uint32_t hash = 5381;
|
||||
while (str < end)
|
||||
hash = (hash << 5) + hash + *str++;
|
||||
return (int32_t) hash;
|
||||
}
|
||||
|
||||
/* Calculate next power of 2. May overflow. If n is 0,
|
||||
* will return 0. */
|
||||
int32_t dst_tablen(int32_t n) {
|
||||
@ -123,6 +125,14 @@ void dst_env_var(DstTable *env, const char *name, Dst val) {
|
||||
dst_table_put(env, dst_csymbolv(name), dst_wrap_table(subt));
|
||||
}
|
||||
|
||||
/* Load many cfunctions at once */
|
||||
void dst_env_cfuns(DstTable *env, const DstReg *cfuns) {
|
||||
while (cfuns->name) {
|
||||
dst_env_def(env, cfuns->name, dst_wrap_cfunction(cfuns->cfun));
|
||||
cfuns++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve a symbol in the environment. Undefined symbols will
|
||||
* resolve to nil */
|
||||
Dst dst_env_resolve(DstTable *env, const char *name) {
|
||||
@ -148,32 +158,6 @@ DstTable *dst_env_arg(DstArgs args) {
|
||||
return module;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
while (low < hi) {
|
||||
size_t mid = low + ((hi - low) / 2);
|
||||
const char **item = (const char **)(tab + 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;
|
||||
}
|
||||
|
||||
/* Read both tuples and arrays as c pointers + int32_t length. Return 1 if the
|
||||
* view can be constructed, 0 if an invalid type. */
|
||||
int dst_seq_view(Dst seq, const Dst **data, int32_t *len) {
|
||||
@ -222,56 +206,46 @@ int dst_hashtable_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Vector code */
|
||||
|
||||
/* 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)); // try to force a NULL pointer exception later
|
||||
}
|
||||
/* Allocate an empty funcdef. This function may have added functionality
|
||||
* as commonalities between asm and compile arise. */
|
||||
DstFuncDef *dst_funcdef_alloc() {
|
||||
DstFuncDef *def = dst_gcalloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||
def->environments = NULL;
|
||||
def->constants = NULL;
|
||||
def->bytecode = NULL;
|
||||
def->flags = 0;
|
||||
def->slotcount = 0;
|
||||
def->arity = 0;
|
||||
def->source = NULL;
|
||||
def->sourcepath = NULL;
|
||||
def->sourcemap = NULL;
|
||||
def->defs = NULL;
|
||||
def->defs_length = 0;
|
||||
def->constants_length = 0;
|
||||
def->bytecode_length = 0;
|
||||
def->environments_length = 1;
|
||||
return def;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
{
|
||||
/* Create a closure from a funcdef and a parent function */
|
||||
DstFunction *dst_function(DstFuncDef *def, DstFunction *parent) {
|
||||
int32_t i;
|
||||
DstFunction *func = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||
int32_t elen = def->environments_length;
|
||||
func->def = def;
|
||||
if (elen) {
|
||||
func->envs = malloc(sizeof(DstFuncEnv *) * elen);
|
||||
if (elen > 1 && !parent) return NULL;
|
||||
if (NULL == func->envs) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
func->envs[0] = NULL;
|
||||
} else {
|
||||
{
|
||||
DST_OUT_OF_MEMORY;
|
||||
func->envs = NULL;
|
||||
}
|
||||
return NULL;
|
||||
for (i = 1; i < def->environments_length; ++i) {
|
||||
int32_t inherit = def->environments[i];
|
||||
func->envs[i] = parent->envs[inherit];
|
||||
}
|
||||
return func;
|
||||
}
|
@ -20,12 +20,16 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Header for unit testing of dst components */
|
||||
|
||||
#ifndef UNIT_H_U09UBW3V
|
||||
#define UNIT_H_U09UBW3V
|
||||
#ifndef DST_UTIL_H_defined
|
||||
#define DST_UTIL_H_defined
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <assert.h>
|
||||
|
||||
#endif /* end of include guard: UNIT_H_U09UBW3V */
|
||||
/* Utils */
|
||||
extern const char dst_base64[65];
|
||||
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);
|
||||
|
||||
#endif
|
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include "opcodes.h"
|
||||
#include <dst/dstopcodes.h>
|
||||
#include "symcache.h"
|
||||
#include "gc.h"
|
||||
|
||||
@ -422,28 +422,10 @@ static int dst_continue(Dst *returnreg) {
|
||||
|
||||
case DOP_CLOSURE:
|
||||
{
|
||||
int32_t i, elen;
|
||||
DstFunction *fn;
|
||||
DstFuncDef *fd;
|
||||
vm_assert((int32_t)oparg(2, 0xFFFF) < func->def->defs_length, "invalid funcdef");
|
||||
fd = func->def->defs[(int32_t)oparg(2, 0xFFFF)];
|
||||
fn = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||
fn->def = fd;
|
||||
elen = fd->environments_length;
|
||||
if (elen) {
|
||||
fn->envs = malloc(sizeof(DstFuncEnv *) * elen);
|
||||
if (NULL == fn->envs) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
fn->envs[0] = NULL;
|
||||
} else {
|
||||
fn->envs = NULL;
|
||||
}
|
||||
for (i = 1; i < fd->environments_length; ++i) {
|
||||
int32_t inherit = fd->environments[i];
|
||||
fn->envs[i] = func->envs[inherit];
|
||||
}
|
||||
stack[oparg(1, 0xFF)] = dst_wrap_function(fn);
|
||||
stack[oparg(1, 0xFF)] = dst_wrap_function(dst_function(fd, func));
|
||||
pc++;
|
||||
vm_checkgc_next();
|
||||
}
|
@ -20,36 +20,33 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_STATE_H_defined
|
||||
#define DST_STATE_H_defined
|
||||
#ifndef DST_STRBINSEARCH_H_defined
|
||||
#define DST_STRBINSEARCH_H_defined
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dstconfig.h"
|
||||
#include "dsttypes.h"
|
||||
/* 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;
|
||||
while (low < hi) {
|
||||
size_t mid = low + ((hi - low) / 2);
|
||||
const char **item = (const char **)(tab + 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;
|
||||
}
|
||||
|
||||
/* Names of all of the types */
|
||||
extern const char *dst_type_names[16];
|
||||
|
||||
/* The VM state. Rather than a struct that is passed
|
||||
* around, the vm state is global for simplicity. */
|
||||
|
||||
/* Garbage collection */
|
||||
extern void *dst_vm_blocks;
|
||||
extern uint32_t dst_vm_gc_interval;
|
||||
extern uint32_t dst_vm_next_collection;
|
||||
|
||||
/* Immutable value cache */
|
||||
extern const uint8_t **dst_vm_cache;
|
||||
extern uint32_t dst_vm_cache_capacity;
|
||||
extern uint32_t dst_vm_cache_count;
|
||||
extern uint32_t dst_vm_cache_deleted;
|
||||
|
||||
/* GC roots */
|
||||
extern Dst *dst_vm_roots;
|
||||
extern uint32_t dst_vm_root_count;
|
||||
extern uint32_t dst_vm_root_capacity;
|
||||
|
||||
/* GC roots - TODO consider a top level fiber pool (per thread?) */
|
||||
extern DstFiber *dst_vm_fiber;
|
||||
|
||||
#endif /* DST_STATE_H_defined */
|
||||
#endif
|
@ -20,31 +20,8 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DST_UTIL_H_defined
|
||||
#define DST_UTIL_H_defined
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
/* Utils internal to dst. */
|
||||
|
||||
/* Type check Dst C Function arguments */
|
||||
typedef struct DstCSig {
|
||||
int32_t flags;
|
||||
DstAbstractType abs;
|
||||
} DstCSig;
|
||||
|
||||
/* Utils */
|
||||
extern const char dst_base64[65];
|
||||
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);
|
||||
int dst_cstrcmp(const uint8_t *str, const char *other);
|
||||
const void *dst_strbinsearch(
|
||||
const void *tab,
|
||||
size_t tabcount,
|
||||
size_t itemsize,
|
||||
const uint8_t *key);
|
||||
#ifndef DST_VECTOR_H_defined
|
||||
#define DST_VECTOR_H_defined
|
||||
|
||||
/*
|
||||
* vector code modified from
|
||||
@ -73,8 +50,63 @@ const void *dst_strbinsearch(
|
||||
#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))))
|
||||
|
||||
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);
|
||||
|
||||
/* Vector code */
|
||||
|
||||
/* Grow the buffer dynamically. Used for push operations. */
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
#endif
|
@ -23,7 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dstcontext.h>
|
||||
#include <dst/dstcompile.h>
|
||||
|
||||
#define DST_CLIENT_HELP 1
|
||||
#define DST_CLIENT_VERBOSE 2
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dstparse.h>
|
||||
|
||||
/* Mark an ast node */
|
||||
static int dst_ast_gcmark(void *p, size_t size) {
|
@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include "util.h"
|
||||
#include <dst/dstparse.h>
|
||||
#include <headerlibs/vector.h>
|
||||
|
||||
/* Quote a value */
|
||||
static Dst quote(Dst x) {
|
||||
@ -450,6 +451,7 @@ int dst_parser_consume(DstParser *parser, uint8_t c) {
|
||||
consumed = state->consumer(parser, state, c);
|
||||
}
|
||||
parser->lookback = c;
|
||||
parser->index++;
|
||||
return 1;
|
||||
}
|
||||
|
7
src/testlib/testlib.c
Normal file
7
src/testlib/testlib.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <dst/dst.h>
|
||||
|
||||
int dst_init_(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "pi", dst_wrap_real(M_PI));
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user