def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value supportedTypes = [Type.INTEGER, Type.FLOAT] if not left.type in supportedTypes: raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.left.pos) if not right.type in supportedTypes: raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.right.pos) if node.operator.value == "*": return getProperTypeProvider(left.value * right.value) if node.operator.value == "/": if right.value == 0: raise RuntimeException("Attempt to divide by 0", node.right.pos) value = left.value / right.value if left.type == right.type == Type.INTEGER and int(value) == value: return Type.integer(int(value)) return getProperTypeProvider(value) raise RuntimeError("This line should never be reached")
def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value if node.operator.value == "==": return cls.equalOperatorEvaluator(left, node.operator, right) if node.operator.value == "!=": return cls.notEqualOperatorEvaluator(left, node.operator, right) return cls.otherRelationOperatorsEvaluator(left, node.operator, right)
def evaluator(cls, node, environment): map = {} keyEvaluator = Evaluator.oneOf( Evaluator.forNodes(lambda node, environment: EvaluationResult.OK(Type.string(node.value)), Identifier), expressionEvaluator(doAssert=True) ) for entry in node.children: key = keyEvaluator(entry.key, environment).value if key in map: raise RuntimeException(f"Duplicated key '{key.stringify()}' found in map", entry.pos) map[key] = expressionEvaluator(doAssert=True)(entry.value, environment).value return Type.map(map)
def evaluator(cls, node, environment): condition = expressionEvaluator(doAssert=True)(node.condition, environment).value if condition.type != Type.BOOL: raise RuntimeException( f"Only {Type.BOOL.name.lower()} types can be used as conditions in conditional expression", node.condition.pos) if condition.value: return expressionEvaluator(doAssert=True)(node.ifNode, environment).value else: return expressionEvaluator(doAssert=True)(node.elseNode, environment).value
def evaluator(cls, node, environment): value = expressionEvaluator(doAssert=True)(node.value, environment).value if value.type != Type.BOOL: raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {Type.BOOL.name.lower()} type", node.value.pos) return Type.bool(not value.value)
def evaluate(node, environment): from smnp.runtime.evaluators.program import ProgramEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.condition import IfElseStatementEvaluator from smnp.runtime.evaluators.block import BlockEvaluator from smnp.runtime.evaluators.imports import ImportEvaluator from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator from smnp.runtime.evaluators.function import ReturnEvaluator from smnp.runtime.evaluators.extend import ExtendEvaluator from smnp.runtime.evaluators.throw import ThrowEvaluator result = Evaluator.oneOf( Evaluator.forNodes(ProgramEvaluator.evaluate, Program), Evaluator.forNodes(IfElseStatementEvaluator.evaluate, IfElse), Evaluator.forNodes(BlockEvaluator.evaluate, Block), Evaluator.forNodes(ImportEvaluator.evaluate, Import), Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinition), Evaluator.forNodes(ReturnEvaluator.evaluate, Return), Evaluator.forNodes(ExtendEvaluator.evaluate, Extend), Evaluator.forNodes(ThrowEvaluator.evaluate, Throw), #Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode), #Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode), #Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode), #Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode), #Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode), expressionEvaluator())(node, environment) if not result.result: raise RuntimeException("Cannot evaluate program", node.pos) return result
def evaluator(cls, node, environment): try: name = node.name.value arguments = abstractIterableEvaluator(expressionEvaluator(True))( node.arguments, environment) return environment.invokeFunction(name, arguments) except RuntimeException as e: raise updatePos(e, node)
def evaluator(cls, node, environment): string = expressionEvaluator(doAssert=True)(node.value, environment).value if string.type != Type.STRING: raise RuntimeException( f"Only {Type.STRING.name.lower()} types can be thrown", node.value.pos) raise CustomException(string.value, node.pos)
def doFilter(cls, filter, environment): if type(filter) is not NoneNode: evaluation = expressionEvaluator(doAssert=True)(filter, environment).value if evaluation.type != Type.BOOL: raise RuntimeException( f"Expected {Type.BOOL.name.lower()} as filter expression, found {evaluation.type.name.lower()}", filter.pos) return evaluation.value return True
def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value if left.type in [Type.INTEGER, Type.FLOAT ] and right.type in [Type.INTEGER, Type.FLOAT]: return cls.numberEvaluator(left, node.operator, right) if left.type == right.type == Type.STRING: return cls.stringEvaluator(left, node.operator, right) if left.type == right.type == Type.LIST: return cls.listEvaluator(left, node.operator, right) if left.type == right.type == Type.MAP: return cls.mapEvaluator(left, node.operator, right) raise RuntimeException( f"Operator {node.operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types", node.operator.pos)
def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)( node.left, environment ).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult right = node.right if type(right) == Identifier: try: return left.properties[right.value] except KeyError: raise RuntimeException( f"Unknown property '{right.value}' of type '{left.type.name.lower()}'", right.pos) if type(right) == FunctionCall: try: arguments = abstractIterableEvaluator( expressionEvaluator(doAssert=True))(right.arguments, environment) return environment.invokeMethod(left, right.name.value, arguments) except RuntimeException as e: raise updatePos(e, right)
def evaluator(cls, node, environment): if len(environment.callStack) > 0: 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 a 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)
def boolEvaluator(cls, node, environment, evaluatedIterator, parameters, filter): output = [] if len(parameters) > 0: raise RuntimeException( f"Loop with logic iterator can't' handle any parameters", node.parameters.pos) condition = evaluatedIterator while condition.value: if cls.doFilter(filter, environment): output.append(evaluate(node.right, environment).value) condition = expressionEvaluator(doAssert=True)(node.left, environment).value return output
def evaluator(cls, node, environment): 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 environment.scopes[-1][target] = value return value # # def evaluateAssignment(assignment, environment): # target = assignment.target.identifier # value = evaluate(assignment.value, environment) # if value.type == Type.VOID: # raise RuntimeException(f"Expected expression, found '{value.type.name}'", assignment.value.pos) # scopeOfExistingVariable = environment.findVariableScope(target) # if scopeOfExistingVariable is not None: # scopeOfExistingVariable[target] = value # else: # environment.scopes[-1][target] = value
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: environment.appendScope() output = { Type.INTEGER: cls.numberEvaluator, Type.BOOL: cls.boolEvaluator, Type.LIST: cls.listEvaluator, Type.MAP: cls.mapEvaluator }[iterator.type](node, environment, iterator, parameters, node.filter) environment.popScope() 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)
def evaluator(cls, node, environment): list = abstractIterableEvaluator(expressionEvaluator(doAssert=True))(node, environment) return Type.list(list)
def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value return Type.bool(left.value and right.value)