4 Commits

Author SHA1 Message Date
Bartłomiej Pluta
49e4c4487e --wip-- [skip ci] 2019-07-11 19:36:25 +02:00
Bartłomiej Pluta
e7674a4834 Create almost working proof of concept with new parsers 2019-07-11 19:10:13 +02:00
Bartłomiej Pluta
ed2c8dc6dd Create base for future parsers 2019-07-11 18:24:05 +02:00
Bartłomiej Pluta
f91e2a75de Create oneOf and allOf parsers 2019-07-11 17:23:39 +02:00
10 changed files with 409 additions and 268 deletions

View File

@@ -1,6 +1,7 @@
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers
from smnp.token.type import TokenType from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class Atom(Node): class Atom(Node):
@@ -43,52 +44,60 @@ class TypeLiteral(Atom):
pass pass
def IntegerParser(input): @SingletonParser
return Parser.oneOf( def IntegerParser():
Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), return Parsers.oneOf(
Parser.allOf( Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
Parser.terminalParser(TokenType.MINUS), Parsers.allOf(
Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), Parsers.terminal(TokenType.MINUS),
Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
createNode=lambda minus, integer: IntegerLiteral.withValue(-integer.value, minus.pos), createNode=lambda minus, integer: IntegerLiteral.withValue(-integer.value, minus.pos),
name="negative integer" name="negativeInteger"
) ),
)(input) name="int"
)
def StringParser(input): @SingletonParser
return Parser.terminalParser(TokenType.STRING, createNode=StringLiteral.withValue)(input) def StringParser():
return Parsers.terminal(TokenType.STRING, createNode=StringLiteral.withValue)
def NoteParser(input): @SingletonParser
return Parser.terminalParser(TokenType.NOTE, createNode=NoteLiteral.withValue)(input) def NoteParser():
return Parsers.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)
def BoolParser(input): @SingletonParser
return Parser.terminalParser(TokenType.BOOL, createNode=BoolLiteral.withValue)(input) def BoolParser():
return Parsers.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)
def TypeParser(input): @SingletonParser
return Parser.terminalParser(TokenType.TYPE, createNode=TypeLiteral.withValue)(input) def TypeParser():
return Parsers.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)
def LiteralParser(input): @SingletonParser
return Parser.oneOf( def LiteralParser():
IntegerParser, return Parsers.oneOf(
StringParser, IntegerParser(),
NoteParser, StringParser(),
BoolParser, NoteParser(),
TypeParser, BoolParser(),
TypeParser(),
name="literal" name="literal"
)(input) )
def AtomParser(input): @SingletonParser
def AtomParser():
from smnp.ast.node.identifier import IdentifierParser from smnp.ast.node.identifier import IdentifierParser
return Parser.oneOf( return Parsers.oneOf(
LiteralParser, LiteralParser(),
IdentifierParser, IdentifierParser(),
name="atom" name="atom"
)(input) )

View File

@@ -1,21 +1,32 @@
from smnp.ast.node.atom import AtomParser
from smnp.ast.node.list import ListParser from smnp.ast.node.list import ListParser
from smnp.ast.node.map import MapParser
from smnp.ast.node.operator import BinaryOperator from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.valuable import Valuable from smnp.ast.node.valuable import Valuable
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers
from smnp.token.type import TokenType from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class Chain(Valuable): class Chain(Valuable):
pass pass
itemParser = Parser.oneOf(
ListParser,
MapParser,
AtomParser,
)
ChainParser = Parser.leftAssociativeOperatorParser(itemParser, [TokenType.DOT], itemParser,
lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right))) @SingletonParser
def ChainParser():
from smnp.ast.node.atom import AtomParser
itemParser = Parsers.oneOf(
ListParser,
#MapParser,
AtomParser,
name="chainItem"
)
return Parsers.leftAssociativeOperatorParser(
itemParser,
[TokenType.DOT],
itemParser,
lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right)),
name="chain"
)

View File

