279 lines
9.1 KiB
Python
279 lines
9.1 KiB
Python
from smnp.ast.node.ignore import IgnoredNode
|
|
from smnp.ast.node.model import ParseResult, Node
|
|
from smnp.ast.node.none import NoneNode
|
|
from smnp.error.syntax import SyntaxException
|
|
|
|
|
|
def parse(input):
|
|
from smnp.ast.node.program import ProgramParser
|
|
return ProgramParser(input).node
|
|
|
|
|
|
class Parser(object):
|
|
def __init__(self, name):
|
|
self.name = name
|
|
|
|
def parse(self, input):
|
|
result = self._parse(input)
|
|
if result is None:
|
|
return ParseResult.FAIL()
|
|
|
|
if not isinstance(result, ParseResult):
|
|
raise RuntimeError(
|
|
f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
|
|
|
|
return result
|
|
|
|
def _parse(self, input):
|
|
raise RuntimeError(f"_name method of '{self.__class__.__name__}' class is not implemented")
|
|
|
|
def grammar(self):
|
|
rules = []
|
|
self._grammarRules(rules)
|
|
return "\n".join(self._uniq(rules))
|
|
|
|
def _uniq(self, seq):
|
|
seen = set()
|
|
seen_add = seen.add
|
|
return [x for x in seq if not (x in seen or seen_add(x))]
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(f"class '{self.__class__.__name__}' does not implement _grammarRules() method")
|
|
|
|
def __call__(self, input):
|
|
return self.parse(input)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
|
|
class Parsers:
|
|
|
|
@staticmethod
|
|
def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
|
|
return TerminalParser(expectedType, createNode, doAssert)
|
|
|
|
@staticmethod
|
|
def oneOf(*parsers, name, exception=None):
|
|
return OneOfParser(*parsers, name=name, exception=exception)
|
|
|
|
@staticmethod
|
|
def allOf(*parsers, createNode, exception=None, name):
|
|
return AllOfParser(*parsers, createNode=createNode, exception=exception, name=name)
|
|
|
|
@staticmethod
|
|
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name):
|
|
return LeftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name)
|
|
|
|
@staticmethod
|
|
def many(itemParser, createNode, name):
|
|
return ManyParser(itemParser, createNode, name)
|
|
|
|
@staticmethod
|
|
def optional(parser, name):
|
|
return OptionalParser(parser, name)
|
|
|
|
@staticmethod
|
|
def loop(startParser, itemParser, endParser, createNode, name):
|
|
return LoopParser(startParser, itemParser, endParser, createNode, name)
|
|
|
|
|
|
class TerminalParser(Parser):
|
|
|
|
def __init__(self, expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
|
|
super().__init__(expectedType.name.lower())
|
|
self.expectedType = expectedType
|
|
self.createNode = createNode
|
|
self.doAssert = doAssert
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(f"{self.name} -> '{self.expectedType.value}'")
|
|
|
|
def _parse(self, input):
|
|
if input.isCurrent(self.expectedType):
|
|
token = input.current()
|
|
input.ahead()
|
|
return ParseResult.OK(self.createNode(token.value, token.pos))
|
|
elif self.doAssert:
|
|
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
|
|
raise SyntaxException(f"Expected '{self.expectedType.key}'{found}", input.currentPos())
|
|
|
|
return ParseResult.FAIL()
|
|
|
|
|
|
|
|
class OneOfParser(Parser):
|
|
def __init__(self, *parsers, name, exception=None):
|
|
super().__init__(name)
|
|
self.parsers = parsers
|
|
self.exception = exception
|
|
|
|
def _parse(self, input):
|
|
snap = input.snapshot()
|
|
for parser in self.parsers:
|
|
value = parser.parse(input)
|
|
if value.result:
|
|
return value
|
|
input.reset(snap) # TODO sprawdzic, czy koneiczne !!!!!
|
|
|
|
if self.exception is not None:
|
|
if callable(self.exception):
|
|
raise self.exception(input)
|
|
else:
|
|
raise self.exception
|
|
|
|
return ParseResult.FAIL()
|
|
|
|
def _grammarRules(self, output):
|
|
output.extend([ f"{self.name} -> {parser.name}" for parser in self.parsers ])
|
|
[ parser._grammarRules(output) for parser in self.parsers ]
|
|
|
|
|
|
class AllOfParser(Parser):
|
|
def __init__(self, *parsers, createNode, exception=None, name):
|
|
super().__init__(name)
|
|
|
|
if len(parsers) == 0:
|
|
raise RuntimeError("Pass one parser at least")
|
|
|
|
self.parsers = parsers
|
|
self.createNode = createNode
|
|
self.exception = exception
|
|
|
|
def _parse(self, input):
|
|
snap = input.snapshot()
|
|
parsedItems = []
|
|
|
|
for parser in self.parsers:
|
|
result = parser.parse(input)
|
|
|
|
if not result.result:
|
|
if self.exception is not None:
|
|
if callable(self.exception):
|
|
raise self.exception(input)
|
|
else:
|
|
raise self.exception
|
|
|
|
input.reset(snap)
|
|
return ParseResult.FAIL()
|
|
|
|
parsedItems.append(result.node)
|
|
|
|
node = self.createNode(*parsedItems)
|
|
if not isinstance(node, Node):
|
|
raise RuntimeError(f"Method 'createNode' of class '{self.__class__.__name__}' haven't returned a Node object. Probably forget to pass 'return'")
|
|
|
|
return ParseResult.OK(node)
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(self.name + ' -> ' + ' '.join([ parser.name for parser in self.parsers ]))
|
|
[ parser._grammarRules(output) for parser in self.parsers ]
|
|
|
|
|
|
class LeftAssociativeOperatorParser(Parser):
|
|
def __init__(self, leftParser, operatorTokenTypes, rightParser, createNode, name):
|
|
from smnp.ast.node.operator import Operator
|
|
|
|
super().__init__(name)
|
|
self.leftParser = leftParser
|
|
self.rightParser = rightParser
|
|
self.createNode = createNode
|
|
self.operators = operatorTokenTypes
|
|
|
|
operatorParsers = [ TerminalParser(expectedType, createNode=lambda val, pos: Operator.withValue(val, pos)) for expectedType in operatorTokenTypes ]
|
|
self.operatorParser = OneOfParser(*operatorParsers, name="not important")
|
|
|
|
def _parse(self, input):
|
|
snap = input.snapshot()
|
|
left = self.leftParser.parse(input)
|
|
if left.result:
|
|
operator = self.operatorParser.parse(input)
|
|
while operator.result:
|
|
right = self.rightParser.parse(input)
|
|
left = ParseResult.OK(self.createNode(left.node, operator.node, right.node))
|
|
operator = self.operatorParser.parse(input)
|
|
return left
|
|
|
|
return ParseResult.FAIL()
|
|
|
|
|
|
def _grammarRules(self, output):
|
|
output.append('\n'.join([f"{self.name} -> {self.leftParser.name} {operator.name.lower()} {self.rightParser.name} | {self.leftParser.name}" for operator in self.operators]))
|
|
self.leftParser._grammarRules(output)
|
|
self.rightParser._grammarRules(output)
|
|
|
|
|
|
class ManyParser(Parser):
|
|
def __init__(self, itemParser, createNode, name):
|
|
super().__init__(name)
|
|
self.itemParser = itemParser
|
|
self.createNode = createNode
|
|
|
|
def _parse(self, input):
|
|
snap = input.snapshot()
|
|
|
|
parsedItems = []
|
|
pos = input.currentPos()
|
|
while True:
|
|
result = self.itemParser.parse(input)
|
|
if result.result:
|
|
parsedItems.append(result.node)
|
|
snap = input.snapshot()
|
|
else:
|
|
input.reset(snap)
|
|
return ParseResult.OK(self.createNode(parsedItems, pos) if len(parsedItems) > 0 else NoneNode())
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(f"{self.name} -> {self.itemParser.name}*")
|
|
self.itemParser._grammarRules(output)
|
|
|
|
|
|
class OptionalParser(Parser):
|
|
def __init__(self, parser, name):
|
|
super().__init__(name)
|
|
self.parser = parser
|
|
|
|
def _parse(self, input):
|
|
result = self.parser.parse(input)
|
|
if result.result:
|
|
return result
|
|
|
|
return ParseResult.OK(NoneNode())
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(f"{self.name} -> {self.parser.name}?")
|
|
|
|
|
|
class LoopParser(Parser):
|
|
def __init__(self, startParser, itemParser, endParser, createNode, name):
|
|
super().__init__(name)
|
|
self.startParser = startParser
|
|
self.itemParser = itemParser
|
|
self.endParser = endParser
|
|
self.createNode = createNode
|
|
|
|
def _parse(self, input):
|
|
items = []
|
|
start = self.startParser.parse(input)
|
|
if start.result:
|
|
while True:
|
|
end = self.endParser.parse(input)
|
|
if end.result:
|
|
return ParseResult.OK(self.createNode(start.node, items, end.node))
|
|
item = self.itemParser.parse(input)
|
|
if not item.result:
|
|
return ParseResult.FAIL()
|
|
items.append(item.node)
|
|
|
|
return ParseResult.FAIL()
|
|
|
|
def _grammarRules(self, output):
|
|
output.append(f"{self.name} -> {self.startParser.name} {self.itemParser.name}* {self.endParser.name}")
|
|
self.startParser._grammarRules(output)
|
|
self.itemParser._grammarRules(output)
|
|
self.endParser._grammarRules(output)
|
|
|