Self host the repl, remove linenoise, and selfhost the

main client.
This commit is contained in:
Calvin Rose 2018-02-07 00:44:51 -05:00
parent 7bfb3145cb
commit 3e1f031576
18 changed files with 255 additions and 1754 deletions

View File

@ -40,18 +40,26 @@ add_custom_command(
COMMENT "Generating stl bootstrap C header for embedding"
)
# Generate header containing main client script
add_custom_command(
OUTPUT clientinit.h
COMMAND xxd ${CMAKE_CURRENT_SOURCE_DIR}/src/mainclient/init.dst clientinit.h dst_mainclient_init
DEPENDS xxd src/mainclient/init.dst
COMMENT "Generating mainclient init C header for embedding"
)
set(ASSEMBLER_SOURCES
src/assembler/asm.c
)
set(COMPILER_SOURCES
src/compiler/compile.c
src/compiler/specials.c
src/compiler/cfuns.c
src/compiler/context.c
src/compiler/run.c
src/compiler/specials.c
src/compiler/stl.c
dststlbootstrap.h
dststlbootstrap.h
src/compiler/compile.h
)
@ -83,9 +91,7 @@ src/core/util.h
set(MAINCLIENT_SOURCES
src/mainclient/main.c
src/mainclient/linenoise.c
src/mainclient/linenoise.h
clientinit.h
)
set(PARSER_SOURCES

25
LICENSE
View File

@ -17,28 +17,3 @@ 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.
Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

View File

@ -9,6 +9,8 @@
[cond & body]
(tuple 'if cond (tuple-prepend body 'do)))
(def identity (fn [x] x))
(def seq (do
(defn array-seq [x]
(def len (length x))
@ -160,3 +162,89 @@
(varset! lastkey (next x lastkey))
ret)
})
# Handle errors
(defn onerr [t e]
(print (string t " error: " e)))
(var *read* nil)
(var *onvalue* identity)
# Cache for require
(def require-loading @{})
# Create a char stream from a function that gets input
(defn char-stream [getchunk ondone]
(fiber (fn [parent]
(def buf @"")
(var len 1)
(while (< 0 len)
(buffer-clear buf)
(getchunk buf)
(varset! len (length buf))
(for [i 0 len]
(transfer parent (get buf i))))
(ondone))))
# Convert a charstream into a value
(defn val-stream [chars]
(fiber (fn [parent]
(var up parent)
(def me (fiber-current))
(def p (parser))
(while true
(def s (parser-status p))
(if (= s :full)
(varset! up (transfer up (parser-produce p)))
(if (= s :error)
# Parse error
(onerr "parse" (parser-error p))
# Normal state, get next char
(parser-byte p (transfer chars me))))))))
(defn require [path]
(when (get require-loading path)
(error (string "circular dependency: module " path "is already loading")))
(def oldread *read*)
(def oldonvalue *onvalue*)
(def f (file-open path))
(def getter (fn [buf] (file-read f 1024 buf)))
(def cs (char-stream getter (fn []
(put require-loading path nil)
(file-close f)
(varset! *read* oldread)
(varset! *onvalue* oldonvalue)
nil)))
(def vs (val-stream cs))
(varset! *onvalue* identity)
(varset! *read* (fn [] (transfer vs (fiber-current))))
nil)
(defn dorepl []
(def oldread *read*)
(def cs (char-stream (fn [buf]
(file-write stdout ">> ")
(file-read stdin :line buf))
(fn []
(varset! *read* oldread)
nil)))
(def vs (val-stream cs))
(varset! *onvalue* (fn [ret]
(put _env '_ @{'value ret})
(describe ret)))
(varset! *read* (fn [] (transfer vs (fiber-current)))))
# Main loop
(defn init-loop []
(while *read*
(def wrapper (fiber (fn []
(while *read*
(def source (*read*))
(def res (compile source _env))
(if (= (type res) :function)
(*onvalue* (res))
(onerr "compile" (get res :error)))))))
(def eb (transfer wrapper))
(if (= (fiber-status wrapper) :error) (onerr "runtime" eb))))
(defn init-repl [] (dorepl) (init-loop))

View File

