diff --git a/README.md b/README.md index c805bd21..588fe8dc 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,21 @@ $ ## Compiling and Running -Dst is built using CMake. There used to be a hand-written Makefile, but in the interest of -easier Windows support I have switched to CMake. +Dst can be built with Make or CMake. +Use Make if you are on a posix system and don't like CMake. +Use CMake if you are on Windows or like CMake. -On a posix system using make, compiling and running is as follows (this is the same as +### Make + +```sh +cd somewhere/my/projects/dst +make +make test +``` + +### CMake + +On a posix system using make as the backend, compiling and running is as follows (this is the same as most CMake based projects). ### Build diff --git a/cmake/dstmainclientinit.cmake b/cmake/dstmainclientinit.cmake index e5135659..356846a4 100644 --- a/cmake/dstmainclientinit.cmake +++ b/cmake/dstmainclientinit.cmake @@ -1,9 +1,9 @@ -# Include bin2h cmake codeo +# Include bin2h cmake code set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") include(bin2h) bin2h ( SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../src/mainclient/init.dst - HEADER_FILE "clientinit.h" - VARIABLE_NAME "dst_mainclient_init" + HEADER_FILE "clientinit.gen.h" + VARIABLE_NAME dst_mainclient_init ) diff --git a/cmake/dststlbootstrap.cmake b/cmake/dststlbootstrap.cmake index 70ed6777..a6938858 100644 --- a/cmake/dststlbootstrap.cmake +++ b/cmake/dststlbootstrap.cmake @@ -1,9 +1,9 @@ -# Include bin2h cmake codeo +# Include bin2h cmake code set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") include(bin2h) bin2h ( SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../src/compiler/boot.dst - HEADER_FILE "dststlbootstrap.h" + HEADER_FILE "dststlbootstrap.gen.h" VARIABLE_NAME dst_stl_bootstrap_gen ) diff --git a/examples/assembly.dst b/examples/assembly.dst index ef72766f..c77c7377 100644 --- a/examples/assembly.dst +++ b/examples/assembly.dst @@ -1,4 +1,4 @@ -# Example of dst assembly +# Example of dst bytecode assembly # Fibonacci sequence, implemented with naive recursion. (def fibasm (asm '{ diff --git a/examples/lazyseqs.dst b/examples/lazyseqs.dst index 026ec48b..b4f26aa4 100644 --- a/examples/lazyseqs.dst +++ b/examples/lazyseqs.dst @@ -1,24 +1,28 @@ # An example implementation of functional, lazy -# sequences, like in clojure. +# sequences, as in clojure. The lazy seq is essentially +# A lazy linked list, where the next value is a function +# that must be called (realizing it), and the memoized. # Use with (import "./path/to/this/file" :prefix "seq/") -(defn- mem0 [f] - "Memoize a 0 arity function." - (var state nil) - (var loaded nil) - (fn [] - (if loaded - state - (do - (def n (f)) - (:= state n) - (:= loaded true) - n)))) - -# This creates one more closure than necessary but oh well +# This shows the need for syntax quoting D: (defmacro delay - "Macro for lazy evaluation" - [& forms] (tuple mem0 (apply1 tuple (array-concat ['fn []] forms)))) + "Macro for lazy evaluation. Returns a function that will evaluate +the body when invoked. If called a second time, will return the first return value +that was memoized." + [& forms] + (def $state (gensym "state")) + (def $loaded (gensym "loaded")) + (def $temp (gensym "temp")) + (tuple 'do + (tuple 'var $state nil) + (tuple 'var $loaded nil) + (tuple 'fn [] + (tuple 'if $loaded $state + (tuple 'do + (tuple 'def $temp (tuple-prepend forms 'do)) + (tuple := $state $temp) + (tuple := $loaded true) + $temp))))) # Use tuples instead of structs to save memory (def HEAD :private 0) @@ -33,11 +37,6 @@ [h t] (delay (tuple h t))) -(defn cons1 - "Create a new sequence cons by prepending a value to the original sequence." - [h t] - (tuple h t)) - (defn empty? "Check if a sequence is empty." [s] @@ -95,6 +94,11 @@ (cons (head s) (take (- n 1) (tail s))) empty-seq)) +(defn randseq + "Return a sequence of random numbers." + [] + (delay (tuple (random) (randseq)))) + (defn take-while "Returns a sequence of values until the predicate is false." [pred s] diff --git a/src/assembler/asm.c b/src/assembler/asm.c index db8a8b62..3bf44f37 100644 --- a/src/assembler/asm.c +++ b/src/assembler/asm.c @@ -324,8 +324,8 @@ static uint32_t doarg( int32_t arg = doarg_1(a, argtype, x); /* Calculate the min and max values that can be stored given * nbytes, and whether or not the storage is signed */ - int32_t min = (-hassign) << ((nbytes << 3) - 1); - int32_t max = ~((-1) << ((nbytes << 3) - hassign)); + int32_t max = (1 << ((nbytes << 3) - hassign)) - 1; + int32_t min = hassign ? -max - 1 : 0; if (arg < min) dst_asm_errorv(a, dst_formatc("instruction argument %v is too small, must be %d byte%s", x, nbytes, nbytes > 1 ? "s" : "")); diff --git a/src/compiler/boot.dst b/src/compiler/boot.dst index 19cd2104..ffdd8a41 100644 --- a/src/compiler/boot.dst +++ b/src/compiler/boot.dst @@ -415,15 +415,19 @@ onvalue." {:more more :next next}) (fn [env chunks onvalue onerr] (defn doone [source] + (var good true) (def f (fiber (fn [] (def res (compile source env)) (if (= (type res) :function) (res) - (onerr "compile" (get res :error)))))) + (do + (:= good false) + (onerr "compile" (get res :error))))))) (def res (resume f)) - (if (= (fiber-status f) :error) - (onerr "runtime" res) - (onvalue res))) + (if good + (if (= (fiber-status f) :error) + (onerr "runtime" res) + (onvalue res)))) (foreach (val-stream chunks onerr) doone) env))) diff --git a/src/compiler/compile.c b/src/compiler/compile.c index 1c4c5d2d..62f8964d 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -378,9 +378,10 @@ static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) { DOP_LOAD_INTEGER); break; } - /* fallthrough */ + goto do_constant; } default: + do_constant: { int32_t cindex = dstc_const(c, ast, k); dstc_emit(c, ast, diff --git a/src/compiler/stl.c b/src/compiler/stl.c index 89f67bfc..15584f60 100644 --- a/src/compiler/stl.c +++ b/src/compiler/stl.c @@ -28,7 +28,7 @@ #include /* Generated header */ -#include "dststlbootstrap.h" +#include "dststlbootstrap.gen.h" static const DstReg cfuns[] = { {"native", dst_core_native}, diff --git a/src/core/symcache.c b/src/core/symcache.c index c9d67402..e81e8fcb 100644 --- a/src/core/symcache.c +++ b/src/core/symcache.c @@ -219,8 +219,8 @@ static void inc_counter(uint8_t *digits, int base, int len) { * symbol will be of the format prefix--XXXXXX, where X is a base64 digit, and * prefix is the argument passed. */ const uint8_t *dst_symbol_gen(const uint8_t *buf, int32_t len) { - const uint8_t **bucket; - int32_t hash; + const uint8_t **bucket = NULL; + int32_t hash = 0; uint8_t counter[6] = {63, 63, 63, 63, 63, 63}; /* Leave spaces for 6 base 64 digits and two dashes. That means 64^6 possible suffixes, which * is enough for resolving collisions. */ diff --git a/src/core/vm.c b/src/core/vm.c index c9035769..3cbbbbc3 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -810,7 +810,7 @@ int dst_init() { * a collection pretty much every cycle, which is * horrible for performance, but helps ensure * there are no memory bugs during dev */ - dst_vm_gc_interval = 0x100000; + dst_vm_gc_interval = 0x10000; dst_symcache_init(); /* Initialize gc roots */ dst_vm_roots = NULL; diff --git a/src/mainclient/line.c b/src/mainclient/line.c index b20502b7..582356ff 100644 --- a/src/mainclient/line.c +++ b/src/mainclient/line.c @@ -71,13 +71,13 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c #include #include #include -#include #include #include #include #include #include #include +#include #include @@ -103,6 +103,15 @@ static const char *badterms[] = { NULL }; +static char *sdup(const char *s) { + size_t len = strlen(s) + 1; + char *mem = malloc(len); + if (!mem) { + return NULL; + } + return memcpy(mem, s, len); +} + /* Ansi terminal raw mode */ static int rawmode() { struct termios t; @@ -227,7 +236,7 @@ static int insert(char c) { static void historymove(int delta) { if (dst_v_count(history) > 1) { free(history[historyi]); - history[historyi] = strdup(buf); + history[historyi] = sdup(buf); historyi += delta; if (historyi < 0) { @@ -247,7 +256,7 @@ static void historymove(int delta) { static void addhistory() { int i, len; - char *newline = strdup(buf); + char *newline = sdup(buf); if (!newline) return; len = dst_v_count(history); if (len < DST_HISTORY_MAX) { @@ -261,7 +270,7 @@ static void addhistory() { } static void replacehistory() { - char *newline = strdup(buf); + char *newline = sdup(buf); if (!newline) return; history[0] = newline; } @@ -418,7 +427,7 @@ static int checktermsupport() { int i; if (!t) return 1; for (i = 0; badterms[i]; i++) - if (!strcasecmp(t, badterms[i])) return 0; + if (!strcmp(t, badterms[i])) return 0; return 1; } diff --git a/src/mainclient/main.c b/src/mainclient/main.c index 582696e5..7ef104c2 100644 --- a/src/mainclient/main.c +++ b/src/mainclient/main.c @@ -23,7 +23,7 @@ #include #include -#include "clientinit.h" +#include "clientinit.gen.h" #include "line.h" int main(int argc, char **argv) { diff --git a/thoughts.md b/thoughts.md index b4694eb1..feb331dd 100644 --- a/thoughts.md +++ b/thoughts.md @@ -16,10 +16,6 @@ A collection of thoughts and todo tasks for the project. which potentially duplicates a fair amount of data. Macros would be easier to write without needing to either unwrap ast values or sacrifice all source mapping. -- Keep track of source file information in the compiler. The compiler could simply accept - and extra argument, sourcefile, which woud append the appropriate metadata to all function - definitions generated with this one form. - - Serialization and deserialization of all datatypes. This would allow loading of bytecode without needing the compiler present. However, loading C functions is currently problematic. C functions could perhaps be wrapped in data structures that contain some meta information @@ -44,6 +40,10 @@ A collection of thoughts and todo tasks for the project. changing certain values of a metatables after it is set, such as gc, for performance reasons. + Currently, tables can have a prototype table, which is used to look up values recursively if they + are not found in the original table. This provides a partial solution to custom user types, + but does not have the felxibility of Lua style metatables. + - Actually make a debugger. While the VM changes to enable debugging are relatively simple, make a useful debugger would be another project. At first, simply inspection of the generated bytecode assembly would be a good start. Single stepping, continuation,