from smnp.ast.node.program import Program from smnp.error.runtime import RuntimeException from smnp.type.model import Type class Evaluator: @classmethod def evaluator(cls, node, environment): pass @classmethod def evaluate(cls, node, environment): result = cls.evaluator(node, environment) if result is None: return EvaluationResult.OK(Type.void()) return EvaluationResult.OK(result) @staticmethod def forNodes(evaluator, *nodes): def nodeEvaluator(node, environment): if type(node) in nodes: return evaluator(node, environment) return EvaluationResult.FAIL() return nodeEvaluator @staticmethod def oneOf(*evaluators): def combinedEvaluator(node, environment): for evaluator in evaluators: result = evaluator(node, environment) if result.result: return result return EvaluationResult.FAIL() return combinedEvaluator class EvaluationResult(): def __init__(self, result, value): if result and value is None: raise RuntimeError("Value musn't be None if result is set to True for EvaluationResult") if type(value) == EvaluationResult: raise RuntimeError(f"Nested EvaluationResult detected. Trying to create EvaluationResult with value = {value}") self.result = result self.value = value @staticmethod def FAIL(): return EvaluationResult(False, None) @staticmethod def OK(value): return EvaluationResult(True, value) def __str__(self): return f"{'OK' if self.result else 'FAILED'}[{self.value}]" def evaluate(node, environment): from smnp.runtime.evaluators.program import ProgramEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator result = Evaluator.oneOf( Evaluator.forNodes(ProgramEvaluator.evaluate, Program), #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