Remove old parser and move new parser to 'ast' package
This commit is contained in:
@@ -1,10 +1,54 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.ignore import IgnoredNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class AccessNode(Node):
|
class AccessNode(ExpressionNode):
|
||||||
def __init__(self, element, property, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.extend([element, property])
|
self.children.append(IgnoredNode(pos))
|
||||||
|
|
||||||
self.element = self.children[0]
|
@property
|
||||||
self.property = self.children[1]
|
def left(self):
|
||||||
|
return self[0]
|
||||||
|
|
||||||
|
@left.setter
|
||||||
|
def left(self, value):
|
||||||
|
self[0] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def right(self):
|
||||||
|
return self[1]
|
||||||
|
|
||||||
|
@right.setter
|
||||||
|
def right(self, value):
|
||||||
|
self[1] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
def createNode(left, right):
|
||||||
|
node = AccessNode(right.pos)
|
||||||
|
node.left = left
|
||||||
|
node.right = right
|
||||||
|
return node
|
||||||
|
|
||||||
|
return Parser.leftAssociativeOperatorParser(
|
||||||
|
cls._literalParser(),
|
||||||
|
TokenType.DOT,
|
||||||
|
cls._parseAccessingProperty(),
|
||||||
|
createNode=createNode
|
||||||
|
)(input)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _literalParser(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parseAccessingProperty():
|
||||||
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
|
|
||||||
|
return Parser.oneOf(
|
||||||
|
IdentifierNode._literalParser(),
|
||||||
|
IdentifierNode._functionCallParser()
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
from smnp.newast.node.iterable import abstractIterableParser
|
from smnp.ast.node.iterable import abstractIterableParser
|
||||||
from smnp.newast.node.model import Node
|
from smnp.ast.node.model import Node
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.none import NoneNode
|
||||||
|
|
||||||
|
|
||||||
class AssignmentNode(Node):
|
class AssignmentNode(ExpressionNode):
|
||||||
def __init__(self, target, value, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.extend([target, value])
|
self.children.append(NoneNode())
|
||||||
|
|
||||||
self.target = self.children[0]
|
@property
|
||||||
self.value = self.children[1]
|
def target(self):
|
||||||
|
return self[0]
|
||||||
|
|
||||||
|
@target.setter
|
||||||
|
def target(self, value):
|
||||||
|
self[0] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
return self[1]
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
def value(self, value):
|
||||||
|
self[1] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
raise RuntimeError("This class is not supposed to be automatically called")
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.none import NoneNode
|
||||||
|
from smnp.ast.node.statement import StatementNode
|
||||||
|
|
||||||
|
|
||||||
class AsteriskNode(Node):
|
class AsteriskNode(StatementNode):
|
||||||
def __init__(self, iterator, statement, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.extend([iterator, statement])
|
self.children = [NoneNode(), NoneNode()]
|
||||||
|
|
||||||
self.iterator = self.children[0]
|
@property
|
||||||
self.statement = self.children[1]
|
def iterator(self):
|
||||||
|
return self[0]
|
||||||
|
|
||||||
|
@iterator.setter
|
||||||
|
def iterator(self, value):
|
||||||
|
self[0] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def statement(self):
|
||||||
|
return self[1]
|
||||||
|
|
||||||
|
@statement.setter
|
||||||
|
def statement(self, value):
|
||||||
|
self[1] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
raise RuntimeError("This class is not supposed to be automatically called")
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.statement import StatementNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class BlockNode(Node):
|
class BlockNode(StatementNode):
|
||||||
pass
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
def createNode(start, items, end):
|
||||||
|
node = BlockNode(start.pos)
|
||||||
|
node.children = items
|
||||||
|
return node
|
||||||
|
|
||||||
class BlockItemNode(Node):
|
return Parser.loop(
|
||||||
def __init__(self, statement, parent, pos):
|
Parser.terminalParser(TokenType.OPEN_BRACKET),
|
||||||
Node.__init__(self, parent, pos)
|
StatementNode.parse,
|
||||||
self.children.append(statement)
|
Parser.terminalParser(TokenType.CLOSE_BRACKET),
|
||||||
|
createNode=createNode
|
||||||
self.statement = self.children[0]
|
)(input)
|
||||||
|
|
||||||
|
|
||||||
class CloseBlockNode(Node):
|
|
||||||
pass
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
from smnp.ast.node.model import Node
|
|
||||||
|
|
||||||
|
|
||||||
class ColonNode(Node):
|
|
||||||
def __init__(self, a, b, parent, pos):
|
|
||||||
Node.__init__(self, parent, pos)
|
|
||||||
self.children.extend([a, b])
|
|
||||||
|
|
||||||
self.a = self.children[0]
|
|
||||||
self.b = self.children[1]
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from smnp.newast.node.asterisk import AsteriskNode
|
from smnp.ast.node.asterisk import AsteriskNode
|
||||||
from smnp.newast.node.model import Node
|
from smnp.ast.node.model import Node
|
||||||
from smnp.newast.node.none import NoneNode
|
from smnp.ast.node.none import NoneNode
|
||||||
from smnp.newast.node.statement import StatementNode
|
from smnp.ast.node.statement import StatementNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -50,11 +50,11 @@ class ExpressionNode(Node):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _expressionParser(cls):
|
def _expressionParser(cls):
|
||||||
from smnp.newast.node.integer import IntegerLiteralNode
|
from smnp.ast.node.integer import IntegerLiteralNode
|
||||||
from smnp.newast.node.string import StringLiteralNode
|
from smnp.ast.node.string import StringLiteralNode
|
||||||
from smnp.newast.node.note import NoteLiteralNode
|
from smnp.ast.node.note import NoteLiteralNode
|
||||||
from smnp.newast.node.identifier import IdentifierNode
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
from smnp.newast.node.list import ListNode
|
from smnp.ast.node.list import ListNode
|
||||||
|
|
||||||
return Parser.oneOf(
|
return Parser.oneOf(
|
||||||
IntegerLiteralNode.parse,
|
IntegerLiteralNode.parse,
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from smnp.newast.node.block import BlockNode
|
from smnp.ast.node.block import BlockNode
|
||||||
from smnp.newast.node.function import FunctionDefinitionNode
|
from smnp.ast.node.function import FunctionDefinitionNode
|
||||||
from smnp.newast.node.identifier import IdentifierNode
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
from smnp.newast.node.none import NoneNode
|
from smnp.ast.node.none import NoneNode
|
||||||
from smnp.newast.node.statement import StatementNode
|
from smnp.ast.node.statement import StatementNode
|
||||||
from smnp.newast.node.type import TypeNode
|
from smnp.ast.node.type import TypeNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +1,67 @@
|
|||||||
|
from smnp.ast.node.block import BlockNode
|
||||||
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
|
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.statement import StatementNode
|
||||||
|
from smnp.ast.node.variable import TypedVariableNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class FunctionCallNode(Node):
|
class ArgumentsDeclarationNode(Node):
|
||||||
def __init__(self, identifier, arguments, parent, pos):
|
|
||||||
Node.__init__(self, parent, pos)
|
|
||||||
self.children.extend([identifier, arguments])
|
|
||||||
|
|
||||||
self.identifier = self.children[0]
|
@classmethod
|
||||||
self.arguments = self.children[1]
|
def _parse(cls, input):
|
||||||
|
raise RuntimeError("This class is not supposed to be automatically called")
|
||||||
|
|
||||||
|
|
||||||
class FunctionDefinitionNode(Node):
|
class FunctionDefinitionNode(StatementNode):
|
||||||
def __init__(self, name, parameters, body, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.extend([name, parameters, body])
|
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||||
|
|
||||||
self.name = self.children[0]
|
@property
|
||||||
self.parameters = self.children[1]
|
def name(self):
|
||||||
self.body = self.children[2]
|
return self[0]
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
self[0] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def arguments(self):
|
||||||
|
return self[1]
|
||||||
|
|
||||||
|
@arguments.setter
|
||||||
|
def arguments(self, value):
|
||||||
|
self[1] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body(self):
|
||||||
|
return self[2]
|
||||||
|
|
||||||
|
@body.setter
|
||||||
|
def body(self, value):
|
||||||
|
self[2] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
def createNode(function, name, arguments, body):
|
||||||
|
node = FunctionDefinitionNode(function.pos)
|
||||||
|
node.name = name
|
||||||
|
node.arguments = arguments
|
||||||
|
node.body = body
|
||||||
|
return node
|
||||||
|
|
||||||
|
return Parser.allOf(
|
||||||
|
Parser.terminalParser(TokenType.FUNCTION),
|
||||||
|
IdentifierNode.identifierParser(),
|
||||||
|
cls._argumentsDeclarationParser(),
|
||||||
|
BlockNode.parse,
|
||||||
|
createNode=createNode
|
||||||
|
)(input)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _argumentsDeclarationParser():
|
||||||
|
return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, TypedVariableNode.parser())
|
||||||
@@ -1,9 +1,54 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.access import AccessNode
|
||||||
|
from smnp.ast.node.args import ArgumentsListNode
|
||||||
|
from smnp.ast.node.assignment import AssignmentNode
|
||||||
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.invocation import FunctionCall
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class IdentifierNode(Node):
|
class IdentifierNode(AccessNode):
|
||||||
def __init__(self, identifier, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.append(identifier)
|
del self.children[1]
|
||||||
|
|
||||||
self.identifier = self.children[0]
|
@classmethod
|
||||||
|
def _literalParser(cls):
|
||||||
|
return Parser.oneOf(
|
||||||
|
IdentifierNode._functionCallParser(),
|
||||||
|
IdentifierNode._assignmentParser(),
|
||||||
|
IdentifierNode.identifierParser()
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assignmentParser():
|
||||||
|
def createNode(target, assignment, value):
|
||||||
|
node = AssignmentNode(assignment.pos)
|
||||||
|
node.target = target
|
||||||
|
node.value = value
|
||||||
|
return node
|
||||||
|
|
||||||
|
return Parser.allOf(
|
||||||
|
IdentifierNode.identifierParser(),
|
||||||
|
Parser.terminalParser(TokenType.ASSIGN),
|
||||||
|
ExpressionNode.parse,
|
||||||
|
createNode=createNode
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _functionCallParser():
|
||||||
|
def createNode(name, arguments):
|
||||||
|
node = FunctionCall(name.pos)
|
||||||
|
node.name = name
|
||||||
|
node.arguments = arguments
|
||||||
|
return node
|
||||||
|
|
||||||
|
return Parser.allOf(
|
||||||
|
IdentifierNode.identifierParser(),
|
||||||
|
ArgumentsListNode.parse,
|
||||||
|
createNode=createNode
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def identifierParser():
|
||||||
|
return Parser.terminalParser(TokenType.IDENTIFIER, lambda val, pos: IdentifierNode.withValue(val, pos))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from smnp.newast.node.model import Node
|
from smnp.ast.node.model import Node
|
||||||
|
|
||||||
|
|
||||||
class IgnoredNode(Node):
|
class IgnoredNode(Node):
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
from smnp.newast.node.identifier import IdentifierNode
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
from smnp.newast.node.model import Node
|
from smnp.ast.node.model import Node
|
||||||
from smnp.newast.node.none import NoneNode
|
from smnp.ast.node.none import NoneNode
|
||||||
from smnp.newast.node.string import StringLiteralNode
|
from smnp.ast.node.string import StringLiteralNode
|
||||||
from smnp.newast.node.type import TypeNode
|
from smnp.ast.node.type import TypeNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +1,31 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.access import AccessNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class IntegerLiteralNode(Node):
|
class IntegerLiteralNode(AccessNode):
|
||||||
def __init__(self, value, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.append(value)
|
del self.children[1]
|
||||||
|
|
||||||
self.value = self.children[0]
|
@classmethod
|
||||||
|
def _literalParser(cls):
|
||||||
|
return Parser.oneOf(
|
||||||
|
cls._negativeIntegerParser(),
|
||||||
|
cls._positiveIntegerParser()
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _negativeIntegerParser(cls):
|
||||||
|
def createNode(minus, integer):
|
||||||
|
return IntegerLiteralNode.withValue(-integer.value, minus.pos)
|
||||||
|
|
||||||
|
return Parser.allOf(
|
||||||
|
Parser.terminalParser(TokenType.MINUS),
|
||||||
|
cls._positiveIntegerParser(),
|
||||||
|
createNode=createNode
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _positiveIntegerParser(cls):
|
||||||
|
return Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteralNode.withValue(int(val), pos))
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
from smnp.ast.node.access import AccessNode
|
||||||
|
|
||||||
|
|
||||||
class FunctionCall(AccessNode):
|
class FunctionCall(AccessNode):
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
from smnp.newast.node.ignore import IgnoredNode
|
from smnp.ast.node.ignore import IgnoredNode
|
||||||
from smnp.newast.node.model import Node, ParseResult
|
from smnp.ast.node.model import Node, ParseResult
|
||||||
from smnp.newast.node.none import NoneNode
|
from smnp.ast.node.none import NoneNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +1,11 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.access import AccessNode
|
||||||
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.iterable import abstractIterableParser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class ListNode(Node):
|
class ListNode(AccessNode):
|
||||||
pass
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
class ListItemNode(Node):
|
def _literalParser(cls):
|
||||||
def __init__(self, value, parent, pos):
|
return abstractIterableParser(ListNode, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, ExpressionNode.parse)
|
||||||
Node.__init__(self, parent, pos)
|
|
||||||
self.children.append(value)
|
|
||||||
|
|
||||||
self.value = self.children[0]
|
|
||||||
|
|
||||||
|
|
||||||
class CloseListNode(Node):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
class LiteralNode(ExpressionNode):
|
class LiteralNode(ExpressionNode):
|
||||||
@@ -1,44 +1,81 @@
|
|||||||
from smnp.note.model import Note
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, parent, pos):
|
def __init__(self, pos, children=None):
|
||||||
self.children = []
|
if children is None:
|
||||||
self.parent = parent
|
children = []
|
||||||
|
self.children = children
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
|
self.parent = None
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
child.parent = self
|
if isinstance(child, Node):
|
||||||
|
child.parent = self
|
||||||
def __repr__(self):
|
|
||||||
return self.__str__()
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.children)
|
return len(self.children)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, key):
|
||||||
return self.children[index]
|
return self.children[key]
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if isinstance(value, Node):
|
||||||
|
value.parent = self
|
||||||
|
self.children[key] = value
|
||||||
|
|
||||||
def append(self, node):
|
def append(self, node):
|
||||||
node.parent = self
|
if isinstance(node, Node):
|
||||||
|
node.parent = self
|
||||||
self.children.append(node)
|
self.children.append(node)
|
||||||
|
|
||||||
def pop(self, index):
|
def pop(self, index):
|
||||||
return self.children.pop(index)
|
return self.children.pop(index)
|
||||||
|
|
||||||
def print(self):
|
@classmethod
|
||||||
print(self._print(0))
|
def _parse(cls, input):
|
||||||
|
pass
|
||||||
|
|
||||||
def _print(self, level):
|
@classmethod
|
||||||
string = f"{pad(level)}{self.__class__.__name__}({self.parent.__class__.__name__}):\n"
|
def parse(cls, input):
|
||||||
for child in self.children:
|
result = cls._parse(input)
|
||||||
if isinstance(child, str) or isinstance(child, int) or isinstance(child, Note):
|
if result is None:
|
||||||
string += pad(level + 1) + f"'{child}'\n"
|
return ParseResult.FAIL()
|
||||||
|
|
||||||
|
if not isinstance(result, ParseResult):
|
||||||
|
raise RuntimeError(f"_parse() method of '{cls.__name__}' class haven't returned ParseResult object")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
self._print(first=True)
|
||||||
|
|
||||||
|
def _print(self, prefix="", last=True, first=False):
|
||||||
|
print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, sep="")
|
||||||
|
prefix += ' ' if last else '│ '
|
||||||
|
for i, child in enumerate(self.children):
|
||||||
|
last = i == len(self.children) - 1
|
||||||
|
if isinstance(child, Node):
|
||||||
|
child._print(prefix, last)
|
||||||
else:
|
else:
|
||||||
string += child._print(level + 1)
|
print(prefix, '└' if last else '├', f"'{str(child)}'", sep="")
|
||||||
return string
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self._print(0)
|
return self.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
|
class ParseResult():
|
||||||
|
def __init__(self, result, node):
|
||||||
|
if result and node is None:
|
||||||
|
raise RuntimeError("Node musn't be None if result is set to True for ParseResult")
|
||||||
|
self.result = result
|
||||||
|
self.node = node
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def FAIL():
|
||||||
|
return ParseResult(False, None)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def OK(node):
|
||||||
|
return ParseResult(True, node)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{'OK' if self.result else 'FAILED'}[{self.node}]"
|
||||||
|
|
||||||
|
|
||||||
def pad(level):
|
|
||||||
return " " * level
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from smnp.newast.node.model import Node
|
from smnp.ast.node.model import Node
|
||||||
|
|
||||||
|
|
||||||
class NoneNode(Node):
|
class NoneNode(Node):
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.access import AccessNode
|
||||||
|
from smnp.ast.node.literal import LiteralNode
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class NoteLiteralNode(Node):
|
class NoteLiteralNode(LiteralNode, AccessNode):
|
||||||
def __init__(self, value, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.append(value)
|
del self.children[1]
|
||||||
|
|
||||||
self.value = self.children[0]
|
@classmethod
|
||||||
|
def _getTokenType(cls):
|
||||||
|
return TokenType.NOTE
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from smnp.ast.node.model import Node
|
|
||||||
|
|
||||||
|
|
||||||
class PercentNode(Node):
|
|
||||||
def __init__(self, value, parent, pos):
|
|
||||||
Node.__init__(self, parent, pos)
|
|
||||||
self.children.append(value)
|
|
||||||
|
|
||||||
self.value = self.children[0]
|
|
||||||
@@ -1,6 +1,32 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.extend import ExtendNode
|
||||||
|
from smnp.ast.node.function import FunctionDefinitionNode
|
||||||
|
from smnp.ast.node.imports import ImportNode
|
||||||
|
from smnp.ast.node.model import Node, ParseResult
|
||||||
|
from smnp.ast.node.statement import StatementNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.error.syntax import SyntaxException
|
||||||
|
|
||||||
|
|
||||||
class Program(Node):
|
class Program(Node):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Node.__init__(self, None, (-1, -1))
|
super().__init__((-1, -1))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
def parseToken(input):
|
||||||
|
return Parser.oneOf(
|
||||||
|
FunctionDefinitionNode.parse,
|
||||||
|
ExtendNode.parse,
|
||||||
|
ExpressionNode.parse,
|
||||||
|
ImportNode.parse,
|
||||||
|
StatementNode.parse,
|
||||||
|
exception = SyntaxException(f"Unknown statement: {input.current().pos}")
|
||||||
|
)(input)
|
||||||
|
|
||||||
|
root = Program()
|
||||||
|
while input.hasCurrent():
|
||||||
|
result = parseToken(input)
|
||||||
|
if result.result:
|
||||||
|
root.append(result.node)
|
||||||
|
return ParseResult.OK(root)
|
||||||
@@ -1,9 +1,32 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.none import NoneNode
|
||||||
|
from smnp.ast.node.statement import StatementNode
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class ReturnNode(Node):
|
class ReturnNode(StatementNode):
|
||||||
def __init__(self, value, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.append(value)
|
self.children.append(NoneNode())
|
||||||
|
|
||||||
self.value = self.children[0]
|
@property
|
||||||
|
def value(self):
|
||||||
|
return self[0]
|
||||||
|
|
||||||
|
@value.setter
|
||||||
|
def value(self, value):
|
||||||
|
self[0] = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
def createNode(ret, value):
|
||||||
|
node = ReturnNode(ret.pos)
|
||||||
|
node.value = value
|
||||||
|
return node
|
||||||
|
|
||||||
|
return Parser.allOf(
|
||||||
|
Parser.terminalParser(TokenType.RETURN),
|
||||||
|
ExpressionNode.parse,
|
||||||
|
createNode=createNode
|
||||||
|
)(input)
|
||||||
17
smnp/ast/node/statement.py
Normal file
17
smnp/ast/node/statement.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from smnp.ast.node.model import Node
|
||||||
|
from smnp.ast.parser import Parser
|
||||||
|
|
||||||
|
|
||||||
|
class StatementNode(Node):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, input):
|
||||||
|
from smnp.ast.node.block import BlockNode
|
||||||
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
|
from smnp.ast.node.ret import ReturnNode
|
||||||
|
|
||||||
|
return Parser.oneOf(
|
||||||
|
BlockNode.parse,
|
||||||
|
ReturnNode.parse,
|
||||||
|
ExpressionNode.parse
|
||||||
|
)(input)
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
from smnp.ast.node.model import Node
|
from smnp.ast.node.access import AccessNode
|
||||||
|
from smnp.ast.node.literal import LiteralNode
|
||||||
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
class StringLiteralNode(Node):
|
class StringLiteralNode(LiteralNode, AccessNode):
|
||||||
def __init__(self, value, parent, pos):
|
def __init__(self, pos):
|
||||||
Node.__init__(self, parent, pos)
|
super().__init__(pos)
|
||||||
self.children.append(value)
|
del self.children[1]
|
||||||
|
|
||||||
self.value = self.children[0]
|
@classmethod
|
||||||
|
def _getTokenType(cls):
|
||||||
|
return TokenType.STRING
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
from smnp.ast.node.access import AccessNode
|
||||||
from smnp.newast.node.literal import LiteralNode
|
from smnp.ast.node.literal import LiteralNode
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
from smnp.ast.node.expression import ExpressionNode
|
||||||
from smnp.newast.node.identifier import IdentifierNode
|
from smnp.ast.node.identifier import IdentifierNode
|
||||||
from smnp.newast.node.none import NoneNode
|
from smnp.ast.node.none import NoneNode
|
||||||
from smnp.newast.node.type import TypeNode
|
from smnp.ast.node.type import TypeNode
|
||||||
from smnp.newast.parser import Parser
|
from smnp.ast.parser import Parser
|
||||||
from smnp.token.type import TokenType
|
from smnp.token.type import TokenType
|
||||||
|
|
||||||
class TypedVariableNode(ExpressionNode):
|
class TypedVariableNode(ExpressionNode):
|
||||||
@@ -1,12 +1,115 @@
|
|||||||
|
from smnp.ast.node.ignore import IgnoredNode
|
||||||
|
from smnp.ast.node.model import ParseResult, Node
|
||||||
from smnp.ast.node.program import Program
|
from smnp.ast.node.program import Program
|
||||||
from smnp.ast.parsers.token import parseToken
|
|
||||||
|
|
||||||
|
|
||||||
def parse(input):
|
def parse(input):
|
||||||
root = Program()
|
return Program.parse(input)
|
||||||
while input.hasCurrent():
|
|
||||||
root.append(parseToken(input, root))
|
class Parser:
|
||||||
return root
|
|
||||||
|
# a -> A
|
||||||
|
@staticmethod
|
||||||
|
def terminalParser(expectedType, createNode=None):
|
||||||
|
def provideNode(value, pos):
|
||||||
|
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))
|
||||||
|
return ParseResult.FAIL()
|
||||||
|
|
||||||
|
return parse
|
||||||
|
|
||||||
|
# oneOf -> a | b | c | ...
|
||||||
|
@staticmethod
|
||||||
|
def oneOf(*parsers, exception=None):
|
||||||
|
def combinedParser(input):
|
||||||
|
snap = input.snapshot()
|
||||||
|
for parser in parsers:
|
||||||
|
value = parser(input)
|
||||||
|
if value.result:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if exception is not None:
|
||||||
|
raise exception
|
||||||
|
|
||||||
|
input.reset(snap)
|
||||||
|
return ParseResult.FAIL()
|
||||||
|
|
||||||
|
return combinedParser
|
||||||
|
|
||||||
|
# allOf -> a b c ...
|
||||||
|
@staticmethod
|
||||||
|
def allOf(*parsers, createNode, exception=None):
|
||||||
|
if len(parsers) == 0:
|
||||||
|
raise RuntimeError("Pass one parser at least")
|
||||||
|
|
||||||
|
def extendedParser(input):
|
||||||
|
snap = input.snapshot()
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for parser in parsers:
|
||||||
|
result = parser(input)
|
||||||
|
|
||||||
|
if not result.result:
|
||||||
|
if exception is not None:
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["parse"]
|
|
||||||
|
return extendedParser
|
||||||
|
|
||||||
|
|
||||||
|
# leftAssociative -> left | left OP right
|
||||||
|
@staticmethod
|
||||||
|
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
|
||||||
|
def parse(input):
|
||||||
|
left = leftParser(input)
|
||||||
|
if left.result:
|
||||||
|
while Parser.terminalParser(operatorTokenType)(input).result:
|
||||||
|
right = rightParser(input)
|
||||||
|
left = ParseResult.OK(createNode(left.node, right.node))
|
||||||
|
|
||||||
|
return left
|
||||||
|
|
||||||
|
return ParseResult.FAIL()
|
||||||
|
|
||||||
|
return parse
|
||||||
|
|
||||||
|
# loop -> start item* end
|
||||||
|
@staticmethod
|
||||||
|
def loop(startParser, itemParser, endParser, createNode):
|
||||||
|
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 parse
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
from smnp.ast.node.access import AccessNode
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# access -> expr '.' expr
|
|
||||||
# TODO: dodać dziedziczenie wszystkich expressions po jednym typie ExpressionNode
|
|
||||||
# i potem sprawdzać przy wszystkich parent.pop(-1) czy pobrany z parenta element
|
|
||||||
# jest rzeczywiście wyrażeniem, bo teraz możliwe jest np. {}.fun()
|
|
||||||
def parseAccess(input, parent):
|
|
||||||
if input.isCurrent(TokenType.DOT):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
element = parent.pop(-1)
|
|
||||||
|
|
||||||
property = parseExpression(input, parent)
|
|
||||||
|
|
||||||
node = AccessNode(element, property, parent, token.pos)
|
|
||||||
element.parent = node
|
|
||||||
property.parent = node
|
|
||||||
|
|
||||||
return node
|
|
||||||
return None
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
from smnp.ast.node.asterisk import AsteriskNode
|
|
||||||
from smnp.ast.parsers.statement import parseStatement
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# asterisk -> expr '*' stmt
|
|
||||||
def parseAsterisk(expr, input, parent):
|
|
||||||
if input.hasMore() and input.isCurrent(TokenType.ASTERISK):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
stmt = parseStatement(input, parent)
|
|
||||||
|
|
||||||
asterisk = AsteriskNode(expr, stmt, parent, token.pos)
|
|
||||||
expr.parent = asterisk
|
|
||||||
stmt.parent = asterisk
|
|
||||||
return asterisk
|
|
||||||
return None
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
from smnp.ast.node.block import BlockNode, CloseBlockNode, BlockItemNode
|
|
||||||
from smnp.ast.parsers.statement import parseStatement
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
def parseBlock(input, parent):
|
|
||||||
# '{'
|
|
||||||
if input.current().type == TokenType.OPEN_BRACKET:
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
node = BlockNode(parent, token.pos)
|
|
||||||
|
|
||||||
# '}'
|
|
||||||
if input.isCurrent(TokenType.CLOSE_BRACKET):
|
|
||||||
input.ahead()
|
|
||||||
return node
|
|
||||||
|
|
||||||
# blockItem
|
|
||||||
if input.hasCurrent():
|
|
||||||
item = parseBlockItem(input, node)
|
|
||||||
node.append(item)
|
|
||||||
return node
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# blockItem -> stmt | '}'
|
|
||||||
def parseBlockItem(input, parent):
|
|
||||||
# '}'
|
|
||||||
if input.isCurrent(TokenType.CLOSE_BRACKET):
|
|
||||||
close = CloseBlockNode(parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
return close
|
|
||||||
|
|
||||||
if input.hasCurrent():
|
|
||||||
stmt = parseStatement(input, parent)
|
|
||||||
|
|
||||||
if stmt is not None:
|
|
||||||
item = BlockItemNode(stmt, parent, stmt.pos)
|
|
||||||
stmt.parent = item
|
|
||||||
nextBlockItem = parseBlockItem(input, item)
|
|
||||||
if nextBlockItem != None:
|
|
||||||
item.append(nextBlockItem)
|
|
||||||
return item
|
|
||||||
|
|
||||||
return None
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from smnp.ast.node.colon import ColonNode
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.error.syntax import SyntaxException
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# colon -> expr ':' expr
|
|
||||||
def parseColon(expr1, input, parent):
|
|
||||||
if input.isCurrent(TokenType.COLON):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
expr2 = parseExpression(input, parent)
|
|
||||||
|
|
||||||
if expr2 is None:
|
|
||||||
raise SyntaxException(f"Expected expression '{input.current().value}'", input.current().pos)
|
|
||||||
colon = ColonNode(expr1, expr2, parent, token.pos)
|
|
||||||
expr1.parent = colon
|
|
||||||
expr2.parent = colon
|
|
||||||
return colon
|
|
||||||
return None
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
def parseExpression(input, parent):
|
|
||||||
from smnp.ast.tools import combineParsers
|
|
||||||
from smnp.ast.parsers.access import parseAccess
|
|
||||||
from smnp.ast.parsers.colon import parseColon
|
|
||||||
from smnp.ast.parsers.identifier import parseIdentifierOrFunctionCallOrAssignment
|
|
||||||
from smnp.ast.parsers.integer import parseIntegerAndPercent
|
|
||||||
from smnp.ast.parsers.list import parseList
|
|
||||||
from smnp.ast.parsers.minus import parseMinus
|
|
||||||
from smnp.ast.parsers.note import parseNote
|
|
||||||
from smnp.ast.parsers.string import parseString
|
|
||||||
|
|
||||||
parsers = [
|
|
||||||
parseIntegerAndPercent,
|
|
||||||
parseMinus,
|
|
||||||
parseString,
|
|
||||||
parseNote,
|
|
||||||
parseList,
|
|
||||||
parseIdentifierOrFunctionCallOrAssignment,
|
|
||||||
parseAccess,
|
|
||||||
]
|
|
||||||
|
|
||||||
expr = combineParsers(parsers)(input, parent)
|
|
||||||
|
|
||||||
colon = parseColon(expr, input, parent)
|
|
||||||
if colon is not None:
|
|
||||||
return colon
|
|
||||||
|
|
||||||
return expr
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
from smnp.ast.node.function import FunctionDefinitionNode
|
|
||||||
from smnp.ast.parsers.block import parseBlock
|
|
||||||
from smnp.ast.parsers.identifier import parseIdentifier
|
|
||||||
from smnp.ast.parsers.list import parseList
|
|
||||||
from smnp.ast.tools import assertToken
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
def parseFunctionDefinition(input, parent):
|
|
||||||
if input.isCurrent(TokenType.FUNCTION):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
assertToken(TokenType.IDENTIFIER, input)
|
|
||||||
identifier = parseIdentifier(input, parent)
|
|
||||||
|
|
||||||
assertToken(TokenType.OPEN_PAREN, input)
|
|
||||||
args = parseList(input, parent)
|
|
||||||
|
|
||||||
assertToken(TokenType.OPEN_BRACKET, input)
|
|
||||||
body = parseBlock(input, parent)
|
|
||||||
|
|
||||||
function = FunctionDefinitionNode(identifier, args, body, parent, token.pos)
|
|
||||||
identifier.parent = function
|
|
||||||
args.parent = function
|
|
||||||
body.parent = function
|
|
||||||
|
|
||||||
return function
|
|
||||||
return None
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
from smnp.ast.node.assignment import AssignmentNode
|
|
||||||
from smnp.ast.node.function import FunctionCallNode
|
|
||||||
from smnp.ast.node.identifier import IdentifierNode
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.ast.parsers.list import parseList
|
|
||||||
from smnp.ast.tools import greedy
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# id -> IDENTIFIER
|
|
||||||
def parseIdentifier(input, parent):
|
|
||||||
if input.isCurrent(TokenType.IDENTIFIER):
|
|
||||||
identifier = IdentifierNode(input.current().value, parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
return identifier
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# identifier -> IDENTIFIER
|
|
||||||
# functionCall -> identifier list
|
|
||||||
# assignment -> identifier '=' expr
|
|
||||||
def parseIdentifierOrFunctionCallOrAssignment(input, parent):
|
|
||||||
identifier = parseIdentifier(input, parent)
|
|
||||||
|
|
||||||
# assignment -> identifier '=' expr
|
|
||||||
if identifier is not None and input.hasCurrent():
|
|
||||||
if input.current().type == TokenType.ASSIGN:
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
expr = greedy(parseExpression)(input, parent)
|
|
||||||
|
|
||||||
assignment = AssignmentNode(identifier, expr, parent, token.pos)
|
|
||||||
identifier.parent = assignment
|
|
||||||
expr.parent = assignment
|
|
||||||
|
|
||||||
return assignment
|
|
||||||
|
|
||||||
# functionCall -> identifier list
|
|
||||||
args = parseList(input, parent)
|
|
||||||
if args is not None:
|
|
||||||
functionCall = FunctionCallNode(identifier, args, parent, identifier.pos)
|
|
||||||
args.parent = functionCall
|
|
||||||
identifier.parent = functionCall
|
|
||||||
return functionCall
|
|
||||||
|
|
||||||
return identifier
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
from smnp.ast.node.integer import IntegerLiteralNode
|
|
||||||
from smnp.ast.node.percent import PercentNode
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# int -> INTEGER
|
|
||||||
def parseInteger(input, parent):
|
|
||||||
if input.isCurrent(TokenType.INTEGER):
|
|
||||||
integer = IntegerLiteralNode(int(input.current().value), parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
return integer
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# percent -> int '%'
|
|
||||||
# int -> int
|
|
||||||
def parseIntegerAndPercent(input, parent):
|
|
||||||
integer = parseInteger(input, parent)
|
|
||||||
if integer is not None and input.isCurrent(TokenType.PERCENT):
|
|
||||||
percent = PercentNode(integer, parent, input.current().pos)
|
|
||||||
integer.parent = percent
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
return percent
|
|
||||||
return integer
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from smnp.ast.node.list import ListNode, ListItemNode, CloseListNode
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.ast.tools import greedy, assertToken
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# list -> CLOSE_PAREN | expr listTail
|
|
||||||
def parseList(input, parent):
|
|
||||||
if input.isCurrent(TokenType.OPEN_PAREN):
|
|
||||||
node = ListNode(parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
# list -> CLOSE_PAREN (end of list)
|
|
||||||
if input.isCurrent(TokenType.CLOSE_PAREN):
|
|
||||||
close = CloseListNode(node, input.current().pos)
|
|
||||||
node.append(close)
|
|
||||||
input.ahead()
|
|
||||||
return node
|
|
||||||
|
|
||||||
# list -> expr listTail
|
|
||||||
if input.hasCurrent():
|
|
||||||
token = input.current()
|
|
||||||
expr = greedy(parseExpression)(input, parent)
|
|
||||||
item = ListItemNode(expr, node, token.pos)
|
|
||||||
expr.parent = item
|
|
||||||
node.append(item)
|
|
||||||
listTail = parseListTail(input, item)
|
|
||||||
item.append(listTail)
|
|
||||||
return node
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# listTail -> COMMA expr listTail | CLOSE_PAREN
|
|
||||||
def parseListTail(input, parent):
|
|
||||||
# listTail -> CLOSE_PAREN
|
|
||||||
if input.isCurrent(TokenType.CLOSE_PAREN):
|
|
||||||
close = CloseListNode(parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
return close
|
|
||||||
|
|
||||||
# listTail -> COMMA expr listTail
|
|
||||||
if input.hasCurrent() and input.hasMore():
|
|
||||||
assertToken(TokenType.COMMA, input)
|
|
||||||
input.ahead()
|
|
||||||
expr = greedy(parseExpression)(input, parent)
|
|
||||||
if expr is not None:
|
|
||||||
item = ListItemNode(expr, parent, expr.pos)
|
|
||||||
expr.parent = item
|
|
||||||
listTail = parseListTail(input, item)
|
|
||||||
item.append(listTail)
|
|
||||||
listTail.parent = item
|
|
||||||
return item
|
|
||||||
|
|
||||||
return None
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from smnp.ast.node.integer import IntegerLiteralNode
|
|
||||||
from smnp.ast.parsers.integer import parseInteger
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# minus -> '-' int
|
|
||||||
def parseMinus(input, parent):
|
|
||||||
if input.isCurrent(TokenType.MINUS):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
if input.hasCurrent():
|
|
||||||
expr = parseInteger(input, parent)
|
|
||||||
|
|
||||||
return IntegerLiteralNode(-expr.value, parent, token.pos)
|
|
||||||
|
|
||||||
return None
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
from smnp.ast.node.note import NoteLiteralNode
|
|
||||||
from smnp.note.model import Note
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# note -> NOTE
|
|
||||||
def parseNote(input, parent):
|
|
||||||
if input.isCurrent(TokenType.NOTE):
|
|
||||||
token = input.current()
|
|
||||||
value = token.value
|
|
||||||
consumedChars = 1
|
|
||||||
notePitch = value[consumedChars]
|
|
||||||
consumedChars += 1
|
|
||||||
octave = 4
|
|
||||||
duration = 4
|
|
||||||
dot = False
|
|
||||||
if consumedChars < len(value) and value[consumedChars] in ('b', '#'):
|
|
||||||
notePitch += value[consumedChars]
|
|
||||||
consumedChars += 1
|
|
||||||
if consumedChars < len(value) and re.match(r'\d', value[consumedChars]):
|
|
||||||
octave = int(value[consumedChars])
|
|
||||||
consumedChars += 1
|
|
||||||
if consumedChars < len(value) and value[consumedChars] == '.':
|
|
||||||
consumedChars += 1
|
|
||||||
durationString = ''
|
|
||||||
while consumedChars < len(value) and re.match(r'\d', value[consumedChars]):
|
|
||||||
durationString += value[consumedChars]
|
|
||||||
consumedChars += 1
|
|
||||||
duration = int(durationString)
|
|
||||||
if consumedChars < len(value) and value[consumedChars] == 'd':
|
|
||||||
dot = True
|
|
||||||
consumedChars += 1
|
|
||||||
|
|
||||||
input.ahead()
|
|
||||||
return NoteLiteralNode(Note(notePitch, octave, duration, dot), parent, token.pos)
|
|
||||||
|
|
||||||
return None
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from smnp.ast.node.ret import ReturnNode
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
def parseReturn(input, parent):
|
|
||||||
if input.isCurrent(TokenType.RETURN):
|
|
||||||
token = input.current()
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
expr = parseExpression(input, parent)
|
|
||||||
|
|
||||||
node = ReturnNode(expr, parent, token.pos)
|
|
||||||
expr.parent = node
|
|
||||||
|
|
||||||
return node
|
|
||||||
return None
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
def parseStatement(input, parent):
|
|
||||||
from smnp.ast.tools import combineParsers
|
|
||||||
from smnp.ast.parsers.asterisk import parseAsterisk
|
|
||||||
from smnp.ast.parsers.block import parseBlock
|
|
||||||
from smnp.ast.parsers.expression import parseExpression
|
|
||||||
from smnp.ast.parsers.function import parseFunctionDefinition
|
|
||||||
from smnp.ast.parsers.ret import parseReturn
|
|
||||||
|
|
||||||
parsers = [
|
|
||||||
parseBlock,
|
|
||||||
parseFunctionDefinition,
|
|
||||||
parseReturn,
|
|
||||||
parseExpression,
|
|
||||||
]
|
|
||||||
|
|
||||||
stmt = combineParsers(parsers)(input, parent)
|
|
||||||
|
|
||||||
asterisk = parseAsterisk(stmt, input, parent)
|
|
||||||
if asterisk is not None:
|
|
||||||
return asterisk
|
|
||||||
|
|
||||||
return stmt
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
from smnp.ast.node.string import StringLiteralNode
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
# string -> STRING
|
|
||||||
def parseString(input, parent):
|
|
||||||
if input.isCurrent(TokenType.STRING):
|
|
||||||
string = StringLiteralNode(input.current().value[1:len(input.current().value) - 1], parent, input.current().pos)
|
|
||||||
input.ahead()
|
|
||||||
|
|
||||||
return string
|
|
||||||
return None
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
from smnp.ast.parsers.statement import parseStatement
|
|
||||||
from smnp.ast.tools import combineParsers
|
|
||||||
from smnp.error.syntax import SyntaxException
|
|
||||||
|
|
||||||
|
|
||||||
def parseToken(input, parent):
|
|
||||||
value = combineParsers([ parseStatement ])(input, parent)
|
|
||||||
|
|
||||||
if value is None:
|
|
||||||
raise SyntaxException("Unknown statement") # TODO
|
|
||||||
|
|
||||||
return value
|
|
||||||
@@ -1,30 +1,8 @@
|
|||||||
from smnp.ast.node.model import Node
|
|
||||||
from smnp.error.syntax import SyntaxException
|
from smnp.error.syntax import SyntaxException
|
||||||
|
|
||||||
|
|
||||||
def greedy(parser):
|
def assertToken(expected, input):
|
||||||
def _rollup(input, parent):
|
|
||||||
node = Node(None, (-1, -1))
|
|
||||||
elem = parser(input, node)
|
|
||||||
while elem is not None:
|
|
||||||
node.append(elem)
|
|
||||||
elem = parser(input, node)
|
|
||||||
return node.children[0] if len(node.children) > 0 else None
|
|
||||||
return _rollup
|
|
||||||
|
|
||||||
|
|
||||||
def assertToken(expected, input):
|
|
||||||
if not input.hasCurrent():
|
if not input.hasCurrent():
|
||||||
raise SyntaxException(f"Expected '{expected}'")
|
raise SyntaxException(f"Expected '{expected}'")
|
||||||
if expected != input.current().type:
|
if expected != input.current().type:
|
||||||
raise SyntaxException(f"Expected '{expected}', found '{input.current().value}'", input.current().pos)
|
raise SyntaxException(f"Expected '{expected}', found '{input.current().value}'", input.current().pos)
|
||||||
|
|
||||||
|
|
||||||
def combineParsers(parsers):
|
|
||||||
def combinedParser(input, parent):
|
|
||||||
for parser in parsers:
|
|
||||||
value = parser(input, parent)
|
|
||||||
if value is not None:
|
|
||||||
return value
|
|
||||||
return None
|
|
||||||
return combinedParser
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from smnp.ast.node.program import Program
|
||||||
from smnp.environment.factory import createEnvironment
|
from smnp.environment.factory import createEnvironment
|
||||||
from smnp.error.base import SmnpException
|
from smnp.error.base import SmnpException
|
||||||
from smnp.newast.node.program import Program
|
|
||||||
from smnp.runtime.evaluator import evaluate
|
from smnp.runtime.evaluator import evaluate
|
||||||
from smnp.token.tokenizer import tokenize
|
from smnp.token.tokenizer import tokenize
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.ignore import IgnoredNode
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class AccessNode(ExpressionNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
self.children.append(IgnoredNode(pos))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def left(self):
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
@left.setter
|
|
||||||
def left(self, value):
|
|
||||||
self[0] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def right(self):
|
|
||||||
return self[1]
|
|
||||||
|
|
||||||
@right.setter
|
|
||||||
def right(self, value):
|
|
||||||
self[1] = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
def createNode(left, right):
|
|
||||||
node = AccessNode(right.pos)
|
|
||||||
node.left = left
|
|
||||||
node.right = right
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.leftAssociativeOperatorParser(
|
|
||||||
cls._literalParser(),
|
|
||||||
TokenType.DOT,
|
|
||||||
cls._parseAccessingProperty(),
|
|
||||||
createNode=createNode
|
|
||||||
)(input)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _literalParser(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parseAccessingProperty():
|
|
||||||
from smnp.newast.node.identifier import IdentifierNode
|
|
||||||
|
|
||||||
return Parser.oneOf(
|
|
||||||
IdentifierNode._literalParser(),
|
|
||||||
IdentifierNode._functionCallParser()
|
|
||||||
)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.none import NoneNode
|
|
||||||
|
|
||||||
|
|
||||||
class AssignmentNode(ExpressionNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
self.children.append(NoneNode())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def target(self):
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
@target.setter
|
|
||||||
def target(self, value):
|
|
||||||
self[0] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self):
|
|
||||||
return self[1]
|
|
||||||
|
|
||||||
@value.setter
|
|
||||||
def value(self, value):
|
|
||||||
self[1] = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
raise RuntimeError("This class is not supposed to be automatically called")
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
from smnp.newast.node.none import NoneNode
|
|
||||||
from smnp.newast.node.statement import StatementNode
|
|
||||||
|
|
||||||
|
|
||||||
class AsteriskNode(StatementNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
self.children = [NoneNode(), NoneNode()]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def iterator(self):
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
@iterator.setter
|
|
||||||
def iterator(self, value):
|
|
||||||
self[0] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def statement(self):
|
|
||||||
return self[1]
|
|
||||||
|
|
||||||
@statement.setter
|
|
||||||
def statement(self, value):
|
|
||||||
self[1] = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
raise RuntimeError("This class is not supposed to be automatically called")
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from smnp.newast.node.statement import StatementNode
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class BlockNode(StatementNode):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
def createNode(start, items, end):
|
|
||||||
node = BlockNode(start.pos)
|
|
||||||
node.children = items
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.loop(
|
|
||||||
Parser.terminalParser(TokenType.OPEN_BRACKET),
|
|
||||||
StatementNode.parse,
|
|
||||||
Parser.terminalParser(TokenType.CLOSE_BRACKET),
|
|
||||||
createNode=createNode
|
|
||||||
)(input)
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
from smnp.newast.node.block import BlockNode
|
|
||||||
from smnp.newast.node.identifier import IdentifierNode
|
|
||||||
from smnp.newast.node.iterable import abstractIterableParser
|
|
||||||
from smnp.newast.node.model import Node
|
|
||||||
from smnp.newast.node.none import NoneNode
|
|
||||||
from smnp.newast.node.statement import StatementNode
|
|
||||||
from smnp.newast.node.variable import TypedVariableNode
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class ArgumentsDeclarationNode(Node):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
raise RuntimeError("This class is not supposed to be automatically called")
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionDefinitionNode(StatementNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
self[0] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def arguments(self):
|
|
||||||
return self[1]
|
|
||||||
|
|
||||||
@arguments.setter
|
|
||||||
def arguments(self, value):
|
|
||||||
self[1] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body(self):
|
|
||||||
return self[2]
|
|
||||||
|
|
||||||
@body.setter
|
|
||||||
def body(self, value):
|
|
||||||
self[2] = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
def createNode(function, name, arguments, body):
|
|
||||||
node = FunctionDefinitionNode(function.pos)
|
|
||||||
node.name = name
|
|
||||||
node.arguments = arguments
|
|
||||||
node.body = body
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.allOf(
|
|
||||||
Parser.terminalParser(TokenType.FUNCTION),
|
|
||||||
IdentifierNode.identifierParser(),
|
|
||||||
cls._argumentsDeclarationParser(),
|
|
||||||
BlockNode.parse,
|
|
||||||
createNode=createNode
|
|
||||||
)(input)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _argumentsDeclarationParser():
|
|
||||||
return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, TypedVariableNode.parser())
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
|
||||||
from smnp.newast.node.args import ArgumentsListNode
|
|
||||||
from smnp.newast.node.assignment import AssignmentNode
|
|
||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.invocation import FunctionCall
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class IdentifierNode(AccessNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
del self.children[1]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _literalParser(cls):
|
|
||||||
return Parser.oneOf(
|
|
||||||
IdentifierNode._functionCallParser(),
|
|
||||||
IdentifierNode._assignmentParser(),
|
|
||||||
IdentifierNode.identifierParser()
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _assignmentParser():
|
|
||||||
def createNode(target, assignment, value):
|
|
||||||
node = AssignmentNode(assignment.pos)
|
|
||||||
node.target = target
|
|
||||||
node.value = value
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.allOf(
|
|
||||||
IdentifierNode.identifierParser(),
|
|
||||||
Parser.terminalParser(TokenType.ASSIGN),
|
|
||||||
ExpressionNode.parse,
|
|
||||||
createNode=createNode
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _functionCallParser():
|
|
||||||
def createNode(name, arguments):
|
|
||||||
node = FunctionCall(name.pos)
|
|
||||||
node.name = name
|
|
||||||
node.arguments = arguments
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.allOf(
|
|
||||||
IdentifierNode.identifierParser(),
|
|
||||||
ArgumentsListNode.parse,
|
|
||||||
createNode=createNode
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def identifierParser():
|
|
||||||
return Parser.terminalParser(TokenType.IDENTIFIER, lambda val, pos: IdentifierNode.withValue(val, pos))
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class IntegerLiteralNode(AccessNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
del self.children[1]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _literalParser(cls):
|
|
||||||
return Parser.oneOf(
|
|
||||||
cls._negativeIntegerParser(),
|
|
||||||
cls._positiveIntegerParser()
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _negativeIntegerParser(cls):
|
|
||||||
def createNode(minus, integer):
|
|
||||||
return IntegerLiteralNode.withValue(-integer.value, minus.pos)
|
|
||||||
|
|
||||||
return Parser.allOf(
|
|
||||||
Parser.terminalParser(TokenType.MINUS),
|
|
||||||
cls._positiveIntegerParser(),
|
|
||||||
createNode=createNode
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _positiveIntegerParser(cls):
|
|
||||||
return Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteralNode.withValue(int(val), pos))
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
|
||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.iterable import abstractIterableParser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class ListNode(AccessNode):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _literalParser(cls):
|
|
||||||
return abstractIterableParser(ListNode, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, ExpressionNode.parse)
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
class Node:
|
|
||||||
def __init__(self, pos, children=None):
|
|
||||||
if children is None:
|
|
||||||
children = []
|
|
||||||
self.children = children
|
|
||||||
self.pos = pos
|
|
||||||
self.parent = None
|
|
||||||
for child in self.children:
|
|
||||||
if isinstance(child, Node):
|
|
||||||
child.parent = self
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.children)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
return self.children[key]
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
if isinstance(value, Node):
|
|
||||||
value.parent = self
|
|
||||||
self.children[key] = value
|
|
||||||
|
|
||||||
def append(self, node):
|
|
||||||
if isinstance(node, Node):
|
|
||||||
node.parent = self
|
|
||||||
self.children.append(node)
|
|
||||||
|
|
||||||
def pop(self, index):
|
|
||||||
return self.children.pop(index)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def parse(cls, input):
|
|
||||||
result = cls._parse(input)
|
|
||||||
if result is None:
|
|
||||||
return ParseResult.FAIL()
|
|
||||||
|
|
||||||
if not isinstance(result, ParseResult):
|
|
||||||
raise RuntimeError(f"_parse() method of '{cls.__name__}' class haven't returned ParseResult object")
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def print(self):
|
|
||||||
self._print(first=True)
|
|
||||||
|
|
||||||
def _print(self, prefix="", last=True, first=False):
|
|
||||||
print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, sep="")
|
|
||||||
prefix += ' ' if last else '│ '
|
|
||||||
for i, child in enumerate(self.children):
|
|
||||||
last = i == len(self.children) - 1
|
|
||||||
if isinstance(child, Node):
|
|
||||||
child._print(prefix, last)
|
|
||||||
else:
|
|
||||||
print(prefix, '└' if last else '├', f"'{str(child)}'", sep="")
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.__class__.__name__
|
|
||||||
|
|
||||||
|
|
||||||
class ParseResult():
|
|
||||||
def __init__(self, result, node):
|
|
||||||
if result and node is None:
|
|
||||||
raise RuntimeError("Node musn't be None if result is set to True for ParseResult")
|
|
||||||
self.result = result
|
|
||||||
self.node = node
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def FAIL():
|
|
||||||
return ParseResult(False, None)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def OK(node):
|
|
||||||
return ParseResult(True, node)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{'OK' if self.result else 'FAILED'}[{self.node}]"
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
|
||||||
from smnp.newast.node.literal import LiteralNode
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class NoteLiteralNode(LiteralNode, AccessNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
del self.children[1]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _getTokenType(cls):
|
|
||||||
return TokenType.NOTE
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
from smnp.error.syntax import SyntaxException
|
|
||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.extend import ExtendNode
|
|
||||||
from smnp.newast.node.function import FunctionDefinitionNode
|
|
||||||
from smnp.newast.node.imports import ImportNode
|
|
||||||
from smnp.newast.node.model import Node, ParseResult
|
|
||||||
from smnp.newast.node.statement import StatementNode
|
|
||||||
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
|
|
||||||
|
|
||||||
class Program(Node):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__((-1, -1))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
def parseToken(input):
|
|
||||||
return Parser.oneOf(
|
|
||||||
FunctionDefinitionNode.parse,
|
|
||||||
ExtendNode.parse,
|
|
||||||
ExpressionNode.parse,
|
|
||||||
ImportNode.parse,
|
|
||||||
StatementNode.parse,
|
|
||||||
exception = SyntaxException(f"Unknown statement: {input.current().pos}")
|
|
||||||
)(input)
|
|
||||||
|
|
||||||
root = Program()
|
|
||||||
while input.hasCurrent():
|
|
||||||
result = parseToken(input)
|
|
||||||
if result.result:
|
|
||||||
root.append(result.node)
|
|
||||||
return ParseResult.OK(root)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.none import NoneNode
|
|
||||||
from smnp.newast.node.statement import StatementNode
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class ReturnNode(StatementNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
self.children.append(NoneNode())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self):
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
@value.setter
|
|
||||||
def value(self, value):
|
|
||||||
self[0] = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
def createNode(ret, value):
|
|
||||||
node = ReturnNode(ret.pos)
|
|
||||||
node.value = value
|
|
||||||
return node
|
|
||||||
|
|
||||||
return Parser.allOf(
|
|
||||||
Parser.terminalParser(TokenType.RETURN),
|
|
||||||
ExpressionNode.parse,
|
|
||||||
createNode=createNode
|
|
||||||
)(input)
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from smnp.newast.node.model import Node
|
|
||||||
from smnp.newast.parser import Parser
|
|
||||||
|
|
||||||
|
|
||||||
class StatementNode(Node):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse(cls, input):
|
|
||||||
from smnp.newast.node.block import BlockNode
|
|
||||||
from smnp.newast.node.expression import ExpressionNode
|
|
||||||
from smnp.newast.node.ret import ReturnNode
|
|
||||||
|
|
||||||
return Parser.oneOf(
|
|
||||||
BlockNode.parse,
|
|
||||||
ReturnNode.parse,
|
|
||||||
ExpressionNode.parse
|
|
||||||
)(input)
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
from smnp.newast.node.access import AccessNode
|
|
||||||
from smnp.newast.node.literal import LiteralNode
|
|
||||||
from smnp.token.type import TokenType
|
|
||||||
|
|
||||||
|
|
||||||
class StringLiteralNode(LiteralNode, AccessNode):
|
|
||||||
def __init__(self, pos):
|
|
||||||
super().__init__(pos)
|
|
||||||
del self.children[1]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _getTokenType(cls):
|
|
||||||
return TokenType.STRING
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
from smnp.newast.node.ignore import IgnoredNode
|
|
||||||
from smnp.newast.node.model import ParseResult, Node
|
|
||||||
|
|
||||||
|
|
||||||
class Parser:
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def nonTerminalParser(parser, createNode):
|
|
||||||
def parse(input):
|
|
||||||
token = input.current()
|
|
||||||
result = parse(input)
|
|
||||||
if result.result:
|
|
||||||
return ParseResult.OK(createNode(result.node, token.pos))
|
|
||||||
return ParseResult.FAIL()
|
|
||||||
return parse
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def terminalParser(expectedType, createNode=None):
|
|
||||||
def provideNode(value, pos):
|
|
||||||
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))
|
|
||||||
return ParseResult.FAIL()
|
|
||||||
|
|
||||||
return parse
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def oneOf(*parsers, exception=None):
|
|
||||||
def combinedParser(input):
|
|
||||||
snap = input.snapshot()
|
|
||||||
for parser in parsers:
|
|
||||||
value = parser(input)
|
|
||||||
if value.result:
|
|
||||||
return value
|
|
||||||
|
|
||||||
if exception is not None:
|
|
||||||
raise exception
|
|
||||||
|
|
||||||
input.reset(snap)
|
|
||||||
return ParseResult.FAIL()
|
|
||||||
|
|
||||||
return combinedParser
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def allOf(*parsers, createNode, exception=None):
|
|
||||||
if len(parsers) == 0:
|
|
||||||
raise RuntimeError("Pass one parser at least")
|
|
||||||
|
|
||||||
def extendedParser(input):
|
|
||||||
snap = input.snapshot()
|
|
||||||
|
|
||||||
results = []
|
|
||||||
|
|
||||||
for parser in parsers:
|
|
||||||
result = parser(input)
|
|
||||||
|
|
||||||
if not result.result:
|
|
||||||
if exception is not None:
|
|
||||||
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 extendedParser
|
|
||||||
|
|
||||||
|
|
||||||
# leftAssociative -> left | left OP right
|
|
||||||
@staticmethod
|
|
||||||
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
|
|
||||||
def parse(input):
|
|
||||||
left = leftParser(input)
|
|
||||||
if left.result:
|
|
||||||
while Parser.terminalParser(operatorTokenType)(input).result:
|
|
||||||
right = rightParser(input)
|
|
||||||
left = ParseResult.OK(createNode(left.node, right.node))
|
|
||||||
|
|
||||||
return left
|
|
||||||
|
|
||||||
return ParseResult.FAIL()
|
|
||||||
|
|
||||||
return parse
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def loop(startParser, itemParser, endParser, createNode):
|
|
||||||
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 parse
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from smnp.error.syntax import SyntaxException
|
|
||||||
|
|
||||||
|
|
||||||
def assertToken(expected, input):
|
|
||||||
if not input.hasCurrent():
|
|
||||||
raise SyntaxException(f"Expected '{expected}'")
|
|
||||||
if expected != input.current().type:
|
|
||||||
raise SyntaxException(f"Expected '{expected}', found '{input.current().value}'", input.current().pos)
|
|
||||||
Reference in New Issue
Block a user