diff options
Diffstat (limited to 'error.c')
-rw-r--r-- | error.c | 49 |
1 files changed, 45 insertions, 4 deletions
@@ -5,7 +5,7 @@ #include "apl9.h" -ErrorHandler globalerror; +ErrorGuard *globalerrorguard; Rune *errorstrs[] = { [ESyntax] = L"SYNTAX ERROR", @@ -20,11 +20,52 @@ Rune *errorstrs[] = { [ENotImplemented] = L"NOT IMPLEMENTED", }; +ErrorGuard * +newerrorguard(Array *codes, Statement *guard) +{ + DfnFrame *fr = getcurrentdfn(); + ErrorGuard *eg = emallocz(sizeof(ErrorGuard), 1); + eg->active = 1; + eg->guard = guard; + + if(fr == nil) + globalerrorguard = eg; + else{ + eg->next = fr->errorguards; + fr->errorguards = eg; + eg->frame = dupdfnframe(fr); + } + + for(int i = 0; i < GetSize(codes); i++) + eg->code |= (1<<codes->intdata[i]); + + return eg; +} + void throwerror(Rune *msg, int err) { - free(globalerror.msg); - globalerror.msg = msg ? runestrdup(msg) : nil; - longjmp(globalerror.jmp, err); + ErrorGuard *matching = globalerrorguard; + DfnFrame *frame = getcurrentdfn(); + ThreadData *td = getthreaddata(); + td->lasterror = err; + if(td->lasterrormsg) + free(td->lasterrormsg); + td->lasterrormsg = msg; + + while(frame != nil){ + for(ErrorGuard *eg = frame->errorguards; eg != nil; eg = eg->next){ + if(!eg->active) + continue; + if(((1<<err) & eg->code) || (eg->code == 1)){ + matching = eg; + goto match; + } + } + frame = frame->prev; + popdfnframe(); + } +match: + longjmp(matching->jmp, 1); } |