1
0
mirror of https://github.com/janet-lang/janet synced 2024-09-27 14:48:13 +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:
Calvin Rose 2019-09-22 17:18:28 -05:00
parent 228d045a06
commit a8afc5b81f
13 changed files with 177 additions and 164 deletions

View File

@ -37,7 +37,7 @@ MANPATH?=$(PREFIX)/share/man/man1/
PKG_CONFIG_PATH?=$(PREFIX)/lib/pkgconfig PKG_CONFIG_PATH?=$(PREFIX)/lib/pkgconfig
DEBUGGER=gdb 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) -DJANET_BUILD=$(JANET_BUILD)
LDFLAGS=-rdynamic LDFLAGS=-rdynamic

View File

@ -1598,19 +1598,33 @@
(defn bad-parse (defn bad-parse
"Default handler for a parse error." "Default handler for a parse error."
[p where] [p where]
(def ec (dyn :err-color))
(def [line col] (parser/where p))
(file/write stderr (file/write stderr
(if ec "\e[31m" "")
"parse error in " "parse error in "
where where
" around byte " " around line "
(string (parser/where p)) (string line)
", column "
(string col)
": " ": "
(parser/error p) (parser/error p)
(if ec "\e[0m" "")
"\n")) "\n"))
(defn bad-compile (defn bad-compile
"Default handler for a compile error." "Default handler for a compile error."
[msg macrof where] [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))) (when macrof (debug/stacktrace macrof)))
(defn run-context (defn run-context
@ -1660,10 +1674,10 @@
(unless compile-only (res)) (unless compile-only (res))
(do (do
(set good false) (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 (def msg
(if (<= 0 start) (if (<= 0 line)
(string err " at (" start ":" end ")") (string err " on line " line ", column " column)
err)) err))
(on-compile-error msg errf where)))) (on-compile-error msg errf where))))
(or guard :a))) (or guard :a)))
@ -1946,7 +1960,7 @@
(def level (+ (dyn :debug-level 0) 1)) (def level (+ (dyn :debug-level 0) 1))
(default env (make-env)) (default env (make-env))
(default chunks (fn [buf p] (getline (string "repl:" (default chunks (fn [buf p] (getline (string "repl:"
(parser/where p) ((parser/where p) 0)
":" ":"
(parser/state p :delimiters) "> ") (parser/state p :delimiters) "> ")
buf))) buf)))
@ -1967,7 +1981,7 @@ _fiber is bound to the suspended fiber
```) ```)
(repl (fn [buf p] (repl (fn [buf p]
(def status (parser/state p :delimiters)) (def status (parser/state p :delimiters))
(def c (parser/where p)) (def c ((parser/where p) 0))
(def prompt (string "debug[" level "]:" c ":" status "> ")) (def prompt (string "debug[" level "]:" c ":" status "> "))
(getline prompt buf)) (getline prompt buf))
onsignal nextenv)) onsignal nextenv))

View File

