mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +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:
		
							
								
								
									
										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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose