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):
|
||||
def __init__(self, element, property, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.extend([element, property])
|
||||
class AccessNode(ExpressionNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children.append(IgnoredNode(pos))
|
||||
|
||||
self.element = self.children[0]
|
||||
self.property = self.children[1]
|
||||
@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.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.newast.node.iterable import abstractIterableParser
|
||||
from smnp.newast.node.model import Node
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
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):
|
||||
def __init__(self, target, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.extend([target, value])
|
||||
class AssignmentNode(ExpressionNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children.append(NoneNode())
|
||||
|
||||
self.target = self.children[0]
|
||||
self.value = self.children[1]
|
||||
@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,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):
|
||||
def __init__(self, iterator, statement, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.extend([iterator, statement])
|
||||
class AsteriskNode(StatementNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode()]
|
||||
|
||||
self.iterator = self.children[0]
|
||||
self.statement = self.children[1]
|
||||
@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,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):
|
||||
pass
|
||||
class BlockNode(StatementNode):
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
def createNode(start, items, end):
|
||||
node = BlockNode(start.pos)
|
||||
node.children = items
|
||||
return node
|
||||
|
||||
class BlockItemNode(Node):
|
||||
def __init__(self, statement, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(statement)
|
||||
|
||||
self.statement = self.children[0]
|
||||
|
||||
|
||||
class CloseBlockNode(Node):
|
||||
pass
|
||||
return Parser.loop(
|
||||
Parser.terminalParser(TokenType.OPEN_BRACKET),
|
||||
StatementNode.parse,
|
||||
Parser.terminalParser(TokenType.CLOSE_BRACKET),
|
||||
createNode=createNode
|
||||
)(input)
|
||||
@@ -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.newast.node.model import Node
|
||||
from smnp.newast.node.none import NoneNode
|
||||
from smnp.newast.node.statement import StatementNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.asterisk import AsteriskNode
|
||||
from smnp.ast.node.model import Node
|
||||
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
|
||||
|
||||
|
||||
@@ -50,11 +50,11 @@ class ExpressionNode(Node):
|
||||
|
||||
@classmethod
|
||||
def _expressionParser(cls):
|
||||
from smnp.newast.node.integer import IntegerLiteralNode
|
||||
from smnp.newast.node.string import StringLiteralNode
|
||||
from smnp.newast.node.note import NoteLiteralNode
|
||||
from smnp.newast.node.identifier import IdentifierNode
|
||||
from smnp.newast.node.list import ListNode
|
||||
from smnp.ast.node.integer import IntegerLiteralNode
|
||||
from smnp.ast.node.string import StringLiteralNode
|
||||
from smnp.ast.node.note import NoteLiteralNode
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.list import ListNode
|
||||
|
||||
return Parser.oneOf(
|
||||
IntegerLiteralNode.parse,
|
||||
@@ -1,10 +1,10 @@
|
||||
from smnp.newast.node.block import BlockNode
|
||||
from smnp.newast.node.function import FunctionDefinitionNode
|
||||
from smnp.newast.node.identifier import IdentifierNode
|
||||
from smnp.newast.node.none import NoneNode
|
||||
from smnp.newast.node.statement import StatementNode
|
||||
from smnp.newast.node.type import TypeNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.block import BlockNode
|
||||
from smnp.ast.node.function import FunctionDefinitionNode
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.statement import StatementNode
|
||||
from smnp.ast.node.type import TypeNode
|
||||
from smnp.ast.parser import Parser
|
||||
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.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):
|
||||
def __init__(self, identifier, arguments, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.extend([identifier, arguments])
|
||||
class ArgumentsDeclarationNode(Node):
|
||||
|
||||
self.identifier = self.children[0]
|
||||
self.arguments = self.children[1]
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
raise RuntimeError("This class is not supposed to be automatically called")
|
||||
|
||||
|
||||
class FunctionDefinitionNode(Node):
|
||||
def __init__(self, name, parameters, body, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.extend([name, parameters, body])
|
||||
class FunctionDefinitionNode(StatementNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
|
||||
self.name = self.children[0]
|
||||
self.parameters = self.children[1]
|
||||
self.body = self.children[2]
|
||||
@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,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):
|
||||
def __init__(self, identifier, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(identifier)
|
||||
class IdentifierNode(AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
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):
|
||||
@@ -1,9 +1,9 @@
|
||||
from smnp.newast.node.identifier import IdentifierNode
|
||||
from smnp.newast.node.model import Node
|
||||
from smnp.newast.node.none import NoneNode
|
||||
from smnp.newast.node.string import StringLiteralNode
|
||||
from smnp.newast.node.type import TypeNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.string import StringLiteralNode
|
||||
from smnp.ast.node.type import TypeNode
|
||||
from smnp.ast.parser import Parser
|
||||
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):
|
||||
def __init__(self, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(value)
|
||||
class IntegerLiteralNode(AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
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):
|
||||
@@ -1,8 +1,8 @@
|
||||
from smnp.newast.node.expression import ExpressionNode
|
||||
from smnp.newast.node.ignore import IgnoredNode
|
||||
from smnp.newast.node.model import Node, ParseResult
|
||||
from smnp.newast.node.none import NoneNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.node.ignore import IgnoredNode
|
||||
from smnp.ast.node.model import Node, ParseResult
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.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):
|
||||
pass
|
||||
class ListNode(AccessNode):
|
||||
|
||||
|
||||
class ListItemNode(Node):
|
||||
def __init__(self, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(value)
|
||||
|
||||
self.value = self.children[0]
|
||||
|
||||
|
||||
class CloseListNode(Node):
|
||||
pass
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
return abstractIterableParser(ListNode, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, ExpressionNode.parse)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from smnp.newast.node.expression import ExpressionNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.parser import Parser
|
||||
|
||||
|
||||
class LiteralNode(ExpressionNode):
|
||||
@@ -1,44 +1,81 @@
|
||||
from smnp.note.model import Note
|
||||
|
||||
class Node:
|
||||
def __init__(self, parent, pos):
|
||||
self.children = []
|
||||
self.parent = parent
|
||||
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:
|
||||
child.parent = self
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
if isinstance(child, Node):
|
||||
child.parent = self
|
||||
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.children[index]
|
||||
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):
|
||||
node.parent = self
|
||||
if isinstance(node, Node):
|
||||
node.parent = self
|
||||
self.children.append(node)
|
||||
|
||||
def pop(self, index):
|
||||
return self.children.pop(index)
|
||||
|
||||
def print(self):
|
||||
print(self._print(0))
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
pass
|
||||
|
||||
def _print(self, level):
|
||||
string = f"{pad(level)}{self.__class__.__name__}({self.parent.__class__.__name__}):\n"
|
||||
for child in self.children:
|
||||
if isinstance(child, str) or isinstance(child, int) or isinstance(child, Note):
|
||||
string += pad(level + 1) + f"'{child}'\n"
|
||||
@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:
|
||||
string += child._print(level + 1)
|
||||
return string
|
||||
print(prefix, '└' if last else '├', f"'{str(child)}'", sep="")
|
||||
|
||||
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):
|
||||
@@ -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):
|
||||
def __init__(self, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(value)
|
||||
class NoteLiteralNode(LiteralNode, AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
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):
|
||||
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):
|
||||
def __init__(self, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(value)
|
||||
class ReturnNode(StatementNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
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):
|
||||
def __init__(self, value, parent, pos):
|
||||
Node.__init__(self, parent, pos)
|
||||
self.children.append(value)
|
||||
class StringLiteralNode(LiteralNode, AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
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.newast.node.literal import LiteralNode
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.literal import LiteralNode
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from smnp.newast.node.expression import ExpressionNode
|
||||
from smnp.newast.node.identifier import IdentifierNode
|
||||
from smnp.newast.node.none import NoneNode
|
||||
from smnp.newast.node.type import TypeNode
|
||||
from smnp.newast.parser import Parser
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.type import TypeNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
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.parsers.token import parseToken
|
||||
|
||||
|
||||
def parse(input):
|
||||
root = Program()
|
||||
while input.hasCurrent():
|
||||
root.append(parseToken(input, root))
|
||||
return root
|
||||
return Program.parse(input)
|
||||
|
||||
class Parser:
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
def greedy(parser):
|
||||
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():
|
||||
raise SyntaxException(f"Expected '{expected}'")
|
||||
if expected != input.current().type:
|
||||
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
|
||||
|
||||
from smnp.ast.node.program import Program
|
||||
from smnp.environment.factory import createEnvironment
|
||||
from smnp.error.base import SmnpException
|
||||
from smnp.newast.node.program import Program
|
||||
from smnp.runtime.evaluator import evaluate
|
||||
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