Преглед на файлове

Enhance runtime errors with file and line

pull/12/head
mtardy преди 4 години
родител
ревизия
72fb9500c3
променени са 2 файла, в които са добавени 141 реда и са изтрити 95 реда
  1. +43
    -7
      object.c
  2. +98
    -88
      parse.leg

+ 43
- 7
object.c Целия файл

@ -414,10 +414,10 @@ oop map_append(oop map, oop value)
bool isHidden(oop obj) {
if (is(Symbol, obj)) {
char *s = get(obj, Symbol, name);
size_t l = strlen(s);
// maybe 'l > 5' because of ____?
return (l > 4 && s[0] == '_' && s[1] == '_' && s[l-2] == '_' && s[l-1] == '_');
char *s = get(obj, Symbol, name);
size_t l = strlen(s);
// maybe 'l > 5' because of ____?
return (l > 4 && s[0] == '_' && s[1] == '_' && s[l-2] == '_' && s[l-1] == '_');
}
return false;
}
@ -439,7 +439,7 @@ oop map_allKeys(oop map)
assert(is(Map, map));
oop keys = makeMap();
for (size_t i = 0; i < get(map, Map, size); i++) {
map_append(keys, get(map, Map, elements)[i].key);
map_append(keys, get(map, Map, elements)[i].key);
}
return keys;
}
@ -486,6 +486,42 @@ void map_print(oop map, int ident)
return;
}
char *toString(oop ast)
{
int length;
assert(ast);
switch (getType(ast)) {
case Undefined:
return "null";
case Integer:
//TODO
length = snprintf(NULL, 0, "%d", getInteger(ast));
printf("length is %i\n", length);
printf("%i", getInteger(ast));
return "null";
case String:
return get(ast, String, value);
case Symbol:
return get(ast, Symbol, name);
case Function:
// TODO
if (get(ast, Function, primitive) == NULL) {
printf("Function:");
} else {
printf("Primitive:");
}
print(get(ast, Function, name));
printf("(");
print(get(ast, Function, param));
printf(")");
case Map:
// TODO
map_print(ast, 0);
}
assert(0);
}
void print(oop ast)
{
assert(ast);
@ -509,9 +545,9 @@ void print(oop ast)
printf("Primitive:");
}
print(get(ast, Function, name));
printf("(");
printf("(");
print(get(ast, Function, param));
printf(")");
printf(")");
return;
case Map:
map_print(ast, 0);

+ 98
- 88
parse.leg Целия файл

