From 48638b832b503e8554092cd451406254e54fbdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 10 Jul 2019 11:39:23 +0200 Subject: [PATCH] Refactor signature builder --- smnp/runtime/evaluators/access.py | 2 +- smnp/runtime/evaluators/extend.py | 2 +- smnp/runtime/evaluators/function.py | 158 +--------------------- smnp/runtime/evaluators/identifier.py | 2 +- smnp/runtime/tools/__init__.py | 0 smnp/runtime/{tools.py => tools/error.py} | 0 smnp/runtime/tools/signature.py | 89 ++++++++++++ 7 files changed, 95 insertions(+), 158 deletions(-) create mode 100644 smnp/runtime/tools/__init__.py rename smnp/runtime/{tools.py => tools/error.py} (100%) create mode 100644 smnp/runtime/tools/signature.py diff --git a/smnp/runtime/evaluators/access.py b/smnp/runtime/evaluators/access.py index 41e26d4..bb610cb 100644 --- a/smnp/runtime/evaluators/access.py +++ b/smnp/runtime/evaluators/access.py @@ -4,7 +4,7 @@ from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator -from smnp.runtime.tools import updatePos +from smnp.runtime.tools.error import updatePos class AccessEvaluator(Evaluator): diff --git a/smnp/runtime/evaluators/extend.py b/smnp/runtime/evaluators/extend.py index a59e993..f1747f9 100644 --- a/smnp/runtime/evaluators/extend.py +++ b/smnp/runtime/evaluators/extend.py @@ -1,7 +1,7 @@ from smnp.ast.node.none import NoneNode from smnp.function.signature import signature from smnp.runtime.evaluator import Evaluator -from smnp.runtime.evaluators.function import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier +from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier from smnp.type.model import Type from smnp.type.signature.matcher.type import ofType diff --git a/smnp/runtime/evaluators/function.py b/smnp/runtime/evaluators/function.py index 87d8d72..ca18562 100644 --- a/smnp/runtime/evaluators/function.py +++ b/smnp/runtime/evaluators/function.py @@ -1,16 +1,10 @@ -from smnp.ast.node.none import NoneNode from smnp.ast.node.ret import ReturnNode -from smnp.ast.node.type import TypeNode from smnp.error.runtime import RuntimeException -from smnp.function.signature import signature, varargSignature from smnp.runtime.evaluator import Evaluator, evaluate from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator -from smnp.runtime.tools import updatePos -from smnp.type.model import Type -from smnp.type.signature.matcher.list import listOfMatchers -from smnp.type.signature.matcher.map import mapOfMatchers -from smnp.type.signature.matcher.type import ofType, oneOf, allTypes +from smnp.runtime.tools.error import updatePos +from smnp.runtime.tools.signature import argumentsNodeToMethodSignature class FunctionCallEvaluator(Evaluator): @@ -36,97 +30,7 @@ class FunctionDefinitionEvaluator(Evaluator): body = node.body environment.addCustomFunction(name, signature, arguments, body) except RuntimeException as e: - e.pos = node.pos - raise e - - -def argumentsNodeToMethodSignature(node): - try: - sign = [] - vararg = None - argumentsCount = len(node.children) - for i, child in enumerate(node.children): - if type(child.type) == TypeNode: - if child.vararg: - if i != argumentsCount-1: - raise RuntimeException("Vararg must be the last argument in signature", child.pos) - vararg = typeMatcher(child.type) - else: - sign.append(typeMatcher(child.type)) - elif type(child.type) == NoneNode: - if child.vararg: - if i != argumentsCount-1: - raise RuntimeException("Vararg must be the last argument in signature", child.pos) - vararg = allTypes() - else: - sign.append(allTypes()) - else: - if child.vararg: - if i != argumentsCount-1: - raise RuntimeException("Vararg must be the last argument in signature", child.pos) - vararg = multipleTypeMatcher(child) - else: - sign.append(multipleTypeMatcher(child)) - - - return varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign) - except RuntimeException as e: - raise updatePos(e, node) - - -def multipleTypeMatcher(typeNode): - subSignature = [] - - if len(typeNode.type.children) == 0: - return allTypes() - - for child in typeNode.type.children: - m = typeMatcher(child) - subSignature.append(m) - - return oneOf(*subSignature) - - -def typeMatcher(typeNode): - if type(typeNode.specifiers) == NoneNode: - return ofType(typeNode.type) - elif typeNode.type == Type.LIST and len(typeNode.specifiers) == 1: - return listSpecifier(typeNode.specifiers[0]) - elif typeNode.type == Type.MAP and len(typeNode.specifiers) == 2: - return mapSpecifier(typeNode.specifiers[0], typeNode.specifiers[1]) - - raise RuntimeException("Unknown type", typeNode.pos) # Todo: Improve pointing position - - - -def listSpecifier(specifier): - subSignature = [] - - if len(specifier.children) == 0: - subSignature.append(allTypes()) - - for child in specifier.children: - subSignature.append(typeMatcher(child)) - - return listOfMatchers(*subSignature) - -def mapSpecifier(keySpecifier, valueSpecifier): - keySubSignature = [] - valueSubSignature = [] - - if len(keySpecifier.children) == 0: - keySubSignature.append(allTypes()) - - if len(valueSpecifier.children) == 0: - valueSubSignature.append(allTypes()) - - for child in keySpecifier.children: - keySubSignature.append(typeMatcher(child)) - - for child in valueSpecifier.children: - valueSubSignature.append(typeMatcher(child)) - - return mapOfMatchers(keySubSignature, valueSubSignature) + raise updatePos(e, node) class BodyEvaluator(Evaluator): @@ -140,59 +44,3 @@ class BodyEvaluator(Evaluator): else: evaluate(child, environment) -# if node.type.specifier is not NoneNode: - # if Type[node.type.upper()] == Type.LIST: - # return listOf([]) - -# -# 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): -# 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): -# 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") \ No newline at end of file diff --git a/smnp/runtime/evaluators/identifier.py b/smnp/runtime/evaluators/identifier.py index 552194b..2b6ac65 100644 --- a/smnp/runtime/evaluators/identifier.py +++ b/smnp/runtime/evaluators/identifier.py @@ -1,6 +1,6 @@ from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator -from smnp.runtime.tools import updatePos +from smnp.runtime.tools.error import updatePos class IdentifierEvaluator(Evaluator): diff --git a/smnp/runtime/tools/__init__.py b/smnp/runtime/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smnp/runtime/tools.py b/smnp/runtime/tools/error.py similarity index 100% rename from smnp/runtime/tools.py rename to smnp/runtime/tools/error.py diff --git a/smnp/runtime/tools/signature.py b/smnp/runtime/tools/signature.py new file mode 100644 index 0000000..934fca8 --- /dev/null +++ b/smnp/runtime/tools/signature.py @@ -0,0 +1,89 @@ +from smnp.ast.node.none import NoneNode +from smnp.ast.node.type import TypeNode, TypeSpecifier +from smnp.error.runtime import RuntimeException +from smnp.function.signature import varargSignature, signature +from smnp.runtime.tools.error import updatePos +from smnp.type.model import Type +from smnp.type.signature.matcher.list import listOfMatchers +from smnp.type.signature.matcher.map import mapOfMatchers +from smnp.type.signature.matcher.type import allTypes, oneOf, ofType + + +def argumentsNodeToMethodSignature(node): + try: + sign = [] + vararg = None + argumentsCount = len(node.children) + for i, child in enumerate(node.children): + matchers = { + TypeNode: (lambda c: c.type, typeMatcher), + NoneNode: (lambda c: c.type, lambda c: allTypes()), + TypeSpecifier: (lambda c: c, multipleTypeMatcher) + } + evaluatedMatcher = matchers[type(child.type)][1](matchers[type(child.type)][0](child)) + if child.vararg: + if i != argumentsCount - 1: + raise RuntimeException("Vararg must be the last argument in signature", child.pos) + vararg = evaluatedMatcher + else: + sign.append(evaluatedMatcher) + + + return varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign) + except RuntimeException as e: + raise updatePos(e, node) + + +def multipleTypeMatcher(typeNode): + subSignature = [] + + if len(typeNode.type.children) == 0: + return allTypes() + + for child in typeNode.type.children: + m = typeMatcher(child) + subSignature.append(m) + + return oneOf(*subSignature) + + +def typeMatcher(typeNode): + if type(typeNode.specifiers) == NoneNode: + return ofType(typeNode.type) + elif typeNode.type == Type.LIST and len(typeNode.specifiers) == 1: + return listSpecifier(typeNode.specifiers[0]) + elif typeNode.type == Type.MAP and len(typeNode.specifiers) == 2: + return mapSpecifier(typeNode.specifiers[0], typeNode.specifiers[1]) + + raise RuntimeException("Unknown type", typeNode.pos) # Todo: Improve pointing position + + +def listSpecifier(specifier): + subSignature = [] + + if len(specifier.children) == 0: + subSignature.append(allTypes()) + + for child in specifier.children: + subSignature.append(typeMatcher(child)) + + return listOfMatchers(*subSignature) + + +def mapSpecifier(keySpecifier, valueSpecifier): + keySubSignature = [] + valueSubSignature = [] + + if len(keySpecifier.children) == 0: + keySubSignature.append(allTypes()) + + if len(valueSpecifier.children) == 0: + valueSubSignature.append(allTypes()) + + for child in keySpecifier.children: + keySubSignature.append(typeMatcher(child)) + + for child in valueSpecifier.children: + valueSubSignature.append(typeMatcher(child)) + + return mapOfMatchers(keySubSignature, valueSubSignature) \ No newline at end of file