From d8cdafe293af5e8a174d41e85cd5a03866750ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Mon, 8 Jul 2019 17:15:54 +0200 Subject: [PATCH] Enable invoking builtin methods --- smnp/environment/environment.py | 40 ++++++++++++++---- smnp/runtime/evaluators/access.py | 60 +++++++++++++++++---------- smnp/runtime/evaluators/expression.py | 3 ++ 3 files changed, 72 insertions(+), 31 deletions(-) diff --git a/smnp/environment/environment.py b/smnp/environment/environment.py index 1a96012..f10a672 100644 --- a/smnp/environment/environment.py +++ b/smnp/environment/environment.py @@ -12,16 +12,41 @@ class Environment(): self.customFunctions = [] self.customMethods = [] - def invokeMethod(self, name, object, args): - for method in self.methods: # TODO to dziaƂa tylko dla wbudowanych funkcji + def invokeMethod(self, object, name, args): + builtinMethodResult = self._invokeBuiltinMethod(object, name, args) + if builtinMethodResult[0]: + return builtinMethodResult[1] + + customMethodResult = self._invokeCustomMethod(object, name, args) + if customMethodResult[0]: + return customMethodResult[1] + + raise MethodNotFoundException(object.type, name) + + def _invokeBuiltinMethod(self, object, name, args): + for method in self.methods: if method.name == name: - ret = method.call(self, [object, *args.value]) + ret = method.call(self, [object, *args]) if ret is not None: - return ret - raise MethodNotFoundException(object.type, name) # TODO method not found + return (True, ret) + + return (False, None) + + def _invokeCustomMethod(self, object, name, args): + for function in self.customMethods: + if function.name == name: + signatureCheckresult = function.signature.check(args) + if signatureCheckresult[0]: + self.scopes.append({argName: argValue for argName, argValue in zip(function.arguments, args)}) + result = BodyEvaluator.evaluate(function.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + self.scopes.pop(-1) + return (True, result) + raise IllegalFunctionInvocationException(f"{function.name}{function.signature.string}", + f"{name}{types(args)}") + return (False, None) def invokeFunction(self, name, args): - builtinFunctionResult = self._invokeFunction(name, args) + builtinFunctionResult = self._invokeBuiltinFunction(name, args) if builtinFunctionResult[0]: return builtinFunctionResult[1] @@ -31,7 +56,7 @@ class Environment(): raise FunctionNotFoundException(name) - def _invokeFunction(self, name, args): + def _invokeBuiltinFunction(self, name, args): for function in self.functions: if function.name == name: ret = function.call(self, args) @@ -45,7 +70,6 @@ class Environment(): if function.name == name: signatureCheckresult = function.signature.check(args) if signatureCheckresult[0]: - self.scopes.append({ argName: argValue for argName, argValue in zip(function.arguments, args) }) result = BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult self.scopes.pop(-1) diff --git a/smnp/runtime/evaluators/access.py b/smnp/runtime/evaluators/access.py index 451bd18..1c8b17b 100644 --- a/smnp/runtime/evaluators/access.py +++ b/smnp/runtime/evaluators/access.py @@ -1,32 +1,46 @@ -from smnp.ast.node.access import AccessNode -from smnp.ast.node.function import FunctionCallNode -from smnp.error.base import SmnpException -from smnp.error.runtime import RuntimeException -from smnp.runtime.evaluator import evaluate -from smnp.runtime.evaluators.list import evaluateList +from smnp.ast.node.identifier import IdentifierNode +from smnp.ast.node.invocation import FunctionCallNode +from smnp.runtime.evaluator import Evaluator +from smnp.runtime.evaluators.expression import expressionEvaluator +from smnp.runtime.evaluators.iterable import abstractIterableEvaluator -def evaluateAccess(access, environment): - element = evaluate(access.element, environment) - if type(access.property) == FunctionCallNode: - return evaluateMethodCall(element, access.property, environment) - if type(access.property) == AccessNode: - return evaluateAccess(access.property, environment) +class AccessEvaluator(Evaluator): - raise RuntimeException("Not implemented yet", access.property.pos) - # TODO only methods can be handled so far + @classmethod + def evaluator(cls, node, environment): + left = expressionEvaluator(doAssert=True)(node.left, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult + right = node.right + if type(node.right) == IdentifierNode: + raise RuntimeError("Accessing properties is not implemented yet") -def evaluateMethodCall(element, methodCall, environment): - try: - methodName = methodCall.identifier.identifier - arguments = evaluateList(methodCall.arguments, environment) + if type(node.right) == FunctionCallNode: + arguments = abstractIterableEvaluator(expressionEvaluator(True))(right.arguments, environment) + return environment.invokeMethod(left, right.name.value, arguments) - return environment.invokeMethod(methodName, element, arguments) - - except SmnpException as e: - e.pos = methodCall.pos - raise e +# +# def evaluateAccess(access, environment): +# element = evaluate(access.element, environment) +# if type(access.property) == FunctionCallNode: +# return evaluateMethodCall(element, access.property, environment) +# if type(access.property) == AccessNode: +# return evaluateAccess(access.property, environment) +# +# raise RuntimeException("Not implemented yet", access.property.pos) +# # TODO only methods can be handled so far +# +# +# def evaluateMethodCall(element, methodCall, environment): +# try: +# methodName = methodCall.identifier.identifier +# arguments = evaluateList(methodCall.arguments, environment) +# +# return environment.invokeMethod(methodName, element, arguments) +# +# except SmnpException as e: +# e.pos = methodCall.pos +# raise e # for name, library in environment.customFunctions.items(): # if funcName == name: # if len(library['params']) != len(arguments): diff --git a/smnp/runtime/evaluators/expression.py b/smnp/runtime/evaluators/expression.py index b89fcb8..9f6dd22 100644 --- a/smnp/runtime/evaluators/expression.py +++ b/smnp/runtime/evaluators/expression.py @@ -1,3 +1,4 @@ +from smnp.ast.node.access import AccessNode from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.integer import IntegerLiteralNode from smnp.ast.node.invocation import FunctionCallNode @@ -18,6 +19,7 @@ def expressionEvaluator(doAssert=False): from smnp.runtime.evaluators.list import ListEvaluator from smnp.runtime.evaluators.function import FunctionCallEvaluator + from smnp.runtime.evaluators.access import AccessEvaluator result = Evaluator.oneOf( Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode), Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode), @@ -25,6 +27,7 @@ def expressionEvaluator(doAssert=False): Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteralNode), Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode), Evaluator.forNodes(ListEvaluator.evaluate, ListNode), + Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode) )(node, environment) if doAssert and result.result and result.value.type == Type.VOID: