diff --git a/smnp/environment/environment.py b/smnp/environment/environment.py index 73283e0..0433056 100644 --- a/smnp/environment/environment.py +++ b/smnp/environment/environment.py @@ -1,7 +1,8 @@ from smnp.error.function import FunctionNotFoundException, MethodNotFoundException, IllegalFunctionInvocationException from smnp.error.runtime import RuntimeException from smnp.function.tools import argsTypesToString -from smnp.runtime.evaluators.function import BodyEvaluator +from smnp.runtime.evaluators.function import BodyEvaluator, Return +from smnp.type.model import Type class Environment(): @@ -41,7 +42,11 @@ class Environment(): self.scopes.append({argName: argValue for argName, argValue in zip(method.arguments, list(signatureCheckresult[1:]))}) self.scopes[-1][method.alias] = object self.callStack.append(CallStackItem(name)) - result = BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + result = Type.void() + try: + BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + except Return as r: + result = r.value self.callStack.pop(-1) self.scopes.pop(-1) return (True, result) @@ -76,7 +81,11 @@ class Environment(): if signatureCheckresult[0]: self.scopes.append({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) }) self.callStack.append(CallStackItem(name)) - result = BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + result = Type.void() + try: + BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + except Return as r: + result = r.value self.callStack.pop(-1) self.scopes.pop(-1) return (True, result) @@ -162,7 +171,6 @@ class Environment(): class CallStackItem: def __init__(self, function): self.function = function - self.value = None class CustomFunction: diff --git a/smnp/runtime/evaluators/function.py b/smnp/runtime/evaluators/function.py index 97e9e14..378598a 100644 --- a/smnp/runtime/evaluators/function.py +++ b/smnp/runtime/evaluators/function.py @@ -4,6 +4,7 @@ from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator from smnp.runtime.tools.error import updatePos from smnp.runtime.tools.signature import argumentsNodeToMethodSignature +from smnp.type.model import Type class FunctionCallEvaluator(Evaluator): @@ -38,8 +39,6 @@ class BodyEvaluator(Evaluator): def evaluator(cls, node, environment): for child in node.children: evaluate(child, environment) - if environment.callStack[-1].value is not None: - return environment.callStack[-1].value class ReturnEvaluator(Evaluator): @@ -47,7 +46,21 @@ class ReturnEvaluator(Evaluator): @classmethod def evaluator(cls, node, environment): if len(environment.callStack) > 0: - returnValue = expressionEvaluator(doAssert=True)(node.value, environment) - environment.callStack[-1].value = returnValue.value + returnValue = expressionEvaluator()(node.value, environment).value + raise Return(returnValue) + # Disclaimer + # Exception system usage to control program execution flow is really bad idea. + # However because of lack of 'goto' instruction equivalent in Python + # there is to need to use some mechanism to break function execution on 'return' statement + # and immediately go to Environment's method 'invokeFunction()' or 'invokeMethod()', + # which can handle value that came with exception and return it to code being executed. else: raise RuntimeException("Cannot use 'return' statement outside a function or method", node.pos, environment) + + +class Return(Exception): + def __init__(self, value): + if value is None: + value = Type.void() + + self.value = value \ No newline at end of file