mirror of
https://github.com/janet-lang/janet
synced 2025-01-11 16:10:27 +00:00
184 lines
6.4 KiB
C
184 lines
6.4 KiB
C
/*
|
|
* 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>
|
|
|
|
/*static void deinit_file(DstContext *c) {*/
|
|
/*FILE *f = (FILE *) (c->user);*/
|
|
/*fclose(f);*/
|
|
/*}*/
|
|
|
|
/* Read input for a repl */
|
|
static void replread(DstContext *c) {
|
|
if (c->buffer.count == 0)
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* Output for a repl */
|
|
static void replonvalue(DstContext *c, Dst value) {
|
|
(void) c;
|
|
dst_puts(dst_formatc("%v\n", value));
|
|
if (dst_checktype(c->env, DST_TABLE))
|
|
dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil());
|
|
}
|
|
|
|
/* Handle errors on repl */
|
|
static void replerror(DstContext *c, 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: %v\n", errtype, err));
|
|
}
|
|
|
|
void dst_context_repl(DstContext *c, Dst env) {
|
|
dst_buffer_init(&c->buffer, 1024);
|
|
c->env = env;
|
|
dst_gcroot(env);
|
|
c->flushed_bytes = 0;
|
|
c->user = NULL;
|
|
if (dst_checktype(c->env, DST_TABLE))
|
|
dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil());
|
|
|
|
c->read_chunk = replread;
|
|
c->on_error = replerror;
|
|
c->on_value = replonvalue;
|
|
}
|
|
|
|
/* Remove everything in the current buffer */
|
|
static void flushcontext(DstContext *c) {
|
|
c->flushed_bytes += c->buffer.count;
|
|
c->buffer.count = 0;
|
|
}
|
|
|
|
/* Shift bytes in buffer down */
|
|
/* TODO Make parser online so there is no need to
|
|
* do too much book keeping with the buffer. */
|
|
static void bshift(DstContext *c, int32_t delta) {
|
|
c->buffer.count -= delta;
|
|
if (delta) {
|
|
memmove(c->buffer.data, c->buffer.data + delta, c->buffer.count);
|
|
}
|
|
}
|
|
|
|
/* Start a context */
|
|
int dst_context_run(DstContext *c) {
|
|
int done = 0;
|
|
int flags = 0;
|
|
while (!done) {
|
|
DstCompileResult cres;
|
|
DstCompileOptions opts;
|
|
DstParseResult res = dst_parse(c->buffer.data, c->buffer.count);
|
|
switch (res.status) {
|
|
case DST_PARSE_NODATA:
|
|
flushcontext(c);
|
|
case DST_PARSE_UNEXPECTED_EOS:
|
|
{
|
|
int32_t countbefore = c->buffer.count;
|
|
c->read_chunk(c);
|
|
/* If the last chunk was empty, finish */
|
|
if (c->buffer.count == countbefore) {
|
|
done = 1;
|
|
flags |= 1 << DST_CONTEXT_ERROR_PARSE;
|
|
if (c->on_error) {
|
|
c->on_error(c, DST_CONTEXT_ERROR_PARSE,
|
|
dst_wrap_string(res.error),
|
|
c->flushed_bytes + res.bytes_read,
|
|
c->flushed_bytes + res.bytes_read);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case DST_PARSE_ERROR:
|
|
if (c->on_error) {
|
|
flags |= 1 << DST_CONTEXT_ERROR_PARSE;
|
|
c->on_error(c, DST_CONTEXT_ERROR_PARSE,
|
|
dst_wrap_string(res.error),
|
|
c->flushed_bytes + res.bytes_read,
|
|
c->flushed_bytes + res.bytes_read);
|
|
}
|
|
bshift(c, res.bytes_read);
|
|
break;
|
|
case DST_PARSE_OK:
|
|
{
|
|
opts.source = res.value;
|
|
opts.flags = 0;
|
|
opts.env = c->env;
|
|
cres = dst_compile(opts);
|
|
if (cres.status == DST_COMPILE_OK) {
|
|
DstFunction *f = dst_compile_func(cres);
|
|
Dst ret;
|
|
if (dst_run(dst_wrap_function(f), &ret)) {
|
|
/* Get location from stacktrace */
|
|
if (c->on_error) {
|
|
flags |= 1 << DST_CONTEXT_ERROR_RUNTIME;
|
|
c->on_error(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1);
|
|
}
|
|
} else {
|
|
if (c->on_value) {
|
|
c->on_value(c, ret);
|
|
}
|
|
}
|
|
} else {
|
|
if (c->on_error) {
|
|
flags |= 1 << DST_CONTEXT_ERROR_COMPILE;
|
|
c->on_error(c, DST_CONTEXT_ERROR_COMPILE,
|
|
dst_wrap_string(cres.error),
|
|
c->flushed_bytes + cres.error_start,
|
|
c->flushed_bytes + cres.error_end);
|
|
}
|
|
}
|
|
bshift(c, res.bytes_read);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
dst_buffer_deinit(&c->buffer);
|
|
if (c->deinit) c->deinit(c);
|
|
dst_gcunroot(c->env);
|
|
|
|
return flags;
|
|
}
|