Files
smnp-py/smnp/runtime/evaluator.py
2019-07-10 12:21:07 +02:00

93 lines
3.0 KiB
Python

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