Files
smnp-py/smnp/ast/node/iterable.py
2019-07-12 00:18:53 +02:00

122 lines
3.0 KiB
Python

from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.node.model import Node, ParseResult
from smnp.ast.node.none import NoneNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser):
class AbstractIterable(Node):
def __init__(self, pos):
super().__init__(pos)
self.children = [NoneNode(), NoneNode()]
@property
def value(self):
return self[0]
@value.setter
def value(self, value):
self[0] = value
@property
def next(self):
return self[1]
@next.setter
def next(self, value):
self[1] = value
class AbstractIterableTail(AbstractIterable):
pass
def abstractIterableParser(input):
return Parser.oneOf(
emptyIterable,
openIterable
)(input)
def emptyIterable(input):
def createNode(open, close):
node = AbstractIterable(open.pos)
node.value = open
node.next = close
return node
return Parser.allOf(
Parser.terminal(openTokenType),
Parser.terminal(closeTokenType),
createNode=createNode
)(input)
def openIterable(input):
def createNode(open, item, tail):
node = AbstractIterable(open.pos)
node.value = item
node.next = tail
return node
return Parser.allOf(
Parser.terminal(openTokenType),
itemParser,
abstractIterableTailParser,
createNode=createNode
)(input)
def abstractIterableTailParser(input):
return Parser.oneOf(
closeIterable,
nextItem,
)(input)
def nextItem(input):
def createNode(comma, item, tail):
node = AbstractIterableTail(item.pos)
node.value = item
node.next = tail
return node
return Parser.allOf(
Parser.terminal(TokenType.COMMA, doAssert=True),
itemParser,
abstractIterableTailParser,
createNode=createNode
)(input)
def closeIterable(input):
return Parser.terminal(closeTokenType)(input)
return toFlatDesiredNode(iterableNodeType, abstractIterableParser)
def toFlatDesiredNode(iterableNodeType, parser):
def parse(input):
result = parser(input)
if result.result:
value = flattenList(result.node)
node = iterableNodeType(result.node.pos)
node.children.clear()
for v in value:
node.append(v)
return ParseResult.OK(node)
return ParseResult.FAIL()
return Parser(parse, "flat", [parser])
def flattenList(node, output=None):
if output is None:
output = []
if type(node.value) != IgnoredNode:
output.append(node.value)
if type(node.next) != IgnoredNode:
flattenList(node.next, output)
return output