mirror of
https://github.com/janet-lang/janet
synced 2024-11-19 23:24:49 +00:00
Self host the repl, remove linenoise, and selfhost the
main client.
This commit is contained in:
parent
7bfb3145cb
commit
3e1f031576
@ -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
25
LICENSE
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
75
src/compiler/run.c
Normal 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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
7
src/mainclient/init.dst
Normal 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
@ -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 */
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user