from smnp.ast.node.block import BlockNode from smnp.ast.node.extend import ExtendNode from smnp.ast.node.function import FunctionDefinitionNode from smnp.ast.node.imports import ImportNode from smnp.ast.node.program import Program from smnp.ast.node.ret import ReturnNode 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 from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator from smnp.runtime.evaluators.extend import ExtendEvaluator from smnp.runtime.evaluators.block import BlockEvaluator from smnp.runtime.evaluators.imports import ImportEvaluator from smnp.runtime.evaluators.function import ReturnEvaluator 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