mirror of
https://github.com/kanaka/mal.git
synced 2024-10-26 14:22:25 +03:00
ps: Fix handling of exceptions thrown from catch* clause
PostScript's exception handling doesn't restore the dictionary or operand stacks to the state they were in when the "stopped" operator started, so mal's EVAL needs to do that itself. To do this, it records the current height of the stacks, but of course it does that in a dictionary. This means that when catching at exception, it relies on the highest instance of "dictcnt" on the dictionary stack being the correct one. EVAL, however, was failing to restore the dictionary stack at the right time. For instance, conside this code (from the tests): (try* (try* (throw "e1") (catch* e (throw "e2"))) (catch* e "c2")) Each "try*" clause saves "dictcnt" into a dictionary on the dictionary stack. When the inner "catch*" clause fires, it pops the dictionary and operand stacks to the correct point, but then calls the second "throw" with the wrong value of "dictcnt" still visible. The result is that the "catch*" clause ends up running with the wrong value of "dictcnt" and restoring the stacks to the wrong place, essentially executing the _inner_ "catch*" clause again, whereupon the error doesn't get caught because there's no "stopped" left on the PostScript execution stack. The fix is to add another dictionary that's just used to hold "dictcnt" and "stackcnt", and to pop that from the dictionary stack as soon as the stacks have been restored (or when it becomes unnecessary because the "try*" clause has returned normally).
This commit is contained in:
parent
89b940ae62
commit
e069ddff67
@ -156,9 +156,11 @@ end } def
|
||||
}{ /try* a0 eq { %if try*
|
||||
ast _count 2 gt { %if has catch* block
|
||||
{ %try
|
||||
2 dict begin % special dict for dict stack count
|
||||
countdictstack /dictcnt exch def
|
||||
count /stackcnt exch def
|
||||
ast 1 _nth env EVAL
|
||||
end
|
||||
} stopped { %catch
|
||||
% clean up the dictionary stack
|
||||
1 1 countdictstack dictcnt sub { %foreach added dict
|
||||
@ -172,6 +174,7 @@ end } def
|
||||
pop pop % pop idx and operand
|
||||
%(popped op stack\n) print pstack
|
||||
} for
|
||||
end % remove special dict
|
||||
% get error data and reset $error dict
|
||||
/errdata get_error_data def
|
||||
$error /newerror false put
|
||||
|
@ -165,9 +165,11 @@ end } def
|
||||
}{ /try* a0 eq { %if try*
|
||||
ast _count 2 gt { %if has catch* block
|
||||
{ %try
|
||||
2 dict begin % special dict for dict stack count
|
||||
countdictstack /dictcnt exch def
|
||||
count /stackcnt exch def
|
||||
ast 1 _nth env EVAL
|
||||
end
|
||||
} stopped { %catch
|
||||
% clean up the dictionary stack
|
||||
1 1 countdictstack dictcnt sub { %foreach added dict
|
||||
@ -181,6 +183,7 @@ end } def
|
||||
pop pop % pop idx and operand
|
||||
%(popped op stack\n) print pstack
|
||||
} for
|
||||
end % remove special dict
|
||||
% get error data and reset $error dict
|
||||
/errdata get_error_data def
|
||||
$error /newerror false put
|
||||
|
Loading…
Reference in New Issue
Block a user