@@ -1,11 +1,10 @@
from smnp.ast.node.atom import Atom from smnp.ast.node.atom import Atom
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.node.operator import BinaryOperator, Operator from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers
from smnp.token.type import TokenType from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class Identifier(Atom): class Identifier(Atom):
@@ -49,24 +48,28 @@ class Assignment(BinaryOperator):
pass pass
def IdentifierParser(input): @SingletonParser
identifierLiteralParser = Parser.terminalParser(TokenType.IDENTIFIER, createNode=Identifier.withValue) def IdentifierParser():
identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)
functionCallParser = Parser.allOf( functionCallParser = Parsers.allOf(
identifierLiteralParser, identifierLiteralParser,
abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser), #abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser),
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments) createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments),
name="functionCall"
) )
assignmentParser = Parser.allOf( assignmentParser = Parsers.allOf(
identifierLiteralParser, identifierLiteralParser,
Parser.terminalParser(TokenType.ASSIGN, createNode=Operator.withValue), Parsers.terminal(TokenType.ASSIGN, createNode=Operator.withValue),
MaxPrecedenceExpressionParser, #MaxPrecedenceExpressionParser,
createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr) createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr),
name="assignment"
) )
return Parser.oneOf( return Parsers.oneOf(
assignmentParser, assignmentParser,
functionCallParser, functionCallParser,
identifierLiteralParser identifierLiteralParser,
)(input) name="idExpr"
)

View File

@@ -1,11 +1,11 @@
from smnp.ast.node.ignore import IgnoredNode from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.node.model import Node, ParseResult from smnp.ast.node.model import Node, ParseResult
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers, DecoratorParser
from smnp.token.type import TokenType from smnp.token.type import TokenType
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser): def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser, name):
class AbstractIterable(Node): class AbstractIterable(Node):
def __init__(self, pos): def __init__(self, pos):
@@ -31,70 +31,74 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item
class AbstractIterableTail(AbstractIterable): class AbstractIterableTail(AbstractIterable):
pass pass
def abstractIterableParser(input): def abstractIterableParser():
return Parser.oneOf( return Parsers.oneOf(
emptyIterable, emptyIterable(),
openIterable openIterable(),
)(input) name=name
)
def emptyIterable(input): def emptyIterable():
def createNode(open, close): def createNode(open, close):
node = AbstractIterable(open.pos) node = AbstractIterable(open.pos)
node.value = open node.value = open
node.next = close node.next = close
return node return node
return Parser.allOf( return Parsers.allOf(
Parser.terminalParser(openTokenType), Parsers.terminal(openTokenType),
Parser.terminalParser(closeTokenType), Parsers.terminal(closeTokenType),
createNode=createNode createNode=createNode,
)(input) name=name+"Empty"
)
def openIterable(input): def openIterable():
def createNode(open, item, tail): def createNode(open, item, tail):
node = AbstractIterable(open.pos) node = AbstractIterable(open.pos)
node.value = item node.value = item
node.next = tail node.next = tail
return node return node
return Parser.allOf( return Parsers.allOf(
Parser.terminalParser(openTokenType), Parsers.terminal(openTokenType),
itemParser, itemParser,
abstractIterableTailParser, abstractIterableTailParser(),
createNode=createNode createNode=createNode,
)(input) name=name+"Open"
)
def abstractIterableTailParser(input): def abstractIterableTailParser():
return Parser.oneOf( return Parsers.oneOf(
closeIterable, closeIterable(),
nextItem, nextItem(),
)(input) name=name+"Tail"
)
def nextItem(input): def nextItem():
def createNode(comma, item, tail): def createNode(comma, item, tail):
node = AbstractIterableTail(item.pos) node = AbstractIterableTail(item.pos)
node.value = item node.value = item
node.next = tail node.next = tail
return node return node
return Parser.allOf( return Parsers.allOf(
Parser.terminalParser(TokenType.COMMA, doAssert=True), Parsers.terminal(TokenType.COMMA, doAssert=True),
itemParser, itemParser,
abstractIterableTailParser, abstractIterableTailParser(),
name=name+"NextItem",
createNode=createNode createNode=createNode
)(input) )
def closeIterable(input): def closeIterable():
return Parser.terminalParser(closeTokenType)(input) return Parsers.terminal(closeTokenType)
return toFlatDesiredNode(iterableNodeType, abstractIterableParser) return abstractIterableParser()
#return toFlatDesiredNode(iterableNodeType, abstractIterableParser())
def toFlatDesiredNode(iterableNodeType, parser): def toFlatDesiredNode(iterableNodeType, parser):
def parse(input): def wrapper(result):
result = parser(input)
if result.result: if result.result:
value = flattenList(result.node) value = flattenList(result.node)
node = iterableNodeType(result.node.pos) node = iterableNodeType(result.node.pos)
@@ -105,7 +109,7 @@ def toFlatDesiredNode(iterableNodeType, parser):
return ParseResult.FAIL() return ParseResult.FAIL()
return Parser(parse, "flat", [parser]) return DecoratorParser(wrapper, parser)
def flattenList(node, output=None): def flattenList(node, output=None):

View File

