diff --git a/CMakeLists.txt b/CMakeLists.txt index 255bda5f..944dc0ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,18 @@ set (CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") include_directories(src/include) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# Make tools for generating embeddable headers +add_executable(xxd src/tools/xxd.c) + +# Generate header containing standard library +add_custom_command( + OUTPUT dststlbootstrap.h + COMMAND xxd ${CMAKE_CURRENT_SOURCE_DIR}/src/compiler/boot.dst dststlbootstrap.h dst_stl_bootstrap_gen + DEPENDS xxd src/compiler/boot.dst + COMMENT "Generating stl bootstrap C header for embedding" +) set(ASSEMBLER_SOURCES src/assembler/asm.c @@ -38,6 +50,7 @@ src/compiler/specials.c src/compiler/cfuns.c src/compiler/context.c src/compiler/stl.c +dststlbootstrap.h src/compiler/compile.h ) diff --git a/src/compiler/boot.dst b/src/compiler/boot.dst new file mode 100644 index 00000000..06cb6103 --- /dev/null +++ b/src/compiler/boot.dst @@ -0,0 +1,78 @@ +(def defmacro macro + (fn [name & more] (tuple 'def name 'macro (tuple-prepend (tuple-prepend more name) 'fn)))) + +(defmacro defn + [name & more] + (tuple 'def name (tuple-prepend (tuple-prepend more name) 'fn))) + +(defmacro when + [cond & body] + (tuple 'if cond (tuple-prepend body 'do))) + +(def seq (do + (defn array-seq [x] + (def len (length x)) + (var i 0) + { + :more (fn [] (< i len)) + :next (fn [] + (def ret (get x i)) + (varset! i (+ i 1)) + ret) + }) + (def seqs { + :array array-seq + :tuple array-seq + :struct (fn [x] x)}) + (fn [x] + (def makeseq (get seqs (type x))) + (if makeseq (makeseq x) (error "expected sequence"))))) + +(defn range [top] + (var i 0) + { + :more (fn [] (< i top)) + :next (fn [] + (def ret i) + (varset! i (+ i 1)) + ret) + }) + +(defn doseq [s] + (def s (seq s)) + (def more? (get s :more)) + (def getnext (get s :next)) + (while (more?) + (getnext))) + +(defn map [f s] + (def s (seq s)) + (def more (get s :more)) + (def getnext (get s :next)) + { + :more more + :next (fn [] (f (getnext))) + }) + +(defn reduce [f start s] + (def s (seq s)) + (def more? (get s :more)) + (def getnext (get s :next)) + (var ret start) + (while (more?) + (varset! ret (f ret (getnext)))) + ret) + +(defmacro for [head & body] + (def head (ast-unwrap head)) + (def sym (get head 0)) + (def start (get head 1)) + (def end (get head 2)) + (def _inc (get head 3)) + (def inc (if _inc _inc 1)) + (tuple 'do + (tuple 'var sym start) + (tuple 'while (tuple '< sym end) + (tuple-prepend body 'do) + (tuple 'varset! sym (tuple '+ sym 1)) + ))) diff --git a/src/compiler/context.c b/src/compiler/context.c index bd7fda9c..9ff7ec84 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -45,21 +45,40 @@ static int replread(DstContext *c, enum DstParserStatus status) { return 0; } -static int cstringread(DstContext *c, enum DstParserStatus status) { - char *src = (char *)(c->user); +static int bytesread(DstContext *c, enum DstParserStatus status) { + const uint8_t *src = (const uint8_t *)(c->user); (void) status; + int32_t n = CHUNKSIZE; DstBuffer *b = &c->buffer; - if (!b->capacity) { - dst_buffer_ensure(b, CHUNKSIZE); - } - if (!*src) return 1; - while (*src && b->count < b->capacity) { - dst_buffer_push_u8(b, *src++); - } - if (!*src) { + b->count = 0; + if (!c->bufsize) { dst_buffer_push_u8(b, '\n'); + return 1; } - c->user = src; + if (c->bufsize < n) n = c->bufsize; + dst_buffer_push_bytes(b, src, n); + c->bufsize -= n; + c->user = (void *)(src + n); + return 0; +} + +/* Chunk readers */ +static void filedeinit(DstContext *c) { + fclose((FILE *) (c->user)); +} + +/* Read chunk from file */ +static int32_t fileread(DstContext *c, enum DstParserStatus status) { + size_t nread; + FILE *f = (FILE *) c->user; + (void) status; + c->buffer.count = 0; + dst_buffer_ensure(&c->buffer, CHUNKSIZE); + nread = fread(c->buffer.data, 1, CHUNKSIZE, f); + if (nread != CHUNKSIZE && ferror(f)) { + return -1; + } + c->buffer.count = (int32_t) nread; return 0; } @@ -90,23 +109,6 @@ static void simpleerror(DstContext *c, enum DstContextErrorType type, Dst err, s dst_puts(dst_formatc("%s error: %s\n", errtype, dst_to_string(err))); } -static void filedeinit(DstContext *c) { - fclose((FILE *) (c->user)); -} - -static int fileread(DstContext *c, enum DstParserStatus status) { - size_t nread; - FILE *f = (FILE *) c->user; - (void) status; - dst_buffer_ensure(&c->buffer, CHUNKSIZE); - nread = fread(c->buffer.data, 1, CHUNKSIZE, f); - if (nread != CHUNKSIZE && ferror(f)) { - return -1; - } - c->buffer.count = (int32_t) nread; - return 0; -} - void dst_context_init(DstContext *c, DstTable *env) { dst_buffer_init(&c->buffer, CHUNKSIZE); c->env = env; @@ -147,10 +149,11 @@ int dst_context_file(DstContext *c, DstTable *env, const char *path) { return 0; } -int dst_context_cstring(DstContext *c, DstTable *env, const char *source) { +int dst_context_bytes(DstContext *c, DstTable *env, const uint8_t *bytes, int32_t len) { dst_context_init(c, env); - c->user = (void *) source; - c->read_chunk = cstringread; + c->user = (void *) bytes; + c->bufsize = len; + c->read_chunk = bytesread; return 0; } diff --git a/src/compiler/stl.c b/src/compiler/stl.c index c4cf5a9e..ce995f9b 100644 --- a/src/compiler/stl.c +++ b/src/compiler/stl.c @@ -27,13 +27,16 @@ #include #include +/* Generated header */ +#include "dststlbootstrap.h" + static const DstReg cfuns[] = { {"native", dst_core_native}, {"print", dst_core_print}, {"describe", dst_core_describe}, {"string", dst_core_string}, {"symbol", dst_core_symbol}, - {"buffer-string", dst_core_buffer_to_string}, + {"buffer", dst_core_buffer}, {"table", dst_core_table}, {"array", dst_core_array}, {"tuple", dst_core_tuple}, @@ -53,10 +56,7 @@ static const DstReg cfuns[] = { {NULL, NULL} }; -static const char *bootstrap = -"(def defmacro macro (fn [name & more] (tuple 'def name 'macro (tuple-prepend (tuple-prepend more name) 'fn))))\n" -"(defmacro defn [name & more] (tuple 'def name (tuple-prepend (tuple-prepend more name) 'fn)))\n" -"(defmacro when [cond & body] (tuple 'if cond (tuple-prepend body 'do)))\n"; +#include DstTable *dst_stl_env() { static uint32_t error_asm[] = { @@ -116,7 +116,7 @@ DstTable *dst_stl_env() { /* Run bootstrap source */ { DstContext ctxt; - dst_context_cstring(&ctxt, env, bootstrap); + dst_context_bytes(&ctxt, env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen)); dst_context_run(&ctxt, 0); } diff --git a/src/core/corelib.c b/src/core/corelib.c index 05f86517..ea68dc3f 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -55,8 +55,9 @@ int dst_core_describe(DstArgs args) { for (j = 0; j < len; ++j) { putc(vstr[j], stdout); } + putc('\n', stdout); } - putc('\n', stdout); + if (!i) putc('\n', stdout); return 0; } @@ -90,12 +91,16 @@ int dst_core_symbol(DstArgs args) { return 0; } -int dst_core_buffer_to_string(DstArgs args) { - DstBuffer *b; - if (args.n != 1) return dst_throw(args, "expected 1 argument"); - if (!dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer"); - b = dst_unwrap_buffer(args.v[0]); - return dst_return(args, dst_wrap_string(dst_string(b->data, b->count))); +int dst_core_buffer(DstArgs args) { + int32_t i; + DstBuffer *b = dst_buffer(0); + for (i = 0; i < args.n; ++i) { + int32_t len; + const uint8_t *str = dst_to_string(args.v[i]); + len = dst_string_length(str); + dst_buffer_push_bytes(b, str, len); + } + return dst_return(args, dst_wrap_buffer(b)); } int dst_core_tuple(DstArgs args) { @@ -139,17 +144,6 @@ int dst_core_fiber(DstArgs args) { return dst_return(args, dst_wrap_fiber(fiber)); } -int dst_core_buffer(DstArgs args) { - DstBuffer *buffer = dst_buffer(10); - int32_t i; - for (i = 0; i < args.n; ++i) { - const uint8_t *bytes = dst_to_string(args.v[i]); - int32_t len = dst_string_length(bytes); - dst_buffer_push_bytes(buffer, bytes, len); - } - return dst_return(args, dst_wrap_buffer(buffer)); -} - int dst_core_gensym(DstArgs args) { if (args.n > 1) return dst_throw(args, "expected one argument"); if (args.n == 0) { diff --git a/src/include/dst/dstcompile.h b/src/include/dst/dstcompile.h index 0bc0e2b9..a0e38cfa 100644 --- a/src/include/dst/dstcompile.h +++ b/src/include/dst/dstcompile.h @@ -45,6 +45,7 @@ struct DstCompileResult { }; DstCompileResult dst_compile(Dst source, DstTable *env, int flags); int dst_compile_cfun(DstArgs args); +int dst_lib_compile(DstArgs args); /* Context - for executing dst in the interpretted form. */ typedef struct DstContext DstContext; @@ -52,13 +53,17 @@ typedef struct DstContext DstContext; /* Get the default environment for dst */ DstTable *dst_stl_env(); +/* Different levels of reporting and configuration */ void dst_context_init(DstContext *c, DstTable *env); -void dst_context_deinit(DstContext *c); -int dst_context_repl(DstContext *c, DstTable *env); int dst_context_file(DstContext *c, DstTable *env, const char *path); -int dst_context_cstring(DstContext *c, DstTable *env, const char *source); +int dst_context_repl(DstContext *c, DstTable *env); +int dst_context_bytes(DstContext *c, DstTable *env, const uint8_t *bytes, int32_t len); + +/* Evaluate a form in the context */ int dst_context_run(DstContext *c, int flags); +void dst_context_deinit(DstContext *c); + /* Parse structs */ enum DstContextErrorType { DST_CONTEXT_ERROR_PARSE, @@ -72,6 +77,7 @@ struct DstContext { DstTable *env; DstBuffer buffer; void *user; + int32_t bufsize; int32_t index; int (*read_chunk)(DstContext *self, enum DstParserStatus status); @@ -80,8 +86,6 @@ struct DstContext { void (*deinit)(DstContext *self); }; -int dst_lib_compile(DstArgs args); - #ifdef __cplusplus } #endif diff --git a/src/include/dst/dstcorelib.h b/src/include/dst/dstcorelib.h index a86f16ac..ee6337ae 100644 --- a/src/include/dst/dstcorelib.h +++ b/src/include/dst/dstcorelib.h @@ -20,8 +20,8 @@ * IN THE SOFTWARE. */ -#ifndef DST_MATH_H_defined -#define DST_MATH_H_defined +#ifndef DST_CORELIB_H_defined +#define DST_CORELIB_H_defined #ifdef __cplusplus extern "C" { @@ -29,12 +29,6 @@ extern "C" { #include "dsttypes.h" -/* Basic C Functions. These are good - * candidates for optimizations like bytecode - * inlining and costant folding. They are exposed publicly - * so that compiles can inject them into funcdefs. Later, a - * different serialization mechanism might be used for cfunctions. */ - /* Native */ int dst_core_native(DstArgs args); @@ -80,7 +74,7 @@ int dst_core_print(DstArgs args); int dst_core_describe(DstArgs args); int dst_core_string(DstArgs args); int dst_core_symbol(DstArgs args); -int dst_core_buffer_to_string(DstArgs args); +int dst_core_buffer(DstArgs args); int dst_core_tuple(DstArgs args); int dst_core_array(DstArgs args); int dst_core_table(DstArgs args); @@ -113,4 +107,4 @@ Dst dst_op_subtract(Dst lhs, Dst rhs); } #endif -#endif /* DST_MATH_H_defined */ +#endif /* DST_CORELIB_H_defined */ diff --git a/src/include/dst/dstparse.h b/src/include/dst/dstparse.h index 3f27dd27..286214f8 100644 --- a/src/include/dst/dstparse.h +++ b/src/include/dst/dstparse.h @@ -62,6 +62,7 @@ int dst_parser_consume(DstParser *parser, uint8_t c); enum 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); int dst_lib_parse(DstArgs args); diff --git a/src/tools/xxd.c b/src/tools/xxd.c new file mode 100644 index 00000000..760ee4e2 --- /dev/null +++ b/src/tools/xxd.c @@ -0,0 +1,97 @@ +/* +* Copyright (c) 2018 Calvin Rose +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + +/* 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 +#include +#include + +#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, "static const unsigned char %s[] = {", argv[3]); + + /* Read in chunks from buffer */ + while ((bytesRead = fread(buf, 1, sizeof(buf), in)) > 0) { + size_t 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 >> 4], out); + fputc(hex[byte & 0xF], out); + + /* Make line index wrap */ + if (lineIndex >= PERLINE) + lineIndex = 0; + + } + } + + /* Write the tail */ + fputs("\n};\n\n", out); + + /* Close the file handles */ + fclose(in); + fclose(out); + + return 0; +} diff --git a/test/boot.dst b/test/boot.dst deleted file mode 100644 index c16b1769..00000000 --- a/test/boot.dst +++ /dev/null @@ -1,76 +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. - -# Bootstrap the language - -(def defmacro macro (fn [name & more] - (tuple 'def name 'macro (tuple-prepend (tuple-prepend more name) 'fn)))) -(defmacro defn - [name & more] - (tuple 'def name - (tuple-prepend (tuple-prepend more name) 'fn))) - -(defmacro when [cond & body] (tuple 'if cond (tuple-prepend body 'do))) - -(defn array-seq [x] - (def len (length x)) - (var i 0) - { - :more (fn [] (< i len)) - :next (fn [] - (def ret (get x i)) - (varset! i (+ i 1)) - ret) - }) - -(def seqs { - :array array-seq - :tuple array-seq - :struct (fn [x] x)}) - -(defn seq [x] - (def makeseq (get seqs (type x))) - (if makeseq (makeseq x) (error "expected sequence"))) - -(defn range [top] - (var i 0) - { - :more (fn [] (< i top)) - :next (fn [] - (def ret i) - (varset! i (+ i 1)) - i) - }) - -(defn doseq [s f] - (def s (seq s)) - (def more? (get s :more)) - (def getnext (get s :next)) - (while (more?) - (f (getnext)))) - -(defn map [f s] - (def s (seq s)) - (def more (get s :more)) - (def getnext (get s :next)) - { - :more more - :next (f (getnext)) - })