Enable checking matching optional arguments with declared types

This commit is contained in:
Bartłomiej Pluta
2019-07-14 00:10:20 +02:00
parent 460deb4981
commit c5435e66ff
4 changed files with 27 additions and 11 deletions

View File

@@ -50,3 +50,15 @@ def expressionEvaluator(doAssert=False):
return evaluateExpression return evaluateExpression
def expressionEvaluatorWithMatcher(matcher, exceptionProvider, doAssert=True):
def evaluate(node, environment):
value = expressionEvaluator(doAssert=doAssert)(node, environment).value
if not matcher.match(value):
raise exceptionProvider(value)
return value
return evaluate

View File

@@ -1,8 +1,7 @@
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.function.signature import signature from smnp.function.signature import signature
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier, \ from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier
evaluateDefaultArguments
from smnp.type.model import Type from smnp.type.model import Type
from smnp.type.signature.matcher.type import ofType from smnp.type.signature.matcher.type import ofType
@@ -33,9 +32,8 @@ class ExtendEvaluator(Evaluator):
@classmethod @classmethod
def _evaluateMethodDefinition(cls, node, environment, type, variable): def _evaluateMethodDefinition(cls, node, environment, type, variable):
name = node.name.value name = node.name.value
signature = argumentsNodeToMethodSignature(node.arguments) defaultArguments, signature = argumentsNodeToMethodSignature(node.arguments, environment)
arguments = [arg.variable.value for arg in node.arguments] arguments = [arg.variable.value for arg in node.arguments]
defaultArguments = evaluateDefaultArguments(node.arguments, environment)
body = node.body body = node.body
environment.addCustomMethod(type, variable, name, signature, arguments, body, defaultArguments) environment.addCustomMethod(type, variable, name, signature, arguments, body, defaultArguments)

View File

@@ -3,7 +3,7 @@ from smnp.runtime.evaluator import Evaluator, evaluate
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.runtime.tools.error import updatePos from smnp.runtime.tools.error import updatePos
from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, evaluateDefaultArguments from smnp.runtime.tools.signature import argumentsNodeToMethodSignature
from smnp.type.model import Type from smnp.type.model import Type
@@ -25,9 +25,8 @@ class FunctionDefinitionEvaluator(Evaluator):
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
try: try:
name = node.name.value name = node.name.value
signature = argumentsNodeToMethodSignature(node.arguments) defaultArguments, signature = argumentsNodeToMethodSignature(node.arguments, environment)
arguments = [ arg.variable.value for arg in node.arguments ] arguments = [ arg.variable.value for arg in node.arguments ]
defaultArguments = evaluateDefaultArguments(node.arguments, environment)
body = node.body body = node.body
environment.addCustomFunction(name, signature, arguments, body, defaultArguments) environment.addCustomFunction(name, signature, arguments, body, defaultArguments)
except RuntimeException as e: except RuntimeException as e:

View File

@@ -3,7 +3,7 @@ from smnp.ast.node.none import NoneNode
from smnp.ast.node.type import TypesList from smnp.ast.node.type import TypesList
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.function.signature import varargSignature, signature, optional from smnp.function.signature import varargSignature, signature, optional
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator, expressionEvaluatorWithMatcher
from smnp.runtime.tools.error import updatePos from smnp.runtime.tools.error import updatePos
from smnp.type.model import Type from smnp.type.model import Type
from smnp.type.signature.matcher.list import listOfMatchers from smnp.type.signature.matcher.list import listOfMatchers
@@ -13,15 +13,17 @@ from smnp.type.signature.matcher.type import allTypes, oneOf, ofType
def evaluateDefaultArguments(node, environment): def evaluateDefaultArguments(node, environment):
defaultValues = { arg.variable.value: expressionEvaluator(doAssert=True)(arg.optionalValue, environment).value for arg in node.children if type(arg.optionalValue) != NoneNode } defaultValues = { arg.variable.value: expressionEvaluator(doAssert=True)(arg.optionalValue, environment).value for arg in node.children if type(arg.optionalValue) != NoneNode }
return defaultValues return defaultValues
def argumentsNodeToMethodSignature(node): def argumentsNodeToMethodSignature(node, environment):
try: try:
sign = [] sign = []
vararg = None vararg = None
argumentsCount = len(node.children) argumentsCount = len(node.children)
checkPositionOfOptionalArguments(node) checkPositionOfOptionalArguments(node)
defaultArgs = {}
for i, child in enumerate(node.children): for i, child in enumerate(node.children):
matchers = { matchers = {
ast.Type: (lambda c: c.type, typeMatcher), ast.Type: (lambda c: c.type, typeMatcher),
@@ -29,17 +31,22 @@ def argumentsNodeToMethodSignature(node):
TypesList: (lambda c: c, multipleTypeMatcher) TypesList: (lambda c: c, multipleTypeMatcher)
} }
evaluatedMatcher = matchers[type(child.type)][1](matchers[type(child.type)][0](child)) evaluatedMatcher = matchers[type(child.type)][1](matchers[type(child.type)][0](child))
if child.vararg: if child.vararg:
if i != argumentsCount - 1: if i != argumentsCount - 1:
raise RuntimeException("Vararg must be the last argument in signature", child.pos) raise RuntimeException("Vararg must be the last argument in signature", child.pos)
vararg = evaluatedMatcher vararg = evaluatedMatcher
else: else:
if type(child.optionalValue) != NoneNode: if type(child.optionalValue) != NoneNode:
defaultArgs[child.variable.value] = expressionEvaluatorWithMatcher(
evaluatedMatcher,
exceptionProvider=lambda value: RuntimeException(
f"Value '{value.stringify()}' doesn't match declared type: {evaluatedMatcher.string}", child.optionalValue.pos)
)(child.optionalValue, environment)
evaluatedMatcher = optional(evaluatedMatcher) evaluatedMatcher = optional(evaluatedMatcher)
sign.append(evaluatedMatcher) sign.append(evaluatedMatcher)
return defaultArgs, (varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign))
return varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign)
except RuntimeException as e: except RuntimeException as e:
raise updatePos(e, node) raise updatePos(e, node)