Create evaluators for literals, list and identifier nodes
This commit is contained in:
@@ -16,10 +16,8 @@ def main():
|
||||
|
||||
ast = parse(tokens)
|
||||
|
||||
|
||||
ast.print()
|
||||
|
||||
sys.exit(0)
|
||||
env = createEnvironment()
|
||||
|
||||
evaluate(ast, env)
|
||||
|
||||
@@ -1,2 +1,78 @@
|
||||
def evaluate(input, environment):
|
||||
pass
|
||||
from smnp.ast.node.program import Program
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
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(Value(Type.VOID, None))
|
||||
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 evaluateExpression
|
||||
|
||||
result = Evaluator.oneOf(
|
||||
Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
|
||||
evaluateExpression
|
||||
)(node, environment)
|
||||
|
||||
if not result.result:
|
||||
raise RuntimeException("Cannot evaluate program", node.pos)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
22
smnp/runtime/evaluators/expression.py
Normal file
22
smnp/runtime/evaluators/expression.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.integer import IntegerLiteralNode
|
||||
from smnp.ast.node.list import ListNode
|
||||
from smnp.ast.node.note import NoteLiteralNode
|
||||
from smnp.ast.node.string import StringLiteralNode
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
|
||||
|
||||
def evaluateExpression(node, environment):
|
||||
from smnp.runtime.evaluators.string import StringEvaluator
|
||||
from smnp.runtime.evaluators.integer import IntegerEvaluator
|
||||
from smnp.runtime.evaluators.note import NoteEvaluator
|
||||
from smnp.runtime.evaluators.identifier import IdentifierEvaluator
|
||||
from smnp.runtime.evaluators.list import ListEvaluator
|
||||
|
||||
return Evaluator.oneOf(
|
||||
Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode),
|
||||
Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteralNode),
|
||||
Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteralNode),
|
||||
Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode),
|
||||
Evaluator.forNodes(ListEvaluator.evaluate, ListNode)
|
||||
)(node, environment)
|
||||
@@ -1,10 +1,13 @@
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
|
||||
|
||||
def evaluateIdentifier(identifier, environment):
|
||||
try:
|
||||
value = environment.findVariable(identifier.identifier)
|
||||
return value
|
||||
except RuntimeException as e:
|
||||
e.pos = identifier.pos
|
||||
raise e
|
||||
class IdentifierEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
try:
|
||||
return environment.findVariable(node.value)
|
||||
except RuntimeException as e:
|
||||
e.pos = node.pos
|
||||
raise e
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def evaluateInteger(integer, environment):
|
||||
return Value(Type.INTEGER, integer.value)
|
||||
class IntegerEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
return Value(Type.INTEGER, node.value)
|
||||
10
smnp/runtime/evaluators/iterable.py
Normal file
10
smnp/runtime/evaluators/iterable.py
Normal file
@@ -0,0 +1,10 @@
|
||||
def abstractIterableEvaluator(itemEvaluator):
|
||||
def evaluator(node, environment):
|
||||
evaluatedItems = []
|
||||
for item in node.children:
|
||||
result = itemEvaluator(item, environment)
|
||||
evaluatedItems.append(result.value)
|
||||
|
||||
return evaluatedItems
|
||||
|
||||
return evaluator
|
||||
@@ -1,17 +1,13 @@
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.runtime.evaluator import evaluate
|
||||
from smnp.runtime.tools import flatListNode
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
from smnp.runtime.evaluators.expression import evaluateExpression
|
||||
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def evaluateList(list, environment):
|
||||
newList = []
|
||||
for elem in flatListNode(list):
|
||||
item = evaluate(elem, environment)
|
||||
if item.type == Type.VOID:
|
||||
raise RuntimeException(f"Expected expression, found '{item.type.name}'", elem.pos)
|
||||
newList.append(item)
|
||||
return Value(Type.LIST, newList)
|
||||
|
||||
class ListEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
list = abstractIterableEvaluator(evaluateExpression)(node, environment)
|
||||
return Value(Type.LIST, list)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def evaluateNote(note, environment):
|
||||
return Value(Type.NOTE, note.value)
|
||||
class NoteEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
return Value(Type.NOTE, node.value)
|
||||
@@ -1,6 +1,9 @@
|
||||
from smnp.runtime.evaluator import evaluate
|
||||
from smnp.runtime.evaluator import Evaluator, evaluate
|
||||
|
||||
|
||||
def evaluateProgram(program, environment):
|
||||
for node in program.children:
|
||||
evaluate(node, environment)
|
||||
class ProgramEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
for n in node.children:
|
||||
evaluate(n, environment)
|
||||
@@ -1,28 +1,25 @@
|
||||
import re
|
||||
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.runtime.evaluator import Evaluator
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def evaluateString(string, environment):
|
||||
value = interpolate(string, environment)
|
||||
return Value(Type.STRING, value)
|
||||
class StringEvaluator(Evaluator):
|
||||
|
||||
@classmethod
|
||||
def evaluator(cls, node, environment):
|
||||
return Value(Type.STRING, node.value)
|
||||
|
||||
def interpolate(string, environment):
|
||||
interpolated = string.value
|
||||
for scope in reversed(environment.scopes):
|
||||
for name, value in scope.items():
|
||||
interpolated = interpolated.replace('{' + name + '}', value.stringify())
|
||||
|
||||
nonMatchedVariables = re.findall(r"\{\w+\}", interpolated)
|
||||
if len(nonMatchedVariables) > 0:
|
||||
raise RuntimeException(f"Variable '{nonMatchedVariables[0][1:len(nonMatchedVariables[0])-1]}' is not declared",
|
||||
(string.pos[0], string.pos[1] + string.value.find(nonMatchedVariables[0])+1))
|
||||
|
||||
return interpolated
|
||||
|
||||
# or scope in reversed(environment.scopes):
|
||||
# for k, v in scope.items():
|
||||
# value = value.replace('{' + k + '}', v) #TODO: poprawic
|
||||
# TODO: make use of complex interpreter for code inside '{' and '}'
|
||||
# def interpolate(string, environment):
|
||||
# interpolated = string.value
|
||||
# for scope in reversed(environment.scopes):
|
||||
# for name, value in scope.items():
|
||||
# interpolated = interpolated.replace('{' + name + '}', value.stringify())
|
||||
#
|
||||
# nonMatchedVariables = re.findall(r"\{\w+\}", interpolated)
|
||||
# if len(nonMatchedVariables) > 0:
|
||||
# raise RuntimeException(f"Variable '{nonMatchedVariables[0][1:len(nonMatchedVariables[0])-1]}' is not declared",
|
||||
# (string.pos[0], string.pos[1] + string.value.find(nonMatchedVariables[0])+1))
|
||||
#
|
||||
# return interpolated
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user