More error handling - locations of refs to undefined symbols.
This commit is contained in:
1 parent
4c7bede5a4
commit
062a6aa6d7
5 files changed
+90
-43
No files matched your search
+32
-8
@@ -3,7 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
|
#include "locfile.h"
|
||||||
|
|
||||||
struct inst {
|
struct inst {
|
||||||
struct inst* next;
|
struct inst* next;
|
||||||
@@ -18,6 +18,8 @@ struct inst {
|
|||||||
struct cfunction* cfunc;
|
struct cfunction* cfunc;
|
||||||
} imm;
|
} imm;
|
||||||
|
|
||||||
|
location source;
|
||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
// An instruction requiring binding (for parameters/variables)
|
// An instruction requiring binding (for parameters/variables)
|
||||||
// is in one of three states:
|
// is in one of three states:
|
||||||
@@ -45,6 +47,7 @@ static inst* inst_new(opcode op) {
|
|||||||
i->bound_by = 0;
|
i->bound_by = 0;
|
||||||
i->symbol = 0;
|
i->symbol = 0;
|
||||||
i->subfn = gen_noop();
|
i->subfn = gen_noop();
|
||||||
|
i->source = UNKNOWN_LOCATION;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +85,16 @@ static inst* block_take(block* b) {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block gen_location(location loc, block b) {
|
||||||
|
for (inst* i = b.first; i; i = i->next) {
|
||||||
|
if (i->source.start == UNKNOWN_LOCATION.start &&
|
||||||
|
i->source.end == UNKNOWN_LOCATION.end) {
|
||||||
|
i->source = loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
block gen_noop() {
|
block gen_noop() {
|
||||||
block b = {0,0};
|
block b = {0,0};
|
||||||
return b;
|
return b;
|
||||||
@@ -429,7 +442,8 @@ static int count_cfunctions(block b) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compile(struct bytecode* bc, block b) {
|
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
||||||
|
int errors = 0;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int var_frame_idx = 0;
|
int var_frame_idx = 0;
|
||||||
bc->nsubfunctions = 0;
|
bc->nsubfunctions = 0;
|
||||||
@@ -442,7 +456,10 @@ static void compile(struct bytecode* bc, block b) {
|
|||||||
|
|
||||||
int opflags = opcode_describe(curr->op)->flags;
|
int opflags = opcode_describe(curr->op)->flags;
|
||||||
if (opflags & OP_HAS_BINDING) {
|
if (opflags & OP_HAS_BINDING) {
|
||||||
assert(curr->bound_by && "unbound term");
|
if (!curr->bound_by) {
|
||||||
|
locfile_locate(locations, curr->source, "error: %s is not defined", curr->symbol);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((opflags & OP_HAS_VARIABLE) &&
|
if ((opflags & OP_HAS_VARIABLE) &&
|
||||||
curr->bound_by == curr) {
|
curr->bound_by == curr) {
|
||||||
@@ -472,7 +489,7 @@ static void compile(struct bytecode* bc, block b) {
|
|||||||
bc->subfunctions[curr->imm.intval] = subfn;
|
bc->subfunctions[curr->imm.intval] = subfn;
|
||||||
subfn->globals = bc->globals;
|
subfn->globals = bc->globals;
|
||||||
subfn->parent = bc;
|
subfn->parent = bc;
|
||||||
compile(subfn, curr->subfn);
|
errors += compile(locations, subfn, curr->subfn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bc->subfunctions = 0;
|
bc->subfunctions = 0;
|
||||||
@@ -483,7 +500,7 @@ static void compile(struct bytecode* bc, block b) {
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
jv constant_pool = jv_array();
|
jv constant_pool = jv_array();
|
||||||
int maxvar = -1;
|
int maxvar = -1;
|
||||||
for (inst* curr = b.first; curr; curr = curr->next) {
|
if (!errors) for (inst* curr = b.first; curr; curr = curr->next) {
|
||||||
const struct opcode_description* op = opcode_describe(curr->op);
|
const struct opcode_description* op = opcode_describe(curr->op);
|
||||||
if (op->length == 0)
|
if (op->length == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -551,18 +568,25 @@ static void compile(struct bytecode* bc, block b) {
|
|||||||
}
|
}
|
||||||
bc->constants = constant_pool;
|
bc->constants = constant_pool;
|
||||||
bc->nlocals = maxvar + 2; // FIXME: frames of size zero?
|
bc->nlocals = maxvar + 2; // FIXME: frames of size zero?
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bytecode* block_compile(block b) {
|
int block_compile(block b, struct locfile* locations, struct bytecode** out) {
|
||||||
struct bytecode* bc = malloc(sizeof(struct bytecode));
|
struct bytecode* bc = malloc(sizeof(struct bytecode));
|
||||||
bc->parent = 0;
|
bc->parent = 0;
|
||||||
bc->globals = malloc(sizeof(struct symbol_table));
|
bc->globals = malloc(sizeof(struct symbol_table));
|
||||||
int ncfunc = count_cfunctions(b);
|
int ncfunc = count_cfunctions(b);
|
||||||
bc->globals->ncfunctions = 0;
|
bc->globals->ncfunctions = 0;
|
||||||
bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc);
|
bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc);
|
||||||
compile(bc, b);
|
int nerrors = compile(locations, bc, b);
|
||||||
assert(bc->globals->ncfunctions == ncfunc);
|
assert(bc->globals->ncfunctions == ncfunc);
|
||||||
return bc;
|
if (nerrors > 0) {
|
||||||
|
bytecode_free(bc);
|
||||||
|
*out = 0;
|
||||||
|
} else {
|
||||||
|
*out = bc;
|
||||||
|
}
|
||||||
|
return nerrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
void block_free(block b) {
|
void block_free(block b) {
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
|
#include "locfile.h"
|
||||||
|
|
||||||
struct inst;
|
struct inst;
|
||||||
typedef struct inst inst;
|
typedef struct inst inst;
|
||||||
@@ -11,6 +12,8 @@ typedef struct block {
|
|||||||
inst* last;
|
inst* last;
|
||||||
} block;
|
} block;
|
||||||
|
|
||||||
|
block gen_location(location, block);
|
||||||
|
|
||||||
block gen_noop();
|
block gen_noop();
|
||||||
block gen_op_simple(opcode op);
|
block gen_op_simple(opcode op);
|
||||||
block gen_op_const(opcode op, jv constant);
|
block gen_op_const(opcode op, jv constant);
|
||||||
@@ -39,7 +42,7 @@ void block_append(block* b, block b2);
|
|||||||
block block_join(block a, block b);
|
block block_join(block a, block b);
|
||||||
block block_bind(block binder, block body, int bindflags);
|
block block_bind(block binder, block body, int bindflags);
|
||||||
|
|
||||||
struct bytecode* block_compile(block);
|
int block_compile(block, struct locfile*, struct bytecode**);
|
||||||
|
|
||||||
void block_free(block);
|
void block_free(block);
|
||||||
|
|
||||||
|
|||||||
+21
-5
@@ -1,10 +1,15 @@
|
|||||||
|
#ifndef _LOCFILE_H
|
||||||
|
#define _LOCFILE_H
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int start, end;
|
int start, end;
|
||||||
} location;
|
} location;
|
||||||
|
|
||||||
|
static const location UNKNOWN_LOCATION = {-1, -1};
|
||||||
|
|
||||||
struct locfile {
|
struct locfile {
|
||||||
const char* data;
|
const char* data;
|
||||||
int length;
|
int length;
|
||||||
@@ -48,15 +53,26 @@ static int locfile_line_length(struct locfile* l, int line) {
|
|||||||
return l->linemap[line+1] - l->linemap[line];
|
return l->linemap[line+1] - l->linemap[line];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void locfile_locate(struct locfile* l, location loc) {
|
static void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) {
|
||||||
|
va_list fmtargs;
|
||||||
|
va_start(fmtargs, fmt);
|
||||||
|
vfprintf(stderr, fmt, fmtargs);
|
||||||
|
va_end(fmtargs);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
if (loc.start == -1) {
|
||||||
|
fprintf(stderr, "<unknown location>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
int startline = locfile_get_line(l, loc.start);
|
int startline = locfile_get_line(l, loc.start);
|
||||||
int offset = l->linemap[startline];
|
int offset = l->linemap[startline];
|
||||||
printf("%.*s\n", locfile_line_length(l, startline), l->data + offset);
|
fprintf(stderr, "%.*s\n", locfile_line_length(l, startline), l->data + offset);
|
||||||
printf("%*s", loc.start - offset, "");
|
fprintf(stderr, "%*s", loc.start - offset, "");
|
||||||
for (int i = loc.start;
|
for (int i = loc.start;
|
||||||
i < loc.end && i < offset + locfile_line_length(l, startline);
|
i < loc.end && i < offset + locfile_line_length(l, startline);
|
||||||
i++){
|
i++){
|
||||||
printf("^");
|
fprintf(stderr, "^");
|
||||||
}
|
}
|
||||||
printf("\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,15 +1,36 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "parser.tab.h"
|
#include "parser.tab.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "jv.h"
|
#include "jv.h"
|
||||||
|
#include "locfile.h"
|
||||||
|
|
||||||
int compile(const char* str, block* answer);
|
int jq_parse(struct locfile* source, block* answer);
|
||||||
|
|
||||||
void jq_init(struct bytecode* bc, jv value);
|
void jq_init(struct bytecode* bc, jv value);
|
||||||
jv jq_next();
|
jv jq_next();
|
||||||
void jq_teardown();
|
void jq_teardown();
|
||||||
|
|
||||||
|
struct bytecode* jq_compile(const char* str) {
|
||||||
|
struct locfile locations;
|
||||||
|
locfile_init(&locations, str, strlen(str));
|
||||||
|
block program;
|
||||||
|
struct bytecode* bc = 0;
|
||||||
|
int nerrors = jq_parse(&locations, &program);
|
||||||
|
if (nerrors == 0) {
|
||||||
|
block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
|
||||||
|
program = gen_cbinding(&builtins, program);
|
||||||
|
nerrors = block_compile(program, &locations, &bc);
|
||||||
|
block_free(program);
|
||||||
|
}
|
||||||
|
if (nerrors) {
|
||||||
|
fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
|
||||||
|
}
|
||||||
|
locfile_free(&locations);
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void run_program(struct bytecode* bc) {
|
void run_program(struct bytecode* bc) {
|
||||||
#if JQ_DEBUG
|
#if JQ_DEBUG
|
||||||
@@ -52,14 +73,8 @@ void run_tests() {
|
|||||||
if (skipline(buf)) continue;
|
if (skipline(buf)) continue;
|
||||||
printf("Testing %s\n", buf);
|
printf("Testing %s\n", buf);
|
||||||
int pass = 1;
|
int pass = 1;
|
||||||
block program;
|
struct bytecode* bc = jq_compile(buf);
|
||||||
int nerrors = compile(buf, &program);
|
assert(bc);
|
||||||
assert(nerrors == 0);
|
|
||||||
block_append(&program, gen_op_simple(YIELD));
|
|
||||||
block_append(&program, gen_op_simple(BACKTRACK));
|
|
||||||
program = gen_cbinding(&builtins, program);
|
|
||||||
struct bytecode* bc = block_compile(program);
|
|
||||||
block_free(program);
|
|
||||||
printf("Disassembly:\n");
|
printf("Disassembly:\n");
|
||||||
dump_disassembly(2, bc);
|
dump_disassembly(2, bc);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -111,16 +126,8 @@ void run_tests() {
|
|||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc == 1) { run_tests(); return 0; }
|
if (argc == 1) { run_tests(); return 0; }
|
||||||
block blk;
|
struct bytecode* bc = jq_compile(argv[1]);
|
||||||
int nerrors = compile(argv[1], &blk);
|
if (!bc) return 1;
|
||||||
if (nerrors > 0) {
|
|
||||||
printf("%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
|
|
||||||
blk = gen_cbinding(&builtins, blk);
|
|
||||||
struct bytecode* bc = block_compile(blk);
|
|
||||||
block_free(blk);
|
|
||||||
run_program(bc);
|
run_program(bc);
|
||||||
bytecode_free(bc);
|
bytecode_free(bc);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+7
-10
@@ -83,8 +83,7 @@
|
|||||||
void yyerror(YYLTYPE* loc, block* answer, int* errors,
|
void yyerror(YYLTYPE* loc, block* answer, int* errors,
|
||||||
struct locfile* locations, yyscan_t lexer, const char *s){
|
struct locfile* locations, yyscan_t lexer, const char *s){
|
||||||
(*errors)++;
|
(*errors)++;
|
||||||
printf("error: %s\n", s);
|
locfile_locate(locations, *loc, "error: %s", s);
|
||||||
locfile_locate(locations, *loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors,
|
int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors,
|
||||||
@@ -293,11 +292,11 @@ LITERAL {
|
|||||||
block_append(&$$, gen_op_simple(POP));
|
block_append(&$$, gen_op_simple(POP));
|
||||||
} |
|
} |
|
||||||
'$' IDENT {
|
'$' IDENT {
|
||||||
$$ = gen_op_var_unbound(LOADV, jv_string_value($2));
|
$$ = gen_location(@$, gen_op_var_unbound(LOADV, jv_string_value($2)));
|
||||||
jv_free($2);
|
jv_free($2);
|
||||||
} |
|
} |
|
||||||
IDENT {
|
IDENT {
|
||||||
$$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)));
|
$$ = gen_location(@$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1))));
|
||||||
jv_free($1);
|
jv_free($1);
|
||||||
} |
|
} |
|
||||||
IDENT '(' Exp ')' {
|
IDENT '(' Exp ')' {
|
||||||
@@ -307,6 +306,7 @@ IDENT '(' Exp ')' {
|
|||||||
"lambda",
|
"lambda",
|
||||||
block_join($3, gen_op_simple(RET))),
|
block_join($3, gen_op_simple(RET))),
|
||||||
gen_noop(), OP_IS_CALL_PSEUDO)));
|
gen_noop(), OP_IS_CALL_PSEUDO)));
|
||||||
|
$$ = gen_location(@1, $$);
|
||||||
jv_free($1);
|
jv_free($1);
|
||||||
} |
|
} |
|
||||||
'(' error ')' { $$ = gen_noop(); } |
|
'(' error ')' { $$ = gen_noop(); } |
|
||||||
@@ -342,17 +342,14 @@ MkDictPair
|
|||||||
| '(' error ')' ':' ExpD { $$ = $5; }
|
| '(' error ')' ':' ExpD { $$ = $5; }
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int compile(const char* str, block* answer) {
|
int jq_parse(struct locfile* locations, block* answer) {
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
YY_BUFFER_STATE buf;
|
YY_BUFFER_STATE buf;
|
||||||
jq_yylex_init_extra(0, &scanner);
|
jq_yylex_init_extra(0, &scanner);
|
||||||
buf = jq_yy_scan_string(str, scanner);
|
buf = jq_yy_scan_bytes(locations->data, locations->length, scanner);
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
struct locfile locations;
|
|
||||||
locfile_init(&locations, str, strlen(str));
|
|
||||||
*answer = gen_noop();
|
*answer = gen_noop();
|
||||||
yyparse(answer, &errors, &locations, scanner);
|
yyparse(answer, &errors, locations, scanner);
|
||||||
locfile_free(&locations);
|
|
||||||
jq_yy_delete_buffer(buf, scanner);
|
jq_yy_delete_buffer(buf, scanner);
|
||||||
jq_yylex_destroy(scanner);
|
jq_yylex_destroy(scanner);
|
||||||
if (errors > 0) {
|
if (errors > 0) {
|
||||||
|
|||||||
Reference in new issue
Block a user