diff --git a/object.c b/object.c index 2841640..28ec8ea 100644 --- a/object.c +++ b/object.c @@ -122,7 +122,7 @@ union object { }; union object _null = {.Undefined = {Undefined}}; -oop null = &_null; +const oop null = &_null; int is(type_t type, oop obj); diff --git a/parse.leg b/parse.leg index 2499f07..22d1980 100644 --- a/parse.leg +++ b/parse.leg @@ -85,7 +85,8 @@ DO_SYMBOLS() DO_PROTOS() #undef _DO -int opt_v = 0; +int opt_v= 0; +oop mrAST= null; typedef struct input_t { @@ -910,10 +911,10 @@ oop clone(oop obj) return obj; } -void runtimeError(oop ast, char *msg) +void runtimeError(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); + char *fileName= get(map_get(mrAST, __file___symbol), String, value); + fprintf(stderr, "\nRuntime error in %s near line %i:\nError: %s\n", fileName, getInteger(map_get(mrAST, __line___symbol)), msg); exit(1); } @@ -924,7 +925,7 @@ oop addOperation(oop ast, oop lhs, oop rhs) } else if (getType(lhs) == String && getType(rhs) == String) { return string_concat(lhs, rhs); } else { - runtimeError(ast, "addition between two incompatible types"); + runtimeError("addition between two incompatible types"); assert(0); // to prevent: control may reach end of non-void function } } @@ -938,7 +939,7 @@ oop mulOperation(oop ast, oop lhs, oop rhs) } else if (getType(lhs) == Integer && getType(rhs) == String) { return string_mul(rhs, lhs); } else { - runtimeError(ast, "multiplication between two incompatible types"); + runtimeError("multiplication between two incompatible types"); assert(0); } } @@ -1076,6 +1077,8 @@ oop eval(oop scope, oop ast) assert(is(Map, ast)); + mrAST= ast; + oop proto = map_get(ast, __proto___symbol); if (proto == null) { return ast; @@ -1100,7 +1103,7 @@ oop eval(oop scope, oop ast) return expandUnquotes(scope, obj); } case t_Unquote: { - runtimeError(ast, "@ outside of `"); + runtimeError("@ outside of `"); } case t_Declaration: { oop lhs = map_get(ast, lhs_symbol); @@ -1315,10 +1318,10 @@ oop eval(oop scope, oop ast) return result; } case j_break: { - runtimeError(ast, "break outside of a loop"); + runtimeError("break outside of a loop"); } case j_continue: { - runtimeError(ast, "continue outside of a loop"); + runtimeError("continue outside of a loop"); } case j_throw: { oop res= jbs->result; @@ -1370,10 +1373,10 @@ oop eval(oop scope, oop ast) return result; } case j_break: { - runtimeError(ast, "break outside of a loop"); + runtimeError("break outside of a loop"); } case j_continue: { - runtimeError(ast, "continue outside of a loop"); + runtimeError("continue outside of a loop"); } case j_throw: { oop res= jbs->result; @@ -1414,53 +1417,40 @@ oop eval(oop scope, oop ast) jbRecPush(); int jbt = sigsetjmp(jbs->jb, 0); - switch (jbt) { - case j_return: { - runtimeError(ast, "return outside of a function"); - } - case j_break: { - runtimeError(ast, "break outside of a loop or switch"); - } - case j_continue: { - runtimeError(ast, "continue outside of a loop"); + if (0 == jbt) { + oop res = eval(scope, try); + jbRecPop(); + eval(scope, finally); + return res; + } + oop res= jbs->result; + jbRecPop(); + // something happend in the try block + if (j_throw == jbt) { + assert(jbs); + jbs->result= res; + + if (null == catch) { + return eval(scope, finally); } - case j_throw: { - oop e= jbs->result; - jbRecPop(); - jbs->result= e; - // that should only be set in the catch local scope - setVariable(scope, exception, e); - jbRecPush(); - jbt = sigsetjmp(jbs->jb, 0); - switch (jbt) { - case j_return: { - runtimeError(ast, "return outside of a function"); - } - case j_break: { - runtimeError(ast, "break outside of a loop or switch"); - } - case j_continue: { - runtimeError(ast, "continue outside of a loop"); - } - case j_throw: { - // transfer exception - oop e= jbs->result; - jbRecPop(); - jbs->result= e; - - eval(scope, finally); - siglongjmp(jbs->jb, j_throw); - } - } - oop catchRes= eval(scope, catch); - eval(scope, finally); + oop localScope= newObject(scope); + setVariable(localScope, exception, res); + + jbRecPush(); + jbt= sigsetjmp(jbs->jb, 0); + if (0 == jbt) { + eval(localScope, catch); jbRecPop(); - return catchRes; + return eval(scope, finally); } + // something happend in the catch block + res= jbs->result; + jbRecPop(); } - oop res = eval(scope, try); - jbRecPop(); - return res; + eval(scope, finally); + assert(jbs); + jbs->result= res; + siglongjmp(jbs->jb, jbt); } case t_Block: { oop statements = map_get(ast, statements_symbol); @@ -1500,13 +1490,13 @@ oop eval(oop scope, oop ast) switch (getType(map)) { case String: if (getInteger(key) >= get(map, String, size)) { - runtimeError(ast, "GetIndex out of range on String"); + runtimeError("GetIndex out of range on String"); } return makeInteger(unescape(get(map, String, value))[getInteger(key)]); case Map: return map_get(map, key); default: - runtimeError(ast, "GetIndex on non Map or String"); + runtimeError("GetIndex on non Map or String"); } } case t_SetIndex: { @@ -1517,7 +1507,7 @@ oop eval(oop scope, oop ast) switch (getType(map)) { case String: if (getInteger(key) >= get(map, String, size)) { - runtimeError(ast, "SetIndex out of range on String"); + runtimeError("SetIndex out of range on String"); } get(map, String, value)[getInteger(key)] = getInteger(value); return value; @@ -1525,7 +1515,7 @@ oop eval(oop scope, oop ast) if (null != op) value= applyOperator(ast, op, map_get(map, key), value); return map_set(map, key, value); default: - runtimeError(ast, "SetIndex on non Map or String"); + runtimeError("SetIndex on non Map or String"); } } @@ -1763,12 +1753,10 @@ oop prim_invoke(oop params) return result; } case j_break: { - fprintf(stderr, "\nbreak outside of a loop\n"); - exit(1); + runtimeError("break outside of a loop or switch"); } case j_continue: { - fprintf(stderr, "\ncontinue outside of a loop\n"); - exit(1); + runtimeError("continue oustide of a loop"); } case j_throw: { oop res= jbs->result; @@ -1805,12 +1793,10 @@ oop apply(oop func, oop args) return result; } case j_break: { - fprintf(stderr, "\nbreak outside of a loop\n"); - exit(1); + runtimeError("break outside of a loop or switch"); } case j_continue: { - fprintf(stderr, "\ncontinue outside of a loop\n"); - exit(1); + runtimeError("continue outside of a loop"); } case j_throw: { oop res= jbs->result; @@ -1894,14 +1880,11 @@ void readEvalPrint(char *fileName) { jbRecPop(); switch (jbt) { case j_return: - fprintf(stderr, "\nreturn outside of a function\n"); - exit(1); + runtimeError("return outside of a function"); case j_break: - fprintf(stderr, "\nbreak outside of a loop or switch\n"); - exit(1); + runtimeError("break outside of a loop or switch"); case j_continue: - fprintf(stderr, "\ncontinue outside of a loop\n"); - exit(1); + runtimeError("continue outside of a loop"); case j_throw: printf("\nunhandled exception: "); println(res); diff --git a/test-runtime-error.txt b/test-runtime-error.txt index cbe6754..b726dc7 100644 --- a/test-runtime-error.txt +++ b/test-runtime-error.txt @@ -1,6 +1,5 @@ 2; 12; -(3*null); a = {} -a.piz = fun f() {continue;} -`invoke(a, (a.piz), {}) +a.piz = fun f() {break;} +invoke(a, (a.piz), {}) diff --git a/test-throw.txt b/test-throw.txt new file mode 100644 index 0000000..311cbd9 --- /dev/null +++ b/test-throw.txt @@ -0,0 +1,237 @@ +fun println() { + apply(print, __arguments__); + print("\n"); + __arguments__; +} + +fun ok() { + println("OK!"); +} + +fun ko() { + println("KO!"); + throw "this is ko'd"; + println("CANNOT HAPPEN"); +} + +println("----------------A"); + +try { + println(ok()); +} + +println("----------------B"); + +try { + println(ko()); +} + +println("----------------C"); + +try { + println(ko()); +} +finally { + println("CLEANUP 1"); +} + +println("----------------D"); + +try { + println(ko()); +} +catch (e) { + println("CAUGHT ", e); +} + +println("----------------E"); + +try { + println(ko()); +} +catch (e) { + println("CAUGHT ", e); +} +finally { + println("CLEANUP 2"); +} + +println("----------------F"); + +try { +try { + println(ko()); +} +catch (e) { + println("CAUGHT ", e); + throw "throwing in catch" +} +finally { + println("CLEANUP 3"); +} +} catch (e) println(e); + +println("----------------G"); + +try { + try { + println(ko()); + } + catch (e) { + println("CAUGHT ", e); + } + finally { + println("CLEANUP 4"); + throw "throwing in finally" + } +} catch (e) println(e); + +println("----------------H"); + +try { + try { + println(ko()); + } + catch (e) { + println("RETHROW ", e); + throw e; + } + finally { + println("CLEANUP 5"); + } +} +catch (e) { + println("CAUGHT ", e); +} + +println("----------------I"); + +try { + try { + try { + try { + try { + try { + println(ko()); + } + catch (e) { + println("RETHROW 6 ", e); + throw e; + } + finally { + println("CLEANUP 6"); + } + } + catch (e) { + println("RETHROW 7 ", e); + throw e; + } + finally { + println("CLEANUP 7"); + } + } + catch (e) { + println("CAUGHT 8") + } + finally { + println("CLEANUP 8"); + } + } + finally { + println("CLEANUP 9"); + } + } + finally { + println("CLEANUP 10"); + } +} +catch (e) { + println("CAUGHT 11 ", e); +} +finally { + println("CLEANUP 11"); +} + +println("----------------J"); + +t=millis(); + +sum= 0; +for (a= 0; a < 100000; a++) { + sum += a; +} + +println(sum, " loop: ", millis()-t); + +t=millis(); + +sum= 0; +for (a= 0; a < 100000; a++) { + sum += a; + continue; +} + +println(sum, " continue: ", millis()-t); + +println("----------------K"); + +t=millis(); + +sum= 0; +for (a= 0; a < 100000; a++) { + try { + try { + try { + try { + try { + try { + try { + try { + try { + try { + sum += a; + // throw "oops"; + } + } + } + } + } + } + } + } + } + } +} + +println(sum, " tries: ", millis()-t); + +t=millis(); + +sum= 0; +for (a= 0; a < 100000; a++) { + try { + try { + try { + try { + try { + try { + try { + try { + try { + try { + sum += a; + throw "oops"; + } + } + } + } + } + } + } + } + } + } + catch (e) {} +} + +println(sum, " throws: ", millis()-t); diff --git a/test-try-catch.txt b/test-try-catch.txt index 08438fc..ee9eebf 100644 --- a/test-try-catch.txt +++ b/test-try-catch.txt @@ -1,18 +1,17 @@ -try { +for(i=0; i<10; ++i) { try { - println("hello") - throw "ERROR 12"; - println("that should not be executed"); + throw i } catch (e) { - println("catch!") - println("inner: ", e) - throw "pizza" - print("after pizza") + if (e == 5) { + continue; + } + println(e) + if (e == 8) { + break; + } } finally { - println("finally...") - throw "oh no" - println("after oh no") + if (i == 3) { + return; + } } -} catch (e) { - println("outer: ", e); } \ No newline at end of file