diff --git a/smnp/ast/node/atom.py b/smnp/ast/node/atom.py index b1cfb6d..a4b2535 100644 --- a/smnp/ast/node/atom.py +++ b/smnp/ast/node/atom.py @@ -1,6 +1,7 @@ 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.util.singleton import SingletonParser class Atom(Node): @@ -43,52 +44,60 @@ class TypeLiteral(Atom): pass -def IntegerParser(input): - return Parser.oneOf( - Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), - Parser.allOf( - Parser.terminalParser(TokenType.MINUS), - Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), +@SingletonParser +def IntegerParser(): + return Parsers.oneOf( + Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), + Parsers.allOf( + 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), - name="negative integer" - ) - )(input) + name="negativeInteger" + ), + name="int" + ) -def StringParser(input): - return Parser.terminalParser(TokenType.STRING, createNode=StringLiteral.withValue)(input) +@SingletonParser +def StringParser(): + return Parsers.terminal(TokenType.STRING, createNode=StringLiteral.withValue) -def NoteParser(input): - return Parser.terminalParser(TokenType.NOTE, createNode=NoteLiteral.withValue)(input) +@SingletonParser +def NoteParser(): + return Parsers.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue) -def BoolParser(input): - return Parser.terminalParser(TokenType.BOOL, createNode=BoolLiteral.withValue)(input) +@SingletonParser +def BoolParser(): + return Parsers.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue) -def TypeParser(input): - return Parser.terminalParser(TokenType.TYPE, createNode=TypeLiteral.withValue)(input) +@SingletonParser +def TypeParser(): + return Parsers.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue) -def LiteralParser(input): - return Parser.oneOf( - IntegerParser, - StringParser, - NoteParser, - BoolParser, - TypeParser, +@SingletonParser +def LiteralParser(): + return Parsers.oneOf( + IntegerParser(), + StringParser(), + NoteParser(), + BoolParser(), + TypeParser(), name="literal" - )(input) + ) -def AtomParser(input): +@SingletonParser +def AtomParser(): from smnp.ast.node.identifier import IdentifierParser - return Parser.oneOf( - LiteralParser, - IdentifierParser, + return Parsers.oneOf( + LiteralParser(), + IdentifierParser(), name="atom" - )(input) + ) diff --git a/smnp/ast/node/chain.py b/smnp/ast/node/chain.py index 8137869..600bde6 100644 --- a/smnp/ast/node/chain.py +++ b/smnp/ast/node/chain.py @@ -1,21 +1,31 @@ -from smnp.ast.node.atom import AtomParser -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.valuable import Valuable -from smnp.ast.parser import Parser +from smnp.ast.parser import Parsers from smnp.token.type import TokenType +from smnp.util.singleton import SingletonParser class Chain(Valuable): 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" + ) diff --git a/smnp/ast/node/identifier.py b/smnp/ast/node/identifier.py index b66aff4..276032a 100644 --- a/smnp/ast/node/identifier.py +++ b/smnp/ast/node/identifier.py @@ -1,11 +1,10 @@ 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.none import NoneNode 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.util.singleton import SingletonParser class Identifier(Atom): @@ -49,24 +48,28 @@ class Assignment(BinaryOperator): pass -def IdentifierParser(input): - identifierLiteralParser = Parser.terminalParser(TokenType.IDENTIFIER, createNode=Identifier.withValue) +@SingletonParser +def IdentifierParser(): + identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue) - functionCallParser = Parser.allOf( + functionCallParser = Parsers.allOf( identifierLiteralParser, - abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser), - createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments) + #abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser), + createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments), + name="functionCall" ) - assignmentParser = Parser.allOf( + assignmentParser = Parsers.allOf( identifierLiteralParser, - Parser.terminalParser(TokenType.ASSIGN, createNode=Operator.withValue), - MaxPrecedenceExpressionParser, - createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr) + Parsers.terminal(TokenType.ASSIGN, createNode=Operator.withValue), + #MaxPrecedenceExpressionParser, + createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr), + name="assignment" ) - return Parser.oneOf( + return Parsers.oneOf( assignmentParser, functionCallParser, - identifierLiteralParser - )(input) + identifierLiteralParser, + name="idExpr" + ) diff --git a/smnp/ast/node/iterable.py b/smnp/ast/node/iterable.py index a7d6ba3..7f39ef9 100644 --- a/smnp/ast/node/iterable.py +++ b/smnp/ast/node/iterable.py @@ -1,11 +1,11 @@ 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.ast.parser import Parsers from smnp.token.type import TokenType -def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser): +def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser, name): class AbstractIterable(Node): def __init__(self, pos): @@ -32,9 +32,10 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item pass def abstractIterableParser(input): - return Parser.oneOf( + return Parsers.oneOf( emptyIterable, - openIterable + openIterable, + name=name )(input) def emptyIterable(input): @@ -44,10 +45,11 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item node.next = close return node - return Parser.allOf( - Parser.terminalParser(openTokenType), - Parser.terminalParser(closeTokenType), - createNode=createNode + return Parsers.allOf( + Parsers.terminal(openTokenType), + Parsers.terminal(closeTokenType), + createNode=createNode, + name=name+"Empty" )(input) def openIterable(input): @@ -57,17 +59,19 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item node.next = tail return node - return Parser.allOf( - Parser.terminalParser(openTokenType), + return Parsers.allOf( + Parsers.terminal(openTokenType), itemParser, abstractIterableTailParser, - createNode=createNode + createNode=createNode, + name=name+"Open" )(input) def abstractIterableTailParser(input): - return Parser.oneOf( + return Parsers.oneOf( closeIterable, nextItem, + name=name+"Tail" )(input) def nextItem(input): @@ -77,15 +81,16 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item node.next = tail return node - return Parser.allOf( - Parser.terminalParser(TokenType.COMMA, doAssert=True), + return Parsers.allOf( + Parsers.terminal(TokenType.COMMA, doAssert=True), itemParser, abstractIterableTailParser, + name=name+"NextItem", createNode=createNode )(input) def closeIterable(input): - return Parser.terminalParser(closeTokenType)(input) + return Parsers.terminal(closeTokenType)(input) return toFlatDesiredNode(iterableNodeType, abstractIterableParser) @@ -105,7 +110,7 @@ def toFlatDesiredNode(iterableNodeType, parser): return ParseResult.FAIL() - return Parser(parse, "flat", [parser]) + #return Parser(parse, "flat", [parser]) def flattenList(node, output=None): diff --git a/smnp/ast/node/map.py b/smnp/ast/node/map.py index 0f8c19f..7bf3a00 100644 --- a/smnp/ast/node/map.py +++ b/smnp/ast/node/map.py @@ -1,8 +1,7 @@ -from smnp.ast.node.atom import LiteralParser from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.model import Node 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 @@ -30,17 +29,19 @@ class Map(Node): 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 - valueParser = MaxPrecedenceExpressionParser + #valueParser = MaxPrecedenceExpressionParser - mapEntryParser = Parser.allOf( + mapEntryParser = Parsers.allOf( keyParser, - Parser.terminalParser(TokenType.ARROW, createNode=Operator.withValue), - valueParser, - createNode=MapEntry.withValues + Parsers.terminal(TokenType.ARROW, createNode=Operator.withValue), + #valueParser, + 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) diff --git a/smnp/main.py b/smnp/main.py index 0763671..831e78a 100644 --- a/smnp/main.py +++ b/smnp/main.py @@ -1,8 +1,7 @@ +from smnp.ast.node.atom import AtomParser from smnp.ast.node.model import Node -from smnp.ast.parser import TerminalParser, OneOfParser, AllOfParser, OptionalParser, LoopParser from smnp.error.base import SmnpException from smnp.token.tokenizer import tokenize -from smnp.token.type import TokenType def main(): @@ -16,24 +15,8 @@ def main(): super().__init__((-1, -1)) self.children = children - tokens = tokenize(['{*1^*1^}']) - parser = LoopParser( - TerminalParser(TokenType.OPEN_CURLY), - AllOfParser( - OneOfParser( - TerminalParser(TokenType.ASSIGN), - TerminalParser(TokenType.ASTERISK), - name="assignOrAsterisk" - ), - OptionalParser(TerminalParser(TokenType.INTEGER), name="optInt"), - TerminalParser(TokenType.DASH), - name="aoaInt", - createNode=lambda a, b, c: TestNode([a, b, c]) - ), - TerminalParser(TokenType.CLOSE_CURLY), - createNode=lambda a, b, c: TestNode([a, b, c]), - name="block", - ) + tokens = tokenize(['"fsfsvd" "Fsefs"']) + parser = AtomParser() print(parser.grammar()) res = parser.parse(tokens) diff --git a/smnp/util/__init__.py b/smnp/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smnp/util/singleton.py b/smnp/util/singleton.py new file mode 100644 index 0000000..2c2da80 --- /dev/null +++ b/smnp/util/singleton.py @@ -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 \ No newline at end of file