Major refactor and restructure. Add CMake for anticipated windows

support.
This commit is contained in:
bakpakin 2018-01-19 16:43:19 -05:00
parent acb706ca3a
commit 30f62ca454
61 changed files with 400 additions and 4638 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Target
/client/dst
dst
build
# Generated files
*.gen.h

104
CMakeLists.txt Normal file
View 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)

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)))

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1 +0,0 @@
#include <dst/dst.h>

View File

@ -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));
}

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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? */

View File

@ -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",

View File

@ -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;
}

View File

@ -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. */

View File

@ -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);

View File

@ -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;
/* 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;
}
func->envs[0] = NULL;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
func->envs = NULL;
}
}
/* Convert a buffer to normal allocated memory (forget capacity) */
void *dst_v_flattenmem(void *v, int32_t itemsize) {
int32_t *p;
int32_t sizen;
if (NULL == v) return NULL;
sizen = itemsize * dst_v__cnt(v);
p = malloc(sizen);
if (NULL != p) {
memcpy(p, v, sizen);
return p;
} else {
{
DST_OUT_OF_MEMORY;
}
return NULL;
for (i = 1; i < def->environments_length; ++i) {
int32_t inherit = def->environments[i];
func->envs[i] = parent->envs[inherit];
}
return func;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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
View 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;
}