diff --git a/asteroid/state.py b/asteroid/state.py
index 605cfeac..74aac668 100644
--- a/asteroid/state.py
+++ b/asteroid/state.py
@@ -23,6 +23,10 @@ def initialize(self,module=""):
# stack of 3-tuples for stack trace of function
# calls: (module,lineno,function name)
self.trace_stack = [(module,1,"")]
+ # if an exception occurs then error_trace will point to
+ # it. an exception handler is responsible for clearing
+ # this.
+ self.error_trace = None
state = State()
@@ -31,10 +35,15 @@ def warning(str):
print("Warning: {}: {}: {}".format(module, lineno, str))
def dump_trace():
- if len(state.trace_stack) == 1:
- return
+ if state.error_trace:
+ _dump_trace(state.error_trace)
+ return
else:
- print("traceback (most recent call last):")
- for i in range(0,len(state.trace_stack)):
- (module,lineno,fname) = state.trace_stack[i]
- print("{}: {}: calling {}".format(module,lineno,fname))
+ _dump_trace(state.trace_stack)
+ return
+
+def _dump_trace(trace):
+ print("traceback (most recent call last):")
+ for i in range(0,len(trace)):
+ (module,lineno,fname) = trace[i]
+ print("{}: {}: calling {}".format(module,lineno,fname))
diff --git a/asteroid/test-suites/regression-tests/test138.ast b/asteroid/test-suites/regression-tests/test138.ast
new file mode 100644
index 00000000..babbed0f
--- /dev/null
+++ b/asteroid/test-suites/regression-tests/test138.ast
@@ -0,0 +1,18 @@
+-- test case for issue #209
+load system io.
+
+function goo with none do
+ throw Error("exception").
+end
+
+function foo with none do
+ let a = 1.
+ try
+ goo().
+ catch _ do
+ io @println "exception caught".
+ end
+ assert(a==1). -- make that a is still in scope
+end
+
+foo ().
diff --git a/asteroid/version.py b/asteroid/version.py
index 6626f8c7..9e7dbc25 100644
--- a/asteroid/version.py
+++ b/asteroid/version.py
@@ -5,4 +5,4 @@
# (c) University of Rhode Island
##########################################################################################
-VERSION = "1.1.3"
+VERSION = "1.1.4"
diff --git a/asteroid/walk.py b/asteroid/walk.py
index d8995ab5..d414dbda 100644
--- a/asteroid/walk.py
+++ b/asteroid/walk.py
@@ -4,7 +4,7 @@
# (c) University of Rhode Island
#########################################################################
-from copy import deepcopy
+from copy import deepcopy,copy
from re import match as re_match
from asteroid.globals import *
@@ -941,6 +941,15 @@ def handle_builtins(node):
else:
raise ValueError("unknown builtin unary operation '{}'".format(opname))
+#########################################################################
+def pop_stackframe(error_trace=False):
+ # pop frame off the stack
+ state.symbol_table.pop_scope()
+ state.symbol_table.set_config(state.symbol_table.saved_configs.pop())
+ if error_trace:
+ state.error_trace = copy(state.trace_stack)
+ state.trace_stack.pop()
+
#########################################################################
def handle_call(obj_ref, fval, actual_val_args, fname):
# Needed for later
@@ -1050,19 +1059,11 @@ def handle_call(obj_ref, fval, actual_val_args, fname):
# Reset settings
except RedundantPatternFound as r:
debugging = old_debugging
-
- # coming back from a function call - restore caller's env
+ # restore caller's env
state.lineinfo = old_lineinfo
-
# Keep debugger up to date
- if debugging:
- debugger.set_lineinfo(state.lineinfo)
-
- state.symbol_table.pop_scope()
- state.symbol_table.set_config(state.symbol_table.saved_configs.pop())
-
- state.trace_stack.pop()
-
+ if debugging: debugger.set_lineinfo(state.lineinfo)
+ pop_stackframe()
raise r
# execute the function
@@ -1089,17 +1090,20 @@ def handle_call(obj_ref, fval, actual_val_args, fname):
function_return_value.pop()
return_value = val.value
- # coming back from a function call - restore caller's env
+ except Exception as e:
+ # we got some other kind of exception within the function call
+ # clean up our runtime stack and rethrow
+ # Note: do not reset lineinfo, this way the state points at the source
+ # of the exception
+ pop_stackframe(error_trace=True)
+ raise e
+
+ # all done with function call -- clean up and exit
+ # restore caller's env
state.lineinfo = old_lineinfo
-
# Keep debugger up to date
if debugging: debugger.set_lineinfo(state.lineinfo)
-
- state.symbol_table.pop_scope()
- state.symbol_table.set_config(state.symbol_table.saved_configs.pop())
-
- state.trace_stack.pop()
-
+ pop_stackframe()
message_explicit("Return: {} from {}",
[("None" if (not return_value[1]) else gen_t2s(return_value)),
fname],
@@ -1331,6 +1335,8 @@ def try_stmt(node):
except PatternMatchFailed:
pass
else:
+ # handler found - null out error_trace
+ state.error_trace = None
declare_unifiers(unifiers)
walk_stmt_list(catch_stmts, step_state=stepping)
return