mirror of
https://github.com/janet-lang/janet
synced 2024-12-25 16:00:27 +00:00
Sourcemapping uses line, column instead of offsets.
This should be friendlier to most users. It does, however, mean we lose range information. However, range information could be recovered by re-parsing, as janet's grammar is simple enough to do this.
This commit is contained in:
parent
228d045a06
commit
a8afc5b81f
2
Makefile
2
Makefile
@ -37,7 +37,7 @@ MANPATH?=$(PREFIX)/share/man/man1/
|
||||
PKG_CONFIG_PATH?=$(PREFIX)/lib/pkgconfig
|
||||
DEBUGGER=gdb
|
||||
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fpic -O2 -fvisibility=hidden \
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -Isrc/conf -fpic -O0 -g -fvisibility=hidden \
|
||||
-DJANET_BUILD=$(JANET_BUILD)
|
||||
LDFLAGS=-rdynamic
|
||||
|
||||
|
@ -1598,19 +1598,33 @@
|
||||
(defn bad-parse
|
||||
"Default handler for a parse error."
|
||||
[p where]
|
||||
(def ec (dyn :err-color))
|
||||
(def [line col] (parser/where p))
|
||||
(file/write stderr
|
||||
(if ec "\e[31m" "")
|
||||
"parse error in "
|
||||
where
|
||||
" around byte "
|
||||
(string (parser/where p))
|
||||
" around line "
|
||||
(string line)
|
||||
", column "
|
||||
(string col)
|
||||
": "
|
||||
(parser/error p)
|
||||
(if ec "\e[0m" "")
|
||||
"\n"))
|
||||
|
||||
(defn bad-compile
|
||||
"Default handler for a compile error."
|
||||
[msg macrof where]
|
||||
(file/write stderr "compile error: " msg " while compiling " where "\n")
|
||||
(def ec (dyn :err-color))
|
||||
(file/write stderr
|
||||
(if ec "\e[31m" "")
|
||||
"compile error: "
|
||||
msg
|
||||
" while compiling "
|
||||
where
|
||||
(if ec "\e[0m" "")
|
||||
"\n")
|
||||
(when macrof (debug/stacktrace macrof)))
|
||||
|
||||
(defn run-context
|
||||
@ -1660,10 +1674,10 @@
|
||||
(unless compile-only (res))
|
||||
(do
|
||||
(set good false)
|
||||
(def {:error err :start start :end end :fiber errf} res)
|
||||
(def {:error err :line line :column column :fiber errf} res)
|
||||
(def msg
|
||||
(if (<= 0 start)
|
||||
(string err " at (" start ":" end ")")
|
||||
(if (<= 0 line)
|
||||
(string err " on line " line ", column " column)
|
||||
err))
|
||||
(on-compile-error msg errf where))))
|
||||
(or guard :a)))
|
||||
@ -1946,7 +1960,7 @@
|
||||
(def level (+ (dyn :debug-level 0) 1))
|
||||
(default env (make-env))
|
||||
(default chunks (fn [buf p] (getline (string "repl:"
|
||||
(parser/where p)
|
||||
((parser/where p) 0)
|
||||
":"
|
||||
(parser/state p :delimiters) "> ")
|
||||
buf)))
|
||||
@ -1967,7 +1981,7 @@ _fiber is bound to the suspended fiber
|
||||
```)
|
||||
(repl (fn [buf p]
|
||||
(def status (parser/state p :delimiters))
|
||||
(def c (parser/where p))
|
||||
(def c ((parser/where p) 0))
|
||||
(def prompt (string "debug[" level "]:" c ":" status "> "))
|
||||
(getline prompt buf))
|
||||
onsignal nextenv))
|
||||
|
@ -705,8 +705,8 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
||||
if (!janet_checkint(tup[1])) {
|
||||
janet_asm_error(&a, "expected integer");
|
||||
}
|
||||
mapping.start = janet_unwrap_integer(tup[0]);
|
||||
mapping.end = janet_unwrap_integer(tup[1]);
|
||||
mapping.line = janet_unwrap_integer(tup[0]);
|
||||
mapping.column = janet_unwrap_integer(tup[1]);
|
||||
def->sourcemap[i] = mapping;
|
||||
}
|
||||
}
|
||||
@ -749,31 +749,31 @@ static const JanetInstructionDef *janet_asm_reverse_lookup(uint32_t instr) {
|
||||
}
|
||||
|
||||
/* Create some constant sized tuples */
|
||||
static Janet tup1(Janet x) {
|
||||
static const Janet *tup1(Janet x) {
|
||||
Janet *tup = janet_tuple_begin(1);
|
||||
tup[0] = x;
|
||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||
return janet_tuple_end(tup);
|
||||
}
|
||||
static Janet tup2(Janet x, Janet y) {
|
||||
static const Janet *tup2(Janet x, Janet y) {
|
||||
Janet *tup = janet_tuple_begin(2);
|
||||
tup[0] = x;
|
||||
tup[1] = y;
|
||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||
return janet_tuple_end(tup);
|
||||
}
|
||||
static Janet tup3(Janet x, Janet y, Janet z) {
|
||||
static const Janet *tup3(Janet x, Janet y, Janet z) {
|
||||
Janet *tup = janet_tuple_begin(3);
|
||||
tup[0] = x;
|
||||
tup[1] = y;
|
||||
tup[2] = z;
|
||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||
return janet_tuple_end(tup);
|
||||
}
|
||||
static Janet tup4(Janet w, Janet x, Janet y, Janet z) {
|
||||
static const Janet *tup4(Janet w, Janet x, Janet y, Janet z) {
|
||||
Janet *tup = janet_tuple_begin(4);
|
||||
tup[0] = w;
|
||||
tup[1] = x;
|
||||
tup[2] = y;
|
||||
tup[3] = z;
|
||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||
return janet_tuple_end(tup);
|
||||
}
|
||||
|
||||
/* Given an argument, convert it to the appropriate integer or symbol */
|
||||
@ -784,41 +784,56 @@ Janet janet_asm_decode_instruction(uint32_t instr) {
|
||||
return janet_wrap_integer((int32_t)instr);
|
||||
}
|
||||
name = janet_csymbolv(def->name);
|
||||
const Janet *ret = NULL;
|
||||
#define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask))
|
||||
switch (janet_instructions[def->opcode]) {
|
||||
case JINT_0:
|
||||
return tup1(name);
|
||||
ret = tup1(name);
|
||||
break;
|
||||
case JINT_S:
|
||||
return tup2(name, janet_wrap_integer(oparg(1, 0xFFFFFF)));
|
||||
ret = tup2(name, janet_wrap_integer(oparg(1, 0xFFFFFF)));
|
||||
break;
|
||||
case JINT_L:
|
||||
return tup2(name, janet_wrap_integer((int32_t)instr >> 8));
|
||||
ret = tup2(name, janet_wrap_integer((int32_t)instr >> 8));
|
||||
break;
|
||||
case JINT_SS:
|
||||
case JINT_ST:
|
||||
case JINT_SC:
|
||||
case JINT_SU:
|
||||
case JINT_SD:
|
||||
return tup3(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFFFF)));
|
||||
ret = tup3(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFFFF)));
|
||||
break;
|
||||
case JINT_SI:
|
||||
case JINT_SL:
|
||||
return tup3(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer((int32_t)instr >> 16));
|
||||
ret = tup3(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer((int32_t)instr >> 16));
|
||||
break;
|
||||
case JINT_SSS:
|
||||
case JINT_SES:
|
||||
case JINT_SSU:
|
||||
return tup4(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFF)),
|
||||
janet_wrap_integer(oparg(3, 0xFF)));
|
||||
ret = tup4(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFF)),
|
||||
janet_wrap_integer(oparg(3, 0xFF)));
|
||||
break;
|
||||
case JINT_SSI:
|
||||
return tup4(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFF)),
|
||||
janet_wrap_integer((int32_t)instr >> 24));
|
||||
ret = tup4(name,
|
||||
janet_wrap_integer(oparg(1, 0xFF)),
|
||||
janet_wrap_integer(oparg(2, 0xFF)),
|
||||
janet_wrap_integer((int32_t)instr >> 24));
|
||||
break;
|
||||
}
|
||||
#undef oparg
|
||||
if (ret) {
|
||||
/* Check if break point set */
|
||||
if (instr & 0x80) {
|
||||
janet_tuple_flag(ret) |= JANET_TUPLE_FLAG_BRACKETCTOR;
|
||||
}
|
||||
return janet_wrap_tuple(ret);
|
||||
}
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
@ -849,7 +864,7 @@ Janet janet_disasm(JanetFuncDef *def) {
|
||||
Janet src = def->constants[i];
|
||||
Janet dest;
|
||||
if (janet_checktype(src, JANET_TUPLE)) {
|
||||
dest = tup2(janet_csymbolv("quote"), src);
|
||||
dest = janet_wrap_tuple(tup2(janet_csymbolv("quote"), src));
|
||||
} else {
|
||||
dest = src;
|
||||
}
|
||||
@ -870,8 +885,8 @@ Janet janet_disasm(JanetFuncDef *def) {
|
||||
for (i = 0; i < def->bytecode_length; i++) {
|
||||
Janet *t = janet_tuple_begin(2);
|
||||
JanetSourceMapping mapping = def->sourcemap[i];
|
||||
t[0] = janet_wrap_integer(mapping.start);
|
||||
t[1] = janet_wrap_integer(mapping.end);
|
||||
t[0] = janet_wrap_integer(mapping.line);
|
||||
t[1] = janet_wrap_integer(mapping.column);
|
||||
sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t));
|
||||
}
|
||||
sourcemap->count = def->bytecode_length;
|
||||
|
@ -474,9 +474,9 @@ static int macroexpand1(
|
||||
if (janet_tuple_length(form) == 0)
|
||||
return 0;
|
||||
/* Source map - only set when we get a tuple */
|
||||
if (janet_tuple_sm_start(form) >= 0) {
|
||||
c->current_mapping.start = janet_tuple_sm_start(form);
|
||||
c->current_mapping.end = janet_tuple_sm_end(form);
|
||||
if (janet_tuple_sm_line(form) >= 0) {
|
||||
c->current_mapping.line = janet_tuple_sm_line(form);
|
||||
c->current_mapping.column = janet_tuple_sm_column(form);
|
||||
}
|
||||
/* Bracketed tuples are not specials or macros! */
|
||||
if (janet_tuple_flag(form) & JANET_TUPLE_FLAG_BRACKETCTOR)
|
||||
@ -664,15 +664,15 @@ static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where)
|
||||
c->recursion_guard = JANET_RECURSION_GUARD;
|
||||
c->env = env;
|
||||
c->source = where;
|
||||
c->current_mapping.start = -1;
|
||||
c->current_mapping.end = -1;
|
||||
c->current_mapping.line = -1;
|
||||
c->current_mapping.column = -1;
|
||||
/* Init result */
|
||||
c->result.error = NULL;
|
||||
c->result.status = JANET_COMPILE_OK;
|
||||
c->result.funcdef = NULL;
|
||||
c->result.macrofiber = NULL;
|
||||
c->result.error_mapping.start = -1;
|
||||
c->result.error_mapping.end = -1;
|
||||
c->result.error_mapping.line = -1;
|
||||
c->result.error_mapping.column = -1;
|
||||
}
|
||||
|
||||
/* Deinitialize a compiler struct */
|
||||
@ -733,8 +733,8 @@ static Janet cfun(int32_t argc, Janet *argv) {
|
||||
} else {
|
||||
JanetTable *t = janet_table(4);
|
||||
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error));
|
||||
janet_table_put(t, janet_ckeywordv("start"), janet_wrap_integer(res.error_mapping.start));
|
||||
janet_table_put(t, janet_ckeywordv("end"), janet_wrap_integer(res.error_mapping.end));
|
||||
janet_table_put(t, janet_ckeywordv("line"), janet_wrap_integer(res.error_mapping.line));
|
||||
janet_table_put(t, janet_ckeywordv("column"), janet_wrap_integer(res.error_mapping.column));
|
||||
if (res.macrofiber) {
|
||||
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
|
||||
}
|
||||
|
@ -52,31 +52,34 @@ void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
|
||||
*/
|
||||
void janet_debug_find(
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t offset) {
|
||||
const uint8_t *source, int32_t sourceLine, int32_t sourceColumn) {
|
||||
/* Scan the heap for right func def */
|
||||
JanetGCObject *current = janet_vm_blocks;
|
||||
/* Keep track of the best source mapping we have seen so far */
|
||||
int32_t besti = -1;
|
||||
int32_t best_range = INT32_MAX;
|
||||
int32_t best_line = -1;
|
||||
int32_t best_column = -1;
|
||||
JanetFuncDef *best_def = NULL;
|
||||
while (NULL != current) {
|
||||
if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
|
||||
JanetFuncDef *def = (JanetFuncDef *)(current + 1);
|
||||
JanetFuncDef *def = (JanetFuncDef *)(current);
|
||||
if (def->sourcemap &&
|
||||
def->source &&
|
||||
!janet_string_compare(source, def->source)) {
|
||||
/* Correct source file, check mappings. The chosen
|
||||
* pc index is the first match with the smallest range. */
|
||||
* pc index is the instruction closest to the given line column, but
|
||||
* not after. */
|
||||
int32_t i;
|
||||
for (i = 0; i < def->bytecode_length; i++) {
|
||||
int32_t start = def->sourcemap[i].start;
|
||||
int32_t end = def->sourcemap[i].end;
|
||||
if (end - start < best_range &&
|
||||
start <= offset &&
|
||||
end >= offset) {
|
||||
best_range = end - start;
|
||||
besti = i;
|
||||
best_def = def;
|
||||
int32_t line = def->sourcemap[i].line;
|
||||
int32_t column = def->sourcemap[i].column;
|
||||
if (line <= sourceLine && line >= best_line) {
|
||||
if (column <= sourceColumn && column > best_column) {
|
||||
best_line = line;
|
||||
best_column = column;
|
||||
besti = i;
|
||||
best_def = def;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,44 +153,8 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
if (frame->func && frame->pc) {
|
||||
int32_t off = (int32_t)(frame->pc - def->bytecode);
|
||||
if (def->sourcemap) {
|
||||
/* Try to get line and column information */
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
char buf[1024];
|
||||
size_t nread;
|
||||
int32_t offset = 0;
|
||||
int32_t line = 1;
|
||||
int32_t col = 1;
|
||||
int notdone = 1;
|
||||
char last = 0;
|
||||
FILE *f;
|
||||
if (def->source && (f = fopen((const char *)def->source, "rb"))) {
|
||||
while (notdone && (nread = fread(buf, 1, sizeof(buf), f)) > 0) {
|
||||
for (size_t i = 0; i < nread; i++) {
|
||||
char c = buf[i];
|
||||
if (c == '\r') {
|
||||
line++;
|
||||
col = 1;
|
||||
} else if (c == '\n') {
|
||||
col = 1;
|
||||
if (last != '\r') {
|
||||
line++;
|
||||
}
|
||||
} else {
|
||||
col++;
|
||||
}
|
||||
last = c;
|
||||
if (offset == mapping.start) {
|
||||
fprintf(out, " on line %d, column %d", line, col);
|
||||
notdone = 0;
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
} else {
|
||||
fprintf(out, " at (%d:%d)", mapping.start, mapping.end);
|
||||
}
|
||||
fprintf(out, " on line %d, column %d", mapping.line, mapping.column);
|
||||
} else {
|
||||
fprintf(out, " pc=%d", off);
|
||||
}
|
||||
@ -208,10 +175,11 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
|
||||
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||
* Takes a source file name and byte offset. */
|
||||
static void helper_find(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_offset) {
|
||||
janet_fixarity(argc, 2);
|
||||
janet_fixarity(argc, 3);
|
||||
const uint8_t *source = janet_getstring(argv, 0);
|
||||
int32_t source_offset = janet_getinteger(argv, 1);
|
||||
janet_debug_find(def, bytecode_offset, source, source_offset);
|
||||
int32_t line = janet_getinteger(argv, 1);
|
||||
int32_t col = janet_getinteger(argv, 2);
|
||||
janet_debug_find(def, bytecode_offset, source, line, col);
|
||||
}
|
||||
|
||||
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||
@ -298,8 +266,8 @@ static Janet doframe(JanetStackFrame *frame) {
|
||||
janet_table_put(t, janet_ckeywordv("pc"), janet_wrap_integer(off));
|
||||
if (def->sourcemap) {
|
||||
JanetSourceMapping mapping = def->sourcemap[off];
|
||||
janet_table_put(t, janet_ckeywordv("source-start"), janet_wrap_integer(mapping.start));
|
||||
janet_table_put(t, janet_ckeywordv("source-end"), janet_wrap_integer(mapping.end));
|
||||
janet_table_put(t, janet_ckeywordv("source-line"), janet_wrap_integer(mapping.line));
|
||||
janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(mapping.column));
|
||||
}
|
||||
if (def->source) {
|
||||
janet_table_put(t, janet_ckeywordv("source"), janet_wrap_string(def->source));
|
||||
@ -349,17 +317,17 @@ static const JanetReg debug_cfuns[] = {
|
||||
{
|
||||
"debug/break", cfun_debug_break,
|
||||
JDOC("(debug/break source byte-offset)\n\n"
|
||||
"Sets a breakpoint with source a key at a given byte offset. An offset "
|
||||
"of 0 is the first byte in a file. Will throw an error if the breakpoint location "
|
||||
"Sets a breakpoint with source a key at a given line and column. "
|
||||
"Will throw an error if the breakpoint location "
|
||||
"cannot be found. For example\n\n"
|
||||
"\t(debug/break \"core.janet\" 1000)\n\n"
|
||||
"wil set a breakpoint at the 1000th byte of the file core.janet.")
|
||||
},
|
||||
{
|
||||
"debug/unbreak", cfun_debug_unbreak,
|
||||
JDOC("(debug/unbreak source byte-offset)\n\n"
|
||||
"Remove a breakpoint with a source key at a given byte offset. An offset "
|
||||
"of 0 is the first byte in a file. Will throw an error if the breakpoint "
|
||||
JDOC("(debug/unbreak source line column)\n\n"
|
||||
"Remove a breakpoint with a source key at a given line and column. "
|
||||
"Will throw an error if the breakpoint "
|
||||
"cannot be found.")
|
||||
},
|
||||
{
|
||||
|
@ -258,9 +258,9 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||
int32_t current = 0;
|
||||
for (int32_t i = 0; i < def->bytecode_length; i++) {
|
||||
JanetSourceMapping map = def->sourcemap[i];
|
||||
pushint(st, map.start - current);
|
||||
pushint(st, map.end - map.start);
|
||||
current = map.end;
|
||||
pushint(st, map.line - current);
|
||||
pushint(st, map.column);
|
||||
current = map.line;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -827,9 +827,8 @@ static const uint8_t *unmarshal_one_def(
|
||||
}
|
||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].start = current;
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].end = current;
|
||||
def->sourcemap[i].line = current;
|
||||
def->sourcemap[i].column = readint(st, &data);
|
||||
}
|
||||
} else {
|
||||
def->sourcemap = NULL;
|
||||
|
@ -106,7 +106,8 @@ struct JanetParseState {
|
||||
int32_t counter;
|
||||
int32_t argn;
|
||||
int flags;
|
||||
size_t start;
|
||||
size_t line;
|
||||
size_t column;
|
||||
Consumer consumer;
|
||||
};
|
||||
|
||||
@ -153,7 +154,8 @@ static void pushstate(JanetParser *p, Consumer consumer, int flags) {
|
||||
s.argn = 0;
|
||||
s.flags = flags;
|
||||
s.consumer = consumer;
|
||||
s.start = p->offset;
|
||||
s.line = p->line;
|
||||
s.column = p->column;
|
||||
_pushstate(p, s);
|
||||
}
|
||||
|
||||
@ -164,8 +166,8 @@ static void popstate(JanetParser *p, Janet val) {
|
||||
if (newtop->flags & PFLAG_CONTAINER) {
|
||||
/* Source mapping info */
|
||||
if (janet_checktype(val, JANET_TUPLE)) {
|
||||
janet_tuple_sm_start(janet_unwrap_tuple(val)) = (int32_t) top.start;
|
||||
janet_tuple_sm_end(janet_unwrap_tuple(val)) = (int32_t) p->offset;
|
||||
janet_tuple_sm_line(janet_unwrap_tuple(val)) = (int32_t) top.line;
|
||||
janet_tuple_sm_column(janet_unwrap_tuple(val)) = (int32_t) top.column;
|
||||
}
|
||||
newtop->argn++;
|
||||
/* Keep track of number of values in the root state */
|
||||
@ -184,8 +186,8 @@ static void popstate(JanetParser *p, Janet val) {
|
||||
t[0] = janet_csymbolv(which);
|
||||
t[1] = val;
|
||||
/* Quote source mapping info */
|
||||
janet_tuple_sm_start(t) = (int32_t) newtop->start;
|
||||
janet_tuple_sm_end(t) = (int32_t) p->offset;
|
||||
janet_tuple_sm_line(t) = (int32_t) newtop->line;
|
||||
janet_tuple_sm_column(t) = (int32_t) newtop->column;
|
||||
val = janet_wrap_tuple(janet_tuple_end(t));
|
||||
} else {
|
||||
return;
|
||||
@ -562,7 +564,16 @@ static void janet_parser_checkdead(JanetParser *parser) {
|
||||
void janet_parser_consume(JanetParser *parser, uint8_t c) {
|
||||
int consumed = 0;
|
||||
janet_parser_checkdead(parser);
|
||||
parser->offset++;
|
||||
if (c == '\r') {
|
||||
parser->line++;
|
||||
parser->column = 0;
|
||||
} else if (c == '\n') {
|
||||
parser->column = 0;
|
||||
if (parser->lookback != '\r')
|
||||
parser->line++;
|
||||
} else {
|
||||
parser->column++;
|
||||
}
|
||||
while (!consumed && !parser->error) {
|
||||
JanetParseState *state = parser->states + parser->statecount - 1;
|
||||
consumed = state->consumer(parser, state, c);
|
||||
@ -572,11 +583,14 @@ void janet_parser_consume(JanetParser *parser, uint8_t c) {
|
||||
|
||||
void janet_parser_eof(JanetParser *parser) {
|
||||
janet_parser_checkdead(parser);
|
||||
size_t oldcolumn = parser->column;
|
||||
size_t oldline = parser->line;
|
||||
janet_parser_consume(parser, '\n');
|
||||
if (parser->statecount > 1) {
|
||||
parser->error = "unexpected end of source";
|
||||
}
|
||||
parser->offset--;
|
||||
parser->line = oldline;
|
||||
parser->column = oldcolumn;
|
||||
parser->flag = 1;
|
||||
}
|
||||
|
||||
@ -630,7 +644,8 @@ void janet_parser_init(JanetParser *parser) {
|
||||
parser->statecap = 0;
|
||||
parser->error = NULL;
|
||||
parser->lookback = -1;
|
||||
parser->offset = 0;
|
||||
parser->line = 1;
|
||||
parser->column = 0;
|
||||
parser->pending = 0;
|
||||
parser->flag = 0;
|
||||
|
||||
@ -648,7 +663,8 @@ void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
|
||||
dest->flag = src->flag;
|
||||
dest->pending = src->pending;
|
||||
dest->lookback = src->lookback;
|
||||
dest->offset = src->offset;
|
||||
dest->line = src->line;
|
||||
dest->column = src->column;
|
||||
dest->error = src->error;
|
||||
|
||||
/* Keep counts */
|
||||
@ -771,7 +787,7 @@ static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
|
||||
JanetParseState *s = p->states + p->statecount - 1;
|
||||
if (s->consumer == tokenchar) {
|
||||
janet_parser_consume(p, ' ');
|
||||
p->offset--;
|
||||
p->column--;
|
||||
s = p->states + p->statecount - 1;
|
||||
}
|
||||
if (s->flags & PFLAG_CONTAINER) {
|
||||
@ -855,15 +871,12 @@ static Janet cfun_parse_flush(int32_t argc, Janet *argv) {
|
||||
}
|
||||
|
||||
static Janet cfun_parse_where(int32_t argc, Janet *argv) {
|
||||
janet_arity(argc, 1, 2);
|
||||
janet_fixarity(argc, 1);
|
||||
JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
|
||||
if (argc > 1) {
|
||||
int32_t offset = janet_getinteger(argv, 1);
|
||||
p->offset = offset;
|
||||
return argv[0];
|
||||
} else {
|
||||
return janet_wrap_integer(p->offset);
|
||||
}
|
||||
Janet *tup = janet_tuple_begin(2);
|
||||
tup[0] = janet_wrap_integer(p->line);
|
||||
tup[1] = janet_wrap_integer(p->column);
|
||||
return janet_wrap_tuple(janet_tuple_end(tup));
|
||||
}
|
||||
|
||||
static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args,
|
||||
@ -928,8 +941,8 @@ static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args,
|
||||
janet_table_put(state, janet_ckeywordv("buffer"), janet_wrap_string(buffer));
|
||||
}
|
||||
|
||||
janet_table_put(state, janet_ckeywordv("start"),
|
||||
janet_wrap_integer(s->start));
|
||||
janet_table_put(state, janet_ckeywordv("line"), janet_wrap_integer(s->line));
|
||||
janet_table_put(state, janet_ckeywordv("column"), janet_wrap_integer(s->column));
|
||||
return janet_wrap_table(state);
|
||||
}
|
||||
|
||||
@ -1121,10 +1134,8 @@ static const JanetReg parse_cfuns[] = {
|
||||
},
|
||||
{
|
||||
"parser/where", cfun_parse_where,
|
||||
JDOC("(parser/where parser &opt offset)\n\n"
|
||||
"Returns the current line number and column number of the parser's location "
|
||||
"in the byte stream as an index, counted from 0. "
|
||||
"If offset is supplied, then the byte offset is updated to that new value.")
|
||||
JDOC("(parser/where parser)\n\n"
|
||||
"Returns the current line number and column of the parser's internal state.")
|
||||
},
|
||||
{
|
||||
"parser/eof", cfun_parse_eof,
|
||||
|
@ -175,8 +175,8 @@ static int destructure(JanetCompiler *c,
|
||||
static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
|
||||
Janet *tup = janet_tuple_begin(3);
|
||||
tup[0] = c->source ? janet_wrap_string(c->source) : janet_wrap_nil();
|
||||
tup[1] = janet_wrap_integer(c->current_mapping.start);
|
||||
tup[2] = janet_wrap_integer(c->current_mapping.end);
|
||||
tup[1] = janet_wrap_integer(c->current_mapping.line);
|
||||
tup[2] = janet_wrap_integer(c->current_mapping.column);
|
||||
return janet_tuple_end(tup);
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@
|
||||
Janet *janet_tuple_begin(int32_t length) {
|
||||
size_t size = sizeof(JanetTupleHead) + (length * sizeof(Janet));
|
||||
JanetTupleHead *head = janet_gcalloc(JANET_MEMORY_TUPLE, size);
|
||||
head->sm_start = -1;
|
||||
head->sm_end = -1;
|
||||
head->sm_line = -1;
|
||||
head->sm_column = -1;
|
||||
head->length = length;
|
||||
return (Janet *)(head->data);
|
||||
}
|
||||
@ -119,16 +119,16 @@ static Janet cfun_tuple_sourcemap(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 1);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
Janet contents[2];
|
||||
contents[0] = janet_wrap_integer(janet_tuple_head(tup)->sm_start);
|
||||
contents[1] = janet_wrap_integer(janet_tuple_head(tup)->sm_end);
|
||||
contents[0] = janet_wrap_integer(janet_tuple_head(tup)->sm_line);
|
||||
contents[1] = janet_wrap_integer(janet_tuple_head(tup)->sm_column);
|
||||
return janet_wrap_tuple(janet_tuple_n(contents, 2));
|
||||
}
|
||||
|
||||
static Janet cfun_tuple_setmap(int32_t argc, Janet *argv) {
|
||||
janet_fixarity(argc, 3);
|
||||
const Janet *tup = janet_gettuple(argv, 0);
|
||||
janet_tuple_head(tup)->sm_start = janet_getinteger(argv, 1);
|
||||
janet_tuple_head(tup)->sm_end = janet_getinteger(argv, 2);
|
||||
janet_tuple_head(tup)->sm_line = janet_getinteger(argv, 1);
|
||||
janet_tuple_head(tup)->sm_column = janet_getinteger(argv, 2);
|
||||
return argv[0];
|
||||
}
|
||||
|
||||
@ -158,16 +158,14 @@ static const JanetReg tuple_cfuns[] = {
|
||||
{
|
||||
"tuple/sourcemap", cfun_tuple_sourcemap,
|
||||
JDOC("(tuple/sourcemap tup)\n\n"
|
||||
"Returns the sourcemap metadata attached to a tuple. "
|
||||
"The mapping is represented by a pair of byte offsets into the "
|
||||
"the source code representing the start and end byte indices where "
|
||||
"the tuple is. ")
|
||||
"Returns the sourcemap metadata attached to a tuple, "
|
||||
" which is another tuple (line, column).")
|
||||
},
|
||||
{
|
||||
"tuple/setmap", cfun_tuple_setmap,
|
||||
JDOC("(tuple/setmap tup start end)\n\n"
|
||||
"Set the sourcemap metadata on a tuple. start and end should "
|
||||
"be integers representing byte offsets into the file. Returns tup.")
|
||||
JDOC("(tuple/setmap tup line column)\n\n"
|
||||
"Set the sourcemap metadata on a tuple. line and column indicate "
|
||||
"should be integers.")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL;
|
||||
* a switch inside an infinite loop. For GCC/clang, we use
|
||||
* computed gotos. */
|
||||
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
|
||||
#define JANET_USE_COMPUTED_GOTOS
|
||||
/*#define JANET_USE_COMPUTED_GOTOS*/
|
||||
#endif
|
||||
|
||||
#ifdef JANET_USE_COMPUTED_GOTOS
|
||||
|
@ -755,8 +755,8 @@ struct JanetTupleHead {
|
||||
JanetGCObject gc;
|
||||
int32_t length;
|
||||
int32_t hash;
|
||||
int32_t sm_start;
|
||||
int32_t sm_end;
|
||||
int32_t sm_line;
|
||||
int32_t sm_column;
|
||||
const Janet data[];
|
||||
};
|
||||
|
||||
@ -798,8 +798,8 @@ struct JanetAbstractHead {
|
||||
|
||||
/* Source mapping structure for a bytecode instruction */
|
||||
struct JanetSourceMapping {
|
||||
int32_t start;
|
||||
int32_t end;
|
||||
int32_t line;
|
||||
int32_t column;
|
||||
};
|
||||
|
||||
/* A function definition. Contains information needed to instantiate closures. */
|
||||
@ -869,7 +869,8 @@ struct JanetParser {
|
||||
size_t statecap;
|
||||
size_t bufcount;
|
||||
size_t bufcap;
|
||||
size_t offset;
|
||||
size_t line;
|
||||
size_t column;
|
||||
size_t pending;
|
||||
int lookback;
|
||||
int flag;
|
||||
@ -1100,7 +1101,7 @@ JANET_API void janet_debug_break(JanetFuncDef *def, int32_t pc);
|
||||
JANET_API void janet_debug_unbreak(JanetFuncDef *def, int32_t pc);
|
||||
JANET_API void janet_debug_find(
|
||||
JanetFuncDef **def_out, int32_t *pc_out,
|
||||
const uint8_t *source, int32_t offset);
|
||||
const uint8_t *source, int32_t line, int32_t column);
|
||||
|
||||
/* Array functions */
|
||||
JANET_API JanetArray *janet_array(int32_t capacity);
|
||||
@ -1133,8 +1134,8 @@ JANET_API void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x);
|
||||
#define janet_tuple_head(t) ((JanetTupleHead *)((char *)t - offsetof(JanetTupleHead, data)))
|
||||
#define janet_tuple_length(t) (janet_tuple_head(t)->length)
|
||||
#define janet_tuple_hash(t) (janet_tuple_head(t)->hash)
|
||||
#define janet_tuple_sm_start(t) (janet_tuple_head(t)->sm_start)
|
||||
#define janet_tuple_sm_end(t) (janet_tuple_head(t)->sm_end)
|
||||
#define janet_tuple_sm_line(t) (janet_tuple_head(t)->sm_line)
|
||||
#define janet_tuple_sm_column(t) (janet_tuple_head(t)->sm_column)
|
||||
#define janet_tuple_flag(t) (janet_tuple_head(t)->gc.flags)
|
||||
JANET_API Janet *janet_tuple_begin(int32_t length);
|
||||
JANET_API const Janet *janet_tuple_end(Janet *tuple);
|
||||
|
@ -80,8 +80,8 @@
|
||||
(print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose"))
|
||||
(defn noprompt [_] "")
|
||||
(defn getprompt [p]
|
||||
(def offset (parser/where p))
|
||||
(string "janet:" offset ":" (parser/state p :delimiters) "> "))
|
||||
(def [line] (parser/where p))
|
||||
(string "janet:" line ":" (parser/state p :delimiters) "> "))
|
||||
(def prompter (if *quiet* noprompt getprompt))
|
||||
(defn getstdin [prompt buf]
|
||||
(file/write stdout prompt)
|
||||
|
@ -155,5 +155,12 @@
|
||||
(assert (= (|(+ $1 $1 $1 $1) 2 4) 16) "function shorthand 8")
|
||||
(assert (= (|(+ $0 $1 $3 $2 $6) 0 1 2 3 4 5 6) 12) "function shorthand 9")
|
||||
|
||||
# Simple function break
|
||||
(debug/fbreak map)
|
||||
(def f (fiber/new (fn [] (map inc [1 2 3])) :a))
|
||||
(resume f)
|
||||
(assert (= :debug (fiber/status f)) "debug/fbreak")
|
||||
(debug/unfbreak map)
|
||||
(map inc [1 2 3])
|
||||
|
||||
(end-suite)
|
||||
|
Loading…
Reference in New Issue
Block a user