@ -995,23 +995,19 @@ int dst_compile_cfun(DstArgs args) {
DstCompileResult res;
DstTable *t;
DstTable *env;
if (args.n < 1)
return dst_throw(args, "expected at least one argument");
if (args.n >= 2) {
if (!dst_checktype(args.v[1], DST_TABLE)) return dst_throw(args, "expected table as environment");
env = dst_unwrap_table(args.v[1]);
} else {
env = dst_stl_env();
}
if (args.n < 2)
return dst_throw(args, "expected at least 2 arguments");
if (!dst_checktype(args.v[1], DST_TABLE)) return dst_throw(args, "expected table as environment");
env = dst_unwrap_table(args.v[1]);
res = dst_compile(args.v[0], env, 0);
if (res.status == DST_COMPILE_OK) {
DstFunction *fun = dst_function(res.funcdef, NULL);
return dst_return(args, dst_wrap_function(fun));
} else {
t = dst_table(2);
dst_table_put(t, dst_cstringv("error"), dst_wrap_string(res.error));
dst_table_put(t, dst_cstringv("error-start"), dst_wrap_integer(res.error_start));
dst_table_put(t, dst_cstringv("error-end"), dst_wrap_integer(res.error_end));
dst_table_put(t, dst_csymbolv(":error"), dst_wrap_string(res.error));
dst_table_put(t, dst_csymbolv(":error-start"), dst_wrap_integer(res.error_start));
dst_table_put(t, dst_csymbolv(":error-end"), dst_wrap_integer(res.error_end));
return dst_return(args, dst_wrap_table(t));
}
}
@ -1021,4 +1017,3 @@ int dst_lib_compile(DstArgs args) {
dst_env_def(env, "compile", dst_wrap_cfunction(dst_compile_cfun));
return 0;
}

View File

@ -1,236 +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 <dst/dstcompile.h>
#include <dst/dstparse.h>
#define CHUNKSIZE 1024
/* read input for a repl */
static int replread(DstContext *c, enum DstParserStatus status) {
if (status == DST_PARSE_PENDING)
printf(">> ");
else
printf("> ");
for (;;) {
int x = fgetc(stdin);
if (x == EOF) {
dst_buffer_push_u8(&c->buffer, '\n');
printf("\n");
break;
}
dst_buffer_push_u8(&c->buffer, x);
if (x == '\n') break;
}
return 0;
}
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;
b->count = 0;
if (!c->bufsize) {
dst_buffer_push_u8(b, '\n');
return 1;
}
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;
}
/* Output for a repl */
static void replonvalue(DstContext *c, Dst value) {
(void) c;
dst_puts(dst_formatc("%v\n", value));
dst_env_def(c->env, "_", value);
}
/* Handle errors on repl */
static void simpleerror(DstContext *c, enum DstContextErrorType type, Dst err, size_t start, size_t end) {
const char *errtype = "";
(void) c;
(void) start;
(void) end;
switch (type) {
case DST_CONTEXT_ERROR_PARSE:
errtype = "parse";
break;
case DST_CONTEXT_ERROR_RUNTIME:
errtype = "runtime";
break;
case DST_CONTEXT_ERROR_COMPILE:
errtype = "compile";
break;
}
dst_puts(dst_formatc("%s error: %s\n", errtype, dst_to_string(err)));
}
void dst_context_init(DstContext *c, DstTable *env) {
dst_buffer_init(&c->buffer, CHUNKSIZE);
c->env = env;
dst_gcroot(dst_wrap_table(env));
c->index = 0;
c->read_chunk = NULL;
c->on_error = NULL;
c->on_value = NULL;
c->deinit = NULL;
}
void dst_context_deinit(DstContext *c) {
dst_buffer_deinit(&c->buffer);
if (c->deinit) c->deinit(c);
dst_gcunroot(dst_wrap_table(c->env));
}
int dst_context_repl(DstContext *c, DstTable *env) {
dst_context_init(c, env);
c->user = NULL;
dst_env_def(c->env, "_", dst_wrap_nil());
c->read_chunk = replread;
c->on_error = simpleerror;
c->on_value = replonvalue;
return 0;
}
int dst_context_file(DstContext *c, DstTable *env, const char *path) {
FILE *f = fopen(path, "r");
if (!f) {
return -1;
}
dst_context_init(c, env);
c->user = f;
c->read_chunk = fileread;
c->on_error = simpleerror;
c->deinit = filedeinit;
return 0;
}
int dst_context_bytes(DstContext *c, DstTable *env, const uint8_t *bytes, int32_t len) {
dst_context_init(c, env);
c->user = (void *) bytes;
c->bufsize = len;
c->read_chunk = bytesread;
return 0;
}
/* Do something on an error. Return flags to or with current flags. */
static int doerror(
DstContext *c,
enum DstContextErrorType type,
Dst err,
int32_t bstart,
int32_t bend) {
if (c->on_error) {
c->on_error(c, type,
err,
bstart,
bend);
}
return 1 << type;
}
/* Start a context */
int dst_context_run(DstContext *c, int flags) {
int done = 0;
int errflags = 0;
DstParser parser;
enum DstParserStatus status;
dst_parser_init(&parser, flags);
while (!done) {
int bufferdone = 0;
while (!bufferdone) {
status = dst_parser_status(&parser);
switch (status) {
case DST_PARSE_FULL:
{
DstCompileResult cres = dst_compile(dst_parser_produce(&parser), c->env, flags);
if (cres.status == DST_COMPILE_OK) {
DstFunction *f = dst_function(cres.funcdef, NULL);
Dst ret;
if (dst_run(dst_wrap_function(f), &ret)) {
/* Get location from stacktrace? */
errflags |= doerror(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1);
} else {
if (c->on_value) {
c->on_value(c, ret);
}
}
} else {
errflags |= doerror(c, DST_CONTEXT_ERROR_COMPILE,
dst_wrap_string(cres.error),
cres.error_start,
cres.error_end);
}
}
break;
case DST_PARSE_ERROR:
doerror(c, DST_CONTEXT_ERROR_PARSE,
dst_cstringv(dst_parser_error(&parser)),
parser.index,
parser.index);
break;
case DST_PARSE_PENDING:
case DST_PARSE_ROOT:
if (c->index >= c->buffer.count) {
bufferdone = 1;
break;
}
dst_parser_consume(&parser, c->buffer.data[c->index++]);
break;
}
}
/* Refill the buffer */
c->buffer.count = 0;
c->index = 0;
if (c->read_chunk(c, status) || c->buffer.count == 0) {
done = 1;
}
}
dst_parser_deinit(&parser);
return errflags;
}

