From 13a6dedba65112c9de588182745c1ce24d8bd8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Fri, 12 Jul 2019 20:36:56 +0200 Subject: [PATCH] Create working PoC of loop statement --- smnp/main.py | 2 +- smnp/runtime/evaluators/assignment.py | 8 +- smnp/runtime/evaluators/expression.py | 10 ++- smnp/runtime/evaluators/loop.py | 109 ++++++++++++++++++++++++++ smnp/type/model.py | 1 + 5 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 smnp/runtime/evaluators/loop.py diff --git a/smnp/main.py b/smnp/main.py index be51437..2bfbec8 100644 --- a/smnp/main.py +++ b/smnp/main.py @@ -7,7 +7,7 @@ from smnp.program.interpreter import Interpreter def main(): try: #stdLibraryEnv = loadStandardLibrary() - Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=True, baseEnvironment=None) + Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=False, execute=True, baseEnvironment=None) #draft() #tokens = tokenize(['function a(b...) { x+y}']) #FunctionDefinitionParser(tokens).node.print() diff --git a/smnp/runtime/evaluators/assignment.py b/smnp/runtime/evaluators/assignment.py index 4e89c7f..f9e9234 100644 --- a/smnp/runtime/evaluators/assignment.py +++ b/smnp/runtime/evaluators/assignment.py @@ -1,4 +1,3 @@ -from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluators.expression import expressionEvaluator @@ -7,11 +6,8 @@ class AssignmentEvaluator(Evaluator): @classmethod def evaluator(cls, node, environment): - target = node.target.value - if target.startswith("_"): - raise RuntimeException("Declaration and assignation variables with names starting with '_' is not allowed", node.target.pos) - - value = expressionEvaluator(doAssert=True)(node.value, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + target = node.left.value + value = expressionEvaluator(doAssert=True)(node.right, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult scopeOfExistingVariable = environment.findVariableScope(target) if scopeOfExistingVariable is None: environment.scopes[-1][target] = value diff --git a/smnp/runtime/evaluators/expression.py b/smnp/runtime/evaluators/expression.py index d31429f..0f641e5 100644 --- a/smnp/runtime/evaluators/expression.py +++ b/smnp/runtime/evaluators/expression.py @@ -1,5 +1,5 @@ -from smnp.ast.node.factor import NotOperator, Power -from smnp.ast.node.identifier import FunctionCall +from smnp.ast.node.factor import NotOperator, Power, Loop +from smnp.ast.node.identifier import FunctionCall, Assignment from smnp.ast.node.unit import MinusOperator, Access from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator @@ -10,17 +10,21 @@ def expressionEvaluator(doAssert=False): def evaluateExpression(node, environment): from smnp.runtime.evaluators.function import FunctionCallEvaluator from smnp.runtime.evaluators.minus import MinusEvaluator - from smnp.runtime.evaluators.atom import AtomEvaluator from smnp.runtime.evaluators.access import AccessEvaluator from smnp.runtime.evaluators.negation import NotEvaluator from smnp.runtime.evaluators.power import PowerEvaluator + + from smnp.runtime.evaluators.loop import LoopEvaluator + from smnp.runtime.evaluators.assignment import AssignmentEvaluator result = Evaluator.oneOf( Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCall), Evaluator.forNodes(MinusEvaluator.evaluate, MinusOperator), Evaluator.forNodes(AccessEvaluator.evaluate, Access), Evaluator.forNodes(NotEvaluator.evaluate, NotOperator), Evaluator.forNodes(PowerEvaluator.evaluate, Power), + Evaluator.forNodes(LoopEvaluator.evaluate, Loop), + Evaluator.forNodes(AssignmentEvaluator.evaluate, Assignment), AtomEvaluator.evaluate )(node, environment) diff --git a/smnp/runtime/evaluators/loop.py b/smnp/runtime/evaluators/loop.py new file mode 100644 index 0000000..d27a4f5 --- /dev/null +++ b/smnp/runtime/evaluators/loop.py @@ -0,0 +1,109 @@ +from smnp.ast.node.none import NoneNode +from smnp.error.runtime import RuntimeException +from smnp.runtime.evaluator import Evaluator, evaluate +from smnp.runtime.evaluators.expression import expressionEvaluator +from smnp.type.model import Type + + +class LoopEvaluator(Evaluator): + + @classmethod + def evaluator(cls, node, environment): + iterator = expressionEvaluator(doAssert=True)(node.left, environment).value + parameters = [ identifier.value for identifier in node.parameters ] if type(node.parameters) != NoneNode() else [] + + try: + output = { + Type.INTEGER: cls.numberEvaluator, + Type.BOOL: cls.boolEvaluator, + Type.LIST: cls.listEvaluator, + Type.MAP: cls.mapEvaluator + }[iterator.type](node, environment, iterator, parameters) + except KeyError: + raise RuntimeException(f"The {iterator.type.name.lower()} type cannot stand as an iterator for loop statement", node.left.pos) + + return Type.list(output) + + @classmethod + def numberEvaluator(cls, node, environment, evaluatedIterator, parameters): + output = [] + + environment.scopes.append({}) + + if len(parameters) > 1: + raise RuntimeException(f"Loop with numeric iterator can handle only one parameter", node.parameters.pos) + + for i in range(evaluatedIterator.value): + if len(parameters) > 0: + environment.scopes[-1][parameters[0]] = Type.integer(i) + + output.append(evaluate(node.right, environment).value) + + environment.scopes.pop(-1) + + return output + + @classmethod + def boolEvaluator(cls, node, environment, evaluatedIterator, parameters): + output = [] + + environment.scopes.append({}) + + if len(parameters) > 0: + raise RuntimeException(f"Loop with logic iterator can't' handle any parameters", node.parameters.pos) + + condition = evaluatedIterator + while condition.value: + output.append(evaluate(node.right, environment).value) + condition = expressionEvaluator(doAssert=True)(node.left, environment).value + + environment.scopes.pop(-1) + + return output + + @classmethod + def listEvaluator(cls, node, environment, evaluatedIterator, parameters): + output = [] + + if len(parameters) > 2: + raise RuntimeException(f"Loop with list iterator can handle only two parameters", node.parameters.pos) + + for i, value in enumerate(evaluatedIterator.value): + if len(parameters) == 1: + environment.scopes[-1][parameters[0]] = value + if len(parameters) == 2: + environment.scopes[-1][parameters[0]] = Type.integer(i) + environment.scopes[-1][parameters[1]] = value + + output.append(evaluate(node.right, environment).value) + + environment.scopes.pop(-1) + + return output + + + @classmethod + def mapEvaluator(cls, node, environment, evaluatedIterator, parameters): + output = [] + + if len(parameters) > 3: + raise RuntimeException(f"Loop with map iterator can handle only three parameters", node.parameters.pos) + + i = 0 + for key, value in evaluatedIterator.value.items(): + if len(parameters) == 1: + environment.scopes[-1][parameters[0]] = value + if len(parameters) == 2: + environment.scopes[-1][parameters[0]] = key + environment.scopes[-1][parameters[1]] = value + if len(parameters) == 3: + environment.scopes[-1][parameters[0]] = Type.integer(i) + environment.scopes[-1][parameters[1]] = key + environment.scopes[-1][parameters[2]] = value + i += 1 + + output.append(evaluate(node.right, environment).value) + + environment.scopes.pop(-1) + + return output diff --git a/smnp/type/model.py b/smnp/type/model.py index dc42a28..f3e4037 100644 --- a/smnp/type/model.py +++ b/smnp/type/model.py @@ -73,6 +73,7 @@ class Type(Enum): def void(): return Value(Type.VOID, None) + def _failStringify(t): raise RuntimeException(f"Not able to interpret {t.name}'", None)