Extend type specifiers to cover maps
This commit is contained in:
2
grammar
2
grammar
@@ -41,7 +41,7 @@ PITCH_MODIFIER = 'b' | '#'
|
||||
|
||||
<typeSpecifier> ::= '<' '>' | '<' <typeSpecifierItem> <typeSpecifierTail>
|
||||
<typeSpecifierTail> ::= <typeSpecifierItem> ', ' <typeSpecifierTail> | '>'
|
||||
<typeSpecifierItem> ::= <type> | <type> <typeSpecifier>
|
||||
<typeSpecifierItem> ::= <type> | <type> <typeSpecifier> [ '&' <typeSpecifier ]*
|
||||
|
||||
<block> ::= '{' <stmt>* '}'
|
||||
|
||||
|
||||
@@ -59,6 +59,12 @@ class Node:
|
||||
def __str__(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
@classmethod
|
||||
def withChildren(cls, children, pos):
|
||||
node = cls(pos)
|
||||
node.children = children
|
||||
return node
|
||||
|
||||
|
||||
class ParseResult():
|
||||
def __init__(self, result, node):
|
||||
|
||||
@@ -20,6 +20,9 @@ class TypeSpecifier(Node):
|
||||
cls.parse
|
||||
)
|
||||
|
||||
class TypeSpecifiers(Node):
|
||||
pass
|
||||
|
||||
|
||||
class TypeNode(AccessNode):
|
||||
def __init__(self, pos):
|
||||
@@ -34,24 +37,24 @@ class TypeNode(AccessNode):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def specifier(self):
|
||||
def specifiers(self):
|
||||
return self[1]
|
||||
|
||||
@specifier.setter
|
||||
def specifier(self, value):
|
||||
@specifiers.setter
|
||||
def specifiers(self, value):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
def createNode(type, specifier):
|
||||
def createNode(type, specifiers):
|
||||
node = TypeNode(type.pos)
|
||||
node.type = Type[type.value.upper()]
|
||||
node.specifier = specifier
|
||||
node.specifiers = specifiers
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
cls._rawTypeParser(),
|
||||
Parser.optional(TypeSpecifier.parse),
|
||||
Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)),
|
||||
createNode=createNode
|
||||
)(input)
|
||||
|
||||
|
||||
@@ -151,3 +151,20 @@ class Parser:
|
||||
return ParseResult.OK(NoneNode())
|
||||
|
||||
return parse
|
||||
|
||||
@staticmethod
|
||||
def many(parser, createNode):
|
||||
def parse(input):
|
||||
results = []
|
||||
snap = input.snapshot()
|
||||
pos = input.currentPos()
|
||||
while True:
|
||||
result = parser(input)
|
||||
if result.result:
|
||||
results.append(result.node)
|
||||
snap = input.snapshot()
|
||||
else:
|
||||
input.reset(snap)
|
||||
return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode())
|
||||
|
||||
return parse
|
||||
|
||||
@@ -53,6 +53,8 @@ def types(args, parentheses=True):
|
||||
for arg in args:
|
||||
if arg.type == Type.LIST:
|
||||
output.append(listTypes(arg.value, []))
|
||||
if arg.type == Type.MAP:
|
||||
output.append(mapTypes(arg.value, {}))
|
||||
else:
|
||||
output.append(arg.type.name.lower())
|
||||
return f"({', '.join(output)})" if parentheses else ', '.join(output)
|
||||
@@ -64,6 +66,22 @@ def listTypes(l, output=None):
|
||||
for item in l:
|
||||
if item.type == Type.LIST:
|
||||
output.append(listTypes(item.value, []))
|
||||
if item.type == Type.MAP:
|
||||
output.append(mapTypes(item.value, {}))
|
||||
else:
|
||||
output.append(item.type.name.lower())
|
||||
return f"{Type.LIST.name.lower()}<{', '.join(set(output))}>"
|
||||
|
||||
def mapTypes(map, output=None):
|
||||
if output is None:
|
||||
output = {}
|
||||
|
||||
for k, v in map.items():
|
||||
if v.type == Type.LIST:
|
||||
output[k] = (listTypes(v.value, []))
|
||||
elif v.type == Type.MAP:
|
||||
output[k] = mapTypes(v.value, {})
|
||||
else:
|
||||
output[k] = v.type.name.lower()
|
||||
|
||||
return f"{Type.MAP.name.lower()}<{', '.join(set([ k.type.name.lower() for k, v in output.items() ]))}><{', '.join(set([ str(v) for k, v in output.items() ]))}>"
|
||||
@@ -120,6 +120,18 @@ def listOfMatchers(*matchers):
|
||||
|
||||
return Matcher(Type.LIST, check, f"{Type.LIST.name.lower()}<{', '.join([m.string for m in matchers])}>")
|
||||
|
||||
def mapOfMatchers(keyMatchers, valueMatchers):
|
||||
def check(map):
|
||||
matched = 0
|
||||
for key, value in map.value.items():
|
||||
matched += 1 if any(matcher.match(key) for matcher in keyMatchers) \
|
||||
and any(matcher.match(value) for matcher in valueMatchers) else 0
|
||||
|
||||
return matched == len(map.value)
|
||||
|
||||
return Matcher(Type.MAP, check, f"{Type.MAP.name.lower()}<{', '.join([m.string for m in keyMatchers])}><{', '.join([m.string for m in valueMatchers])}>")
|
||||
|
||||
|
||||
def listMatches(*pattern):
|
||||
def check(value):
|
||||
return signature(*pattern).check(value.value)[0]
|
||||
|
||||
@@ -6,6 +6,7 @@ from smnp.program.interpreter import Interpreter
|
||||
|
||||
def main():
|
||||
try:
|
||||
|
||||
Interpreter.interpretFile(sys.argv[1], printAst=True)
|
||||
|
||||
except SmnpException as e:
|
||||
|
||||
@@ -2,7 +2,7 @@ from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.ret import ReturnNode
|
||||
from smnp.ast.node.variable import TypedVariableNode
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.library.signature import signature, listOfMatchers, ofType
|
||||
from smnp.library.signature import signature, listOfMatchers, ofType, mapOfMatchers
|
||||
from smnp.runtime.evaluator import Evaluator, evaluate
|
||||
from smnp.runtime.evaluators.expression import expressionEvaluator
|
||||
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
|
||||
@@ -38,29 +38,66 @@ class FunctionDefinitionEvaluator(Evaluator):
|
||||
|
||||
|
||||
def argumentsNodeToMethodSignature(node):
|
||||
sign = []
|
||||
try:
|
||||
sign = []
|
||||
|
||||
for child in node.children:
|
||||
if type(child) == TypedVariableNode:
|
||||
if type(child.type.specifier) == NoneNode:
|
||||
sign.append(ofType(child.type.type))
|
||||
elif child.type.type == Type.LIST:
|
||||
sign.append(listSpecifier(child.type.specifier))
|
||||
for child in node.children:
|
||||
if type(child) == TypedVariableNode:
|
||||
if type(child.type.specifiers) == NoneNode:
|
||||
sign.append(ofType(child.type.type))
|
||||
elif child.type.type == Type.LIST and len(child.type.specifiers) == 1:
|
||||
sign.append(listSpecifier(child.type.specifiers[0]))
|
||||
elif child.type.type == Type.MAP and len(child.type.specifiers) == 2:
|
||||
sign.append(mapSpecifier(child.type.specifiers[0], child.type.specifiers[1]))
|
||||
else:
|
||||
raise RuntimeException("Unknown type", child.pos) # Todo: Improve pointing position
|
||||
|
||||
return signature(*sign)
|
||||
return signature(*sign)
|
||||
except RuntimeException as e:
|
||||
raise updatePos(e, node)
|
||||
|
||||
|
||||
def listSpecifier(specifier):
|
||||
subSignature = []
|
||||
|
||||
for child in specifier.children:
|
||||
if type(child.specifier) == NoneNode:
|
||||
if type(child.specifiers) == NoneNode:
|
||||
subSignature.append(ofType(child.type))
|
||||
elif child.type == Type.LIST:
|
||||
subSignature.append(listSpecifier(child.specifier))
|
||||
elif child.type == Type.LIST and len(child.type.specifiers) == 1:
|
||||
subSignature.append(listSpecifier(child.specifiers[0]))
|
||||
elif child.type == Type.MAP and len(child.specifiers) == 2:
|
||||
subSignature.append(mapSpecifier(child.specifiers[0], child.specifiers[1]))
|
||||
else:
|
||||
raise RuntimeException("Unknown type", None)
|
||||
|
||||
return listOfMatchers(*subSignature)
|
||||
|
||||
def mapSpecifier(keySpecifier, valueSpecifier):
|
||||
keySubSignature = []
|
||||
valueSubSignature = []
|
||||
|
||||
for child in keySpecifier.children:
|
||||
if type(child.specifiers) == NoneNode:
|
||||
keySubSignature.append(ofType(child.type))
|
||||
elif child.type == Type.LIST and len(child.specifiers) == 1:
|
||||
keySubSignature.append(listSpecifier(child.specifiers[0]))
|
||||
elif child.type == Type.MAP and len(child.specifiers) == 2:
|
||||
keySubSignature.append(mapSpecifier(child.specifiers[0], child.specifiers[1]))
|
||||
else:
|
||||
raise RuntimeException("Unknown type", None)
|
||||
|
||||
for child in valueSpecifier.children:
|
||||
if type(child.specifiers) == NoneNode:
|
||||
valueSubSignature.append(ofType(child.type))
|
||||
elif child.type == Type.LIST and len(child.specifiers) == 1:
|
||||
valueSubSignature.append(listSpecifier(child.specifiers[0]))
|
||||
elif child.type == Type.MAP and len(child.specifiers) == 2:
|
||||
valueSubSignature.append(mapSpecifier(child.specifiers[0], child.specifiers[1]))
|
||||
else:
|
||||
raise RuntimeException("Unknown type", None)
|
||||
|
||||
return mapOfMatchers(keySubSignature, valueSubSignature)
|
||||
|
||||
|
||||
class BodyEvaluator(Evaluator):
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ tokenizers = (
|
||||
defaultTokenizer(TokenType.ARROW),
|
||||
defaultTokenizer(TokenType.COMMA),
|
||||
defaultTokenizer(TokenType.MINUS),
|
||||
defaultTokenizer(TokenType.AMP),
|
||||
defaultTokenizer(TokenType.DOT),
|
||||
|
||||
# Types
|
||||
|
||||
@@ -15,6 +15,7 @@ class TokenType(Enum):
|
||||
ARROW = '->'
|
||||
COMMA = ','
|
||||
MINUS = '-'
|
||||
AMP = '&'
|
||||
DOT = '.'
|
||||
INTEGER = 'integer'
|
||||
STRING = 'string'
|
||||
|
||||
Reference in New Issue
Block a user