Create evaluator for function call
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from smnp.ast.node.access import AccessNode
|
from smnp.ast.node.access import AccessNode
|
||||||
from smnp.ast.node.assignment import AssignmentNode
|
from smnp.ast.node.assignment import AssignmentNode
|
||||||
from smnp.ast.node.expression import ExpressionNode
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
from smnp.ast.node.invocation import FunctionCall, ArgumentsListNode
|
from smnp.ast.node.invocation import FunctionCallNode, ArgumentsListNode
|
||||||
from smnp.ast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class IdentifierNode(AccessNode):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _functionCallParser():
|
def _functionCallParser():
|
||||||
def createNode(name, arguments):
|
def createNode(name, arguments):
|
||||||
node = FunctionCall(name.pos)
|
node = FunctionCallNode(name.pos)
|
||||||
node.name = name
|
node.name = name
|
||||||
node.arguments = arguments
|
node.arguments = arguments
|
||||||
return node
|
return node
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ArgumentsListNode(Node):
|
|||||||
Parser.doAssert(ExpressionNode.parse, "expression"))(input)
|
Parser.doAssert(ExpressionNode.parse, "expression"))(input)
|
||||||
|
|
||||||
|
|
||||||
class FunctionCall(AccessNode):
|
class FunctionCallNode(AccessNode):
|
||||||
def __init__(self, pos):
|
def __init__(self, pos):
|
||||||
super().__init__(pos)
|
super().__init__(pos)
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def types(args):
|
|||||||
if arg.type == Type.LIST:
|
if arg.type == Type.LIST:
|
||||||
output.append(listTypes(arg.value, []))
|
output.append(listTypes(arg.value, []))
|
||||||
else:
|
else:
|
||||||
output.append(arg.type.name)
|
output.append(arg.type.name.lower())
|
||||||
return f"({', '.join(output)})"
|
return f"({', '.join(output)})"
|
||||||
|
|
||||||
|
|
||||||
@@ -64,5 +64,5 @@ def listTypes(l, output=[]):
|
|||||||
if item.type == Type.LIST:
|
if item.type == Type.LIST:
|
||||||
output.append(listTypes(item.value, []))
|
output.append(listTypes(item.value, []))
|
||||||
else:
|
else:
|
||||||
output.append(item.type.name)
|
output.append(item.type.name.lower())
|
||||||
return f"LIST<{'|'.join(set(output))}>"
|
return f"{Type.LIST.name.lower()}<{'|'.join(set(output))}>"
|
||||||
@@ -92,14 +92,14 @@ def allTypes():
|
|||||||
def ofTypes(*types):
|
def ofTypes(*types):
|
||||||
def check(value):
|
def check(value):
|
||||||
return value.type in types
|
return value.type in types
|
||||||
return Matcher(None, check, f"<{'|'.join([t.name for t in types])}>")
|
return Matcher(None, check, f"<{', '.join([t.name.lower() for t in types])}>")
|
||||||
|
|
||||||
|
|
||||||
def listOf(*types):
|
def listOf(*types):
|
||||||
def check(value):
|
def check(value):
|
||||||
return len([item for item in value.value if not item.type in types]) == 0
|
return len([item for item in value.value if not item.type in types]) == 0
|
||||||
|
|
||||||
return Matcher(Type.LIST, check, f"{Type.LIST.name}<{'|'.join([t.name for t in types])}>")
|
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([t.name.lower() for t in types])}>")
|
||||||
|
|
||||||
|
|
||||||
def listMatches(*pattern):
|
def listMatches(*pattern):
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ class EvaluationResult():
|
|||||||
|
|
||||||
def evaluate(node, environment):
|
def evaluate(node, environment):
|
||||||
from smnp.runtime.evaluators.program import ProgramEvaluator
|
from smnp.runtime.evaluators.program import ProgramEvaluator
|
||||||
from smnp.runtime.evaluators.expression import evaluateExpression
|
from smnp.runtime.evaluators.expression import expressionEvaluator
|
||||||
|
|
||||||
result = Evaluator.oneOf(
|
result = Evaluator.oneOf(
|
||||||
Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
|
Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
|
||||||
evaluateExpression
|
expressionEvaluator()
|
||||||
)(node, environment)
|
)(node, environment)
|
||||||
|
|
||||||
if not result.result:
|
if not result.result:
|
||||||
|
|||||||
@@ -1,22 +1,36 @@
|
|||||||
from smnp.ast.node.identifier import IdentifierNode
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
from smnp.ast.node.integer import IntegerLiteralNode
|
from smnp.ast.node.integer import IntegerLiteralNode
|
||||||
|
from smnp.ast.node.invocation import FunctionCallNode
|
||||||
from smnp.ast.node.list import ListNode
|
from smnp.ast.node.list import ListNode
|
||||||
from smnp.ast.node.note import NoteLiteralNode
|
from smnp.ast.node.note import NoteLiteralNode
|
||||||
from smnp.ast.node.string import StringLiteralNode
|
from smnp.ast.node.string import StringLiteralNode
|
||||||
|
from smnp.error.runtime import RuntimeException
|
||||||
from smnp.runtime.evaluator import Evaluator
|
from smnp.runtime.evaluator import Evaluator
|
||||||
|
from smnp.type.model import Type
|
||||||
|
|
||||||
|
|
||||||
def evaluateExpression(node, environment):
|
def expressionEvaluator(doAssert=False):
|
||||||
from smnp.runtime.evaluators.string import StringEvaluator
|
def evaluateExpression(node, environment):
|
||||||
from smnp.runtime.evaluators.integer import IntegerEvaluator
|
from smnp.runtime.evaluators.string import StringEvaluator
|
||||||
from smnp.runtime.evaluators.note import NoteEvaluator
|
from smnp.runtime.evaluators.integer import IntegerEvaluator
|
||||||
from smnp.runtime.evaluators.identifier import IdentifierEvaluator
|
from smnp.runtime.evaluators.note import NoteEvaluator
|
||||||
from smnp.runtime.evaluators.list import ListEvaluator
|
from smnp.runtime.evaluators.identifier import IdentifierEvaluator
|
||||||
|
from smnp.runtime.evaluators.list import ListEvaluator
|
||||||
|
from smnp.runtime.evaluators.function import FunctionCallEvaluator
|
||||||
|
|
||||||
|
result = 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),
|
||||||
|
Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode)
|
||||||
|
)(node, environment)
|
||||||
|
|
||||||
|
if doAssert and result.result and result.value.type == Type.VOID:
|
||||||
|
raise RuntimeException(f"Expected expression", node.pos)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
return evaluateExpression
|
||||||
|
|
||||||
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,40 +1,45 @@
|
|||||||
from smnp.ast.node.identifier import IdentifierNode
|
from smnp.runtime.evaluator import Evaluator
|
||||||
from smnp.ast.node.program import Program
|
from smnp.runtime.evaluators.expression import expressionEvaluator
|
||||||
from smnp.error.base import SmnpException
|
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
|
||||||
from smnp.error.runtime import RuntimeException
|
|
||||||
from smnp.runtime.evaluators.list import evaluateList
|
|
||||||
from smnp.runtime.tools import flatListNode
|
|
||||||
|
|
||||||
|
|
||||||
def evaluateFunctionDefinition(definition, environment):
|
class FunctionCallEvaluator(Evaluator):
|
||||||
name = definition.name
|
|
||||||
params = list([p for p in flatListNode(definition.parameters)])
|
|
||||||
body = definition.body
|
|
||||||
|
|
||||||
if not isinstance(definition.parent, Program):
|
@classmethod
|
||||||
raise RuntimeException(f"Functions can be defined only on the top level of script", name.pos)
|
def evaluator(cls, node, environment):
|
||||||
|
name = node.name.value
|
||||||
for p in params:
|
arguments = abstractIterableEvaluator(expressionEvaluator(True))(node.arguments, environment)
|
||||||
if not isinstance(p, IdentifierNode):
|
return environment.invokeFunction(name, arguments)
|
||||||
raise RuntimeException("Parameter of function definition must be an identifier", p.pos, )
|
#
|
||||||
|
# def evaluateFunctionDefinition(definition, environment):
|
||||||
if name.identifier in environment.customFunctions or name.identifier in environment.functions:
|
# name = definition.name
|
||||||
raise RuntimeException(f"Function '{name.identifier}' already exists", name.pos)
|
# params = list([p for p in flatListNode(definition.parameters)])
|
||||||
|
# body = definition.body
|
||||||
environment.customFunctions[name.identifier] = {
|
#
|
||||||
'params': params,
|
# if not isinstance(definition.parent, Program):
|
||||||
'body': flatListNode(body)
|
# 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):
|
||||||
def evaluateFunctionCall(functionCall, environment):
|
# raise RuntimeException("Parameter of function definition must be an identifier", p.pos, )
|
||||||
try:
|
#
|
||||||
functionName = functionCall.identifier.identifier
|
# if name.identifier in environment.customFunctions or name.identifier in environment.functions:
|
||||||
arguments = evaluateList(functionCall.arguments, environment).value
|
# raise RuntimeException(f"Function '{name.identifier}' already exists", name.pos)
|
||||||
return environment.invokeFunction(functionName, arguments)
|
#
|
||||||
except SmnpException as e:
|
# environment.customFunctions[name.identifier] = {
|
||||||
e.pos = functionCall.pos
|
# 'params': params,
|
||||||
raise e
|
# 'body': flatListNode(body)
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def evaluateFunctionCall(functionCall, environment):
|
||||||
|
# try:
|
||||||
|
# functionName = functionCall.identifier.identifier
|
||||||
|
# arguments = evaluateList(functionCall.arguments, environment).value
|
||||||
|
# return environment.invokeFunction(functionName, arguments)
|
||||||
|
# except SmnpException as e:
|
||||||
|
# e.pos = functionCall.pos
|
||||||
|
# raise e
|
||||||
|
|
||||||
|
|
||||||
# def evaluateFunctionCall(functionCall, environment):
|
# def evaluateFunctionCall(functionCall, environment):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from smnp.runtime.evaluator import Evaluator
|
from smnp.runtime.evaluator import Evaluator
|
||||||
from smnp.runtime.evaluators.expression import evaluateExpression
|
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
|
from smnp.type.model import Type
|
||||||
from smnp.type.value import Value
|
from smnp.type.value import Value
|
||||||
@@ -9,5 +9,5 @@ class ListEvaluator(Evaluator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def evaluator(cls, node, environment):
|
def evaluator(cls, node, environment):
|
||||||
list = abstractIterableEvaluator(evaluateExpression)(node, environment)
|
list = abstractIterableEvaluator(expressionEvaluator(doAssert=True))(node, environment)
|
||||||
return Value(Type.LIST, list)
|
return Value(Type.LIST, list)
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ def stringTokenizer(input, current, line):
|
|||||||
char = input[current + consumedChars]
|
char = input[current + consumedChars]
|
||||||
value += char
|
value += char
|
||||||
consumedChars += 1
|
consumedChars += 1
|
||||||
return (consumedChars, Token(TokenType.STRING, value, (line, current)))
|
return (consumedChars, Token(TokenType.STRING, value[1:len(value)-1], (line, current)))
|
||||||
return (0, None)
|
return (0, None)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from smnp.note.model import Note
|
|||||||
class Type(Enum):
|
class Type(Enum):
|
||||||
INTEGER = (int, lambda x: str(x))
|
INTEGER = (int, lambda x: str(x))
|
||||||
STRING = (str, lambda x: x)
|
STRING = (str, lambda x: x)
|
||||||
LIST = (list, lambda x: f"({', '.join([e.stringify() for e in x])})")
|
LIST = (list, lambda x: f"[{', '.join([e.stringify() for e in x])}]")
|
||||||
PERCENT = (float, lambda x: f"{int(x * 100)}%")
|
PERCENT = (float, lambda x: f"{int(x * 100)}%")
|
||||||
NOTE = (Note, lambda x: x.note.name)
|
NOTE = (Note, lambda x: x.note.name)
|
||||||
VOID = (type(None), lambda x: _failStringify(Type.VOID))
|
VOID = (type(None), lambda x: _failStringify(Type.VOID))
|
||||||
@@ -17,7 +17,7 @@ class Type(Enum):
|
|||||||
|
|
||||||
|
|
||||||
def _failStringify(t):
|
def _failStringify(t):
|
||||||
raise RuntimeException(f"Not able to interpret {t.name}'")
|
raise RuntimeException(f"Not able to interpret {t.name}'", None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user