Create evaluator for custom functions definition (but invocation doesn't work yet)

This commit is contained in:
Bartłomiej Pluta
2019-07-08 15:36:13 +02:00
parent 1e634180d6
commit 606d93c319
5 changed files with 86 additions and 5 deletions

View File

@@ -3,6 +3,7 @@ from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
from smnp.type.model import Type
class TypeSpecifier(Node): class TypeSpecifier(Node):
@@ -44,7 +45,7 @@ class TypeNode(AccessNode):
def _parse(cls, input): def _parse(cls, input):
def createNode(type, specifier): def createNode(type, specifier):
node = TypeNode(type.pos) node = TypeNode(type.pos)
node.type = type.value node.type = Type[type.value.upper()]
node.specifier = specifier node.specifier = specifier
return node return node

View File

@@ -7,8 +7,8 @@ class Environment():
self.scopes = scopes self.scopes = scopes
self.functions = functions self.functions = functions
self.methods = methods self.methods = methods
self.customFunctions = {} self.customFunctions = []
self.callStack = [] #TODO remove self.customMethods = []
def invokeMethod(self, name, object, args): def invokeMethod(self, name, object, args):
for method in self.methods: # TODO to działa tylko dla wbudowanych funkcji for method in self.methods: # TODO to działa tylko dla wbudowanych funkcji
@@ -27,6 +27,9 @@ class Environment():
raise FunctionNotFoundException(name) raise FunctionNotFoundException(name)
# TODO raise nie znaleziono funkcji # TODO raise nie znaleziono funkcji
def addCustomFunction(self, name, signature, arguments, body):
self.customFunctions.append(CustomFunction(name, signature, arguments, body))
def findVariable(self, name, type=None, pos=None): def findVariable(self, name, type=None, pos=None):
for scope in reversed(self.scopes): for scope in reversed(self.scopes):
if name in scope: if name in scope:
@@ -54,12 +57,26 @@ class Environment():
def functionsToString(self): def functionsToString(self):
return "Functions:\n" + ("\n".join([ f" {function.name}(...)" for function in self.functions ])) return "Functions:\n" + ("\n".join([ f" {function.name}(...)" for function in self.functions ]))
def customFunctionsToString(self):
return "Custom Functions:\n" + ("\n".join([ f" {function.name}(...)" for function in self.customFunctions ]))
def methodsToString(self): def methodsToString(self):
return "Methods:\n" + ("\n".join([f" {function.name}(...)" for function in self.methods])) return "Methods:\n" + ("\n".join([f" {function.name}(...)" for function in self.methods]))
def customMethodsToString(self):
return "Custom Methods:\n" + ("\n".join([ f" {function.name}(...)" for function in self.customMethods ]))
def __str__(self): def __str__(self):
return self.scopesToString() + self.functionsToString() + self.methodsToString() return self.scopesToString() + self.functionsToString() + self.methodsToString() + self.customFunctionsToString() + self.customMethodsToString()
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
class CustomFunction:
def __init__(self, name, signature, arguments, body):
self.name = name
self.signature = signature
self.arguments = arguments
self.body = body

View File

@@ -94,6 +94,11 @@ def ofTypes(*types):
return value.type in types return value.type in types
return Matcher(None, check, f"<{', '.join([t.name.lower() for t in types])}>") return Matcher(None, check, f"<{', '.join([t.name.lower() for t in types])}>")
def ofType(type):
def check(value):
return value.type == type
return Matcher(None, check, type.name.lower())
def listOf(*types): def listOf(*types):
def check(value): def check(value):
@@ -101,6 +106,15 @@ def listOf(*types):
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([t.name.lower() for t in types])}>") return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([t.name.lower() for t in types])}>")
def listOfMatchers(*matchers):
def check(value):
matched = 0
for item in value.value:
matched += 1 if any(matcher.match(item) for matcher in matchers) else 0
return matched == len(value.value)
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([m.string for m in matchers])}>")
def listMatches(*pattern): def listMatches(*pattern):
def check(value): def check(value):

View File

@@ -1,3 +1,4 @@
from smnp.ast.node.function import FunctionDefinitionNode
from smnp.ast.node.program import Program from smnp.ast.node.program import Program
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.type.model import Type from smnp.type.model import Type
@@ -66,8 +67,10 @@ def evaluate(node, environment):
from smnp.runtime.evaluators.program import ProgramEvaluator from smnp.runtime.evaluators.program import ProgramEvaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator
result = Evaluator.oneOf( result = Evaluator.oneOf(
Evaluator.forNodes(ProgramEvaluator.evaluate, Program), Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
expressionEvaluator() expressionEvaluator()
)(node, environment) )(node, environment)

View File

@@ -1,6 +1,10 @@
from smnp.ast.node.none import NoneNode
from smnp.ast.node.variable import TypedVariableNode
from smnp.library.signature import signature, listOfMatchers, ofType
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
from smnp.type.model import Type
class FunctionCallEvaluator(Evaluator): class FunctionCallEvaluator(Evaluator):
@@ -10,6 +14,48 @@ class FunctionCallEvaluator(Evaluator):
name = node.name.value name = node.name.value
arguments = abstractIterableEvaluator(expressionEvaluator(True))(node.arguments, environment) arguments = abstractIterableEvaluator(expressionEvaluator(True))(node.arguments, environment)
return environment.invokeFunction(name, arguments) return environment.invokeFunction(name, arguments)
class FunctionDefinitionEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
name = node.name.value
signature = argumentsNodeToMethodSignature(node.arguments)
arguments = [ arg.variable.value for arg in node.arguments ]
body = node.body
environment.addCustomFunction(name, signature, arguments, body)
def argumentsNodeToMethodSignature(node):
sign = []
for child in node.children:
if type(child) == TypedVariableNode:
if type(child.type.specifier) == NoneNode:
sign.append(ofType(child.type.type))
elif child.type.type == Type.LIST:
sign.append(listSpecifier(child.type.specifier))
return signature(*sign)
def listSpecifier(specifier):
subSignature = []
for child in specifier.children:
if type(child.specifier) == NoneNode:
subSignature.append(ofType(child.type))
elif child.type == Type.LIST:
subSignature.append(listSpecifier(child.specifier))
return listOfMatchers(*subSignature)
# if node.type.specifier is not NoneNode:
# if Type[node.type.upper()] == Type.LIST:
# return listOf([])
# #
# def evaluateFunctionDefinition(definition, environment): # def evaluateFunctionDefinition(definition, environment):
# name = definition.name # name = definition.name