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