1
0
mirror of https://github.com/janet-lang/janet synced 2025-10-23 19:57:40 +00:00

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

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