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>
|
<typeSpecifier> ::= '<' '>' | '<' <typeSpecifierItem> <typeSpecifierTail>
|
||||||
<typeSpecifierTail> ::= <typeSpecifierItem> ', ' <typeSpecifierTail> | '>'
|
<typeSpecifierTail> ::= <typeSpecifierItem> ', ' <typeSpecifierTail> | '>'
|
||||||
<typeSpecifierItem> ::= <type> | <type> <typeSpecifier>
|
<typeSpecifierItem> ::= <type> | <type> <typeSpecifier> [ '&' <typeSpecifier ]*
|
||||||
|
|
||||||
<block> ::= '{' <stmt>* '}'
|
<block> ::= '{' <stmt>* '}'
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ class Node:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def withChildren(cls, children, pos):
|
||||||
|
node = cls(pos)
|
||||||
|
node.children = children
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
class ParseResult():
|
class ParseResult():
|
||||||
def __init__(self, result, node):
|
def __init__(self, result, node):
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ class TypeSpecifier(Node):
|
|||||||
cls.parse
|
cls.parse
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class TypeSpecifiers(Node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TypeNode(AccessNode):
|
class TypeNode(AccessNode):
|
||||||
def __init__(self, pos):
|
def __init__(self, pos):
|
||||||
@@ -34,24 +37,24 @@ class TypeNode(AccessNode):
|
|||||||
self[0] = value
|
self[0] = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def specifier(self):
|
def specifiers(self):
|
||||||
return self[1]
|
return self[1]
|
||||||
|
|
||||||
@specifier.setter
|
@specifiers.setter
|
||||||
def specifier(self, value):
|
def specifiers(self, value):
|
||||||
self[1] = value
|
self[1] = value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _parse(cls, input):
|
def _parse(cls, input):
|
||||||
def createNode(type, specifier):
|
def createNode(type, specifiers):
|
||||||
node = TypeNode(type.pos)
|
node = TypeNode(type.pos)
|
||||||
node.type = Type[type.value.upper()]
|
node.type = Type[type.value.upper()]
|
||||||
node.specifier = specifier
|
node.specifiers = specifiers
|
||||||
return node
|
return node
|
||||||
|
|
||||||
return Parser.allOf(
|
return Parser.allOf(
|
||||||
cls._rawTypeParser(),
|
cls._rawTypeParser(),
|
||||||
Parser.optional(TypeSpecifier.parse),
|
Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)),
|
||||||
createNode=createNode
|
createNode=createNode
|
||||||
)(input)
|
)(input)
|
||||||
|
|
||||||
|
|||||||
@@ -151,3 +151,20 @@ class Parser:
|
|||||||
return ParseResult.OK(NoneNode())
|
return ParseResult.OK(NoneNode())
|
||||||
|
|
||||||
return parse
|
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:
|
for arg in args:
|
||||||
if arg.type == Type.LIST:
|
if arg.type == Type.LIST:
|
||||||
output.append(listTypes(arg.value, []))
|
output.append(listTypes(arg.value, []))
|
||||||
|
if arg.type == Type.MAP:
|
||||||
|
output.append(mapTypes(arg.value, {}))
|
||||||
else:
|
else:
|
||||||
output.append(arg.type.name.lower())
|
output.append(arg.type.name.lower())
|
||||||
return f"({', '.join(output)})" if parentheses else ', '.join(output)
|
return f"({', '.join(output)})" if parentheses else ', '.join(output)
|
||||||
@@ -64,6 +66,22 @@ def listTypes(l, output=None):
|
|||||||
for item in l:
|
for item in l:
|
||||||
if item.type == Type.LIST:
|
if item.type == Type.LIST:
|
||||||
output.append(listTypes(item.value, []))
|
output.append(listTypes(item.value, []))
|
||||||
|
if item.type == Type.MAP:
|
||||||
|
output.append(mapTypes(item.value, {}))
|
||||||
else:
|
else:
|
||||||
output.append(item.type.name.lower())
|
output.append(item.type.name.lower())
|
||||||
return f"{Type.LIST.name.lower()}<{', '.join(set(output))}>"
|
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])}>")
|
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 listMatches(*pattern):
|
||||||
def check(value):
|
def check(value):
|
||||||
return signature(*pattern).check(value.value)[0]
|
return signature(*pattern).check(value.value)[0]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from smnp.program.interpreter import Interpreter
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
|
|
||||||
Interpreter.interpretFile(sys.argv[1], printAst=True)
|
Interpreter.interpretFile(sys.argv[1], printAst=True)
|
||||||
|
|
||||||
except SmnpException as e:
|
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.ret import ReturnNode
|
||||||
from smnp.ast.node.variable import TypedVariableNode
|
from smnp.ast.node.variable import TypedVariableNode
|
||||||
from smnp.error.runtime import RuntimeException
|
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.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
|
||||||
@@ -38,29 +38,66 @@ class FunctionDefinitionEvaluator(Evaluator):
|
|||||||
|
|
||||||
|
|
||||||
def argumentsNodeToMethodSignature(node):
|
def argumentsNodeToMethodSignature(node):
|
||||||
sign = []
|
try:
|
||||||
|
sign = []
|
||||||
|
|
||||||
for child in node.children:
|
for child in node.children:
|
||||||
if type(child) == TypedVariableNode:
|
if type(child) == TypedVariableNode:
|
||||||
if type(child.type.specifier) == NoneNode:
|
if type(child.type.specifiers) == NoneNode:
|
||||||
sign.append(ofType(child.type.type))
|
sign.append(ofType(child.type.type))
|
||||||
elif child.type.type == Type.LIST:
|
elif child.type.type == Type.LIST and len(child.type.specifiers) == 1:
|
||||||
sign.append(listSpecifier(child.type.specifier))
|
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):
|
def listSpecifier(specifier):
|
||||||
subSignature = []
|
subSignature = []
|
||||||
|
|
||||||
for child in specifier.children:
|
for child in specifier.children:
|
||||||
if type(child.specifier) == NoneNode:
|
if type(child.specifiers) == NoneNode:
|
||||||
subSignature.append(ofType(child.type))
|
subSignature.append(ofType(child.type))
|
||||||
elif child.type == Type.LIST:
|
elif child.type == Type.LIST and len(child.type.specifiers) == 1:
|
||||||
subSignature.append(listSpecifier(child.specifier))
|
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)
|
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):
|
class BodyEvaluator(Evaluator):
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ tokenizers = (
|
|||||||
defaultTokenizer(TokenType.ARROW),
|
defaultTokenizer(TokenType.ARROW),
|
||||||
defaultTokenizer(TokenType.COMMA),
|
defaultTokenizer(TokenType.COMMA),
|
||||||
defaultTokenizer(TokenType.MINUS),
|
defaultTokenizer(TokenType.MINUS),
|
||||||
|
defaultTokenizer(TokenType.AMP),
|
||||||
defaultTokenizer(TokenType.DOT),
|
defaultTokenizer(TokenType.DOT),
|
||||||
|
|
||||||
# Types
|
# Types
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class TokenType(Enum):
|
|||||||
ARROW = '->'
|
ARROW = '->'
|
||||||
COMMA = ','
|
COMMA = ','
|
||||||
MINUS = '-'
|
MINUS = '-'
|
||||||
|
AMP = '&'
|
||||||
DOT = '.'
|
DOT = '.'
|
||||||
INTEGER = 'integer'
|
INTEGER = 'integer'
|
||||||
STRING = 'string'
|
STRING = 'string'
|
||||||
|
|||||||
Reference in New Issue
Block a user