|
@@ -416,18 +416,18 @@ int is_required(char *path) {
|
|
|
}
|
|
|
|
|
|
char *traverse(char *source, size_t pos, size_t *line, size_t *col) {
|
|
|
- *line = 1;
|
|
|
- *col = 1;
|
|
|
+ if (line) *line = 1;
|
|
|
+ if (col) *col = 1;
|
|
|
|
|
|
size_t p = 0;
|
|
|
|
|
|
for (size_t i = 0; i < pos; i++) {
|
|
|
if (source[i] == '\n') {
|
|
|
- (*line)++;
|
|
|
- (*col) = 1;
|
|
|
+ if (line) (*line)++;
|
|
|
+ if (col) (*col) = 1;
|
|
|
|
|
|
p = i+1;
|
|
|
- } else (*col)++;
|
|
|
+ } else if (col) (*col)++;
|
|
|
}
|
|
|
|
|
|
return &source[p];
|
|
@@ -812,6 +812,10 @@ list_t *tokenize(char *source) {
|
|
|
return toks;
|
|
|
}
|
|
|
|
|
|
+int DEBUG = 0;
|
|
|
+list_t *DEBUGDATA;
|
|
|
+list_t *FUNCNAMES;
|
|
|
+
|
|
|
struct _node_t {
|
|
|
enum {
|
|
|
N_TOPLEVEL,
|
|
@@ -2493,9 +2497,30 @@ list_t *CONSTANTS;
|
|
|
#define LBPUSH() list_push(lbl, table_new())
|
|
|
#define LBPOP() list_pop(lbl)
|
|
|
|
|
|
+size_t insert_debug(node_t *node) {
|
|
|
+ size_t line;
|
|
|
+ (void)traverse(GETSRC(node->fi), node->pos, &line, NULL);
|
|
|
+
|
|
|
+ buffer_t *tbuf = buffer_new();
|
|
|
+ buffer_fmt(tbuf, "File \"%s\", line %d", GETFNAME(node->fi), line);
|
|
|
+
|
|
|
+ if (FUNCNAMES->length)
|
|
|
+ buffer_fmt(tbuf, ", in %s", list_index(FUNCNAMES, -1));
|
|
|
+
|
|
|
+ list_push(DEBUGDATA, buffer_read(tbuf));
|
|
|
+
|
|
|
+ return DEBUGDATA->length - 1;
|
|
|
+}
|
|
|
+
|
|
|
+void emit_debug(buffer_t *buf, node_t *node) {
|
|
|
+ buffer_fmt(buf, "state->_debug_data = __debugData[%d];\n", insert_debug(node));
|
|
|
+}
|
|
|
+
|
|
|
void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, stack_t *lstk, stack_t *sstk, list_t *lbl, node_t *node, char *name) {
|
|
|
NEWGID();
|
|
|
|
|
|
+ char *funname = name? name: node->t? node->t->text: "<anon>";
|
|
|
+
|
|
|
buffer_t *tbuf = buffer_new();
|
|
|
|
|
|
buffer_fmt(tbuf, "qi_value_t *__func%d(qi_state_t *state, qi_size_t pargc, qi_list_t *pargs) {\n", gid);
|
|
@@ -2504,6 +2529,9 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
|
CTXPUSH("gap");
|
|
|
CTXPUSH("func");
|
|
|
list_push(CONSTANTS, table_new());
|
|
|
+ list_push(FUNCNAMES, funname);
|
|
|
+
|
|
|
+ if (DEBUG) emit_debug(tbuf, node);
|
|
|
|
|
|
size_t optargc = 0;
|
|
|
|
|
@@ -2528,6 +2556,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
|
|
|
|
compile_node(gbuf, tbuf, ctx, table_new(), stack_new(), stack_new(), lbl, node->a);
|
|
|
|
|
|
+ list_pop(FUNCNAMES);
|
|
|
list_pop(CONSTANTS);
|
|
|
CTXPOP();
|
|
|
CTXPOP();
|
|
@@ -2540,7 +2569,7 @@ void compile_func(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
|
|
|
|
tbuf = buffer_new();
|
|
|
|
|
|
- buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", name? name: node->t? node->t->text: "<anon>", !node->h? 0: (node->h->used - optargc), gid);
|
|
|
+ buffer_fmt(tbuf, "qi_make_function(state, \"%s\", %d, __func%d, ", funname, !node->h? 0: (node->h->used - optargc), gid);
|
|
|
compile_table(gbuf, tbuf, ctx, ltab, lstk, sstk, lbl, node->h2);
|
|
|
buffer_fmt(tbuf, ")");
|
|
|
|
|
@@ -2670,6 +2699,8 @@ void compile_block(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, st
|
|
|
if (n->tag == N_CONST || n->tag == N_FUNCDEF || n->tag == N_CLASS || n->tag == N_PASS)
|
|
|
continue;
|
|
|
|
|
|
+ if (DEBUG) emit_debug(buf, n);
|
|
|
+
|
|
|
compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, n);
|
|
|
|
|
|
EMIT("\n");
|
|
@@ -3809,10 +3840,19 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, table_t *ltab, sta
|
|
|
break;
|
|
|
|
|
|
case N_CALL:
|
|
|
- EMIT("qi_call(state, ");
|
|
|
+ if (DEBUG) {
|
|
|
+ EMIT("qi_call_debug(state, ");
|
|
|
+ } else {
|
|
|
+ EMIT("qi_call(state, ");
|
|
|
+ }
|
|
|
+
|
|
|
compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->a);
|
|
|
EMIT(", ");
|
|
|
compile_list(gbuf, buf, ctx, ltab, lstk, sstk, lbl, node->l);
|
|
|
+
|
|
|
+ if (DEBUG)
|
|
|
+ buffer_fmt(buf, ", __debugData[%d]", insert_debug(node));
|
|
|
+
|
|
|
EMIT(")");
|
|
|
break;
|
|
|
|
|
@@ -4505,6 +4545,19 @@ void compile_into(char *source, buffer_t *gbuf, buffer_t *buf, list_t *ctx, tabl
|
|
|
compile_node(gbuf, buf, ctx, ltab, lstk, sstk, lbl, n);
|
|
|
}
|
|
|
|
|
|
+char *escape(char *s) {
|
|
|
+ buffer_t *buf = buffer_new();
|
|
|
+
|
|
|
+ while (*s) {
|
|
|
+ if (*s == '\\' || *s == '"')
|
|
|
+ buffer_append(buf, '\\');
|
|
|
+
|
|
|
+ buffer_append(buf, *s++);
|
|
|
+ }
|
|
|
+
|
|
|
+ return buffer_read(buf);
|
|
|
+}
|
|
|
+
|
|
|
char *compile(char *source, list_t *required) {
|
|
|
list_t *ctx = list_new();
|
|
|
table_t *ltab = table_new();
|
|
@@ -4531,13 +4584,28 @@ char *compile(char *source, list_t *required) {
|
|
|
buffer_t *rbuf = buffer_new();
|
|
|
|
|
|
buffer_appends(rbuf, "#include <qirt.h>\n");
|
|
|
+
|
|
|
+ if (DEBUG && DEBUGDATA->length) {
|
|
|
+ buffer_fmt(rbuf, "static const char *__debugData[%d] = {\n", DEBUGDATA->length);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < DEBUGDATA->length; i++)
|
|
|
+ buffer_fmt(rbuf, "\"%s\",\n", escape(DEBUGDATA->data[i]));
|
|
|
+
|
|
|
+ buffer_fmt(rbuf, "};\n");
|
|
|
+ }
|
|
|
+
|
|
|
buffer_appendb(rbuf, HBUF);
|
|
|
|
|
|
buffer_appendb(rbuf, gbuf);
|
|
|
|
|
|
buffer_appends(rbuf, "int main(int argc, char **argv) {\n");
|
|
|
buffer_appends(rbuf, "qi_state_t *state;\n");
|
|
|
- buffer_appends(rbuf, "qi_state_init(&state);\n");
|
|
|
+
|
|
|
+ if (DEBUG)
|
|
|
+ buffer_appends(rbuf, "qi_state_init_debug(&state);\n");
|
|
|
+ else
|
|
|
+ buffer_appends(rbuf, "qi_state_init(&state);\n");
|
|
|
+
|
|
|
buffer_appends(rbuf, "qi_list_t *args = qi_list_make();\n");
|
|
|
buffer_appends(rbuf, "for (int i = 0; i < argc; i++)\n");
|
|
|
buffer_appends(rbuf, " qi_list_push(args, qi_make_string(state, argv[i]));\n");
|
|
@@ -4579,6 +4647,9 @@ char *compile_file(char *filename, FILE *fd, list_t *required) {
|
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
+ DEBUGDATA = list_new();
|
|
|
+ FUNCNAMES = list_new();
|
|
|
+
|
|
|
FILES = list_new();
|
|
|
REQUIRED = list_new();
|
|
|
|
|
@@ -4590,19 +4661,37 @@ int main(int argc, char **argv) {
|
|
|
genmathlib();
|
|
|
|
|
|
char *out;
|
|
|
+ char *main = NULL;
|
|
|
+ list_t *required = NULL;
|
|
|
+ int readstdin = 0;
|
|
|
+
|
|
|
+ for (size_t i = 1; i < argc; i++) {
|
|
|
+ if (*argv[i] == '-') {
|
|
|
+ if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0)
|
|
|
+ DEBUG = 1;
|
|
|
+ else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--stdin") == 0)
|
|
|
+ readstdin = 1;
|
|
|
+ else {
|
|
|
+ fprintf(stderr, "fatal: unknown commandline argument: '%s'\n", argv[i]);
|
|
|
|
|
|
- if (argc < 2)
|
|
|
- out = compile_file("<stdin>", stdin, NULL);
|
|
|
- else {
|
|
|
- char *main = argv[1];
|
|
|
- list_t *required = NULL;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
|
|
|
- if (argc > 2)
|
|
|
- required = list_new();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!readstdin && !main) main = argv[i];
|
|
|
+ else {
|
|
|
+ if (!required)
|
|
|
+ required = list_new();
|
|
|
|
|
|
- for (size_t i = 2; i < argc; i++)
|
|
|
list_push(required, argv[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (readstdin || !main)
|
|
|
+ out = compile_file("<stdin>", stdin, required);
|
|
|
+ else {
|
|
|
FILE *fd = fopen(main, "rb");
|
|
|
if (!fd) {
|
|
|
fprintf(stderr, "fatal: unable to open file: '%s'\n", main);
|