mirror of
https://github.com/janet-lang/janet
synced 2024-12-29 01:40:26 +00:00
Add extra information in repl to show state of parsing.
This commit is contained in:
parent
7e63427208
commit
55f0e759d9
@ -853,13 +853,16 @@ onvalue."
|
||||
# Are we done yet?
|
||||
(var going true)
|
||||
|
||||
# The parser object
|
||||
(def p (parser 1))
|
||||
|
||||
# Fiber stream of characters
|
||||
(def chars (coro
|
||||
(def buf @"")
|
||||
(var len 1)
|
||||
(while (< 0 len)
|
||||
(buffer-clear buf)
|
||||
(chunks buf)
|
||||
(chunks buf p)
|
||||
(:= len (length buf))
|
||||
(for [i 0 len]
|
||||
(yield (get buf i))))
|
||||
@ -867,7 +870,6 @@ onvalue."
|
||||
|
||||
# Fiber stream of values
|
||||
(def vals (coro
|
||||
(def p (parser 1))
|
||||
(while going
|
||||
(switch (parser-status p)
|
||||
:full (yield (parser-produce p))
|
||||
@ -977,18 +979,18 @@ environment is needed, use run-context."
|
||||
(:= k (next newenv k))))
|
||||
|
||||
(defmacro import [path & args]
|
||||
(apply tuple import* '_env path args))
|
||||
(apply tuple import* '_env path args))
|
||||
|
||||
(defn repl [getchunk]
|
||||
"Run a repl. The first parameter is an optional function to call to
|
||||
"Run a repl. The first parameter is an optional function to call to
|
||||
get a chunk of source code. Should return nil for end of file."
|
||||
(def newenv (make-env))
|
||||
(defn chunks [buf]
|
||||
(file-write stdout "> ")
|
||||
(file-flush stdout)
|
||||
(file-read stdin :line buf))
|
||||
(defn chunks [buf p]
|
||||
(file-write stdout (string (parser-state p) "> "))
|
||||
(file-flush stdout)
|
||||
(file-read stdin :line buf))
|
||||
(defn onvalue [x]
|
||||
(put newenv '_ @{:value x})
|
||||
(pp x))
|
||||
(put newenv '_ @{:value x})
|
||||
(pp x))
|
||||
(run-context newenv (if getchunk getchunk chunks)
|
||||
onvalue default-error-handler))
|
||||
|
@ -221,7 +221,9 @@ static int dst_io_fwrite(DstArgs args) {
|
||||
return dst_throw(args, "file is not writeable");
|
||||
for (i = 1; i < args.n; i++) {
|
||||
if (!checkchars(args, i, &str, &len)) return 1;
|
||||
if (!fwrite(str, len, 1, iof->file)) return dst_throw(args, "error writing to file");
|
||||
if (len) {
|
||||
if (!fwrite(str, len, 1, iof->file)) return dst_throw(args, "error writing to file");
|
||||
}
|
||||
}
|
||||
return dst_return(args, dst_wrap_abstract(iof));
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ int dst_parser_consume(DstParser *parser, uint8_t c);
|
||||
enum DstParserStatus dst_parser_status(DstParser *parser);
|
||||
Dst dst_parser_produce(DstParser *parser);
|
||||
const char *dst_parser_error(DstParser *parser);
|
||||
void dst_parser_flush(DstParser *parser);
|
||||
|
||||
int dst_parse_cfun(DstArgs args);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
(var *should-repl* :private false)
|
||||
(var *no-file* :private true)
|
||||
(var *use-getline* :private true)
|
||||
|
||||
# Flag handlers
|
||||
(def handlers :private {
|
||||
@ -10,11 +11,13 @@
|
||||
(print "Options are:")
|
||||
(print " -h Show this help")
|
||||
(print " -v Print the version string")
|
||||
(print " -s Use raw stdin instead of getline like functionality")
|
||||
(print " -e Execute a string of dst")
|
||||
(print " -r Enter the repl after running all scripts")
|
||||
(os-exit 0)
|
||||
1)
|
||||
"v" (fn [] (print VERSION) (os-exit 0) 1)
|
||||
"s" (fn [] (:= *use-getline* false) (:= *should-repl* true) 1)
|
||||
"r" (fn [] (:= *should-repl* true) 1)
|
||||
"e" (fn [i]
|
||||
(:= *no-file* false)
|
||||
@ -38,8 +41,12 @@
|
||||
(import arg)
|
||||
(++ i))))
|
||||
|
||||
(defn xgetline [buf p]
|
||||
(def prompt (string (parser-state p) "> "))
|
||||
(getline prompt buf))
|
||||
|
||||
(when (or *should-repl* *no-file*)
|
||||
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
|
||||
(repl getline))
|
||||
(repl (if *use-getline* xgetline)))
|
||||
|
||||
)
|
||||
|
@ -24,9 +24,12 @@
|
||||
|
||||
/* Common */
|
||||
int dst_line_getter(DstArgs args) {
|
||||
if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER))
|
||||
return dst_throw(args, "expected buffer");
|
||||
dst_line_get(dst_unwrap_buffer(args.v[0]));
|
||||
dst_fixarity(args, 2);
|
||||
dst_check(args, 0, DST_STRING);
|
||||
dst_check(args, 1, DST_BUFFER);
|
||||
dst_line_get(
|
||||
dst_unwrap_string(args.v[0]),
|
||||
dst_unwrap_buffer(args.v[1]));
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
@ -54,8 +57,8 @@ void dst_line_deinit() {
|
||||
;
|
||||
}
|
||||
|
||||
void dst_line_get(DstBuffer *buffer) {
|
||||
fputs("> ", stdout);
|
||||
void dst_line_get(const uint8_t *p, DstBuffer *buffer) {
|
||||
fputs((const char *)p, stdout);
|
||||
simpleline(buffer);
|
||||
}
|
||||
|
||||
@ -431,7 +434,8 @@ static int checktermsupport() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dst_line_get(DstBuffer *buffer) {
|
||||
void dst_line_get(const uint8_t *p, DstBuffer *buffer) {
|
||||
prompt = (const char *)p;
|
||||
buffer->count = 0;
|
||||
historyi = 0;
|
||||
if (!isatty(STDIN_FILENO) || !checktermsupport()) {
|
||||
|
@ -28,7 +28,7 @@
|
||||
void dst_line_init();
|
||||
void dst_line_deinit();
|
||||
|
||||
void dst_line_get(DstBuffer *buffer);
|
||||
void dst_line_get(const uint8_t *p, DstBuffer *buffer);
|
||||
int dst_line_getter(DstArgs args);
|
||||
|
||||
#endif
|
||||
|
@ -120,7 +120,10 @@ struct DstParseState {
|
||||
|
||||
#define PFLAG_CONTAINER 1
|
||||
#define PFLAG_BUFFER 2
|
||||
#define PFLAG_SQRBRACKETS 4
|
||||
#define PFLAG_PARENS 4
|
||||
#define PFLAG_SQRBRACKETS 8
|
||||
#define PFLAG_CURLYBRACKETS 16
|
||||
#define PFLAG_STRING 32
|
||||
|
||||
static void pushstate(DstParser *p, Consumer consumer, int flags) {
|
||||
DstParseState s;
|
||||
@ -372,8 +375,8 @@ static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
return root(p, state, c);
|
||||
}
|
||||
|
||||
#define PFLAG_INSTRING 8
|
||||
#define PFLAG_END_CANDIDATE 16
|
||||
#define PFLAG_INSTRING 64
|
||||
#define PFLAG_END_CANDIDATE 128
|
||||
static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
if (state->flags & PFLAG_INSTRING) {
|
||||
/* We are inside the long string */
|
||||
@ -426,19 +429,19 @@ static int ampersand(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
dst_v_pop(p->states);
|
||||
switch (c) {
|
||||
case '{':
|
||||
pushstate(p, dotable, PFLAG_CONTAINER);
|
||||
pushstate(p, dotable, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
|
||||
return 1;
|
||||
case '"':
|
||||
pushstate(p, stringchar, PFLAG_BUFFER);
|
||||
pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
|
||||
return 1;
|
||||
case '\\':
|
||||
pushstate(p, longstring, PFLAG_BUFFER);
|
||||
pushstate(p, longstring, PFLAG_BUFFER | PFLAG_STRING);
|
||||
return 1;
|
||||
case '[':
|
||||
pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
|
||||
return 1;
|
||||
case '(':
|
||||
pushstate(p, doarray, PFLAG_CONTAINER);
|
||||
pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_PARENS);
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
@ -479,13 +482,13 @@ static int root(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
p->error = "mismatched delimiter";
|
||||
return 1;
|
||||
case '(':
|
||||
pushstate(p, dotuple, PFLAG_CONTAINER);
|
||||
pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_PARENS);
|
||||
return 1;
|
||||
case '[':
|
||||
pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
|
||||
return 1;
|
||||
case '{':
|
||||
pushstate(p, dostruct, PFLAG_CONTAINER);
|
||||
pushstate(p, dostruct, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -509,14 +512,18 @@ enum DstParserStatus dst_parser_status(DstParser *parser) {
|
||||
return DST_PARSE_ROOT;
|
||||
}
|
||||
|
||||
void dst_parser_flush(DstParser *parser) {
|
||||
dst_v_empty(parser->argstack);
|
||||
dst_v__cnt(parser->states) = 1;
|
||||
dst_v_empty(parser->buf);
|
||||
}
|
||||
|
||||
const char *dst_parser_error(DstParser *parser) {
|
||||
enum DstParserStatus status = dst_parser_status(parser);
|
||||
if (status == DST_PARSE_ERROR) {
|
||||
const char *e = parser->error;
|
||||
dst_v_empty(parser->argstack);
|
||||
dst_v__cnt(parser->states) = 1;
|
||||
parser->error = NULL;
|
||||
dst_v_empty(parser->buf);
|
||||
dst_parser_flush(parser);
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
@ -688,6 +695,36 @@ static int cfun_produce(DstArgs args) {
|
||||
return dst_return(args, val);
|
||||
}
|
||||
|
||||
static int cfun_flush(DstArgs args) {
|
||||
DstParser *p = checkparser(args);
|
||||
if (!p) return 1;
|
||||
dst_parser_flush(p);
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_state(DstArgs args) {
|
||||
int32_t i;
|
||||
uint8_t *buf = NULL;
|
||||
const uint8_t *str;
|
||||
DstParser *p = checkparser(args);
|
||||
if (!p) return 1;
|
||||
for (i = 0; i < dst_v_count(p->states); i++) {
|
||||
DstParseState *s = p->states + i;
|
||||
if (s->flags & PFLAG_PARENS) {
|
||||
dst_v_push(buf, '(');
|
||||
} else if (s->flags & PFLAG_SQRBRACKETS) {
|
||||
dst_v_push(buf, '[');
|
||||
} else if (s->flags & PFLAG_CURLYBRACKETS) {
|
||||
dst_v_push(buf, '{');
|
||||
} else if (s->flags & PFLAG_STRING) {
|
||||
dst_v_push(buf, '"');
|
||||
}
|
||||
}
|
||||
str = dst_string(buf, dst_v_count(buf));
|
||||
dst_v_free(buf);
|
||||
return dst_return(args, dst_wrap_string(str));
|
||||
}
|
||||
|
||||
/* AST */
|
||||
static int cfun_unwrap1(DstArgs args) {
|
||||
if (args.n != 1) return dst_throw(args, "expected 1 argument");
|
||||
@ -730,6 +767,8 @@ static const DstReg cfuns[] = {
|
||||
{"parser-byte", cfun_byte},
|
||||
{"parser-error", cfun_error},
|
||||
{"parser-status", cfun_status},
|
||||
{"parser-flush", cfun_flush},
|
||||
{"parser-state", cfun_state},
|
||||
{"ast-unwrap", cfun_unwrap},
|
||||
{"ast-unwrap1", cfun_unwrap1},
|
||||
{"ast-wrap", cfun_wrap},
|
||||
|
@ -73,4 +73,6 @@
|
||||
(assert (= "hello, \"world\"" \\hello, "world"\\), "long string with embedded quotes")
|
||||
(assert (= "hello, \\\\\\ \"world\"" \=\hello, \\\ "world"\=\), "long string with embedded quotes and backslashes")
|
||||
|
||||
(print :hello)
|
||||
|
||||
(end-suite)
|
||||
|
Loading…
Reference in New Issue
Block a user