diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2022-01-21 15:18:22 +0000 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2022-01-21 15:18:22 +0000 |
commit | 40c021d964bc60d2b60dd78022e180c964ea1b67 (patch) | |
tree | aee97fdfef0378c94871579b8bc12cbdca583553 | |
parent | 1ddd7de5b15f52c13a5c084445253655a94bd970 (diff) |
Implement better error handling, but still no error guards
-rw-r--r-- | apl9.h | 37 | ||||
-rw-r--r-- | error.c | 29 | ||||
-rw-r--r-- | eval.c | 49 | ||||
-rw-r--r-- | functions.c | 192 | ||||
-rw-r--r-- | lexer.c | 5 | ||||
-rw-r--r-- | main.c | 22 | ||||
-rw-r--r-- | mkfile | 1 | ||||
-rw-r--r-- | operators.c | 7 | ||||
-rw-r--r-- | quadnames.c | 2 |
9 files changed, 194 insertions, 150 deletions
@@ -39,6 +39,20 @@ typedef enum FunctypeQuad, } functionType; +typedef enum +{ + ESyntax = 1, + EParse, + EValue, + EDomain, + ERank, + EType, + ELength, + EIndex, + EShape, + ENotImplemented, +} errorCodes; + /* Data types */ typedef struct Array Array; typedef struct Statement Statement; @@ -48,6 +62,8 @@ typedef struct Datum Datum; typedef struct Symbol Symbol; typedef struct Symtab Symtab; typedef struct QuadnameDef QuadnameDef; +typedef struct ErrorHandler ErrorHandler; + struct Array { arrayDataType type; @@ -143,6 +159,12 @@ struct QuadnameDef opdyad dyadop; }; +struct ErrorHandler +{ + Rune *msg; + jmp_buf jmp; +}; + /* Function prototypes for the different source files */ /* main.c */ Datum *evalline(Rune *, int); @@ -196,6 +218,16 @@ Array *rundfn(Rune *, Array *, Array *); /* quadnames.c */ Datum quadnamedatum(QuadnameDef); +/* error.c */ +void throwerror(Rune *, int); +#define SETUPERROR(e) {\ + jmp_buf old;\ + memcpy(old, globalerror.jmp, sizeof(jmp_buf));\ + e = setjmp(globalerror.jmp);\ + if(e != 0)\ + memcpy(globalerror.jmp, old, sizeof(jmp_buf));\ +} + /* Monadic functions from function.c */ Array *fnSame(Array *); Array *fnTally(Array *); @@ -238,7 +270,6 @@ Array *opOver(Datum *, Datum *, Array *, Array *); /* Global variables */ extern int traceeval; /* eval.c */ extern int debugmem; /* memory.c */ -extern Rune *errormsg; /* eval.c */ extern int datasizes[]; /* array.c */ extern Rune primfuncnames[]; /* functions.c */ extern Rune primmonopnames[]; /* operators.c */ @@ -252,4 +283,6 @@ extern Symtab *globalsymtab; /* symbol.c */ extern Symtab *currentsymtab; /* symbol.c */ extern int alloccounts; /* memory.c */ extern QuadnameDef quadnames[]; /* quadnames.c */ -extern int printprecision; /* print.c */
\ No newline at end of file +extern int printprecision; /* print.c */ +extern ErrorHandler globalerror; /* error.c */ +extern Rune *errorstrs[]; /* error.c */
\ No newline at end of file @@ -0,0 +1,29 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "apl9.h" + +ErrorHandler globalerror; + +Rune *errorstrs[] = { + [ESyntax] = L"SYNTAX ERROR", + [EParse] = L"PARSE ERROR", + [EValue] = L"VALUE ERROR", + [EDomain] = L"DOMAIN ERROR", + [ERank] = L"RANK ERROR", + [EType] = L"TYPE ERROR", + [ELength] = L"LENGTH ERROR", + [EIndex] = L"INDEX ERROR", + [EShape] = L"SHAPE ERROR", + [ENotImplemented] = L"NOT IMPLEMENTED", +}; + +void +throwerror(Rune *msg, int err) +{ + free(globalerror.msg); + globalerror.msg = msg ? runestrdup(msg) : nil; + longjmp(globalerror.jmp, err); +} + @@ -6,7 +6,6 @@ #define traceprint if(traceeval)print -Rune *errormsg; int traceeval; typedef Datum (*evalfn)(Datum, Datum); @@ -54,16 +53,9 @@ evalfn evalfns[11][11] = { Datum * eval(Statement *stmt, int toplevel) { - errormsg = nil; - /* start by looking up first variable if needed */ - if(stmt->ntoks > 0 && stmt->toks[stmt->ntoks-1].tag == NameTag){ - Datum *value = lookup(stmt->toks[stmt->ntoks-1]); - if(value == nil) - return nil; - else - stmt->toks[stmt->ntoks-1] = *value; - } + if(stmt->ntoks > 0 && stmt->toks[stmt->ntoks-1].tag == NameTag) + stmt->toks[stmt->ntoks-1] = *lookup(stmt->toks[stmt->ntoks-1]);; while(stmt->ntoks > 1){ int maxlevel = 0; @@ -82,13 +74,8 @@ retry: } if(level == 0 && stmt->toks[offset-1].tag == NameTag){ - Datum *value = lookup(stmt->toks[offset-1]); - if(value == nil) - return nil; - else{ - stmt->toks[offset-1] = *value; - goto retry; - } + stmt->toks[offset-1] = *lookup(stmt->toks[offset-1]); + goto retry; }else if(level < maxlevel){ Datum left = stmt->toks[offset]; Datum right = stmt->toks[offset+1]; @@ -98,10 +85,9 @@ retry: }else if(level > maxlevel) maxlevel = level; } - if(maxlevel == 0){ - errormsg = L"No reduce rule. Syntax error."; - return nil; - }else{ + if(maxlevel == 0) + throwerror(L"No reduce rule", EParse); + else{ Datum new = fn(stmt->toks[offset],stmt->toks[offset+1]); traceprint("handler fn done\n"); if(stmt->toks[offset].tag == ArrayTag) @@ -135,12 +121,13 @@ retry: guardOK = 0; else if(stmt->toks[0].array->intdata[0] != 0 && stmt->toks[0].array->intdata[0] != 1) guardOK = 0; - if(!guardOK){ - print("Guard expected single valued boolean\n"); - exits(nil); + if(!guardOK) + throwerror(L"Guard expected single valued boolean", EDomain); + else{ + stop = 0; + if(stmt->toks[0].array->intdata[0] == 1) + return eval(stmt->guard, toplevel); } - if(stmt->toks[0].array->intdata[0] == 1) - return eval(stmt->guard, toplevel); } if(stmt->next && !stop) return eval(stmt->next, toplevel); @@ -156,8 +143,8 @@ lookup(Datum var) traceprint("VAR LOOKUP %S\n", var.symbol->name); if(var.symbol->undefined){ - errormsg = runesmprint("Variable undefined: %S\n", var.symbol->name); - return nil; + Rune *msg = runesmprint("Undefined name: %S", var.symbol->name); + throwerror(msg, EValue); } Datum *val; @@ -240,10 +227,8 @@ assign(Datum left, Datum right) { if(left.symbol->setfn != nil){ int ok = left.symbol->setfn(right); - if(!ok){ - print("Assignment failed\n"); - exits(nil); - } + if(!ok) + throwerror(nil, ESyntax); }else{ if(left.symbol->undefined == 0 && left.symbol->value.tag == ArrayTag) freearray(left.symbol->value.array); diff --git a/functions.c b/functions.c index 55a72ad..3e5c902 100644 --- a/functions.c +++ b/functions.c @@ -143,21 +143,52 @@ runfunc(Function f, Array *left, Array *right) currentsymtab = tmpsymtab; return (*dfnres).array; /* TODO what if the evaluation failed */ }else if(f.type == FunctypePrim){ - if(left) - return dyadfunctiondefs[f.code](left, right); - else - return monadfunctiondefs[f.code](right); + if(left){ + fndyad d = dyadfunctiondefs[f.code]; + if(d == nil){ + Rune *err = runesmprint("dyadic %C", primfuncnames[f.code]); + throwerror(err, ENotImplemented); + } + return d(left, right); + }else{ + fnmonad m = monadfunctiondefs[f.code]; + if(m == nil){ + Rune *err = runesmprint("monadic %C", primfuncnames[f.code]); + throwerror(err, ENotImplemented); + } + return m(right); + } }else if(f.type == FunctypeOp){ /* TODO assumes prim op, not dop */ - if(f.operator.dyadic) - return dyadoperatordefs[f.operator.code](f.operator.left, f.operator.right, left, right); - else - return monadoperatordefs[f.operator.code](f.operator.left, left, right); + if(f.operator.dyadic){ + opdyad d = dyadoperatordefs[f.operator.code]; + if(d == nil){ + Rune *err = runesmprint("dyadic %C", primdyadopnames[f.operator.code]); + throwerror(err, ENotImplemented); + } + return d(f.operator.left, f.operator.right, left, right); + }else{ + opmonad m = monadoperatordefs[f.operator.code]; + if(m == nil){ + Rune *err = runesmprint("monadic %C", primmonopnames[f.operator.code]); + throwerror(err, ENotImplemented); + } + return m(f.operator.left, left, right); + } }else if(f.type == FunctypeQuad){ - if(left) + if(left){ + if(f.quad->dyadfn == nil){ + Rune *err = runesmprint("dyadic %S", f.quad->name); + throwerror(err, ENotImplemented); + } return f.quad->dyadfn(left, right); - else + }else{ + if(f.quad->monadfn == nil){ + Rune *err = runesmprint("monadic %S", f.quad->name); + throwerror(err, ENotImplemented); + } return f.quad->monadfn(right); + } }else return nil; } @@ -306,10 +337,8 @@ fnEnclose(Array *right) Array * fnGradeUp(Array *right) { - if(right->rank == 0){ - print("Rank 0 not allowed in ⍋\n"); - exits("rank"); - } + if(right->rank == 0) + throwerror(nil, ERank); int i,j; int len = right->shape[0]; @@ -488,16 +517,12 @@ fnPlus(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 0); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++){ @@ -519,16 +544,12 @@ fnMinus(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 0); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++){ @@ -550,16 +571,12 @@ fnTimes(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 0); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++){ @@ -581,16 +598,12 @@ fnDivide(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 1); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++) @@ -608,16 +621,12 @@ fnPower(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 0); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++){ @@ -639,16 +648,12 @@ fnLogarithm(Array *left, Array *right) Array *leftarr; Array *rightarr; int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); int typeok = commontype(leftarr, rightarr, &left, &right, 1); - if(!typeok){ - print("Types don't match lol\n"); - exits(nil); - } + if(!typeok) + throwerror(nil, EType); Array *res = duparray(left); for(int i = 0; i < left->size; i++) @@ -686,10 +691,12 @@ fnMatch(Array *left, Array *right) Array * fnTake(Array *left, Array *right) { - if(left->type != AtypeInt || left->rank > 1 || left->size > right->rank){ - print("Invalid left arg to ↑\n"); - exits(nil); - } + if(left->type != AtypeInt) + throwerror(nil, EType); + if(left->rank > 1) + throwerror(nil, ERank); + if(left->size > right->rank) + throwerror(nil, ELength); int i; if(left->size == right->rank) @@ -749,18 +756,12 @@ fnIndex(Array *left, Array *right) int io = currentsymtab->io; int i; - if(left->rank > 1){ - print("Index vector rank too large\n"); - exits(nil); - } - if(left->type != AtypeArray && left->type != AtypeInt){ - print("Index vector wrong type\n"); - exits(nil); - } - if(left->size > right->rank){ - print("Index vector too long\n"); - exits(nil); - } + if(left->rank > 1) + throwerror(nil, ERank); + if(left->type != AtypeArray && left->type != AtypeInt) + throwerror(nil, EType); + if(left->size > right->rank) + throwerror(nil, ELength); /* extend left index vector to full format */ Array *oldleft = left; @@ -772,22 +773,16 @@ fnIndex(Array *left, Array *right) left->arraydata[i] = fnIndexGenerator(n); freearray(n); }else if(oldleft->type == AtypeInt){ - if(oldleft->intdata[i] < io || oldleft->intdata[i] >= io + right->shape[i]){ - print("Index error\n"); - exits(nil); - } + if(oldleft->intdata[i] < io || oldleft->intdata[i] >= io + right->shape[i]) + throwerror(nil, EIndex); left->arraydata[i] = mkscalarint(oldleft->intdata[i]); }else if(oldleft->type == AtypeArray){ Array *sub = oldleft->arraydata[i]; - if(sub->type != AtypeInt){ - print("Type error\n"); - exits(nil); - } + if(sub->type != AtypeInt) + throwerror(nil, EType); for(int j = 0; j < sub->size; j++){ - if(sub->intdata[j] < io || sub->intdata[j] >= io + right->shape[i]){ - print("Index error\n"); - exits(nil); - } + if(sub->intdata[j] < io || sub->intdata[j] >= io + right->shape[i]) + throwerror(nil, EIndex); } left->arraydata[i] = oldleft->arraydata[i]; incref(left->arraydata[i]); @@ -846,8 +841,8 @@ fnIndex(Array *left, Array *right) Array * fnCatenateFirst(Array *left, Array *right) { - Array *leftarr; - Array *rightarr; + Array *leftarr = nil; + Array *rightarr = nil; if(left->rank == 0 && right->rank != 0){ /* extend left to right->rank with first axis=1 */ @@ -890,17 +885,12 @@ fnCatenateFirst(Array *left, Array *right) }else if(right->rank == left->rank){ leftarr = fnSame(left); rightarr = fnSame(right); - }else{ - print("Ranks don't match\n"); - exits(nil); - return nil; - } + }else + throwerror(nil, ERank); for(int i = 1; i < leftarr->rank; i++) - if(leftarr->shape[i] != rightarr->shape[i]){ - print("Shapes don't match, lol\n"); - exits(nil); - } + if(leftarr->shape[i] != rightarr->shape[i]) + throwerror(nil, EShape); } int type, rank, leftsize, rightsize; @@ -182,11 +182,12 @@ get_digits: else stmt->toks[stmt->ntoks].array = mkrunearray(buf); }else{ + Rune *err; syntax_error: - print("Can't lex: %S\n", &line[offset]); + err = runesmprint("Can't lex: %S", &line[offset]); free(stmt->toks); free(stmt); - return 0; + throwerror(err, ESyntax); } stmt->ntoks++; } @@ -27,23 +27,31 @@ main(int argc, char *argv[]) break; }ARGEND + int errorcode; +restart: + SETUPERROR(errorcode); + if(errorcode){ + if(globalerror.msg) + print("%S: %S\n", errorstrs[errorcode], globalerror.msg); + else + print("%S\n", errorstrs[errorcode]); + goto restart; + } + while(!off){ checkmem("main loop"); Rune *input = prompt(L"\t"); Datum *result = evalline(input, 1); - if(result == nil){ - if(errormsg == nil) - off = 1; - else - print("ERROR: %S\n", errormsg); - }else{ + if(result == nil) + continue; + else{ if(result[0].shy == 0) print("%S\n", ppdatum(*result)); if(result->tag == ArrayTag) freearray(result->array); free(result); } - print("Unfreed arrays: %d\n", alloccounts); + /* print("Unfreed arrays: %d\n", alloccounts); */ } exits(nil); } @@ -12,6 +12,7 @@ OFILES=\ memory.$O\ operators.$O\ quadnames.$O\ + error.$O\ HFILES=\ apl9.h\ diff --git a/operators.c b/operators.c index 226f27b..65948de 100644 --- a/operators.c +++ b/operators.c @@ -36,12 +36,9 @@ opEach(Datum *lefto, Array *left, Array *right) Array *leftarr; Array *rightarr; if(left){ - int rankok = scalarextend(left, right, &leftarr, &rightarr); - if(!rankok){ - print("Ranks don't match lol\n"); - exits(nil); - } + if(!rankok) + throwerror(nil, ERank); }else{ leftarr = nil; rightarr = fnSame(right); diff --git a/quadnames.c b/quadnames.c index e7ebbdd..a582abb 100644 --- a/quadnames.c +++ b/quadnames.c @@ -43,7 +43,7 @@ quadnamedatum(QuadnameDef q) case DyadicOpTag: default: print("Can't use quad names with type=%d\n", q.tag); - exits("quadname"); + exits(nil); } return d; } |