@@ -1,3 +1,4 @@
from smnp.ast.node.atom import AtomParser
from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.token.type import TokenType from smnp.token.type import TokenType
@@ -7,7 +8,6 @@ class List(Node):
pass pass
def ListParser(input): def ListParser():
from smnp.ast.node.expression import MaxPrecedenceExpressionParser return abstractIterableParser(List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, AtomParser(), name="list")
return abstractIterableParser(List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, #MaxPrecedenceExpressionParser)(input)
MaxPrecedenceExpressionParser)(input)

View File

@@ -1,8 +1,7 @@
from smnp.ast.node.atom import LiteralParser
from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.node.operator import BinaryOperator, Operator from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers
from smnp.token.type import TokenType from smnp.token.type import TokenType
@@ -30,17 +29,19 @@ class Map(Node):
def MapParser(input): def MapParser(input):
from smnp.ast.node.expression import MaxPrecedenceExpressionParser from smnp.ast.node.atom import LiteralParser
#from smnp.ast.node.expression import MaxPrecedenceExpressionParser
keyParser = LiteralParser keyParser = LiteralParser
valueParser = MaxPrecedenceExpressionParser #valueParser = MaxPrecedenceExpressionParser
mapEntryParser = Parser.allOf( mapEntryParser = Parsers.allOf(
keyParser, keyParser,
Parser.terminalParser(TokenType.ARROW, createNode=Operator.withValue), Parsers.terminal(TokenType.ARROW, createNode=Operator.withValue),
valueParser, #valueParser,
createNode=MapEntry.withValues createNode=MapEntry.withValues,
name="mapEntry"
) )
mapParser = abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser) return abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser)
return Parser(mapParser, "map", [mapParser])(input)

View File

@@ -9,15 +9,8 @@ def parse(input):
return ProgramParser(input).node return ProgramParser(input).node
class Parser: class Parser(object):
def __init__(self, parse, name=None, parsers=None): def __init__(self, name):
if parsers is None:
parsers = []
self.parsers = parsers
self._parse = parse
if name is None:
name = parse.__name__
self.name = name self.name = name
def parse(self, input): def parse(self, input):
@@ -26,10 +19,27 @@ class Parser:
return ParseResult.FAIL() return ParseResult.FAIL()
if not isinstance(result, ParseResult): if not isinstance(result, ParseResult):
raise RuntimeError(f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object") raise RuntimeError(
f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
return result 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): def __call__(self, input):
return self.parse(input) return self.parse(input)
@@ -39,171 +49,242 @@ class Parser:
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
# a -> A
class Parsers:
@staticmethod @staticmethod
def terminalParser(expectedType, createNode=None, doAssert=False): def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
def provideNode(value, pos): return TerminalParser(expectedType, createNode, doAssert)
if createNode is None:
return IgnoredNode(pos)
return createNode(value, pos)
def parse(input):
if input.hasCurrent() and input.current().type == expectedType:
token = input.current()
input.ahead()
return ParseResult.OK(provideNode(token.value, token.pos))
elif doAssert:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected '{expectedType.key}'{found}", input.currentPos())
return ParseResult.FAIL()
return Parser(parse, name=expectedType.name.lower())
# oneOf -> a | b | c | ...
@staticmethod @staticmethod
def oneOf(*parsers, exception=None, name="or"): def oneOf(*parsers, name, exception=None):
def combinedParser(input): return OneOfParser(*parsers, name=name, exception=exception)
snap = input.snapshot()
for parser in parsers:
value = parser(input)
if value.result:
return value
if exception is not None:
if callable(exception):
raise exception(input)
else:
raise exception
input.reset(snap)
return ParseResult.FAIL()
return Parser(combinedParser, name=name, parsers=parsers)
# allOf -> a b c ...
@staticmethod @staticmethod
def allOf(*parsers, createNode, exception=None, name="all"): 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 DecoratorParser(Parser):
def __init__(self, wrapper, parser):
super().__init__(parser.name)
self.wrapper = wrapper
self.parser = parser
self._grammarRules = parser._grammarRules
def _parse(self, input):
result = self.parser.parse(input)
return self.wrapper(result)
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: if len(parsers) == 0:
raise RuntimeError("Pass one parser at least") raise RuntimeError("Pass one parser at least")
def extendedParser(input): self.parsers = parsers
snap = input.snapshot() self.createNode = createNode
self.exception = exception
results = [] def _parse(self, input):
snap = input.snapshot()
parsedItems = []
for parser in parsers: for parser in self.parsers:
result = parser(input) result = parser.parse(input)
if not result.result:
if exception is not None:
if callable(exception):
raise exception(input)
else:
raise exception
input.reset(snap)
return ParseResult.FAIL()
results.append(result.node)
node = createNode(*results)
if not isinstance(node, Node):
raise RuntimeError("Function 'createNode' haven't returned a Node object. Probably forget to pass 'return'")
return ParseResult.OK(node)
return Parser(extendedParser, name=name, parsers=parsers)
# leftAssociative -> left | left OP right
@staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name="leftAssoc"):
from smnp.ast.node.operator import Operator
def parse(input):
operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: Operator.withChildren([val], pos))
left = leftParser(input)
if left.result:
operator = operatorParser(input)
while operator.result:
right = rightParser(input)
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
operator = operatorParser(input)
return left
return ParseResult.FAIL()
return Parser(parse, name=name, parsers=[leftParser, '|'.join([t.value for t in operatorTokenTypes]), rightParser])
@staticmethod
def oneOfTerminals(*tokenTypes, createNode=None):
return Parser.oneOf(*[ Parser.terminalParser(expectedType, createNode=createNode) for expectedType in tokenTypes ], name='|'.join([t.value for t in tokenTypes]))
# loop -> start item* end
@staticmethod
def loop(startParser, itemParser, endParser, createNode, name="loop"):
def parse(input):
items = []
start = startParser(input)
if start.result:
while True:
end = endParser(input)
if end.result:
return ParseResult.OK(createNode(start.node, items, end.node))
item = itemParser(input)
if not item.result:
return ParseResult.FAIL()
items.append(item.node)
return ParseResult.FAIL()
return Parser(parse, name, parsers=[startParser, itemParser, endParser])
@staticmethod
def doAssert(parser, expected, name="!!"):
def parse(input):
result = parser(input)
if not result.result: if not result.result:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else '' if self.exception is not None:
if callable(self.exception):
raise self.exception(input)
else:
raise self.exception
raise SyntaxException(f"Expected {expected}{found}", input.currentPos()) 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 result
return Parser(parse, name, parsers=parser) return ParseResult.OK(NoneNode())
@staticmethod def _grammarRules(self, output):
def optional(parser, name="??"): output.append(f"{self.name} -> {self.parser.name}?")
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
return Parser(parse, name, parsers=[parser]) 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
@staticmethod def _parse(self, input):
def epsilon(): items = []
return lambda *args: ParseResult.OK(NoneNode()) start = self.startParser.parse(input)
if start.result:
@staticmethod
def many(parser, createNode, name="*"):
def parse(input):
results = []
snap = input.snapshot()
pos = input.currentPos()
while True: while True:
result = parser(input) end = self.endParser.parse(input)
if result.result: if end.result:
results.append(result.node) return ParseResult.OK(self.createNode(start.node, items, end.node))
snap = input.snapshot() item = self.itemParser.parse(input)
else: if not item.result:
input.reset(snap) return ParseResult.FAIL()
return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode()) 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)
return Parser(parse, name, parsers=[parser])

