Enable varargs in signatures

This commit is contained in:
Bartłomiej Pluta
2019-07-10 00:32:42 +02:00
parent 99647df061
commit 39eaa2b4d5
5 changed files with 63 additions and 21 deletions

View File

@@ -20,7 +20,7 @@ class ArgumentsDeclarationNode(Node):
class ArgumentDefinitionNode(ExpressionNode): class ArgumentDefinitionNode(ExpressionNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
self.children.append(NoneNode()) self.children.extend([NoneNode(), False])
@property @property
def type(self): def type(self):
@@ -38,8 +38,39 @@ class ArgumentDefinitionNode(ExpressionNode):
def variable(self, value): def variable(self, value):
self[1] = value self[1] = value
@property
def vararg(self):
return self[2]
@vararg.setter
def vararg(self, value):
self[2] = value
@classmethod @classmethod
def parser(cls): def parser(cls):
return Parser.oneOf(
cls._varargParser(),
cls._normalParser()
)
@classmethod
def _varargParser(cls):
def createNode(type, variable, dots):
node = ArgumentDefinitionNode(type.pos)
node.type = type
node.variable = variable
node.vararg = True
return node
return Parser.allOf(
TypeNode.parse,
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
Parser.terminalParser(TokenType.DOTS),
createNode=createNode
)
@classmethod
def _normalParser(cls):
def createNode(type, variable): def createNode(type, variable):
node = ArgumentDefinitionNode(type.pos) node = ArgumentDefinitionNode(type.pos)
node.type = type node.type = type

View File

@@ -1,3 +0,0 @@

View File

@@ -37,7 +37,7 @@ class Environment():
if method.typeSignature.check([object])[0] and method.name == name: #Todo sprawdzic sygnature typu if method.typeSignature.check([object])[0] and method.name == name: #Todo sprawdzic sygnature typu
signatureCheckresult = method.signature.check(args) signatureCheckresult = method.signature.check(args)
if signatureCheckresult[0]: if signatureCheckresult[0]:
self.scopes.append({argName: argValue for argName, argValue in zip(method.arguments, args)}) self.scopes.append({argName: argValue for argName, argValue in zip(method.arguments, list(signatureCheckresult[1:]))})
self.scopes[-1][method.alias] = object self.scopes[-1][method.alias] = object
result = BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult result = BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
self.scopes.pop(-1) self.scopes.pop(-1)
@@ -71,7 +71,7 @@ class Environment():
if function.name == name: if function.name == name:
signatureCheckresult = function.signature.check(args) signatureCheckresult = function.signature.check(args)
if signatureCheckresult[0]: if signatureCheckresult[0]:
self.scopes.append({ argName: argValue for argName, argValue in zip(function.arguments, args) }) self.scopes.append({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) })
result = BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult result = BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
self.scopes.pop(-1) self.scopes.pop(-1)
return (True, result) return (True, result)

View File

@@ -1,5 +1,6 @@
# from smnp.type.model import Type # from smnp.type.model import Type
# #
from smnp.type.model import Type
class Signature: class Signature:
@@ -9,7 +10,7 @@ class Signature:
self.matchers = matchers self.matchers = matchers
def varargSignature(varargMatcher, *basicSignature): def varargSignature(varargMatcher, *basicSignature, wrapVarargInValue=False):
def check(args): def check(args):
if len(basicSignature) > len(args): if len(basicSignature) > len(args):
return doesNotMatchVararg(basicSignature) return doesNotMatchVararg(basicSignature)
@@ -22,7 +23,10 @@ def varargSignature(varargMatcher, *basicSignature):
if not varargMatcher.match(args[i]): if not varargMatcher.match(args[i]):
return doesNotMatchVararg(basicSignature) return doesNotMatchVararg(basicSignature)
return True, (*args[:len(basicSignature)]), args[len(basicSignature):] if wrapVarargInValue:
return True, (*args[:len(basicSignature)]), Type.list(args[len(basicSignature):])
else:
return True, (*args[:len(basicSignature)]), args[len(basicSignature):]
string = f"({', '.join([str(m) for m in basicSignature])}{', ' if len(basicSignature) > 0 else ''}{str(varargMatcher)}...)" string = f"({', '.join([str(m) for m in basicSignature])}{', ' if len(basicSignature) > 0 else ''}{str(varargMatcher)}...)"
@@ -32,8 +36,6 @@ def varargSignature(varargMatcher, *basicSignature):
def doesNotMatchVararg(basicSignature): def doesNotMatchVararg(basicSignature):
return (False, *[None for n in basicSignature], None) return (False, *[None for n in basicSignature], None)
def signature(*signature): def signature(*signature):
def check(args): def check(args):
if len(signature) != len(args): if len(signature) != len(args):

View File

@@ -2,7 +2,7 @@ from smnp.ast.node.function import ArgumentDefinitionNode
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.node.ret import ReturnNode from smnp.ast.node.ret import ReturnNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.function.signature import signature from smnp.function.signature import signature, varargSignature
from smnp.runtime.evaluator import Evaluator, evaluate 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
@@ -43,23 +43,35 @@ class FunctionDefinitionEvaluator(Evaluator):
def argumentsNodeToMethodSignature(node): def argumentsNodeToMethodSignature(node):
try: try:
sign = [] sign = []
vararg = None
for child in node.children: argumentsCount = len(node.children)
for i, child in enumerate(node.children):
if type(child) == ArgumentDefinitionNode: if type(child) == ArgumentDefinitionNode:
if type(child.type.specifiers) == NoneNode: if child.vararg:
sign.append(ofType(child.type.type)) if i != argumentsCount-1:
elif child.type.type == Type.LIST and len(child.type.specifiers) == 1: raise RuntimeException("Vararg must be the last argument in signature", child.pos)
sign.append(listSpecifier(child.type.specifiers[0])) vararg = typeMatcher(child)
elif child.type.type == Type.MAP and len(child.type.specifiers) == 2:
sign.append(mapSpecifier(child.type.specifiers[0], child.type.specifiers[1]))
else: else:
raise RuntimeException("Unknown type", child.pos) # Todo: Improve pointing position sign.append(typeMatcher(child))
return 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)
def typeMatcher(typeNode):
if type(typeNode.type.specifiers) == NoneNode:
return ofType(typeNode.type.type)
elif typeNode.type.type == Type.LIST and len(typeNode.type.specifiers) == 1:
return listSpecifier(typeNode.type.specifiers[0])
elif typeNode.type.type == Type.MAP and len(typeNode.type.specifiers) == 2:
return mapSpecifier(typeNode.type.specifiers[0], typeNode.type.specifiers[1])
raise RuntimeException("Unknown type", typeNode.pos) # Todo: Improve pointing position
def listSpecifier(specifier): def listSpecifier(specifier):
subSignature = [] subSignature = []