@ -705,8 +705,8 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
if (!janet_checkint(tup[1])) { if (!janet_checkint(tup[1])) {
janet_asm_error(&a, "expected integer"); janet_asm_error(&a, "expected integer");
} }
mapping.start = janet_unwrap_integer(tup[0]); mapping.line = janet_unwrap_integer(tup[0]);
mapping.end = janet_unwrap_integer(tup[1]); mapping.column = janet_unwrap_integer(tup[1]);
def->sourcemap[i] = mapping; def->sourcemap[i] = mapping;
} }
} }
@ -749,31 +749,31 @@ static const JanetInstructionDef *janet_asm_reverse_lookup(uint32_t instr) {
} }
/* Create some constant sized tuples */ /* Create some constant sized tuples */
static Janet tup1(Janet x) { static const Janet *tup1(Janet x) {
Janet *tup = janet_tuple_begin(1); Janet *tup = janet_tuple_begin(1);
tup[0] = x; 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); Janet *tup = janet_tuple_begin(2);
tup[0] = x; tup[0] = x;
tup[1] = y; 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); Janet *tup = janet_tuple_begin(3);
tup[0] = x; tup[0] = x;
tup[1] = y; tup[1] = y;
tup[2] = z; 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); Janet *tup = janet_tuple_begin(4);
tup[0] = w; tup[0] = w;
tup[1] = x; tup[1] = x;
tup[2] = y; tup[2] = y;
tup[3] = z; 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 */ /* 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); return janet_wrap_integer((int32_t)instr);
} }
name = janet_csymbolv(def->name); name = janet_csymbolv(def->name);
const Janet *ret = NULL;
#define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask)) #define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask))
switch (janet_instructions[def->opcode]) { switch (janet_instructions[def->opcode]) {
case JINT_0: case JINT_0:
return tup1(name); ret = tup1(name);
break;
case JINT_S: 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: 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_SS:
case JINT_ST: case JINT_ST:
case JINT_SC: case JINT_SC:
case JINT_SU: case JINT_SU:
case JINT_SD: case JINT_SD:
return tup3(name, ret = tup3(name,
janet_wrap_integer(oparg(1, 0xFF)), janet_wrap_integer(oparg(1, 0xFF)),
janet_wrap_integer(oparg(2, 0xFFFF))); janet_wrap_integer(oparg(2, 0xFFFF)));
break;
case JINT_SI: case JINT_SI:
case JINT_SL: case JINT_SL:
return tup3(name, ret = tup3(name,
janet_wrap_integer(oparg(1, 0xFF)), janet_wrap_integer(oparg(1, 0xFF)),
janet_wrap_integer((int32_t)instr >> 16)); janet_wrap_integer((int32_t)instr >> 16));
break;
case JINT_SSS: case JINT_SSS:
case JINT_SES: case JINT_SES:
case JINT_SSU: case JINT_SSU:
return tup4(name, ret = tup4(name,
janet_wrap_integer(oparg(1, 0xFF)), janet_wrap_integer(oparg(1, 0xFF)),
janet_wrap_integer(oparg(2, 0xFF)), janet_wrap_integer(oparg(2, 0xFF)),
janet_wrap_integer(oparg(3, 0xFF))); janet_wrap_integer(oparg(3, 0xFF)));
break;
case JINT_SSI: case JINT_SSI:
return tup4(name, ret = tup4(name,
janet_wrap_integer(oparg(1, 0xFF)), janet_wrap_integer(oparg(1, 0xFF)),
janet_wrap_integer(oparg(2, 0xFF)), janet_wrap_integer(oparg(2, 0xFF)),
janet_wrap_integer((int32_t)instr >> 24)); janet_wrap_integer((int32_t)instr >> 24));
break;
} }
#undef oparg #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(); return janet_wrap_nil();
} }
@ -849,7 +864,7 @@ Janet janet_disasm(JanetFuncDef *def) {
Janet src = def->constants[i]; Janet src = def->constants[i];
Janet dest; Janet dest;
if (janet_checktype(src, JANET_TUPLE)) { if (janet_checktype(src, JANET_TUPLE)) {
dest = tup2(janet_csymbolv("quote"), src); dest = janet_wrap_tuple(tup2(janet_csymbolv("quote"), src));
} else { } else {
dest = src; dest = src;
} }
@ -870,8 +885,8 @@ Janet janet_disasm(JanetFuncDef *def) {
for (i = 0; i < def->bytecode_length; i++) { for (i = 0; i < def->bytecode_length; i++) {
Janet *t = janet_tuple_begin(2); Janet *t = janet_tuple_begin(2);
JanetSourceMapping mapping = def->sourcemap[i]; JanetSourceMapping mapping = def->sourcemap[i];
t[0] = janet_wrap_integer(mapping.start); t[0] = janet_wrap_integer(mapping.line);
t[1] = janet_wrap_integer(mapping.end); t[1] = janet_wrap_integer(mapping.column);
sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t)); sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t));
} }
sourcemap->count = def->bytecode_length; sourcemap->count = def->bytecode_length;

View File

@ -474,9 +474,9 @@ static int macroexpand1(
if (janet_tuple_length(form) == 0) if (janet_tuple_length(form) == 0)
return 0; return 0;
/* Source map - only set when we get a tuple */ /* Source map - only set when we get a tuple */
if (janet_tuple_sm_start(form) >= 0) { if (janet_tuple_sm_line(form) >= 0) {
c->current_mapping.start = janet_tuple_sm_start(form); c->current_mapping.line = janet_tuple_sm_line(form);
c->current_mapping.end = janet_tuple_sm_end(form); c->current_mapping.column = janet_tuple_sm_column(form);
} }
/* Bracketed tuples are not specials or macros! */ /* Bracketed tuples are not specials or macros! */
if (janet_tuple_flag(form) & JANET_TUPLE_FLAG_BRACKETCTOR) 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->recursion_guard = JANET_RECURSION_GUARD;
c->env = env; c->env = env;
c->source = where; c->source = where;
c->current_mapping.start = -1; c->current_mapping.line = -1;
c->current_mapping.end = -1; c->current_mapping.column = -1;
/* Init result */ /* Init result */
c->result.error = NULL; c->result.error = NULL;
c->result.status = JANET_COMPILE_OK; c->result.status = JANET_COMPILE_OK;
c->result.funcdef = NULL; c->result.funcdef = NULL;
c->result.macrofiber = NULL; c->result.macrofiber = NULL;
c->result.error_mapping.start = -1; c->result.error_mapping.line = -1;
c->result.error_mapping.end = -1; c->result.error_mapping.column = -1;
} }
/* Deinitialize a compiler struct */ /* Deinitialize a compiler struct */
@ -733,8 +733,8 @@ static Janet cfun(int32_t argc, Janet *argv) {
} else { } else {
JanetTable *t = janet_table(4); JanetTable *t = janet_table(4);
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error)); 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("line"), janet_wrap_integer(res.error_mapping.line));
janet_table_put(t, janet_ckeywordv("end"), janet_wrap_integer(res.error_mapping.end)); janet_table_put(t, janet_ckeywordv("column"), janet_wrap_integer(res.error_mapping.column));
if (res.macrofiber) { if (res.macrofiber) {
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber)); janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
} }