75
src/compiler/run.c Normal file
View File

@ -0,0 +1,75 @@
/*
* 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 <dst/dstcorelib.h>
#include <dst/dstcompile.h>
#include <dst/dstparse.h>
/* Run a string */
int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len) {
DstParser parser;
int errflags = 0;
int32_t index = 0;
dst_parser_init(&parser, DST_PARSEFLAG_SOURCEMAP);
for (;;) {
switch (dst_parser_status(&parser)) {
case DST_PARSE_FULL:
{
Dst form = dst_parser_produce(&parser);
DstCompileResult cres = dst_compile(form, env, 0);
if (cres.status == DST_COMPILE_OK) {
DstFunction *f = dst_function(cres.funcdef, NULL);
Dst ret;
if (dst_run(dst_wrap_function(f), &ret)) {
printf("internal runtime error: %s\n", (const char *) dst_to_string(ret));
errflags |= 0x01;
}
} else {
printf("internal compile error: %s\n", (const char *) cres.error);
errflags |= 0x02;
}
}
break;
case DST_PARSE_ERROR:
errflags |= 0x04;
printf("internal parse error: %s\n", dst_parser_error(&parser));
break;
case DST_PARSE_PENDING:
if (index >= len)
printf("internal parse error: unexpected end of source\n");
/* fallthrough */
case DST_PARSE_ROOT:
if (index >= len) return errflags;
dst_parser_consume(&parser, bytes[index++]);
break;
}
}
}
int dst_dostring(DstTable *env, const char *str) {
int32_t len = 0;
while (str[len]) ++len;
return dst_dobytes(env, (const uint8_t *)str, len);
}

View File

