diff --git a/object.c b/object.c index c99ab18..2841640 100644 --- a/object.c +++ b/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); diff --git a/parse.leg b/parse.leg index 4d14505..273b382 100644 --- a/parse.leg +++ b/parse.leg @@ -73,7 +73,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() @@ -85,6 +85,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= ""; + } + 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))); @@ -99,6 +136,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; } @@ -506,43 +546,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= ""; - } - 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); \ @@ -555,9 +558,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); } @@ -576,7 +579,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 } @@ -678,8 +681,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 @@ -884,19 +887,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)); @@ -905,8 +915,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); } } @@ -997,13 +1007,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)); @@ -1067,8 +1077,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); @@ -1226,7 +1235,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); @@ -1251,6 +1260,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); @@ -1281,12 +1292,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"); } case j_throw: { oop res= jbs->result; @@ -1338,12 +1347,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"); } case j_throw: { oop res= jbs->result; @@ -1402,7 +1409,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); } @@ -1414,16 +1421,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: { @@ -1434,18 +1438,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"); } } @@ -1489,14 +1490,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, % ); @@ -1648,6 +1649,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; diff --git a/test-proto.txt b/test-proto.txt index ebac30b..a75342d 100644 --- a/test-proto.txt +++ b/test-proto.txt @@ -1,4 +1,7 @@ -fun println() { apply(print, __arguments__); print("\n"); } +fun println() { + apply(print, __arguments__); + print("\n"); +} var Object = { __name__: #"Object" }; diff --git a/test-runtime-error.txt b/test-runtime-error.txt new file mode 100644 index 0000000..cbe6754 --- /dev/null +++ b/test-runtime-error.txt @@ -0,0 +1,6 @@ +2; +12; +(3*null); +a = {} +a.piz = fun f() {continue;} +`invoke(a, (a.piz), {}) diff --git a/test3.txt b/test3.txt deleted file mode 100644 index 5a9c243..0000000 --- a/test3.txt +++ /dev/null @@ -1,8 +0,0 @@ -a = {} -a.b = fun () { - switch (1) { - case 1: - throw { name: "EvalError", message: "oops" } - } -} -invoke(a, a.b, {}) \ No newline at end of file