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
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.function.signature import signature
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier, \
evaluateDefaultArguments
from smnp.runtime.tools.signature import argumentsNodeToMethodSignature, listSpecifier, mapSpecifier
from smnp.type.model import Type
from smnp.type.signature.matcher.type import ofType
@@ -33,9 +32,8 @@ class ExtendEvaluator(Evaluator):
@classmethod
def _evaluateMethodDefinition(cls, node, environment, type, variable):
name = node.name.value
signature = argumentsNodeToMethodSignature(node.arguments)
defaultArguments, signature = argumentsNodeToMethodSignature(node.arguments, environment)
arguments = [arg.variable.value for arg in node.arguments]
defaultArguments = evaluateDefaultArguments(node.arguments, environment)
body = node.body
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.iterable import abstractIterableEvaluator
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
@@ -25,9 +25,8 @@ class FunctionDefinitionEvaluator(Evaluator):
def evaluator(cls, node, environment):
try:
name = node.name.value
signature = argumentsNodeToMethodSignature(node.arguments)
defaultArguments, signature = argumentsNodeToMethodSignature(node.arguments, environment)
arguments = [ arg.variable.value for arg in node.arguments ]
defaultArguments = evaluateDefaultArguments(node.arguments, environment)
body = node.body
environment.addCustomFunction(name, signature, arguments, body, defaultArguments)
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.error.runtime import RuntimeException
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.type.model import Type
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):
defaultValues = { arg.variable.value: expressionEvaluator(doAssert=True)(arg.optionalValue, environment).value for arg in node.children if type(arg.optionalValue) != NoneNode }
return defaultValues
def argumentsNodeToMethodSignature(node):
def argumentsNodeToMethodSignature(node, environment):
try:
sign = []
vararg = None
argumentsCount = len(node.children)
checkPositionOfOptionalArguments(node)
defaultArgs = {}
for i, child in enumerate(node.children):
matchers = {
ast.Type: (lambda c: c.type, typeMatcher),
@@ -29,17 +31,22 @@ def argumentsNodeToMethodSignature(node):
TypesList: (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:
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)
sign.append(evaluatedMatcher)
return varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign)
return defaultArgs, (varargSignature(vararg, *sign, wrapVarargInValue=True) if vararg is not None else signature(*sign))
except RuntimeException as e:
raise updatePos(e, node)