View File

@@ -1,14 +1,32 @@
import sys from smnp.ast.node.atom import AtomParser
from smnp.ast.node.chain import ChainParser
from smnp.ast.node.list import ListParser
from smnp.ast.node.model import Node
from smnp.error.base import SmnpException from smnp.error.base import SmnpException
from smnp.program.interpreter import Interpreter from smnp.token.tokenizer import tokenize
def main(): def main():
try: try:
#stdLibraryEnv = loadStandardLibrary() # stdLibraryEnv = loadStandardLibrary()
Interpreter.interpretFile(sys.argv[1], printTokens=True, printAst=True, execute=False, baseEnvironment=None) # Interpreter.interpretFile(sys.argv[1], printTokens=True, printAst=True, execute=False, baseEnvironment=None)
#draft() # draft()
class TestNode(Node):
def __init__(self, children):
super().__init__((-1, -1))
self.children = children
tokens = tokenize(['[1, 2]'])
parser = ListParser()
#print(parser.grammar())
res = parser.parse(tokens)
print()
if res.result:
res.node.print()
else:
print("nie sparsowano")
except SmnpException as e: except SmnpException as e:
print(e.message()) print(e.message())

0
smnp/util/__init__.py Normal file
View File

14
smnp/util/singleton.py Normal file
View File

@@ -0,0 +1,14 @@
from smnp.ast.parser import Parser
def SingletonParser(function):
def wrapper(*args, **kwargs):
if not hasattr(function, 'instance'):
function.instance = function(*args, **kwargs)
if not isinstance(function.instance, Parser):
raise RuntimeError(f"Function {function.__name__} haven't returned Parser object")
return function.instance
return wrapper