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"
),
name="int"
) )
)(input)
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(
@SingletonParser
def ChainParser():
from smnp.ast.node.atom import AtomParser
itemParser = Parsers.oneOf(
ListParser, ListParser,
MapParser, #MapParser,
AtomParser, AtomParser,
) name="chainItem"
)
ChainParser = Parser.leftAssociativeOperatorParser(itemParser, [TokenType.DOT], itemParser, return Parsers.leftAssociativeOperatorParser(
lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right))) 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
@staticmethod
def terminalParser(expectedType, createNode=None, doAssert=False):
def provideNode(value, pos):
if createNode is None:
return IgnoredNode(pos)
return createNode(value, pos)
def parse(input): class Parsers:
if input.hasCurrent() and input.current().type == expectedType:
@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 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() token = input.current()
input.ahead() input.ahead()
return ParseResult.OK(provideNode(token.value, token.pos)) return ParseResult.OK(self.createNode(token.value, token.pos))
elif doAssert: elif self.doAssert:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else "" found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected '{expectedType.key}'{found}", input.currentPos()) raise SyntaxException(f"Expected '{self.expectedType.key}'{found}", input.currentPos())
return ParseResult.FAIL() return ParseResult.FAIL()
return Parser(parse, name=expectedType.name.lower())
# oneOf -> a | b | c | ...
@staticmethod class OneOfParser(Parser):
def oneOf(*parsers, exception=None, name="or"): def __init__(self, *parsers, name, exception=None):
def combinedParser(input): super().__init__(name)
self.parsers = parsers
self.exception = exception
def _parse(self, input):
snap = input.snapshot() snap = input.snapshot()
for parser in parsers: for parser in self.parsers:
value = parser(input) value = parser.parse(input)
if value.result: if value.result:
return value return value
input.reset(snap) # TODO sprawdzic, czy koneiczne !!!!!
if exception is not None: if self.exception is not None:
if callable(exception): if callable(self.exception):
raise exception(input) raise self.exception(input)
else: else:
raise exception raise self.exception
input.reset(snap)
return ParseResult.FAIL() return ParseResult.FAIL()
return Parser(combinedParser, name=name, parsers=parsers) 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)
# allOf -> a b c ...
@staticmethod
def allOf(*parsers, createNode, exception=None, name="all"):
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
self.createNode = createNode
self.exception = exception
def _parse(self, input):
snap = input.snapshot() snap = input.snapshot()
parsedItems = []
results = [] for parser in self.parsers:
result = parser.parse(input)
for parser in parsers:
result = parser(input)
if not result.result: if not result.result:
if exception is not None: if self.exception is not None:
if callable(exception): if callable(self.exception):
raise exception(input) raise self.exception(input)
else: else:
raise exception raise self.exception
input.reset(snap) input.reset(snap)
return ParseResult.FAIL() return ParseResult.FAIL()
results.append(result.node) parsedItems.append(result.node)
node = createNode(*results) node = self.createNode(*parsedItems)
if not isinstance(node, Node): if not isinstance(node, Node):
raise RuntimeError("Function 'createNode' haven't returned a Node object. Probably forget to pass 'return'") 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) return ParseResult.OK(node)
def _grammarRules(self, output):
return Parser(extendedParser, name=name, parsers=parsers) output.append(self.name + ' -> ' + ' '.join([ parser.name for parser in self.parsers ]))
[ parser._grammarRules(output) for parser in self.parsers ]
# leftAssociative -> left | left OP right class LeftAssociativeOperatorParser(Parser):
@staticmethod def __init__(self, leftParser, operatorTokenTypes, rightParser, createNode, name):
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name="leftAssoc"):
from smnp.ast.node.operator import Operator from smnp.ast.node.operator import Operator
def parse(input): super().__init__(name)
operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: Operator.withChildren([val], pos)) self.leftParser = leftParser
left = leftParser(input) 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: if left.result:
operator = operatorParser(input) operator = self.operatorParser.parse(input)
while operator.result: while operator.result:
right = rightParser(input) right = self.rightParser.parse(input)
left = ParseResult.OK(createNode(left.node, operator.node, right.node)) left = ParseResult.OK(self.createNode(left.node, operator.node, right.node))
operator = operatorParser(input) operator = self.operatorParser.parse(input)
return left return left
return ParseResult.FAIL() return ParseResult.FAIL()
return Parser(parse, name=name, parsers=[leftParser, '|'.join([t.value for t in operatorTokenTypes]), rightParser])
@staticmethod def _grammarRules(self, output):
def oneOfTerminals(*tokenTypes, createNode=None): output.append('\n'.join([f"{self.name} -> {self.leftParser.name} {operator.name.lower()} {self.rightParser.name} | {self.leftParser.name}" for operator in self.operators]))
return Parser.oneOf(*[ Parser.terminalParser(expectedType, createNode=createNode) for expectedType in tokenTypes ], name='|'.join([t.value for t in tokenTypes])) self.leftParser._grammarRules(output)
self.rightParser._grammarRules(output)
# loop -> start item* end
@staticmethod class ManyParser(Parser):
def loop(startParser, itemParser, endParser, createNode, name="loop"): def __init__(self, itemParser, createNode, name):
def parse(input): 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 = [] items = []
start = startParser(input) start = self.startParser.parse(input)
if start.result: if start.result:
while True: while True:
end = endParser(input) end = self.endParser.parse(input)
if end.result: if end.result:
return ParseResult.OK(createNode(start.node, items, end.node)) return ParseResult.OK(self.createNode(start.node, items, end.node))
item = itemParser(input) item = self.itemParser.parse(input)
if not item.result: if not item.result:
return ParseResult.FAIL() return ParseResult.FAIL()
items.append(item.node) items.append(item.node)
return ParseResult.FAIL() return ParseResult.FAIL()
return Parser(parse, name, parsers=[startParser, itemParser, endParser]) 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)
@staticmethod
def doAssert(parser, expected, name="!!"):
def parse(input):
result = parser(input)
if not result.result:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ''
raise SyntaxException(f"Expected {expected}{found}", input.currentPos())
return result
return Parser(parse, name, parsers=parser)
@staticmethod
def optional(parser, name="??"):
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
return Parser(parse, name, parsers=[parser])
@staticmethod
def epsilon():
return lambda *args: ParseResult.OK(NoneNode())
@staticmethod
def many(parser, createNode, name="*"):
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 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