View File

@ -52,31 +52,34 @@ void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
*/ */
void janet_debug_find( void janet_debug_find(
JanetFuncDef **def_out, int32_t *pc_out, 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 */ /* Scan the heap for right func def */
JanetGCObject *current = janet_vm_blocks; JanetGCObject *current = janet_vm_blocks;
/* Keep track of the best source mapping we have seen so far */ /* Keep track of the best source mapping we have seen so far */
int32_t besti = -1; int32_t besti = -1;
int32_t best_range = INT32_MAX; int32_t best_line = -1;
int32_t best_column = -1;
JanetFuncDef *best_def = NULL; JanetFuncDef *best_def = NULL;
while (NULL != current) { while (NULL != current) {
if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) { if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
JanetFuncDef *def = (JanetFuncDef *)(current + 1); JanetFuncDef *def = (JanetFuncDef *)(current);
if (def->sourcemap && if (def->sourcemap &&
def->source && def->source &&
!janet_string_compare(source, def->source)) { !janet_string_compare(source, def->source)) {
/* Correct source file, check mappings. The chosen /* 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; int32_t i;
for (i = 0; i < def->bytecode_length; i++) { for (i = 0; i < def->bytecode_length; i++) {
int32_t start = def->sourcemap[i].start; int32_t line = def->sourcemap[i].line;
int32_t end = def->sourcemap[i].end; int32_t column = def->sourcemap[i].column;
if (end - start < best_range && if (line <= sourceLine && line >= best_line) {
start <= offset && if (column <= sourceColumn && column > best_column) {
end >= offset) { best_line = line;
best_range = end - start; best_column = column;
besti = i; besti = i;
best_def = def; best_def = def;
}
} }
} }
} }
@ -150,44 +153,8 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
if (frame->func && frame->pc) { if (frame->func && frame->pc) {
int32_t off = (int32_t)(frame->pc - def->bytecode); int32_t off = (int32_t)(frame->pc - def->bytecode);
if (def->sourcemap) { if (def->sourcemap) {
/* Try to get line and column information */
JanetSourceMapping mapping = def->sourcemap[off]; JanetSourceMapping mapping = def->sourcemap[off];
char buf[1024]; fprintf(out, " on line %d, column %d", mapping.line, mapping.column);
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);
}
} else { } else {
fprintf(out, " pc=%d", off); 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. /* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
* Takes a source file name and byte offset. */ * Takes a source file name and byte offset. */
static void helper_find(int32_t argc, Janet *argv, JanetFuncDef **def, int32_t *bytecode_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); const uint8_t *source = janet_getstring(argv, 0);
int32_t source_offset = janet_getinteger(argv, 1); int32_t line = janet_getinteger(argv, 1);
janet_debug_find(def, bytecode_offset, source, source_offset); 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. /* 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)); janet_table_put(t, janet_ckeywordv("pc"), janet_wrap_integer(off));
if (def->sourcemap) { if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off]; 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-line"), janet_wrap_integer(mapping.line));
janet_table_put(t, janet_ckeywordv("source-end"), janet_wrap_integer(mapping.end)); janet_table_put(t, janet_ckeywordv("source-column"), janet_wrap_integer(mapping.column));
} }
if (def->source) { if (def->source) {
janet_table_put(t, janet_ckeywordv("source"), janet_wrap_string(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, "debug/break", cfun_debug_break,
JDOC("(debug/break source byte-offset)\n\n" JDOC("(debug/break source byte-offset)\n\n"
"Sets a breakpoint with source a key at a given byte offset. An offset " "Sets a breakpoint with source a key at a given line and column. "
"of 0 is the first byte in a file. Will throw an error if the breakpoint location " "Will throw an error if the breakpoint location "
"cannot be found. For example\n\n" "cannot be found. For example\n\n"
"\t(debug/break \"core.janet\" 1000)\n\n" "\t(debug/break \"core.janet\" 1000)\n\n"
"wil set a breakpoint at the 1000th byte of the file core.janet.") "wil set a breakpoint at the 1000th byte of the file core.janet.")
}, },
{ {
"debug/unbreak", cfun_debug_unbreak, "debug/unbreak", cfun_debug_unbreak,
JDOC("(debug/unbreak source byte-offset)\n\n" JDOC("(debug/unbreak source line column)\n\n"
"Remove a breakpoint with a source key at a given byte offset. An offset " "Remove a breakpoint with a source key at a given line and column. "
"of 0 is the first byte in a file. Will throw an error if the breakpoint " "Will throw an error if the breakpoint "
"cannot be found.") "cannot be found.")
}, },
{ {

View File

@ -258,9 +258,9 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
int32_t current = 0; int32_t current = 0;
for (int32_t i = 0; i < def->bytecode_length; i++) { for (int32_t i = 0; i < def->bytecode_length; i++) {
JanetSourceMapping map = def->sourcemap[i]; JanetSourceMapping map = def->sourcemap[i];
pushint(st, map.start - current); pushint(st, map.line - current);
pushint(st, map.end - map.start); pushint(st, map.column);
current = map.end; current = map.line;
} }
} }
} }
@ -827,9 +827,8 @@ static const uint8_t *unmarshal_one_def(
} }
for (int32_t i = 0; i < bytecode_length; i++) { for (int32_t i = 0; i < bytecode_length; i++) {
current += readint(st, &data); current += readint(st, &data);
def->sourcemap[i].start = current; def->sourcemap[i].line = current;
current += readint(st, &data); def->sourcemap[i].column = readint(st, &data);
def->sourcemap[i].end = current;
} }
} else { } else {
def->sourcemap = NULL; def->sourcemap = NULL;

View File

@ -106,7 +106,8 @@ struct JanetParseState {
int32_t counter; int32_t counter;
int32_t argn; int32_t argn;
int flags; int flags;
size_t start; size_t line;
size_t column;
Consumer consumer; Consumer consumer;
}; };
@ -153,7 +154,8 @@ static void pushstate(JanetParser *p, Consumer consumer, int flags) {
s.argn = 0; s.argn = 0;
s.flags = flags; s.flags = flags;
s.consumer = consumer; s.consumer = consumer;
s.start = p->offset; s.line = p->line;
s.column = p->column;
_pushstate(p, s); _pushstate(p, s);
} }
@ -164,8 +166,8 @@ static void popstate(JanetParser *p, Janet val) {
if (newtop->flags & PFLAG_CONTAINER) { if (newtop->flags & PFLAG_CONTAINER) {
/* Source mapping info */ /* Source mapping info */
if (janet_checktype(val, JANET_TUPLE)) { if (janet_checktype(val, JANET_TUPLE)) {
janet_tuple_sm_start(janet_unwrap_tuple(val)) = (int32_t) top.start; janet_tuple_sm_line(janet_unwrap_tuple(val)) = (int32_t) top.line;
janet_tuple_sm_end(janet_unwrap_tuple(val)) = (int32_t) p->offset; janet_tuple_sm_column(janet_unwrap_tuple(val)) = (int32_t) top.column;
} }
newtop->argn++; newtop->argn++;
/* Keep track of number of values in the root state */ /* 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[0] = janet_csymbolv(which);
t[1] = val; t[1] = val;
/* Quote source mapping info */ /* Quote source mapping info */
janet_tuple_sm_start(t) = (int32_t) newtop->start; janet_tuple_sm_line(t) = (int32_t) newtop->line;
janet_tuple_sm_end(t) = (int32_t) p->offset; janet_tuple_sm_column(t) = (int32_t) newtop->column;
val = janet_wrap_tuple(janet_tuple_end(t)); val = janet_wrap_tuple(janet_tuple_end(t));
} else { } else {
return; return;
@ -562,7 +564,16 @@ static void janet_parser_checkdead(JanetParser *parser) {
void janet_parser_consume(JanetParser *parser, uint8_t c) { void janet_parser_consume(JanetParser *parser, uint8_t c) {
int consumed = 0; int consumed = 0;
janet_parser_checkdead(parser); 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) { while (!consumed && !parser->error) {
JanetParseState *state = parser->states + parser->statecount - 1; JanetParseState *state = parser->states + parser->statecount - 1;
consumed = state->consumer(parser, state, c); 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) { void janet_parser_eof(JanetParser *parser) {
janet_parser_checkdead(parser); janet_parser_checkdead(parser);
size_t oldcolumn = parser->column;
size_t oldline = parser->line;
janet_parser_consume(parser, '\n'); janet_parser_consume(parser, '\n');
if (parser->statecount > 1) { if (parser->statecount > 1) {
parser->error = "unexpected end of source"; parser->error = "unexpected end of source";
} }
parser->offset--; parser->line = oldline;
parser->column = oldcolumn;
parser->flag = 1; parser->flag = 1;
} }
@ -630,7 +644,8 @@ void janet_parser_init(JanetParser *parser) {
parser->statecap = 0; parser->statecap = 0;
parser->error = NULL; parser->error = NULL;
parser->lookback = -1; parser->lookback = -1;
parser->offset = 0; parser->line = 1;
parser->column = 0;
parser->pending = 0; parser->pending = 0;
parser->flag = 0; parser->flag = 0;
@ -648,7 +663,8 @@ void janet_parser_clone(const JanetParser *src, JanetParser *dest) {
dest->flag = src->flag; dest->flag = src->flag;
dest->pending = src->pending; dest->pending = src->pending;
dest->lookback = src->lookback; dest->lookback = src->lookback;
dest->offset = src->offset; dest->line = src->line;
dest->column = src->column;
dest->error = src->error; dest->error = src->error;
/* Keep counts */ /* Keep counts */
@ -771,7 +787,7 @@ static Janet cfun_parse_insert(int32_t argc, Janet *argv) {
JanetParseState *s = p->states + p->statecount - 1; JanetParseState *s = p->states + p->statecount - 1;
if (s->consumer == tokenchar) { if (s->consumer == tokenchar) {
janet_parser_consume(p, ' '); janet_parser_consume(p, ' ');
p->offset--; p->column--;
s = p->states + p->statecount - 1; s = p->states + p->statecount - 1;
} }
if (s->flags & PFLAG_CONTAINER) { 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) { 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); JanetParser *p = janet_getabstract(argv, 0, &janet_parse_parsertype);
if (argc > 1) { Janet *tup = janet_tuple_begin(2);
int32_t offset = janet_getinteger(argv, 1); tup[0] = janet_wrap_integer(p->line);
p->offset = offset; tup[1] = janet_wrap_integer(p->column);
return argv[0]; return janet_wrap_tuple(janet_tuple_end(tup));
} else {
return janet_wrap_integer(p->offset);
}
} }
static Janet janet_wrap_parse_state(JanetParseState *s, Janet *args, 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("buffer"), janet_wrap_string(buffer));
} }
janet_table_put(state, janet_ckeywordv("start"), janet_table_put(state, janet_ckeywordv("line"), janet_wrap_integer(s->line));
janet_wrap_integer(s->start)); janet_table_put(state, janet_ckeywordv("column"), janet_wrap_integer(s->column));
return janet_wrap_table(state); return janet_wrap_table(state);
} }
@ -1121,10 +1134,8 @@ static const JanetReg parse_cfuns[] = {
}, },
{ {
"parser/where", cfun_parse_where, "parser/where", cfun_parse_where,
JDOC("(parser/where parser &opt offset)\n\n" JDOC("(parser/where parser)\n\n"
"Returns the current line number and column number of the parser's location " "Returns the current line number and column of the parser's internal state.")
"in the byte stream as an index, counted from 0. "
"If offset is supplied, then the byte offset is updated to that new value.")
}, },
{ {
"parser/eof", cfun_parse_eof, "parser/eof", cfun_parse_eof,

View File

@ -175,8 +175,8 @@ static int destructure(JanetCompiler *c,
static const Janet *janetc_make_sourcemap(JanetCompiler *c) { static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
Janet *tup = janet_tuple_begin(3); Janet *tup = janet_tuple_begin(3);
tup[0] = c->source ? janet_wrap_string(c->source) : janet_wrap_nil(); tup[0] = c->source ? janet_wrap_string(c->source) : janet_wrap_nil();
tup[1] = janet_wrap_integer(c->current_mapping.start); tup[1] = janet_wrap_integer(c->current_mapping.line);
tup[2] = janet_wrap_integer(c->current_mapping.end); tup[2] = janet_wrap_integer(c->current_mapping.column);
return janet_tuple_end(tup); return janet_tuple_end(tup);
} }

View File

@ -33,8 +33,8 @@
Janet *janet_tuple_begin(int32_t length) { Janet *janet_tuple_begin(int32_t length) {
size_t size = sizeof(JanetTupleHead) + (length * sizeof(Janet)); size_t size = sizeof(JanetTupleHead) + (length * sizeof(Janet));
JanetTupleHead *head = janet_gcalloc(JANET_MEMORY_TUPLE, size); JanetTupleHead *head = janet_gcalloc(JANET_MEMORY_TUPLE, size);
head->sm_start = -1; head->sm_line = -1;
head->sm_end = -1; head->sm_column = -1;
head->length = length; head->length = length;
return (Janet *)(head->data); return (Janet *)(head->data);
} }
@ -119,16 +119,16 @@ static Janet cfun_tuple_sourcemap(int32_t argc, Janet *argv) {
janet_fixarity(argc, 1); janet_fixarity(argc, 1);
const Janet *tup = janet_gettuple(argv, 0); const Janet *tup = janet_gettuple(argv, 0);
Janet contents[2]; Janet contents[2];
contents[0] = janet_wrap_integer(janet_tuple_head(tup)->sm_start); contents[0] = janet_wrap_integer(janet_tuple_head(tup)->sm_line);
contents[1] = janet_wrap_integer(janet_tuple_head(tup)->sm_end); contents[1] = janet_wrap_integer(janet_tuple_head(tup)->sm_column);
return janet_wrap_tuple(janet_tuple_n(contents, 2)); return janet_wrap_tuple(janet_tuple_n(contents, 2));
} }
static Janet cfun_tuple_setmap(int32_t argc, Janet *argv) { static Janet cfun_tuple_setmap(int32_t argc, Janet *argv) {
janet_fixarity(argc, 3); janet_fixarity(argc, 3);
const Janet *tup = janet_gettuple(argv, 0); const Janet *tup = janet_gettuple(argv, 0);
janet_tuple_head(tup)->sm_start = janet_getinteger(argv, 1); janet_tuple_head(tup)->sm_line = janet_getinteger(argv, 1);
janet_tuple_head(tup)->sm_end = janet_getinteger(argv, 2); janet_tuple_head(tup)->sm_column = janet_getinteger(argv, 2);
return argv[0]; return argv[0];
} }
@ -158,16 +158,14 @@ static const JanetReg tuple_cfuns[] = {
{ {
"tuple/sourcemap", cfun_tuple_sourcemap, "tuple/sourcemap", cfun_tuple_sourcemap,
JDOC("(tuple/sourcemap tup)\n\n" JDOC("(tuple/sourcemap tup)\n\n"
"Returns the sourcemap metadata attached to a tuple. " "Returns the sourcemap metadata attached to a tuple, "
"The mapping is represented by a pair of byte offsets into the " " which is another tuple (line, column).")
"the source code representing the start and end byte indices where "
"the tuple is. ")
}, },
{ {
"tuple/setmap", cfun_tuple_setmap, "tuple/setmap", cfun_tuple_setmap,
JDOC("(tuple/setmap tup start end)\n\n" JDOC("(tuple/setmap tup line column)\n\n"
"Set the sourcemap metadata on a tuple. start and end should " "Set the sourcemap metadata on a tuple. line and column indicate "
"be integers representing byte offsets into the file. Returns tup.") "should be integers.")
}, },
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };

View File

@ -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 * a switch inside an infinite loop. For GCC/clang, we use
* computed gotos. */ * computed gotos. */
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__) #if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
#define JANET_USE_COMPUTED_GOTOS /*#define JANET_USE_COMPUTED_GOTOS*/
#endif #endif
#ifdef JANET_USE_COMPUTED_GOTOS #ifdef JANET_USE_COMPUTED_GOTOS

View File

@ -755,8 +755,8 @@ struct JanetTupleHead {
JanetGCObject gc; JanetGCObject gc;
int32_t length; int32_t length;
int32_t hash; int32_t hash;
int32_t sm_start; int32_t sm_line;
int32_t sm_end; int32_t sm_column;
const Janet data[]; const Janet data[];
}; };
@ -798,8 +798,8 @@ struct JanetAbstractHead {
/* Source mapping structure for a bytecode instruction */ /* Source mapping structure for a bytecode instruction */
struct JanetSourceMapping { struct JanetSourceMapping {
int32_t start; int32_t line;
int32_t end; int32_t column;
}; };
/* A function definition. Contains information needed to instantiate closures. */ /* A function definition. Contains information needed to instantiate closures. */
@ -869,7 +869,8 @@ struct JanetParser {
size_t statecap; size_t statecap;
size_t bufcount; size_t bufcount;
size_t bufcap; size_t bufcap;
size_t offset; size_t line;
size_t column;
size_t pending; size_t pending;
int lookback; int lookback;
int flag; 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_unbreak(JanetFuncDef *def, int32_t pc);
JANET_API void janet_debug_find( JANET_API void janet_debug_find(
JanetFuncDef **def_out, int32_t *pc_out, 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 */ /* Array functions */
JANET_API JanetArray *janet_array(int32_t capacity); 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_head(t) ((JanetTupleHead *)((char *)t - offsetof(JanetTupleHead, data)))
#define janet_tuple_length(t) (janet_tuple_head(t)->length) #define janet_tuple_length(t) (janet_tuple_head(t)->length)
#define janet_tuple_hash(t) (janet_tuple_head(t)->hash) #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_line(t) (janet_tuple_head(t)->sm_line)
#define janet_tuple_sm_end(t) (janet_tuple_head(t)->sm_end) #define janet_tuple_sm_column(t) (janet_tuple_head(t)->sm_column)
#define janet_tuple_flag(t) (janet_tuple_head(t)->gc.flags) #define janet_tuple_flag(t) (janet_tuple_head(t)->gc.flags)
JANET_API Janet *janet_tuple_begin(int32_t length); JANET_API Janet *janet_tuple_begin(int32_t length);
JANET_API const Janet *janet_tuple_end(Janet *tuple); JANET_API const Janet *janet_tuple_end(Janet *tuple);

View File

@ -80,8 +80,8 @@
(print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose")) (print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose"))
(defn noprompt [_] "") (defn noprompt [_] "")
(defn getprompt [p] (defn getprompt [p]
(def offset (parser/where p)) (def [line] (parser/where p))
(string "janet:" offset ":" (parser/state p :delimiters) "> ")) (string "janet:" line ":" (parser/state p :delimiters) "> "))
(def prompter (if *quiet* noprompt getprompt)) (def prompter (if *quiet* noprompt getprompt))
(defn getstdin [prompt buf] (defn getstdin [prompt buf]
(file/write stdout prompt) (file/write stdout prompt)

View File

@ -155,5 +155,12 @@
(assert (= (|(+ $1 $1 $1 $1) 2 4) 16) "function shorthand 8") (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") (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) (end-suite)