Compare commits
4 Commits
master
...
new-parser
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49e4c4487e | ||
|
|
e7674a4834 | ||
|
|
ed2c8dc6dd | ||
|
|
f91e2a75de |
@@ -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)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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])
|
|
||||||
|
|||||||
30
smnp/main.py
30
smnp/main.py
@@ -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
0
smnp/util/__init__.py
Normal file
14
smnp/util/singleton.py
Normal file
14
smnp/util/singleton.py
Normal 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
|
||||||
Reference in New Issue
Block a user