mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Make source mapping use byte offset instead of line and col
for better debugging support in repl. Add debug module for better debugging support.
This commit is contained in:
parent
4b01409d2d
commit
e8c0dcd14e
@ -710,8 +710,8 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
|
|||||||
if (!janet_checktype(tup[1], JANET_INTEGER)) {
|
if (!janet_checktype(tup[1], JANET_INTEGER)) {
|
||||||
janet_asm_error(&a, "expected integer");
|
janet_asm_error(&a, "expected integer");
|
||||||
}
|
}
|
||||||
mapping.line = janet_unwrap_integer(tup[0]);
|
mapping.start = janet_unwrap_integer(tup[0]);
|
||||||
mapping.column = janet_unwrap_integer(tup[1]);
|
mapping.end = janet_unwrap_integer(tup[1]);
|
||||||
def->sourcemap[i] = mapping;
|
def->sourcemap[i] = mapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -876,8 +876,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.line);
|
t[0] = janet_wrap_integer(mapping.start);
|
||||||
t[1] = janet_wrap_integer(mapping.column);
|
t[1] = janet_wrap_integer(mapping.end);
|
||||||
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;
|
||||||
|
@ -125,10 +125,10 @@ int32_t janet_verify(JanetFuncDef *def) {
|
|||||||
for (i = 0; i < def->bytecode_length; i++) {
|
for (i = 0; i < def->bytecode_length; i++) {
|
||||||
uint32_t instr = def->bytecode[i];
|
uint32_t instr = def->bytecode[i];
|
||||||
/* Check for invalid instructions */
|
/* Check for invalid instructions */
|
||||||
if ((instr & 0xFF) >= JOP_INSTRUCTION_COUNT) {
|
if ((instr & 0x7F) >= JOP_INSTRUCTION_COUNT) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
enum JanetInstructionType type = janet_instructions[instr & 0xFF];
|
enum JanetInstructionType type = janet_instructions[instr & 0x7F];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case JINT_0:
|
case JINT_0:
|
||||||
continue;
|
continue;
|
||||||
|
@ -462,9 +462,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_line(form) > 0) {
|
if (janet_tuple_sm_start(form) >= 0) {
|
||||||
c->current_mapping.line = janet_tuple_sm_line(form);
|
c->current_mapping.start = janet_tuple_sm_start(form);
|
||||||
c->current_mapping.column = janet_tuple_sm_col(form);
|
c->current_mapping.end = janet_tuple_sm_end(form);
|
||||||
}
|
}
|
||||||
if (!janet_checktype(form[0], JANET_SYMBOL))
|
if (!janet_checktype(form[0], JANET_SYMBOL))
|
||||||
return 0;
|
return 0;
|
||||||
@ -648,15 +648,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.line = 0;
|
c->current_mapping.start = -1;
|
||||||
c->current_mapping.column = 0;
|
c->current_mapping.end = -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.line = 0;
|
c->result.error_mapping.start = -1;
|
||||||
c->result.error_mapping.column = 0;
|
c->result.error_mapping.end = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deinitialize a compiler struct */
|
/* Deinitialize a compiler struct */
|
||||||
@ -717,8 +717,8 @@ static int cfun(JanetArgs args) {
|
|||||||
} else {
|
} else {
|
||||||
t = janet_table(4);
|
t = janet_table(4);
|
||||||
janet_table_put(t, janet_csymbolv(":error"), janet_wrap_string(res.error));
|
janet_table_put(t, janet_csymbolv(":error"), janet_wrap_string(res.error));
|
||||||
janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(res.error_mapping.line));
|
janet_table_put(t, janet_csymbolv(":start"), janet_wrap_integer(res.error_mapping.start));
|
||||||
janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(res.error_mapping.column));
|
janet_table_put(t, janet_csymbolv(":end"), janet_wrap_integer(res.error_mapping.end));
|
||||||
if (res.macrofiber) {
|
if (res.macrofiber) {
|
||||||
janet_table_put(t, janet_csymbolv(":fiber"), janet_wrap_fiber(res.macrofiber));
|
janet_table_put(t, janet_csymbolv(":fiber"), janet_wrap_fiber(res.macrofiber));
|
||||||
}
|
}
|
||||||
|
@ -1252,11 +1252,11 @@ value, one key will be ignored."
|
|||||||
(res)
|
(res)
|
||||||
(do
|
(do
|
||||||
(:= good false)
|
(:= good false)
|
||||||
(def {:error err :line errl :column errc :fiber errf} res)
|
(def {:error err :start start :end end :fiber errf} res)
|
||||||
(onstatus
|
(onstatus
|
||||||
:compile
|
:compile
|
||||||
(if (< 0 errl)
|
(if (<= 0 start)
|
||||||
(string err "\n in a form at line " errl ", column " errc)
|
(string err "\n at (" start ":" end ")")
|
||||||
err)
|
err)
|
||||||
errf
|
errf
|
||||||
where))))
|
where))))
|
||||||
@ -1309,7 +1309,7 @@ value, one key will be ignored."
|
|||||||
"\n")
|
"\n")
|
||||||
(when f
|
(when f
|
||||||
(loop
|
(loop
|
||||||
[nf :in (reverse (fiber/lineage f))
|
[nf :in (reverse (debug/lineage f))
|
||||||
:before (file/write stderr " (fiber)\n")
|
:before (file/write stderr " (fiber)\n")
|
||||||
{:function func
|
{:function func
|
||||||
:tail tail
|
:tail tail
|
||||||
@ -1317,8 +1317,8 @@ value, one key will be ignored."
|
|||||||
:c c
|
:c c
|
||||||
:name name
|
:name name
|
||||||
:source source
|
:source source
|
||||||
:line source-line
|
:source-start start
|
||||||
:column source-col} :in (fiber/stack nf)]
|
:source-end end} :in (debug/stack nf)]
|
||||||
(file/write stderr " in")
|
(file/write stderr " in")
|
||||||
(when c (file/write stderr " cfunction"))
|
(when c (file/write stderr " cfunction"))
|
||||||
(if name
|
(if name
|
||||||
@ -1327,14 +1327,15 @@ value, one key will be ignored."
|
|||||||
(if source
|
(if source
|
||||||
(do
|
(do
|
||||||
(file/write stderr " [" source "]")
|
(file/write stderr " [" source "]")
|
||||||
(if source-line
|
(if start
|
||||||
(file/write
|
(file/write
|
||||||
stderr
|
stderr
|
||||||
" on line "
|
" at ("
|
||||||
(string source-line)
|
(string start)
|
||||||
", column "
|
":"
|
||||||
(string source-col)))))
|
(string end)
|
||||||
(if (and (not source-line) pc)
|
")"))))
|
||||||
|
(if (and (not start) pc)
|
||||||
(file/write stderr " (pc=" (string pc) ")"))
|
(file/write stderr " (pc=" (string pc) ")"))
|
||||||
(when tail (file/write stderr " (tailcall)"))
|
(when tail (file/write stderr " (tailcall)"))
|
||||||
(file/write stderr "\n"))))
|
(file/write stderr "\n"))))
|
||||||
@ -1507,6 +1508,7 @@ value, one key will be ignored."
|
|||||||
(def newenv (make-env))
|
(def newenv (make-env))
|
||||||
(default chunks (fn [buf _] (file/read stdin :line buf)))
|
(default chunks (fn [buf _] (file/read stdin :line buf)))
|
||||||
(default onsignal (fn [sig x f source]
|
(default onsignal (fn [sig x f source]
|
||||||
|
(put newenv '_fiber @{:value f})
|
||||||
(case sig
|
(case sig
|
||||||
:dead (do
|
:dead (do
|
||||||
(put newenv '_ @{:value x})
|
(put newenv '_ @{:value x})
|
||||||
|
@ -801,6 +801,7 @@ JanetTable *janet_core_env(void) {
|
|||||||
janet_lib_os(args);
|
janet_lib_os(args);
|
||||||
janet_lib_parse(args);
|
janet_lib_parse(args);
|
||||||
janet_lib_compile(args);
|
janet_lib_compile(args);
|
||||||
|
janet_lib_debug(args);
|
||||||
janet_lib_string(args);
|
janet_lib_string(args);
|
||||||
janet_lib_marsh(args);
|
janet_lib_marsh(args);
|
||||||
#ifdef JANET_ASSEMBLER
|
#ifdef JANET_ASSEMBLER
|
||||||
|
289
src/core/debug.c
Normal file
289
src/core/debug.c
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <janet/janet.h>
|
||||||
|
#include "gc.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
/* Implements functionality to build a debugger from within janet.
|
||||||
|
* The repl should also be able to serve as pretty featured debugger
|
||||||
|
* out of the box. */
|
||||||
|
|
||||||
|
/* Add a break point to a function */
|
||||||
|
int janet_debug_break(JanetFuncDef *def, int32_t pc) {
|
||||||
|
if (pc >= def->bytecode_length || pc < 0)
|
||||||
|
return 1;
|
||||||
|
def->bytecode[pc] |= 0x80;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove a break point from a function */
|
||||||
|
int janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
|
||||||
|
if (pc >= def->bytecode_length || pc < 0)
|
||||||
|
return 1;
|
||||||
|
def->bytecode[pc] &= ~((uint32_t)0x80);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a location for a breakpoint given a source file an
|
||||||
|
* location.
|
||||||
|
*/
|
||||||
|
int janet_debug_find(
|
||||||
|
JanetFuncDef **def_out, int32_t *pc_out,
|
||||||
|
const uint8_t *source, int32_t offset) {
|
||||||
|
/* Scan the heap for right func def */
|
||||||
|
JanetGCMemoryHeader *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;
|
||||||
|
JanetFuncDef *best_def = NULL;
|
||||||
|
while (NULL != current) {
|
||||||
|
if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
|
||||||
|
JanetFuncDef *def = (JanetFuncDef *)(current + 1);
|
||||||
|
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. */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
if (best_def) {
|
||||||
|
*def_out = best_def;
|
||||||
|
*pc_out = besti;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CFuns
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||||
|
* Takes a source file name and byte offset. */
|
||||||
|
static int helper_find(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
|
||||||
|
const uint8_t *source;
|
||||||
|
int32_t source_offset;
|
||||||
|
JANET_FIXARITY(args, 2);
|
||||||
|
JANET_ARG_STRING(source, args, 0);
|
||||||
|
JANET_ARG_INTEGER(source_offset, args, 1);
|
||||||
|
if (janet_debug_find(
|
||||||
|
def, bytecode_offset, source, source_offset)) {
|
||||||
|
JANET_THROW(args, "could not find breakpoint");
|
||||||
|
}
|
||||||
|
JANET_RETURN_NIL(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
|
||||||
|
* Takes a function and byte offset*/
|
||||||
|
static int helper_find_fun(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
|
||||||
|
JanetFunction *func;
|
||||||
|
int32_t offset = 0;
|
||||||
|
JANET_MINARITY(args, 1);
|
||||||
|
JANET_MAXARITY(args, 2);
|
||||||
|
JANET_ARG_FUNCTION(func, args, 0);
|
||||||
|
if (args.n == 2) {
|
||||||
|
JANET_ARG_INTEGER(offset, args, 1);
|
||||||
|
}
|
||||||
|
*def = func->def;
|
||||||
|
*bytecode_offset = offset;
|
||||||
|
JANET_RETURN_NIL(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_break(JanetArgs args) {
|
||||||
|
JanetFuncDef *def;
|
||||||
|
int32_t offset;
|
||||||
|
int status = helper_find(args, &def, &offset);
|
||||||
|
if (status == 0) janet_debug_break(def, offset);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_unbreak(JanetArgs args) {
|
||||||
|
JanetFuncDef *def;
|
||||||
|
int32_t offset;
|
||||||
|
int status = helper_find(args, &def, &offset);
|
||||||
|
if (status == 0) janet_debug_unbreak(def, offset);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_fbreak(JanetArgs args) {
|
||||||
|
JanetFuncDef *def;
|
||||||
|
int32_t offset;
|
||||||
|
int status = helper_find_fun(args, &def, &offset);
|
||||||
|
if (status == 0) {
|
||||||
|
if (janet_debug_break(def, offset)) {
|
||||||
|
JANET_THROW(args, "could not find breakpoint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_unfbreak(JanetArgs args) {
|
||||||
|
JanetFuncDef *def;
|
||||||
|
int32_t offset;
|
||||||
|
int status = helper_find_fun(args, &def, &offset);
|
||||||
|
if (status == 0) {
|
||||||
|
if (janet_debug_unbreak(def, offset)) {
|
||||||
|
JANET_THROW(args, "could not find breakpoint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_lineage(JanetArgs args) {
|
||||||
|
JanetFiber *fiber;
|
||||||
|
JanetArray *array;
|
||||||
|
JANET_FIXARITY(args, 1);
|
||||||
|
JANET_ARG_FIBER(fiber, args, 0);
|
||||||
|
array = janet_array(0);
|
||||||
|
while (fiber) {
|
||||||
|
janet_array_push(array, janet_wrap_fiber(fiber));
|
||||||
|
fiber = fiber->child;
|
||||||
|
}
|
||||||
|
JANET_RETURN_ARRAY(args, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract info from one stack frame */
|
||||||
|
static Janet doframe(JanetStackFrame *frame) {
|
||||||
|
int32_t off;
|
||||||
|
JanetTable *t = janet_table(3);
|
||||||
|
JanetFuncDef *def = NULL;
|
||||||
|
if (frame->func) {
|
||||||
|
janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
|
||||||
|
def = frame->func->def;
|
||||||
|
if (def->name) {
|
||||||
|
janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
||||||
|
if (cfun) {
|
||||||
|
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
||||||
|
if (!janet_checktype(name, JANET_NIL)) {
|
||||||
|
janet_table_put(t, janet_csymbolv(":name"), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
|
||||||
|
}
|
||||||
|
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
|
||||||
|
janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
|
||||||
|
}
|
||||||
|
if (frame->func && frame->pc) {
|
||||||
|
off = (int32_t) (frame->pc - def->bytecode);
|
||||||
|
janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
|
||||||
|
if (def->sourcemap) {
|
||||||
|
JanetSourceMapping mapping = def->sourcemap[off];
|
||||||
|
janet_table_put(t, janet_csymbolv(":source-start"), janet_wrap_integer(mapping.start));
|
||||||
|
janet_table_put(t, janet_csymbolv(":source-end"), janet_wrap_integer(mapping.end));
|
||||||
|
}
|
||||||
|
if (def->source) {
|
||||||
|
janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return janet_wrap_table(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cfun_stack(JanetArgs args) {
|
||||||
|
JanetFiber *fiber;
|
||||||
|
JanetArray *array;
|
||||||
|
JANET_FIXARITY(args, 1);
|
||||||
|
JANET_ARG_FIBER(fiber, args, 0);
|
||||||
|
array = janet_array(0);
|
||||||
|
{
|
||||||
|
int32_t i = fiber->frame;
|
||||||
|
JanetStackFrame *frame;
|
||||||
|
while (i > 0) {
|
||||||
|
frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
||||||
|
janet_array_push(array, doframe(frame));
|
||||||
|
i = frame->prevframe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JANET_RETURN_ARRAY(args, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetReg cfuns[] = {
|
||||||
|
{"debug/break", cfun_break,
|
||||||
|
"(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 "
|
||||||
|
"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_unbreak,
|
||||||
|
"(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 "
|
||||||
|
"cannot be found."},
|
||||||
|
{"debug/fbreak", cfun_fbreak,
|
||||||
|
"(debug/fbreak fun [,pc=0])\n\n"
|
||||||
|
"Set a breakpoint in a given function. pc is an optional offset, which "
|
||||||
|
"is in bytecode instructions. fun is a function value. Will throw an error "
|
||||||
|
"if the offset is too large or negative."},
|
||||||
|
{"debug/funbreak", cfun_unfbreak,
|
||||||
|
"(debug/fbreak fun [,pc=0])\n\n"
|
||||||
|
"Unset a breakpoint set with debug/fbreak."},
|
||||||
|
{"debug/stack", cfun_stack,
|
||||||
|
"(debug/stack fib)\n\n"
|
||||||
|
"Gets information about the stack as an array of tables. Each table "
|
||||||
|
"in the array contains information about a stack frame. The top most, current "
|
||||||
|
"stack frame is the first table in the array, and the bottom most stack frame "
|
||||||
|
"is the last value. Each stack frame contains some of the following attributes:\n\n"
|
||||||
|
"\t:c - true if the stack frame is a c function invocation\n"
|
||||||
|
"\t:column - the current source column of the stack frame\n"
|
||||||
|
"\t:function - the function that the stack frame represents\n"
|
||||||
|
"\t:line - the current source line of the stack frame\n"
|
||||||
|
"\t:name - the human friendly name of the function\n"
|
||||||
|
"\t:pc - integer indicating the location of the program counter\n"
|
||||||
|
"\t:source - string with filename or other identifier for the source code\n"
|
||||||
|
"\t:tail - boolean indicating a tail call"
|
||||||
|
},
|
||||||
|
{"debug/lineage", cfun_lineage,
|
||||||
|
"(debug/lineage fib)\n\n"
|
||||||
|
"Returns an array of all child fibers from a root fiber. This function "
|
||||||
|
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
|
||||||
|
"the fiber handling the error can see which fiber raised the signal. This function should "
|
||||||
|
"be used mostly for debugging purposes."
|
||||||
|
},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Module entry point */
|
||||||
|
int janet_lib_debug(JanetArgs args) {
|
||||||
|
JanetTable *env = janet_env(args);
|
||||||
|
janet_cfuns(env, NULL, cfuns);
|
||||||
|
return 0;
|
||||||
|
}
|
114
src/core/fiber.c
114
src/core/fiber.c
@ -349,88 +349,11 @@ static int cfun_new(JanetArgs args) {
|
|||||||
|
|
||||||
static int cfun_status(JanetArgs args) {
|
static int cfun_status(JanetArgs args) {
|
||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
const char *status = "";
|
|
||||||
JANET_FIXARITY(args, 1);
|
JANET_FIXARITY(args, 1);
|
||||||
JANET_ARG_FIBER(fiber, args, 0);
|
JANET_ARG_FIBER(fiber, args, 0);
|
||||||
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
|
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
|
||||||
JANET_FIBER_STATUS_OFFSET;
|
JANET_FIBER_STATUS_OFFSET;
|
||||||
switch (s) {
|
JANET_RETURN_CSYMBOL(args, janet_status_names[s]);
|
||||||
case JANET_STATUS_DEAD: status = ":dead"; break;
|
|
||||||
case JANET_STATUS_ERROR: status = ":error"; break;
|
|
||||||
case JANET_STATUS_DEBUG: status = ":debug"; break;
|
|
||||||
case JANET_STATUS_PENDING: status = ":pending"; break;
|
|
||||||
case JANET_STATUS_USER0: status = ":user0"; break;
|
|
||||||
case JANET_STATUS_USER1: status = ":user1"; break;
|
|
||||||
case JANET_STATUS_USER2: status = ":user2"; break;
|
|
||||||
case JANET_STATUS_USER3: status = ":user3"; break;
|
|
||||||
case JANET_STATUS_USER4: status = ":user4"; break;
|
|
||||||
case JANET_STATUS_USER5: status = ":user5"; break;
|
|
||||||
case JANET_STATUS_USER6: status = ":user6"; break;
|
|
||||||
case JANET_STATUS_USER7: status = ":user7"; break;
|
|
||||||
case JANET_STATUS_USER8: status = ":user8"; break;
|
|
||||||
case JANET_STATUS_USER9: status = ":user9"; break;
|
|
||||||
case JANET_STATUS_NEW: status = ":new"; break;
|
|
||||||
default:
|
|
||||||
case JANET_STATUS_ALIVE: status = ":alive"; break;
|
|
||||||
}
|
|
||||||
JANET_RETURN_CSYMBOL(args, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract info from one stack frame */
|
|
||||||
static Janet doframe(JanetStackFrame *frame) {
|
|
||||||
int32_t off;
|
|
||||||
JanetTable *t = janet_table(3);
|
|
||||||
JanetFuncDef *def = NULL;
|
|
||||||
if (frame->func) {
|
|
||||||
janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
|
|
||||||
def = frame->func->def;
|
|
||||||
if (def->name) {
|
|
||||||
janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JanetCFunction cfun = (JanetCFunction)(frame->pc);
|
|
||||||
if (cfun) {
|
|
||||||
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
|
|
||||||
if (!janet_checktype(name, JANET_NIL)) {
|
|
||||||
janet_table_put(t, janet_csymbolv(":name"), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
|
|
||||||
}
|
|
||||||
if (frame->flags & JANET_STACKFRAME_TAILCALL) {
|
|
||||||
janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
|
|
||||||
}
|
|
||||||
if (frame->func && frame->pc) {
|
|
||||||
off = (int32_t) (frame->pc - def->bytecode);
|
|
||||||
janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
|
|
||||||
if (def->sourcemap) {
|
|
||||||
JanetSourceMapping mapping = def->sourcemap[off];
|
|
||||||
janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(mapping.line));
|
|
||||||
janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(mapping.column));
|
|
||||||
}
|
|
||||||
if (def->source) {
|
|
||||||
janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return janet_wrap_table(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfun_stack(JanetArgs args) {
|
|
||||||
JanetFiber *fiber;
|
|
||||||
JanetArray *array;
|
|
||||||
JANET_FIXARITY(args, 1);
|
|
||||||
JANET_ARG_FIBER(fiber, args, 0);
|
|
||||||
array = janet_array(0);
|
|
||||||
{
|
|
||||||
int32_t i = fiber->frame;
|
|
||||||
JanetStackFrame *frame;
|
|
||||||
while (i > 0) {
|
|
||||||
frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
|
|
||||||
janet_array_push(array, doframe(frame));
|
|
||||||
i = frame->prevframe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JANET_RETURN_ARRAY(args, array);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfun_current(JanetArgs args) {
|
static int cfun_current(JanetArgs args) {
|
||||||
@ -438,19 +361,6 @@ static int cfun_current(JanetArgs args) {
|
|||||||
JANET_RETURN_FIBER(args, janet_vm_fiber);
|
JANET_RETURN_FIBER(args, janet_vm_fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfun_lineage(JanetArgs args) {
|
|
||||||
JanetFiber *fiber;
|
|
||||||
JanetArray *array;
|
|
||||||
JANET_FIXARITY(args, 1);
|
|
||||||
JANET_ARG_FIBER(fiber, args, 0);
|
|
||||||
array = janet_array(0);
|
|
||||||
while (fiber) {
|
|
||||||
janet_array_push(array, janet_wrap_fiber(fiber));
|
|
||||||
fiber = fiber->child;
|
|
||||||
}
|
|
||||||
JANET_RETURN_ARRAY(args, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfun_maxstack(JanetArgs args) {
|
static int cfun_maxstack(JanetArgs args) {
|
||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
JANET_FIXARITY(args, 1);
|
JANET_FIXARITY(args, 1);
|
||||||
@ -500,32 +410,10 @@ static const JanetReg cfuns[] = {
|
|||||||
"\t:alive - the fiber is currently running and cannot be resumed\n"
|
"\t:alive - the fiber is currently running and cannot be resumed\n"
|
||||||
"\t:new - the fiber has just been created and not yet run"
|
"\t:new - the fiber has just been created and not yet run"
|
||||||
},
|
},
|
||||||
{"fiber/stack", cfun_stack,
|
|
||||||
"(fiber/stack fib)\n\n"
|
|
||||||
"Gets information about the stack as an array of tables. Each table "
|
|
||||||
"in the array contains information about a stack frame. The top most, current "
|
|
||||||
"stack frame is the first table in the array, and the bottom most stack frame "
|
|
||||||
"is the last value. Each stack frame contains some of the following attributes:\n\n"
|
|
||||||
"\t:c - true if the stack frame is a c function invokation\n"
|
|
||||||
"\t:column - the current source column of the stack frame\n"
|
|
||||||
"\t:function - the function that the stack frame represents\n"
|
|
||||||
"\t:line - the current source line of the stack frame\n"
|
|
||||||
"\t:name - the human friendly name of the function\n"
|
|
||||||
"\t:pc - integer indicating the location of the program counter\n"
|
|
||||||
"\t:source - string with filename or other identifier for the source code\n"
|
|
||||||
"\t:tail - boolean indicating a tail call"
|
|
||||||
},
|
|
||||||
{"fiber/current", cfun_current,
|
{"fiber/current", cfun_current,
|
||||||
"(fiber/current)\n\n"
|
"(fiber/current)\n\n"
|
||||||
"Returns the currently running fiber."
|
"Returns the currently running fiber."
|
||||||
},
|
},
|
||||||
{"fiber/lineage", cfun_lineage,
|
|
||||||
"(fiber/lineage fib)\n\n"
|
|
||||||
"Returns an array of all child fibers from a root fiber. This function "
|
|
||||||
"is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
|
|
||||||
"the fiber handling the error can see which fiber raised the signal. This function should "
|
|
||||||
"be used mostly for debugging purposes."
|
|
||||||
},
|
|
||||||
{"fiber/maxstack", cfun_maxstack,
|
{"fiber/maxstack", cfun_maxstack,
|
||||||
"(fiber/maxstack fib)\n\n"
|
"(fiber/maxstack fib)\n\n"
|
||||||
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
|
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
|
||||||
|
@ -234,8 +234,8 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
|||||||
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
|
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
|
||||||
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.line);
|
pushint(st, map.start);
|
||||||
pushint(st, map.column);
|
pushint(st, map.end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -740,8 +740,8 @@ static const uint8_t *unmarshal_one_def(
|
|||||||
JANET_OUT_OF_MEMORY;
|
JANET_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||||
def->sourcemap[i].line = readint(st, &data);
|
def->sourcemap[i].start = readint(st, &data);
|
||||||
def->sourcemap[i].column = readint(st, &data);
|
def->sourcemap[i].end = readint(st, &data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
def->sourcemap = NULL;
|
def->sourcemap = NULL;
|
||||||
|
@ -102,8 +102,7 @@ struct JanetParseState {
|
|||||||
int32_t counter;
|
int32_t counter;
|
||||||
int32_t argn;
|
int32_t argn;
|
||||||
int flags;
|
int flags;
|
||||||
size_t start_line;
|
size_t start;
|
||||||
size_t start_col;
|
|
||||||
Consumer consumer;
|
Consumer consumer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -147,8 +146,7 @@ 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_line = p->line;
|
s.start = p->offset;
|
||||||
s.start_col = p->col;
|
|
||||||
_pushstate(p, s);
|
_pushstate(p, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +157,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_line(janet_unwrap_tuple(val)) = (int32_t) top.start_line;
|
janet_tuple_sm_start(janet_unwrap_tuple(val)) = (int32_t) top.start;
|
||||||
janet_tuple_sm_col(janet_unwrap_tuple(val)) = (int32_t) top.start_col;
|
janet_tuple_sm_end(janet_unwrap_tuple(val)) = (int32_t) p->offset;
|
||||||
}
|
}
|
||||||
newtop->argn++;
|
newtop->argn++;
|
||||||
push_arg(p, val);
|
push_arg(p, val);
|
||||||
@ -176,8 +174,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_line(t) = (int32_t) newtop->start_line;
|
janet_tuple_sm_start(t) = (int32_t) newtop->start;
|
||||||
janet_tuple_sm_col(t) = (int32_t) newtop->start_col;
|
janet_tuple_sm_end(t) = (int32_t) p->offset;
|
||||||
val = janet_wrap_tuple(janet_tuple_end(t));
|
val = janet_wrap_tuple(janet_tuple_end(t));
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -522,16 +520,11 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
|
|||||||
int janet_parser_consume(JanetParser *parser, uint8_t c) {
|
int janet_parser_consume(JanetParser *parser, uint8_t c) {
|
||||||
int consumed = 0;
|
int consumed = 0;
|
||||||
if (parser->error) return 0;
|
if (parser->error) return 0;
|
||||||
if (c == '\n') {
|
|
||||||
parser->line++;
|
|
||||||
parser->col = 0;
|
|
||||||
} else if (c != '\r') {
|
|
||||||
parser->col++;
|
|
||||||
}
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
parser->offset++;
|
||||||
parser->lookback = c;
|
parser->lookback = c;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -584,9 +577,8 @@ void janet_parser_init(JanetParser *parser) {
|
|||||||
parser->statecount = 0;
|
parser->statecount = 0;
|
||||||
parser->statecap = 0;
|
parser->statecap = 0;
|
||||||
parser->error = NULL;
|
parser->error = NULL;
|
||||||
parser->line = 1;
|
|
||||||
parser->col = 0;
|
|
||||||
parser->lookback = -1;
|
parser->lookback = -1;
|
||||||
|
parser->offset = 0;
|
||||||
|
|
||||||
pushstate(parser, root, PFLAG_CONTAINER);
|
pushstate(parser, root, PFLAG_CONTAINER);
|
||||||
}
|
}
|
||||||
@ -742,10 +734,7 @@ static int cfun_where(JanetArgs args) {
|
|||||||
JANET_FIXARITY(args, 1);
|
JANET_FIXARITY(args, 1);
|
||||||
JANET_CHECKABSTRACT(args, 0, &janet_parse_parsertype);
|
JANET_CHECKABSTRACT(args, 0, &janet_parse_parsertype);
|
||||||
p = (JanetParser *) janet_unwrap_abstract(args.v[0]);
|
p = (JanetParser *) janet_unwrap_abstract(args.v[0]);
|
||||||
Janet *tup = janet_tuple_begin(2);
|
JANET_RETURN_INTEGER(args, p->offset);
|
||||||
tup[0] = janet_wrap_integer((int32_t)p->line);
|
|
||||||
tup[1] = janet_wrap_integer((int32_t)p->col);
|
|
||||||
JANET_RETURN_TUPLE(args, janet_tuple_end(tup));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cfun_state(JanetArgs args) {
|
static int cfun_state(JanetArgs args) {
|
||||||
|
@ -67,7 +67,7 @@ void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
|
|||||||
int32_t off = (int32_t) (frame->pc - def->bytecode);
|
int32_t off = (int32_t) (frame->pc - def->bytecode);
|
||||||
if (def->sourcemap) {
|
if (def->sourcemap) {
|
||||||
JanetSourceMapping mapping = def->sourcemap[off];
|
JanetSourceMapping mapping = def->sourcemap[off];
|
||||||
fprintf(stderr, " on line %d, column %d", mapping.line, mapping.column);
|
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, " pc=%d", off);
|
fprintf(stderr, " pc=%d", off);
|
||||||
}
|
}
|
||||||
@ -75,6 +75,8 @@ void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
janet_v_free(fibers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run a string */
|
/* Run a string */
|
||||||
|
@ -32,8 +32,8 @@ Janet *janet_tuple_begin(int32_t length) {
|
|||||||
char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 4 * sizeof(int32_t) + length * sizeof(Janet));
|
char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 4 * sizeof(int32_t) + length * sizeof(Janet));
|
||||||
Janet *tuple = (Janet *)(data + (4 * sizeof(int32_t)));
|
Janet *tuple = (Janet *)(data + (4 * sizeof(int32_t)));
|
||||||
janet_tuple_length(tuple) = length;
|
janet_tuple_length(tuple) = length;
|
||||||
janet_tuple_sm_line(tuple) = 0;
|
janet_tuple_sm_start(tuple) = -1;
|
||||||
janet_tuple_sm_col(tuple) = 0;
|
janet_tuple_sm_end(tuple) = -1;
|
||||||
return tuple;
|
return tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,42 @@ const char *const janet_type_names[16] = {
|
|||||||
":abstract"
|
":abstract"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *const janet_signal_names[14] = {
|
||||||
|
":ok",
|
||||||
|
":error",
|
||||||
|
":debug",
|
||||||
|
":yield",
|
||||||
|
":user0",
|
||||||
|
":user1",
|
||||||
|
":user2",
|
||||||
|
":user3",
|
||||||
|
":user4",
|
||||||
|
":user5",
|
||||||
|
":user6",
|
||||||
|
":user7",
|
||||||
|
":user8",
|
||||||
|
":user9"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const janet_status_names[16] = {
|
||||||
|
":dead",
|
||||||
|
":error",
|
||||||
|
":debug",
|
||||||
|
":pending",
|
||||||
|
":user0",
|
||||||
|
":user1",
|
||||||
|
":user2",
|
||||||
|
":user3",
|
||||||
|
":user4",
|
||||||
|
":user5",
|
||||||
|
":user6",
|
||||||
|
":user7",
|
||||||
|
":user8",
|
||||||
|
":user9",
|
||||||
|
":new",
|
||||||
|
":alive"
|
||||||
|
};
|
||||||
|
|
||||||
/* Calculate hash for string */
|
/* Calculate hash for string */
|
||||||
|
|
||||||
int32_t janet_string_calchash(const uint8_t *str, int32_t len) {
|
int32_t janet_string_calchash(const uint8_t *str, int32_t len) {
|
||||||
|
@ -57,5 +57,6 @@ int janet_lib_parse(JanetArgs args);
|
|||||||
int janet_lib_asm(JanetArgs args);
|
int janet_lib_asm(JanetArgs args);
|
||||||
#endif
|
#endif
|
||||||
int janet_lib_compile(JanetArgs args);
|
int janet_lib_compile(JanetArgs args);
|
||||||
|
int janet_lib_debug(JanetArgs args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,6 +54,8 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
/* Expected types on type error */
|
/* Expected types on type error */
|
||||||
uint16_t expected_types;
|
uint16_t expected_types;
|
||||||
|
|
||||||
|
uint8_t first_opcode;
|
||||||
|
|
||||||
/* Signal to return when done */
|
/* Signal to return when done */
|
||||||
JanetSignal signal = JANET_SIGNAL_OK;
|
JanetSignal signal = JANET_SIGNAL_OK;
|
||||||
|
|
||||||
@ -92,16 +94,24 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
* instruction. */
|
* instruction. */
|
||||||
retreg = in;
|
retreg = in;
|
||||||
goto vm_resume_child;
|
goto vm_resume_child;
|
||||||
} else if (startstatus != JANET_STATUS_NEW) {
|
} else if (startstatus != JANET_STATUS_NEW &&
|
||||||
|
((*pc & 0xFF) == JOP_SIGNAL)) {
|
||||||
/* Only should be hit if child is waiting on a SIGNAL instruction */
|
/* Only should be hit if child is waiting on a SIGNAL instruction */
|
||||||
/* If waiting for response to signal, use input and increment pc */
|
/* If waiting for response to signal, use input and increment pc */
|
||||||
stack[oparg(1, 0xFF)] = in;
|
stack[oparg(1, 0xFF)] = in;
|
||||||
pc++;
|
pc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The first opcode to execute. If the first opcode has
|
||||||
|
* the breakpoint bit set and we were in the debug state, skip
|
||||||
|
* that first breakpoint. */
|
||||||
|
first_opcode = (startstatus == JANET_STATUS_DEBUG)
|
||||||
|
? (*pc & 0x7F)
|
||||||
|
: (*pc & 0xFF);
|
||||||
|
|
||||||
/* Use computed gotos for GCC and clang, otherwise use switch */
|
/* Use computed gotos for GCC and clang, otherwise use switch */
|
||||||
#ifdef __GNUC__
|
#ifdef ____GNUC__
|
||||||
#define VM_START() {vm_next();
|
#define VM_START() { goto *op_lookup[first_opcode];
|
||||||
#define VM_END() }
|
#define VM_END() }
|
||||||
#define VM_OP(op) label_##op :
|
#define VM_OP(op) label_##op :
|
||||||
#define VM_DEFAULT() label_unknown_op:
|
#define VM_DEFAULT() label_unknown_op:
|
||||||
@ -193,11 +203,11 @@ static void *op_lookup[255] = {
|
|||||||
&&label_unknown_op
|
&&label_unknown_op
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
#define VM_START() for(;;){switch(*pc & 0xFF){
|
#define VM_START() uint8_t opcode = first_opcode; for (;;) {switch(opcode) {
|
||||||
#define VM_END() }}
|
#define VM_END() }}
|
||||||
#define VM_OP(op) case op :
|
#define VM_OP(op) case op :
|
||||||
#define VM_DEFAULT() default:
|
#define VM_DEFAULT() default:
|
||||||
#define vm_next() continue
|
#define vm_next() opcode = *pc & 0xFF; continue
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define vm_checkgc_next() janet_maybe_collect(); vm_next()
|
#define vm_checkgc_next() janet_maybe_collect(); vm_next()
|
||||||
@ -279,6 +289,7 @@ static void *op_lookup[255] = {
|
|||||||
VM_START();
|
VM_START();
|
||||||
|
|
||||||
VM_DEFAULT();
|
VM_DEFAULT();
|
||||||
|
signal = JANET_SIGNAL_DEBUG;
|
||||||
retreg = janet_wrap_nil();
|
retreg = janet_wrap_nil();
|
||||||
goto vm_exit;
|
goto vm_exit;
|
||||||
|
|
||||||
@ -535,7 +546,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_GREATER_THAN_INTEGER)
|
VM_OP(JOP_GREATER_THAN_INTEGER)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_integer(stack[oparg(2, 0xFF)]) >
|
janet_unwrap_integer(stack[oparg(2, 0xFF)]) >
|
||||||
@ -543,7 +553,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_GREATER_THAN_IMMEDIATE)
|
VM_OP(JOP_GREATER_THAN_IMMEDIATE)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_integer(stack[oparg(2, 0xFF)]) > ((*(int32_t *)pc) >> 24)
|
janet_unwrap_integer(stack[oparg(2, 0xFF)]) > ((*(int32_t *)pc) >> 24)
|
||||||
@ -551,7 +560,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_GREATER_THAN_REAL)
|
VM_OP(JOP_GREATER_THAN_REAL)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_real(stack[oparg(2, 0xFF)]) >
|
janet_unwrap_real(stack[oparg(2, 0xFF)]) >
|
||||||
@ -559,7 +567,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_GREATER_THAN_EQUAL_REAL)
|
VM_OP(JOP_GREATER_THAN_EQUAL_REAL)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_real(stack[oparg(2, 0xFF)]) >=
|
janet_unwrap_real(stack[oparg(2, 0xFF)]) >=
|
||||||
@ -575,7 +582,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_EQUALS_INTEGER)
|
VM_OP(JOP_EQUALS_INTEGER)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_integer(stack[oparg(2, 0xFF)]) ==
|
janet_unwrap_integer(stack[oparg(2, 0xFF)]) ==
|
||||||
@ -584,7 +590,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_EQUALS_REAL)
|
VM_OP(JOP_EQUALS_REAL)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_real(stack[oparg(2, 0xFF)]) ==
|
janet_unwrap_real(stack[oparg(2, 0xFF)]) ==
|
||||||
@ -593,7 +598,6 @@ static void *op_lookup[255] = {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
/* Candidate */
|
|
||||||
VM_OP(JOP_EQUALS_IMMEDIATE)
|
VM_OP(JOP_EQUALS_IMMEDIATE)
|
||||||
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
|
||||||
janet_unwrap_integer(stack[oparg(2, 0xFF)]) == ((*(int32_t *)pc) >> 24)
|
janet_unwrap_integer(stack[oparg(2, 0xFF)]) == ((*(int32_t *)pc) >> 24)
|
||||||
|
@ -204,6 +204,8 @@ extern "C" {
|
|||||||
|
|
||||||
/* Names of all of the types */
|
/* Names of all of the types */
|
||||||
extern const char *const janet_type_names[16];
|
extern const char *const janet_type_names[16];
|
||||||
|
extern const char *const janet_signal_names[14];
|
||||||
|
extern const char *const janet_status_names[16];
|
||||||
|
|
||||||
/* Fiber signals */
|
/* Fiber signals */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -667,8 +669,8 @@ struct JanetKV {
|
|||||||
|
|
||||||
/* Source mapping structure for a bytecode instruction */
|
/* Source mapping structure for a bytecode instruction */
|
||||||
struct JanetSourceMapping {
|
struct JanetSourceMapping {
|
||||||
int32_t line;
|
int32_t start;
|
||||||
int32_t column;
|
int32_t end;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A function definition. Contains information needed to instantiate closures. */
|
/* A function definition. Contains information needed to instantiate closures. */
|
||||||
@ -731,8 +733,7 @@ struct JanetParser {
|
|||||||
size_t statecap;
|
size_t statecap;
|
||||||
size_t bufcount;
|
size_t bufcount;
|
||||||
size_t bufcap;
|
size_t bufcap;
|
||||||
size_t line;
|
size_t offset;
|
||||||
size_t col;
|
|
||||||
int lookback;
|
int lookback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -967,8 +968,8 @@ JANET_API int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x);
|
|||||||
#define janet_tuple_raw(t) ((int32_t *)(t) - 4)
|
#define janet_tuple_raw(t) ((int32_t *)(t) - 4)
|
||||||
#define janet_tuple_length(t) (janet_tuple_raw(t)[0])
|
#define janet_tuple_length(t) (janet_tuple_raw(t)[0])
|
||||||
#define janet_tuple_hash(t) ((janet_tuple_raw(t)[1]))
|
#define janet_tuple_hash(t) ((janet_tuple_raw(t)[1]))
|
||||||
#define janet_tuple_sm_line(t) ((janet_tuple_raw(t)[2]))
|
#define janet_tuple_sm_start(t) ((janet_tuple_raw(t)[2]))
|
||||||
#define janet_tuple_sm_col(t) ((janet_tuple_raw(t)[3]))
|
#define janet_tuple_sm_end(t) ((janet_tuple_raw(t)[3]))
|
||||||
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);
|
||||||
JANET_API const Janet *janet_tuple_n(const Janet *values, int32_t n);
|
JANET_API const Janet *janet_tuple_n(const Janet *values, int32_t n);
|
||||||
|
@ -55,6 +55,6 @@
|
|||||||
(do
|
(do
|
||||||
(print (string "Janet " janet/version "-" janet/build " Copyright (C) 2017-2018 Calvin Rose"))
|
(print (string "Janet " janet/version "-" janet/build " Copyright (C) 2017-2018 Calvin Rose"))
|
||||||
(repl (fn [buf p]
|
(repl (fn [buf p]
|
||||||
(def [line] (parser/where p))
|
(def offset (parser/where p))
|
||||||
(def prompt (string "janet:" line ":" (parser/state p) "> "))
|
(def prompt (string "janet:" offset ":" (parser/state p) "> "))
|
||||||
(getline prompt buf)))))))
|
(getline prompt buf)))))))
|
||||||
|
Loading…
Reference in New Issue
Block a user