Reformat evaluator #1

This commit is contained in:
Bartłomiej Pluta
2019-07-04 17:57:12 +02:00
parent f0cbf37fe9
commit 34a0eda199
36 changed files with 470 additions and 270 deletions

View File

View File

@@ -0,0 +1,33 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluators.list import evaluateList
def evaluateAccess(access, environment):
pass
#element = evaluate(access.element, environment)
# TODO: narazie tylko metody działają
#e = evaluateMethodCall(element, access.property, environment)
def evaluateMethodCall(element, functionCall, environment):
funcName = functionCall.identifier.identifier
arguments = evaluateList(functionCall.arguments, environment)
arguments.insert(0, element)
# for name, library in environment.customFunctions.items():
# if funcName == name:
# if len(library['params']) != len(arguments):
# raise RuntimeException(functionCall.pos, f"Calling '{funcName}' requires {len(library['params'])} and {len(arguments)} was passed")
# environment.scopes.append({ library['params'][i].identifier: v for i, v in enumerate(arguments) })
# returnValue = None
# for node in library['body']:
# if not isinstance(node, ReturnNode):
# evaluate(node, environment)
# else:
# returnValue = evaluateReturn(node, environment)
# environment.scopes.pop(-1)
# return returnValue
for name, definition in environment.methods[type(element)].items():
if name == funcName:
return definition(arguments, environment)
raise RuntimeException(f"Method '{funcName}' does not exist", functionCall.pos)

View File

@@ -0,0 +1,15 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import evaluate
from smnp.type.model import Type
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

View File

@@ -0,0 +1,48 @@
from smnp.ast.node.identifier import IdentifierNode
from smnp.runtime.evaluator import evaluate
from smnp.type.model import Type
from smnp.type.value import Value
def evaluateAsterisk(asterisk, environment):
iterator = evaluate(asterisk.iterator, environment)
if iterator.type == Type.INTEGER:
evaluateAsteriskForNumber(asterisk, environment, iterator)
if iterator.type == Type.LIST:
evaluateAsteriskForList(asterisk, environment, iterator)
def evaluateAsteriskForNumber(asterisk, environment, count):
for i in range(count.value):
if type(asterisk.iterator) == IdentifierNode:
environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1)
else:
environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1)
evaluate(asterisk.statement, environment)
if type(asterisk.iterator) == IdentifierNode:
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
else:
del environment.scopes[-1]["_"]
def evaluateAsteriskForList(asterisk, environment, list):
for i, v in enumerate(list.value):
if type(asterisk.iterator) == IdentifierNode:
environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = Value(Type.INTEGER, i+1)
environment.scopes[-1][f"{asterisk.iterator.identifier}_"] = v
else:
environment.scopes[-1]["_"] = Value(Type.INTEGER, i+1)
environment.scopes[-1]["__"] = v
evaluate(asterisk.statement, environment)
if type(asterisk.iterator) == IdentifierNode:
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
del environment.scopes[-1][f"{asterisk.iterator.identifier}_"]
else:
del environment.scopes[-1]["_"]
del environment.scopes[-1]["__"]

View File

@@ -0,0 +1,11 @@
from smnp.runtime.evaluator import evaluate
from smnp.runtime.tools import flatListNode
def evaluateBlock(block, environment):
environment.scopes.append({})
for node in flatListNode(block):
evaluate(node, environment)
environment.scopes.pop(-1)

View File

@@ -0,0 +1,16 @@
from smnp.ast.node.integer import IntegerLiteralNode
from smnp.ast.node.note import NoteLiteralNode
from smnp.error.runtime import RuntimeException
from smnp.note.model import Note
from smnp.type.model import Type
from smnp.type.value import Value
def evaluateColon(colon, environment):
if isinstance(colon.a, NoteLiteralNode) and isinstance(colon.b, NoteLiteralNode):
return Value(Type.LIST, [Value(Type.NOTE, n) for n in Note.range(colon.a.value, colon.b.value)])
elif isinstance(colon.a, IntegerLiteralNode) and isinstance(colon.b, IntegerLiteralNode):
return Value(Type.LIST, [Value(Type.INTEGER, i) for i in range(colon.a.value, colon.b.value + 1)])
raise RuntimeException("Invalid colon arguments", colon.pos)

View File

@@ -0,0 +1,54 @@
from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.program import Program
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluators.list import evaluateList
from smnp.runtime.tools import flatListNode
def evaluateFunctionDefinition(definition, environment):
name = definition.name
params = list([p for p in flatListNode(definition.parameters)])
body = definition.body
if not isinstance(definition.parent, Program):
raise RuntimeException(f"Functions can be defined only on the top level of script", name.pos)
for p in params:
if not isinstance(p, IdentifierNode):
raise RuntimeException("Parameter of function definition must be an identifier", p.pos, )
if name.identifier in environment.customFunctions or name.identifier in environment.functions:
raise RuntimeException(f"Function '{name.identifier}' already exists", name.pos)
environment.customFunctions[name.identifier] = {
'params': params,
'body': flatListNode(body)
}
def evaluateFunctionCall(functionCall, environment):
functionName = functionCall.identifier.identifier
arguments = evaluateList(functionCall.arguments, environment).value
return environment.invokeFunction(functionName, arguments)
# def evaluateFunctionCall(functionCall, environment):
# funcName = functionCall.identifier.identifier
# arguments = evaluateList(functionCall.arguments, environment)
# for name, function in environment.customFunctions.items():
# if funcName == name:
# if len(function['params']) != len(arguments):
# raise RuntimeException(functionCall.pos, f"Calling '{funcName}' requires {len(function['params'])} and {len(arguments)} was passed")
# environment.scopes.append({ function['params'][i].identifier: v for i, v in enumerate(arguments) })
# returnValue = None
# for node in function['body']:
# if not isinstance(node, ReturnNode):
# evaluate(node, environment)
# else:
# returnValue = evaluateReturn(node, environment)
# environment.scopes.pop(-1)
# return returnValue
# for name, definition in environment.functions.items():
# if name == funcName:
# return definition(arguments, environment)
# raise RuntimeException(functionCall.pos, f"Function '{funcName}' does not exist")

View File

@@ -0,0 +1,10 @@
from smnp.error.runtime import RuntimeException
def evaluateIdentifier(identifier, environment):
try:
value = environment.findVariable(identifier.identifier)
return value
except RuntimeException as e:
e.pos = identifier.pos
raise e

View File

@@ -0,0 +1,6 @@
from smnp.type.model import Type
from smnp.type.value import Value
def evaluateInteger(integer, environment):
return Value(Type.INTEGER, integer.value)

View File

@@ -0,0 +1,17 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import evaluate
from smnp.runtime.tools import flatListNode
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)

View File

@@ -0,0 +1,6 @@
from smnp.type.model import Type
from smnp.type.value import Value
def evaluateNote(note, environment):
return Value(Type.NOTE, note.value)

View File

@@ -0,0 +1,6 @@
from smnp.type.model import Type
from smnp.type.value import Value
def evaluatePercent(percent, environment):
return Value(Type.PERCENT, percent.value.value * 0.01)

View File

@@ -0,0 +1,6 @@
from smnp.runtime.evaluator import evaluate
def evaluateProgram(program, environment):
for node in program.children:
evaluate(node, environment)

View File

@@ -0,0 +1,5 @@
from smnp.runtime.evaluator import evaluate
def evaluateReturn(returnNode, environment):
return evaluate(returnNode.value, environment)

View File

@@ -0,0 +1,28 @@
import re
from smnp.error.runtime import RuntimeException
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)
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