@ -42,13 +42,16 @@ static const DstReg cfuns[] = {
{"tuple", dst_core_tuple},
{"struct", dst_core_struct},
{"fiber", dst_core_fiber},
{"status", dst_core_status},
{"fiber-status", dst_core_fiber_status},
{"fiber-current", dst_core_fiber_current},
{"buffer", dst_core_buffer},
{"gensym", dst_core_gensym},
{"get", dst_core_get},
{"put", dst_core_put},
{"length", dst_core_length},
{"gccollect", dst_core_gccollect},
{"gcsetinterval", dst_core_gcsetinterval},
{"gcinterval", dst_core_gcinterval},
{"type", dst_core_type},
{"next", dst_core_next},
{"hash", dst_core_hash},
@ -88,6 +91,8 @@ DstTable *dst_stl_env() {
dst_env_def(env, "yield", dst_wrap_function(dst_quick_asm(1, 0, 2, yield_asm, sizeof(yield_asm))));
dst_env_def(env, "transfer", dst_wrap_function(dst_quick_asm(2, 0, 2, transfer_asm, sizeof(transfer_asm))));
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
/* Allow references to the environment */
dst_env_def(env, "_env", ret);
@ -111,11 +116,7 @@ DstTable *dst_stl_env() {
}
/* Run bootstrap source */
{
DstContext ctxt;
dst_context_bytes(&ctxt, env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen));
dst_context_run(&ctxt, 0);
}
dst_dobytes(env, dst_stl_bootstrap_gen, sizeof(dst_stl_bootstrap_gen));
dst_gcunroot(dst_wrap_table(env));

View File

@ -139,8 +139,8 @@ int dst_core_fiber(DstArgs args) {
if (args.n < 1) return dst_throw(args, "expected at least one argument");
if (!dst_checktype(args.v[0], DST_FUNCTION)) return dst_throw(args, "expected a function");
fiber = dst_fiber(64);
dst_fiber_funcframe(fiber, dst_unwrap_function(args.v[0]));
fiber->parent = dst_vm_fiber;
dst_fiber_funcframe(fiber, dst_unwrap_function(args.v[0]));
return dst_return(args, dst_wrap_fiber(fiber));
}
@ -172,7 +172,7 @@ int dst_core_get(DstArgs args) {
return dst_return(args, ds);
}
int dst_core_status(DstArgs args) {
int dst_core_fiber_status(DstArgs args) {
const char *status = "";
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber");
@ -196,6 +196,10 @@ int dst_core_status(DstArgs args) {
return dst_return(args, dst_csymbolv(status));
}
int dst_core_fiber_current(DstArgs args) {
return dst_return(args, dst_wrap_fiber(dst_vm_fiber));
}
int dst_core_put(DstArgs args) {
Dst ds, key, value;
DstArgs subargs = args;
@ -215,6 +219,19 @@ int dst_core_gccollect(DstArgs args) {
return 0;
}
int dst_core_gcsetinterval(DstArgs args) {
if (args.n < 1 ||
!dst_checktype(args.v[0], DST_INTEGER) ||
dst_unwrap_integer(args.v[0]) < 0)
return dst_throw(args, "expected non-negative integer");
dst_vm_gc_interval = dst_unwrap_integer(args.v[0]);
return dst_return(args, dst_wrap_integer(dst_vm_gc_interval));
}
int dst_core_gcinterval(DstArgs args) {
return dst_return(args, dst_wrap_integer(dst_vm_gc_interval));
}
int dst_core_type(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (dst_checktype(args.v[0], DST_ABSTRACT)) {

View File

@ -253,6 +253,7 @@ void dst_fiber_cframe(DstFiber *fiber) {
* NULL if there are no more frames */
void dst_fiber_popframe(DstFiber *fiber) {
DstStackFrame *frame = dst_fiber_frame(fiber);
if (fiber->frame == 0) return;
/* Clean up the frame (detach environments) */
if (NULL != frame->func)

View File

@ -206,7 +206,7 @@ static int dst_io_fread(DstArgs args) {
ntoread = len;
nread = fread((char *)(b->data + b->count), 1, ntoread, iof->file);
if (nread != ntoread && ferror(iof->file)) return dst_throw(args, "could not read file");
b->count += len;
b->count += nread;
return dst_return(args, dst_wrap_buffer(b));
}

View File

@ -28,7 +28,6 @@ extern "C" {
#endif
#include "dsttypes.h"
#include "dstparse.h"
typedef struct DstCompileOptions DstCompileOptions;
typedef struct DstCompileResult DstCompileResult;
@ -47,47 +46,14 @@ 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;
/* Get the default environment for dst */
DstTable *dst_stl_env();
/* Different levels of reporting and configuration */
void dst_context_init(DstContext *c, DstTable *env);
int dst_context_file(DstContext *c, DstTable *env, const char *path);
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,
DST_CONTEXT_ERROR_COMPILE,
DST_CONTEXT_ERROR_RUNTIME
};
/* Evaluation context. Encapsulates parsing and compiling for easier integration
* with client programs. */
struct DstContext {
DstTable *env;
DstBuffer buffer;
void *user;
int32_t bufsize;
int32_t index;
int (*read_chunk)(DstContext *self, enum DstParserStatus status);
void (*on_error)(DstContext *self, enum DstContextErrorType type, Dst err, size_t start, size_t end);
void (*on_value)(DstContext *self, Dst value);
void (*deinit)(DstContext *self);
};
int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len);
int dst_dostring(DstTable *env, const char *str);
#ifdef __cplusplus
}
#endif
#endif /* DST_COMPILE_H_defined */
#endif

View File

@ -84,9 +84,12 @@ int dst_core_buffer(DstArgs args);
int dst_core_gensym(DstArgs args);
int dst_core_length(DstArgs args);
int dst_core_get(DstArgs args);
int dst_core_status(DstArgs args);
int dst_core_fiber_status(DstArgs args);
int dst_core_fiber_current(DstArgs args);
int dst_core_put(DstArgs args);
int dst_core_gccollect(DstArgs args);
int dst_core_gcsetinterval(DstArgs args);
int dst_core_gcinterval(DstArgs args);
int dst_core_type(DstArgs args);
int dst_core_next(DstArgs args);
int dst_core_hash(DstArgs args);

7
src/mainclient/init.dst Normal file
View File

@ -0,0 +1,7 @@
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
# Process arguments
(for [i 0 (length args)]
(print (get args i)))
(init-repl)

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
/* linenoise.h -- VERSION 1.0
*
* Guerrilla line editing library against the idea that a line editing lib
* needs to be 20,000 lines of C code.
*
* See linenoise.c for more information.
*
* ------------------------------------------------------------------------
*
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LINENOISE_H
#define __LINENOISE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
typedef void(linenoiseFreeHintsCallback)(void *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
char *linenoise(const char *prompt);
void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
#ifdef __cplusplus
}
#endif
#endif /* __LINENOISE_H */

View File

@ -20,163 +20,34 @@
* IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <dst/dst.h>
#include <dst/dstcompile.h>
#include "linenoise.h"
#include <errno.h>
#define DST_CLIENT_HELP 1
#define DST_CLIENT_VERBOSE 2
#define DST_CLIENT_VERSION 4
#define DST_CLIENT_REPL 8
#define DST_CLIENT_UNKNOWN 16
static const char *replsplash =
"Dst " DST_VERSION " Copyright (C) 2017-2018 Calvin Rose";
static int client_strequal(const char *a, const char *b) {
while (*a) if (*a++ != *b++) return 0;
return *a == *b;
}
static int client_strequal_witharg(const char *a, const char *b) {
while (*b) if (*a++ != *b++) return 0;
return *a == '=';
}
static int linenoiseread(DstContext *c, enum DstParserStatus status) {
const char *prompt = (status == DST_PARSE_PENDING)
? ">> "
: "> ";
char *line = linenoise(prompt);
if (line) {
linenoiseHistoryAdd(line);
dst_buffer_push_cstring(&c->buffer, line);
free(line);
} else if (errno) {
return 1;
}
dst_buffer_push_u8(&c->buffer, '\n');
return 0;
}
#include "clientinit.h"
int main(int argc, char **argv) {
int status = 0;
int i;
int fileRead = 0;
uint32_t gcinterval = 0x10000;
uint64_t flags = 0;
int i, status;
DstArray *args;
DstTable *env;
/* Read the arguments. Ignore files. */
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (*arg == '-') {
/* Flag or option */
if (arg[1] == '-') {
/* Option */
if (client_strequal(arg + 2, "help")) {
flags |= DST_CLIENT_HELP;
} else if (client_strequal(arg + 2, "version")) {
flags |= DST_CLIENT_VERSION;
} else if (client_strequal(arg + 2, "verbose")) {
flags |= DST_CLIENT_VERBOSE;
} else if (client_strequal(arg + 2, "repl")) {
flags |= DST_CLIENT_REPL;
} else if (client_strequal_witharg(arg + 2, "gcinterval")) {
int status = 0;
int32_t m;
const uint8_t *start = (const uint8_t *)(arg + 13);
const uint8_t *end = start;
while (*end) ++end;
m = dst_scan_integer(start, end - start, &status);
if (!status)
gcinterval = m;
} else {
flags |= DST_CLIENT_UNKNOWN;
}
} else if (*arg) {
/* Flag */
const char *c = arg;
while (*(++c)) {
switch (*c) {
case 'h':
flags |= DST_CLIENT_HELP;
break;
case 'v':
flags |= DST_CLIENT_VERSION;
break;
case 'V':
flags |= DST_CLIENT_VERBOSE;
break;
case 'r':
flags |= DST_CLIENT_REPL;
break;
default:
flags |= DST_CLIENT_UNKNOWN;
break;
}
}
}
}
}
/* Handle flags and options */
if ((flags & DST_CLIENT_HELP) || (flags & DST_CLIENT_UNKNOWN)) {
printf( "Usage:\n"
"%s -opts --fullopt1 --fullopt2 file1 file2...\n"
"\n"
" -h --help Shows this information.\n"
" -V --verbose Show more output.\n"
" -r --repl Launch a repl after all files are processed.\n"
" -v --version Print the version number and exit.\n"
" --gcinterval=[int] Set the amount of memory to allocate before\n"
" forcing a collection in bytes. Max is 2^31-1,\n"
" min is 0.\n\n",
argv[0]);
return 0;
}
if (flags & DST_CLIENT_VERSION) {
printf("%s\n", DST_VERSION);
return 0;
}
/* Set up VM */
dst_init();
dst_vm_gc_interval = gcinterval;
env = dst_stl_env();
dst_gcroot(dst_wrap_table(env));
/* Read the arguments. Only process files. */
for (i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (*arg != '-') {
DstContext ctxt;
fileRead = 1;
if (dst_context_file(&ctxt, env, arg)) {
printf("file %s not found\n", arg);
status |= 2;
continue;
}
status |= dst_context_run(&ctxt, DST_PARSEFLAG_SOURCEMAP);
}
/* Create process tuple */
args = dst_array(argc);
for (i = 0; i < argc; i++) {
dst_array_push(args, dst_cstringv(argv[i]));
}
/* Run a repl if nothing else happened, or the flag is set */
if (!fileRead || (flags & DST_CLIENT_REPL)) {
DstContext ctxt;
dst_context_repl(&ctxt, env);
#ifndef DST_WINDOWS
ctxt.read_chunk = linenoiseread;
linenoiseSetMultiLine(1);
#endif
puts(replsplash);
status = dst_context_run(&ctxt, DST_PARSEFLAG_SOURCEMAP);
}
/* Allow access to runtime argument */
dst_env_def(env, "args", dst_wrap_array(args));
/* Run startup script */
status = dst_dobytes(env, dst_mainclient_init, sizeof(dst_mainclient_init));
/* Deinitialize vm */
dst_deinit();
return status;

View File

@ -598,25 +598,35 @@ static int cfun_consume(DstArgs args) {
return dst_return(args, dst_wrap_nil());
}
static int cfun_byte(DstArgs args) {
DstParser *p;
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
p = checkparser(args);
if (!p) return 1;
if (!dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected integer");
dst_parser_consume(p, 0xFF & dst_unwrap_integer(args.v[1]));
return dst_return(args, args.v[0]);
}
static int cfun_status(DstArgs args) {
const char *stat = NULL;
DstParser *p = checkparser(args);
if (!p) return 1;
switch (dst_parser_status(p)) {
case DST_PARSE_FULL:
stat = "full";
stat = ":full";
break;
case DST_PARSE_PENDING:
stat = "pending";
stat = ":pending";
break;
case DST_PARSE_ERROR:
stat = "error";
stat = ":error";
break;
case DST_PARSE_ROOT:
stat = "root";
stat = ":root";
break;
}
return dst_return(args, dst_cstringv(stat));
return dst_return(args, dst_csymbolv(stat));
}
static int cfun_error(DstArgs args) {
@ -678,6 +688,7 @@ static const DstReg cfuns[] = {
{"parser", cfun_parser},
{"parser-produce", cfun_produce},
{"parser-consume", cfun_consume},
{"parser-byte", cfun_byte},
{"parser-error", cfun_error},
{"parser-status", cfun_status},
{"ast-unwrap", cfun_unwrap},

View File

@ -163,7 +163,7 @@
(def afiber-result (transfer afiber "world!"))
(assert (= afiber-result "hello, world!") "fiber error result")
(assert (= (status afiber) :error) "fiber error status")
(assert (= (fiber-status afiber) :error) "fiber error status")
# yield tests
@ -172,7 +172,7 @@
(assert (= 1 (transfer t)) "initial transfer to new fiber")
(assert (= 2 (transfer t)) "second transfer to fiber")
(assert (= 3 (transfer t)) "return from fiber")
(assert (= (status t) :dead) "finished fiber is dead")
(assert (= (fiber-status t) :dead) "finished fiber is dead")
# Var arg tests