@ -49,11 +49,12 @@ typedef struct jb_record
jb_record *jbs= NULL;
void jbsCheck(char *msg)
void runtimeError(oop ast, char *msg);
void jbsCheck(oop ast, char *msg)
{
if (NULL == jbs) {
fprintf(stderr, "\n%s\n", msg);
exit(1);
runtimeError(ast, msg);
}
}
@ -80,7 +81,7 @@ oop globals= 0;
DO_PROTOS() _DO(__proto__) _DO(__name__) _DO(__default__) _DO(__arguments__) \
_DO(name) _DO(body) _DO(param) _DO(key) _DO(value) _DO(condition) _DO(consequent) _DO(alternate) \
_DO(lhs) _DO(rhs) _DO(scope) _DO(args) _DO(expression) _DO(labels) _DO(statements) _DO(initialise) \
_DO(update) _DO(this) _DO(fixed) _DO(operator) _DO(map) _DO(func)
_DO(update) _DO(this) _DO(fixed) _DO(operator) _DO(map) _DO(func) _DO(__line__) _DO(__file__)
#define _DO(NAME) oop NAME##_symbol;
DO_SYMBOLS()
@ -92,6 +93,43 @@ DO_PROTOS()
int opt_v = 0;
typedef struct input_t
{
oop name;
FILE *file;
struct input_t *next;
int lineNumber;
} input_t;
input_t *inputStack= NULL;
void inputStackPush(char *name) {
FILE *file = stdin;
if (NULL != name) {
file= fopen(name, "rb");
if (NULL == file) {
perror(name);
exit(1);
}
} else {
name= "<stdin>";
}
input_t *input = memcheck(malloc(sizeof(input_t)));
input->name= makeString(name);
input->lineNumber= 1;
input->file= file;
input->next= inputStack;
inputStack= input;
return;
}
input_t *inputStackPop(void) {
assert(inputStack);
input_t *first= inputStack;
inputStack= first->next;
return first;
}
int isFalse(oop obj)
{
return obj == null || (isInteger(obj) && (0 == getInteger(obj)));
@ -106,6 +144,9 @@ oop newObject(oop proto)
{
oop map = makeMap();
map_set(map, __proto___symbol, proto);
// set context (file and line) for runtime error msg
map_set(map, __line___symbol, makeInteger(inputStack->lineNumber));
map_set(map, __file___symbol, inputStack->name);
return map;
}
@ -513,43 +554,6 @@ oop newContinue(void)
oop fold(oop ast);
typedef struct input_t
{
char *name;
FILE *file;
struct input_t *next;
int lineNumber;
} input_t;
input_t *inputStack= NULL;
void inputStackPush(char *name) {
FILE *file = stdin;
if (NULL != name) {
file= fopen(name, "rb");
if (NULL == file) {
perror(name);
exit(1);
}
} else {
name= "<stdin>";
}
input_t *input = memcheck(malloc(sizeof(input_t)));
input->name= memcheck(strdup(name));
input->lineNumber= 1;
input->file= file;
input->next= inputStack;
inputStack= input;
return;
}
input_t *inputStackPop(void) {
assert(inputStack);
input_t *first= inputStack;
inputStack= first->next;
return first;
}
#define YY_INPUT(buf, result, max_size) \
{ \
int yyc= getc(inputStack->file); \
@ -562,9 +566,9 @@ YYSTYPE yylval;
int errorLine= 1;
void error(char *text)
void syntaxError(char *text)
{
fprintf(stderr, "\nSyntax error in %s near line %i:\n%s\n", inputStack->name, errorLine, text);
fprintf(stderr, "\nSyntax error in %s near line %i:\n%s\n", get(inputStack->name, String, value), errorLine, text);
exit(1);
}
@ -583,7 +587,7 @@ start = - ( IMPORT s:STRING { yylval = null; in
)
error = { errorLine= inputStack->lineNumber }
eol* < (!eol .)* eol* (!eol .)* > { error(yytext) }
eol* < (!eol .)* eol* (!eol .)* > { syntaxError(yytext) }
stmt = e:exp SEMICOLON* { $$ = e }
| s:block { $$ = s }
@ -684,8 +688,8 @@ shift = l:sum
)* { $$ = l }
sum = l:prod
( PLUS r:prod { l = newBinary(Add_proto, l, r) }
| MINUS r:prod { l = newBinary(Sub_proto, l, r) }
( PLUS r:prod { l = newBinary(Add_proto, l, r) }
| MINUS r:prod { l = newBinary(Sub_proto, l, r) }
)* { $$ = l }
prod = l:prefix
@ -886,19 +890,26 @@ oop clone(oop obj)
return obj;
}
oop addOperation(oop lhs, oop rhs)
void runtimeError(oop ast, char *msg)
{
char *fileName= get(map_get(ast, __file___symbol), String, value);
fprintf(stderr, "\nRuntime error in %s near line %i:\nError: %s\n", fileName, getInteger(map_get(ast, __line___symbol)), msg);
exit(1);
}
oop addOperation(oop ast, oop lhs, oop rhs)
{
if (getType(lhs) == Integer && getType(rhs) == Integer) {
return makeInteger(getInteger(lhs) + getInteger(rhs));
} else if (getType(lhs) == String && getType(rhs) == String) {
return string_concat(lhs, rhs);
} else {
fprintf(stderr, "\naddition between two incompatible types\n");
exit(1);
runtimeError(ast, "addition between two incompatible types");
assert(0); // to prevent: control may reach end of non-void function
}
}
oop mulOperation(oop lhs, oop rhs)
oop mulOperation(oop ast, oop lhs, oop rhs)
{
if (getType(lhs) == Integer && getType(rhs) == Integer) {
return makeInteger(getInteger(lhs) * getInteger(rhs));
@ -907,8 +918,8 @@ oop mulOperation(oop lhs, oop rhs)
} else if (getType(lhs) == Integer && getType(rhs) == String) {
return string_mul(rhs, lhs);
} else {
fprintf(stderr, "\nmultiplication between two incompatible types\n");
exit(1);
runtimeError(ast, "multiplication between two incompatible types");
assert(0);
}
}
@ -999,13 +1010,13 @@ oop fold(oop ast)
return null;
}
oop applyOperator(oop op, oop lhs, oop rhs)
oop applyOperator(oop ast, oop op, oop lhs, oop rhs)
{
if (null != op) { assert(is(Symbol, op));
switch (get(op, Symbol, prototype)) {
case t_Add: return addOperation(lhs, rhs);
case t_Add: return addOperation(ast, lhs, rhs);
case t_Sub: return makeInteger(getInteger(lhs) - getInteger(rhs));
case t_Mul: return makeInteger(getInteger(lhs) * getInteger(rhs));
case t_Mul: return mulOperation(ast, lhs, rhs);
case t_Div: return makeInteger(getInteger(lhs) / getInteger(rhs));
case t_Mod: return makeInteger(getInteger(lhs) % getInteger(rhs));
case t_Bitor: return makeInteger(getInteger(lhs) | getInteger(rhs));
@ -1069,8 +1080,7 @@ oop eval(oop scope, oop ast)
return expandUnquotes(scope, obj);
}
case t_Unquote: {
fprintf(stderr, "\n@ outside of `\n");
exit(1);
runtimeError(ast, "@ outside of `");
}
case t_Declaration: {
oop lhs = map_get(ast, lhs_symbol);
@ -1094,7 +1104,7 @@ oop eval(oop scope, oop ast)
case j_return: {
oop result = jbs->result;
jbRecPop();
jbsCheck("return outside a function");
jbsCheck(ast, "return outside a function");
jbs->result = result;
siglongjmp(jbs->jb, j_return);
assert(0);
@ -1123,7 +1133,7 @@ oop eval(oop scope, oop ast)
case j_return: {
oop result = jbs->result;
jbRecPop();
jbsCheck("return outside a function");
jbsCheck(ast, "return outside a function");
jbs->result = result;
siglongjmp(jbs->jb, j_return);
assert(0);
@ -1158,7 +1168,7 @@ oop eval(oop scope, oop ast)
case j_return: {
oop result = jbs->result;
jbRecPop();
jbsCheck("return outside a function");
jbsCheck(ast, "return outside a function");
jbs->result = result;
siglongjmp(jbs->jb, j_return);
assert(0);
@ -1195,7 +1205,7 @@ oop eval(oop scope, oop ast)
case j_return: {
oop result = jbs->result;
jbRecPop();
jbsCheck("return outside a function");
jbsCheck(ast, "return outside a function");
jbs->result = result;
siglongjmp(jbs->jb, j_return);
assert(0);
@ -1206,7 +1216,7 @@ oop eval(oop scope, oop ast)
}
case j_continue: {
jbRecPop();
jbsCheck("continue outside a loop");
jbsCheck(ast, "continue outside a loop");
siglongjmp(jbs->jb, j_continue);
assert(0);
}
@ -1222,7 +1232,7 @@ oop eval(oop scope, oop ast)
oop lhs = map_get(ast, lhs_symbol);
oop op = map_get(ast, operator_symbol);
oop rhs = eval(scope, map_get(ast, rhs_symbol));
if (null != op) rhs= applyOperator(op, getVariable(scope, lhs), rhs);
if (null != op) rhs= applyOperator(ast, op, getVariable(scope, lhs), rhs);
setVariable(scope, lhs, rhs);
if (is(Function, rhs) && null == get(rhs, Function, name)) {
set(rhs, Function, name, lhs);
@ -1247,6 +1257,8 @@ oop eval(oop scope, oop ast)
case t_Call: {
oop func = eval(scope, map_get(ast, func_symbol));
if (!is(Function, func)) {
// TODO better error printing
// Please search for ISSUE1 in parse.leg
printf("cannot call ");
println(func);
exit(1);
@ -1277,12 +1289,10 @@ oop eval(oop scope, oop ast)
return result;
}
case j_break: {
fprintf(stderr, "\nbreak outside of a loop\n");
exit(1);
runtimeError(ast, "break outside of a loop");
}
case j_continue: {
fprintf(stderr, "\ncontinue outside of a loop\n");
exit(1);
runtimeError(ast, "continue outside of a loop");
}
}
@ -1328,12 +1338,10 @@ oop eval(oop scope, oop ast)
return result;
}
case j_break: {
fprintf(stderr, "\nbreak outside of a loop\n");
exit(1);
runtimeError(ast, "break outside of a loop");
}
case j_continue: {
fprintf(stderr, "\ncontinue outside of a loop\n");
exit(1);
runtimeError(ast, "continue outside of a loop");
}
}
@ -1343,16 +1351,16 @@ oop eval(oop scope, oop ast)
}
case t_Return: {
jbsCheck("return outside a function");
jbsCheck(ast, "return outside a function");
jbs->result = eval(scope, map_get(ast, value_symbol));
siglongjmp(jbs->jb, j_return);
}
case t_Break: {
jbsCheck("break outside a loop");
jbsCheck(ast, "break outside a loop");
siglongjmp(jbs->jb, j_break);
}
case t_Continue: {
jbsCheck("continue outside a loop");
jbsCheck(ast, "continue outside a loop");
siglongjmp(jbs->jb, j_continue);
}
case t_Block: {
@ -1381,7 +1389,7 @@ oop eval(oop scope, oop ast)
oop key = map_get(ast, key_symbol);
oop op = map_get(ast, operator_symbol);
oop value = eval(scope, map_get(ast, value_symbol));
if (null != op) value= applyOperator(op, getMember(map, key), value);
if (null != op) value= applyOperator(ast, op, getMember(map, key), value);
if (is(Function, value) && null == get(value, Function, name)) {
set(value, Function, name, key);
}
@ -1393,16 +1401,13 @@ oop eval(oop scope, oop ast)
switch (getType(map)) {
case String:
if (getInteger(key) >= get(map, String, size)) {
fprintf(stderr, "\nGetIndex out of range on String\n");
exit(1);
runtimeError(ast, "GetIndex out of range on String");
}
return makeInteger(unescape(get(map, String, value))[getInteger(key)]);
case Map:
return map_get(map, key);
default:
// should it returns null instead?
fprintf(stderr, "\nGetIndex on non Map or String\n");
exit(1);
runtimeError(ast, "GetIndex on non Map or String");
}
}
case t_SetIndex: {
@ -1413,18 +1418,15 @@ oop eval(oop scope, oop ast)
switch (getType(map)) {
case String:
if (getInteger(key) >= get(map, String, size)) {
fprintf(stderr, "\nSetIndex out of range on String\n");
exit(1);
runtimeError(ast, "SetIndex out of range on String");
}
get(map, String, value)[getInteger(key)] = getInteger(value);
return value;
case Map:
if (null != op) value= applyOperator(op, map_get(map, key), value);
if (null != op) value= applyOperator(ast, op, map_get(map, key), value);
return map_set(map, key, value);
default:
// should it returns null instead?
fprintf(stderr, "\nSetIndex on non Map or String\n");
exit(1);
runtimeError(ast, "SetIndex on non Map or String");
}
}
@ -1468,14 +1470,14 @@ oop eval(oop scope, oop ast)
case t_Add: {
oop lhs = eval(scope, map_get(ast, lhs_symbol));
oop rhs = eval(scope, map_get(ast, rhs_symbol));
return addOperation(lhs, rhs);
return addOperation(ast, lhs, rhs);
}
BINARY(Sub, - );
// BINARY(Mul, * );
case t_Mul: {
oop lhs = eval(scope, map_get(ast, lhs_symbol));
oop rhs = eval(scope, map_get(ast, rhs_symbol));
return mulOperation(lhs, rhs);
return mulOperation(ast, lhs, rhs);
}
BINARY(Div, / );
BINARY(Mod, % );
@ -1627,6 +1629,14 @@ oop prim_length(oop params)
return null;
}
// TODO
// ISSUE1: how can I handle the "cannot invoke " with nice printing the func name and its args
// it would be really nice to have a toString() function (that would be directly used in print())
// but it seems that it's really complicated to write a toString() for integer, function and maps...
// please see the draft line 490 in object.c
// ISSUE2: how can I tackle the 2 fprintf(stderr, "\nbreak/continue oustide of a loop\n") in prim_invoke and prim_apply
// in this situation it seems that I don't have access to any AST
oop prim_invoke(oop params)
{
oop this= null; if (map_hasIntegerKey(params, 0)) this= get(params, Map, elements)[0].value;

Зареждане…
Отказ
Запис