Enable evaluating asterisk

This commit is contained in:
Bartłomiej Pluta
2019-07-08 19:33:14 +02:00
parent 63c020fbb9
commit 21cbf2bcbd
6 changed files with 120 additions and 35 deletions

View File

@@ -122,7 +122,7 @@ class Environment():
def __str__(self): 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): def __repr__(self):
return self.__str__() return self.__str__()

View File

@@ -16,7 +16,7 @@ def main():
ast = parse(tokens) ast = parse(tokens)
#ast.print() ast.print()
env = createEnvironment() env = createEnvironment()

View File

@@ -1,3 +1,4 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
@@ -7,6 +8,9 @@ class AssignmentEvaluator(Evaluator):
@classmethod @classmethod
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
target = node.target.value 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 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) scopeOfExistingVariable = environment.findVariableScope(target)
if scopeOfExistingVariable is None: if scopeOfExistingVariable is None:

View File

@@ -1,48 +1,122 @@
from smnp.ast.node.identifier import IdentifierNode 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.model import Type
from smnp.type.value import Value from smnp.type.value import Value
def evaluateAsterisk(asterisk, environment): class AsteriskEvaluator(Evaluator):
iterator = evaluate(asterisk.iterator, environment)
if iterator.type == Type.INTEGER:
evaluateAsteriskForNumber(asterisk, environment, iterator)
if iterator.type == Type.LIST: @classmethod
evaluateAsteriskForList(asterisk, environment, iterator) 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): return EvaluationResult.OK(Value(Type.LIST, results).decompose())
for i in range(count.value):
if type(asterisk.iterator) == IdentifierNode: return EvaluationResult.FAIL()
environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1)
return evaluator
@classmethod
def _automaticNamedVariable(cls, iteratorNode, environment, prefix=''):
if type(iteratorNode) == IdentifierNode:
return cls._automaticVariableName(environment, prefix, iteratorNode.value, False)
else: 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: return variableName(number)
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
else:
del environment.scopes[-1]["_"]
@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): del environment.scopes[-1][automaticVariableKey]
for i, v in enumerate(list.value): del environment.scopes[-1][automaticVariableValue]
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) return EvaluationResult.OK(Value(Type.LIST, results).decompose())
if type(asterisk.iterator) == IdentifierNode: return EvaluationResult.FAIL()
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
del environment.scopes[-1][f"{asterisk.iterator.identifier}_"] return evaluator
else:
del environment.scopes[-1]["_"] #
del environment.scopes[-1]["__"] # 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]["__"]

View File

@@ -5,9 +5,13 @@ class BlockEvaluator(Evaluator):
@classmethod @classmethod
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
environment.scopes.append({})
for child in node.children: for child in node.children:
evaluate(child, environment) evaluate(child, environment)
environment.scopes.pop(-1)
# #
# def evaluateBlock(block, environment): # def evaluateBlock(block, environment):
# environment.scopes.append({}) # environment.scopes.append({})

View File

@@ -1,5 +1,6 @@
from smnp.ast.node.access import AccessNode from smnp.ast.node.access import AccessNode
from smnp.ast.node.assignment import AssignmentNode 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.identifier import IdentifierNode
from smnp.ast.node.integer import IntegerLiteralNode from smnp.ast.node.integer import IntegerLiteralNode
from smnp.ast.node.invocation import FunctionCallNode 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.access import AccessEvaluator
from smnp.runtime.evaluators.assignment import AssignmentEvaluator from smnp.runtime.evaluators.assignment import AssignmentEvaluator
from smnp.runtime.evaluators.asterisk import AsteriskEvaluator
result = Evaluator.oneOf( result = Evaluator.oneOf(
Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode), Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode),
Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode), Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode),
@@ -30,7 +32,8 @@ def expressionEvaluator(doAssert=False):
Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode), Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode),
Evaluator.forNodes(ListEvaluator.evaluate, ListNode), Evaluator.forNodes(ListEvaluator.evaluate, ListNode),
Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode), Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode),
Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode) Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode),
Evaluator.forNodes(AsteriskEvaluator.evaluate, AsteriskNode)
)(node, environment) )(node, environment)
if doAssert and result.result and result.value.type == Type.VOID: if doAssert and result.result and result.value.type == Type.VOID: