From 21cbf2bcbde68c3bcb731ce657607925afbe5b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Mon, 8 Jul 2019 19:33:14 +0200 Subject: [PATCH] Enable evaluating asterisk --- smnp/environment/environment.py | 2 +- smnp/main.py | 2 +- smnp/runtime/evaluators/assignment.py | 4 + smnp/runtime/evaluators/asterisk.py | 138 ++++++++++++++++++++------ smnp/runtime/evaluators/block.py | 4 + smnp/runtime/evaluators/expression.py | 5 +- 6 files changed, 120 insertions(+), 35 deletions(-) diff --git a/smnp/environment/environment.py b/smnp/environment/environment.py index d3c8021..6eb4370 100644 --- a/smnp/environment/environment.py +++ b/smnp/environment/environment.py @@ -122,7 +122,7 @@ class Environment(): def __str__(self): - return self.scopesToString() + self.functionsToString() + self.methodsToString() + self.customFunctionsToString() + self.customMethodsToString() + return f"{self.scopesToString()}\n{self.functionsToString()}\n{self.methodsToString()}\n{self.customFunctionsToString()}\n{self.customMethodsToString()}" def __repr__(self): return self.__str__() diff --git a/smnp/main.py b/smnp/main.py index 2259a49..aed51e0 100644 --- a/smnp/main.py +++ b/smnp/main.py @@ -16,7 +16,7 @@ def main(): ast = parse(tokens) - #ast.print() + ast.print() env = createEnvironment() diff --git a/smnp/runtime/evaluators/assignment.py b/smnp/runtime/evaluators/assignment.py index 3aa6b77..691ce74 100644 --- a/smnp/runtime/evaluators/assignment.py +++ b/smnp/runtime/evaluators/assignment.py @@ -1,3 +1,4 @@ +from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluators.expression import expressionEvaluator @@ -7,6 +8,9 @@ class AssignmentEvaluator(Evaluator): @classmethod def evaluator(cls, node, environment): target = node.target.value + if target.startswith("_"): + raise RuntimeException("Usage of 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 scopeOfExistingVariable = environment.findVariableScope(target) if scopeOfExistingVariable is None: diff --git a/smnp/runtime/evaluators/asterisk.py b/smnp/runtime/evaluators/asterisk.py index ce390d2..c80856c 100644 --- a/smnp/runtime/evaluators/asterisk.py +++ b/smnp/runtime/evaluators/asterisk.py @@ -1,48 +1,122 @@ from smnp.ast.node.identifier import IdentifierNode -from smnp.runtime.evaluator import evaluate +from smnp.runtime.evaluator import evaluate, Evaluator, EvaluationResult +from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.type.model import Type from smnp.type.value import Value -def evaluateAsterisk(asterisk, environment): - iterator = evaluate(asterisk.iterator, environment) - if iterator.type == Type.INTEGER: - evaluateAsteriskForNumber(asterisk, environment, iterator) +class AsteriskEvaluator(Evaluator): - if iterator.type == Type.LIST: - evaluateAsteriskForList(asterisk, environment, iterator) + @classmethod + def evaluator(cls, node, environment): + iterator = expressionEvaluator(doAssert=True)(node.iterator, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + return Evaluator.oneOf( + cls._numberIteratorAsteriskEvaluator(iterator), + cls._listIteratorAsteriskEvaluator(iterator) + )(node, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + @classmethod + def _numberIteratorAsteriskEvaluator(cls, evaluatedIterator): + def evaluator(node, environment): + if evaluatedIterator.type == Type.INTEGER: + results = [] + automaticVariable = cls._automaticNamedVariable(node.iterator, environment, "_") + for i in range(evaluatedIterator.value): + environment.scopes[-1][automaticVariable] = Value(Type.INTEGER, i + 1) + result = evaluate(node.statement, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + if result is not None and result.type != Type.VOID: + results.append(result) + del environment.scopes[-1][automaticVariable] -def evaluateAsteriskForNumber(asterisk, environment, count): - for i in range(count.value): - if type(asterisk.iterator) == IdentifierNode: - environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1) + return EvaluationResult.OK(Value(Type.LIST, results).decompose()) + + return EvaluationResult.FAIL() + + return evaluator + + @classmethod + def _automaticNamedVariable(cls, iteratorNode, environment, prefix=''): + if type(iteratorNode) == IdentifierNode: + return cls._automaticVariableName(environment, prefix, iteratorNode.value, False) else: - environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1) + return cls._automaticVariableName(environment, prefix, '', True) - evaluate(asterisk.statement, environment) + @classmethod + def _automaticVariableName(cls, environment, prefix='', suffix='', startWithNumber=False): + number = 1 if startWithNumber else '' + variableName = lambda x: f"{prefix}{x}{suffix}" + while environment.findVariableScope(variableName(number)) is not None: + if number == '': + number = 1 + else: + number += 1 - if type(asterisk.iterator) == IdentifierNode: - del environment.scopes[-1][f"_{asterisk.iterator.identifier}"] - else: - del environment.scopes[-1]["_"] + return variableName(number) + @classmethod + def _listIteratorAsteriskEvaluator(cls, evaluatedIterator): + def evaluator(node, environment): + if evaluatedIterator.type == Type.LIST: + results = [] + automaticVariableKey = cls._automaticNamedVariable(node.iterator, environment, "_") + automaticVariableValue = cls._automaticNamedVariable(node.iterator, environment, "__") + for i, v in enumerate(evaluatedIterator.value): + environment.scopes[-1][automaticVariableKey] = Value(Type.INTEGER, i + 1) + environment.scopes[-1][automaticVariableValue] = v + result = evaluate(node.statement, environment).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + if result is not None and result.type != Type.VOID: + results.append(result) -def evaluateAsteriskForList(asterisk, environment, list): - for i, v in enumerate(list.value): - if type(asterisk.iterator) == IdentifierNode: - environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1) - environment.scopes[-1][f"{asterisk.iterator.identifier}_"] = v - else: - environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1) - environment.scopes[-1]["__"] = v + del environment.scopes[-1][automaticVariableKey] + del environment.scopes[-1][automaticVariableValue] - evaluate(asterisk.statement, environment) + return EvaluationResult.OK(Value(Type.LIST, results).decompose()) - if type(asterisk.iterator) == IdentifierNode: - del environment.scopes[-1][f"_{asterisk.iterator.identifier}"] - del environment.scopes[-1][f"{asterisk.iterator.identifier}_"] - else: - del environment.scopes[-1]["_"] - del environment.scopes[-1]["__"] \ No newline at end of file + return EvaluationResult.FAIL() + + return evaluator + +# +# def evaluateAsterisk(asterisk, environment): +# iterator = evaluate(asterisk.iterator, environment) +# if iterator.type == Type.INTEGER: +# evaluateAsteriskForNumber(asterisk, environment, iterator) +# +# if iterator.type == Type.LIST: +# evaluateAsteriskForList(asterisk, environment, iterator) +# +# +# +# def evaluateAsteriskForNumber(asterisk, environment, count): +# for i in range(count.value): +# if type(asterisk.iterator) == IdentifierNode: +# environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1) +# else: +# environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1) +# +# evaluate(asterisk.statement, environment) +# +# if type(asterisk.iterator) == IdentifierNode: +# del environment.scopes[-1][f"_{asterisk.iterator.identifier}"] +# else: +# del environment.scopes[-1]["_"] +# +# +# def evaluateAsteriskForList(asterisk, environment, list): +# for i, v in enumerate(list.value): +# if type(asterisk.iterator) == IdentifierNode: +# environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1) +# environment.scopes[-1][f"{asterisk.iterator.identifier}_"] = v +# else: +# environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1) +# environment.scopes[-1]["__"] = v +# +# evaluate(asterisk.statement, environment) +# +# if type(asterisk.iterator) == IdentifierNode: +# del environment.scopes[-1][f"_{asterisk.iterator.identifier}"] +# del environment.scopes[-1][f"{asterisk.iterator.identifier}_"] +# else: +# del environment.scopes[-1]["_"] +# del environment.scopes[-1]["__"] diff --git a/smnp/runtime/evaluators/block.py b/smnp/runtime/evaluators/block.py index f8ae4c8..c4f4c6e 100644 --- a/smnp/runtime/evaluators/block.py +++ b/smnp/runtime/evaluators/block.py @@ -5,9 +5,13 @@ class BlockEvaluator(Evaluator): @classmethod def evaluator(cls, node, environment): + environment.scopes.append({}) + for child in node.children: evaluate(child, environment) + environment.scopes.pop(-1) + # # def evaluateBlock(block, environment): # environment.scopes.append({}) diff --git a/smnp/runtime/evaluators/expression.py b/smnp/runtime/evaluators/expression.py index 02b9283..fcb15f3 100644 --- a/smnp/runtime/evaluators/expression.py +++ b/smnp/runtime/evaluators/expression.py @@ -1,5 +1,6 @@ from smnp.ast.node.access import AccessNode from smnp.ast.node.assignment import AssignmentNode +from smnp.ast.node.asterisk import AsteriskNode from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.integer import IntegerLiteralNode from smnp.ast.node.invocation import FunctionCallNode @@ -22,6 +23,7 @@ def expressionEvaluator(doAssert=False): from smnp.runtime.evaluators.access import AccessEvaluator from smnp.runtime.evaluators.assignment import AssignmentEvaluator + from smnp.runtime.evaluators.asterisk import AsteriskEvaluator result = Evaluator.oneOf( Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode), Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode), @@ -30,7 +32,8 @@ def expressionEvaluator(doAssert=False): Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode), Evaluator.forNodes(ListEvaluator.evaluate, ListNode), Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode), - Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode) + Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode), + Evaluator.forNodes(AsteriskEvaluator.evaluate, AsteriskNode) )(node, environment) if doAssert and result.result and result.value.type == Type.VOID: