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()
|
||||
)
|
||||
|
||||
11
smnp/ast/node/args.py
Normal file
11
smnp/ast/node/args.py
Normal file
@@ -0,0 +1,11 @@
|
||||
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
|
||||
|
||||
|
||||
class ArgumentsListNode(Node):
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return abstractIterableParser(ArgumentsListNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, ExpressionNode.parse)(input)
|
||||
@@ -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]
|
||||
65
smnp/ast/node/expression.py
Normal file
65
smnp/ast/node/expression.py
Normal file
@@ -0,0 +1,65 @@
|
||||
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
|
||||
|
||||
|
||||
class ExpressionNode(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos, [NoneNode()])
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self[0]
|
||||
|
||||
|
||||
@value.setter
|
||||
def value(self, v):
|
||||
self[0] = v
|
||||
|
||||
|
||||
@classmethod
|
||||
def withValue(cls, val, pos):
|
||||
node = cls(pos)
|
||||
node.value = val
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return Parser.oneOf(
|
||||
cls._asteriskParser(),
|
||||
cls._expressionParser(),
|
||||
)(input)
|
||||
|
||||
@classmethod
|
||||
def _asteriskParser(cls):
|
||||
def createNode(iterator, asterisk, statement):
|
||||
node = AsteriskNode(asterisk.pos)
|
||||
node.iterator = iterator
|
||||
node.statement = statement
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
cls._expressionParser(),
|
||||
Parser.terminalParser(TokenType.ASTERISK),
|
||||
StatementNode.parse,
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _expressionParser(cls):
|
||||
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,
|
||||
StringLiteralNode.parse,
|
||||
NoteLiteralNode.parse,
|
||||
IdentifierNode.parse,
|
||||
ListNode.parse
|
||||
)
|
||||
70
smnp/ast/node/extend.py
Normal file
70
smnp/ast/node/extend.py
Normal file
@@ -0,0 +1,70 @@
|
||||
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
|
||||
|
||||
|
||||
class ExtendNode(StatementNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def variable(self):
|
||||
return self[1]
|
||||
|
||||
@variable.setter
|
||||
def variable(self, value):
|
||||
self[1] = value
|
||||
|
||||
@property
|
||||
def methods(self):
|
||||
return self[2]
|
||||
|
||||
@methods.setter
|
||||
def methods(self, value):
|
||||
self[2] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
def createNode(extend, type, asKeyword, variable, methods):
|
||||
node = ExtendNode(extend.pos)
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
node.methods = methods
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.EXTEND),
|
||||
TypeNode.parse,
|
||||
Parser.terminalParser(TokenType.AS),
|
||||
IdentifierNode.identifierParser(),
|
||||
cls._methodsDeclarationsParser(),
|
||||
createNode=createNode
|
||||
)(input)
|
||||
|
||||
@classmethod
|
||||
def _methodsDeclarationsParser(cls):
|
||||
def createNode(openBracket, items, closeBracket):
|
||||
node = BlockNode(openBracket.pos)
|
||||
node.children = items
|
||||
return node
|
||||
|
||||
return Parser.loop(
|
||||
Parser.terminalParser(TokenType.OPEN_BRACKET),
|
||||
FunctionDefinitionNode.parse,
|
||||
Parser.terminalParser(TokenType.CLOSE_BRACKET),
|
||||
createNode=createNode
|
||||
)
|
||||
@@ -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))
|
||||
|
||||
6
smnp/ast/node/ignore.py
Normal file
6
smnp/ast/node/ignore.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from smnp.ast.node.model import Node
|
||||
|
||||
|
||||
class IgnoredNode(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
76
smnp/ast/node/imports.py
Normal file
76
smnp/ast/node/imports.py
Normal file
@@ -0,0 +1,76 @@
|
||||
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
|
||||
|
||||
|
||||
class ImportNode(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
return self[0]
|
||||
|
||||
@source.setter
|
||||
def source(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[1]
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[1] = value
|
||||
|
||||
@property
|
||||
def variable(self):
|
||||
return self[2]
|
||||
|
||||
@variable.setter
|
||||
def variable(self, value):
|
||||
self[2] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return Parser.oneOf(
|
||||
cls._literalImportParser(),
|
||||
cls._fileImportParser()
|
||||
)(input)
|
||||
|
||||
@classmethod
|
||||
def _literalImportParser(cls):
|
||||
def createNode(importKeyword, type, fromKeyword, source, asKeyword, variable):
|
||||
node = ImportNode(importKeyword.pos)
|
||||
node.source = source
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.IMPORT),
|
||||
TypeNode.parse,
|
||||
Parser.terminalParser(TokenType.FROM),
|
||||
StringLiteralNode._literalParser(),
|
||||
Parser.terminalParser(TokenType.AS),
|
||||
IdentifierNode.identifierParser(),
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _fileImportParser(cls):
|
||||
def createNode(importKeyword, source):
|
||||
node = ImportNode(importKeyword.pos)
|
||||
node.source = source
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.IMPORT),
|
||||
StringLiteralNode._literalParser(),
|
||||
createNode=createNode
|
||||
)
|
||||
@@ -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))
|
||||
27
smnp/ast/node/invocation.py
Normal file
27
smnp/ast/node/invocation.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
|
||||
|
||||
class FunctionCall(AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
|
||||
@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
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
raise RuntimeError("This class is not supposed to be automatically called")
|
||||
|
||||
130
smnp/ast/node/iterable.py
Normal file
130
smnp/ast/node/iterable.py
Normal file
@@ -0,0 +1,130 @@
|
||||
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
|
||||
|
||||
|
||||
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser):
|
||||
class AbstractIterableTailNode(ExpressionNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
|
||||
self.children.append(NoneNode())
|
||||
|
||||
@property
|
||||
def next(self):
|
||||
return self[1]
|
||||
|
||||
@next.setter
|
||||
def next(self, value):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return Parser.oneOf(
|
||||
AbstractIterableTailNode._parser1(),
|
||||
AbstractIterableTailNode._parser2(),
|
||||
)(input)
|
||||
|
||||
@staticmethod
|
||||
def _parser1():
|
||||
return Parser.terminalParser(closeTokenType)
|
||||
|
||||
@staticmethod
|
||||
def _parser2():
|
||||
def createNode(comma, expr, iterableTail):
|
||||
node = AbstractIterableTailNode(expr.pos)
|
||||
node.value = expr
|
||||
node.next = iterableTail
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.COMMA),
|
||||
itemParser,
|
||||
AbstractIterableTailNode.parse,
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
class AbstractIterableNode(ExpressionNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
|
||||
self.children.append(NoneNode())
|
||||
|
||||
@property
|
||||
def next(self):
|
||||
return self[1]
|
||||
|
||||
@next.setter
|
||||
def next(self, value):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return Parser.oneOf(
|
||||
AbstractIterableNode._parser1(),
|
||||
AbstractIterableNode._parser2()
|
||||
)(input)
|
||||
|
||||
@staticmethod
|
||||
def _parser1():
|
||||
def emptyIterable(openToken, closeToken):
|
||||
node = AbstractIterableNode(openToken.pos)
|
||||
node.value = openToken
|
||||
node.next = closeToken
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(openTokenType),
|
||||
Parser.terminalParser(closeTokenType),
|
||||
createNode=emptyIterable
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parser2():
|
||||
def createNode(openParen, expr, iterableTail):
|
||||
node = AbstractIterableNode(openParen.pos)
|
||||
node.value = expr
|
||||
node.next = iterableTail
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(openTokenType, lambda val, pos: Node(pos)),
|
||||
itemParser,
|
||||
AbstractIterableTailNode.parse,
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
return toFlatDesiredNode(iterableNodeType, AbstractIterableNode.parse)
|
||||
|
||||
|
||||
def toFlatDesiredNode(iterableNodeType, parser):
|
||||
def parse(input):
|
||||
result = parser(input)
|
||||
|
||||
if result.result:
|
||||
value = flattenList(result.node)
|
||||
node = iterableNodeType(result.node.pos)
|
||||
node.children.clear()
|
||||
for v in value:
|
||||
node.append(v)
|
||||
return ParseResult.OK(node)
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return parse
|
||||
|
||||
|
||||
def flattenList(node, output=None):
|
||||
if output is None:
|
||||
output = []
|
||||
|
||||
if type(node.value) != IgnoredNode:
|
||||
output.append(node.value)
|
||||
|
||||
if type(node.next) != IgnoredNode:
|
||||
flattenList(node.next, output)
|
||||
|
||||
return output
|
||||
@@ -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)
|
||||
|
||||
18
smnp/ast/node/literal.py
Normal file
18
smnp/ast/node/literal.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.parser import Parser
|
||||
|
||||
|
||||
class LiteralNode(ExpressionNode):
|
||||
|
||||
@classmethod
|
||||
def _getTokenType(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def _processValue(cls, value):
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
createNode = lambda val, pos: cls.withValue(cls._processValue(val), pos)
|
||||
return Parser.terminalParser(cls._getTokenType(), createNode)
|
||||
@@ -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
|
||||
9
smnp/ast/node/none.py
Normal file
9
smnp/ast/node/none.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from smnp.ast.node.model import Node
|
||||
|
||||
|
||||
class NoneNode(Node):
|
||||
def __init__(self):
|
||||
super().__init__((-1, -1))
|
||||
|
||||
def _parse(self, input):
|
||||
pass
|
||||
@@ -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
|
||||
13
smnp/ast/node/type.py
Normal file
13
smnp/ast/node/type.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.literal import LiteralNode
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class TypeNode(LiteralNode, AccessNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
del self.children[1]
|
||||
|
||||
@classmethod
|
||||
def _getTokenType(cls):
|
||||
return TokenType.TYPE
|
||||
46
smnp/ast/node/variable.py
Normal file
46
smnp/ast/node/variable.py
Normal file
@@ -0,0 +1,46 @@
|
||||
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):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children.append(NoneNode())
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def variable(self):
|
||||
return self[1]
|
||||
|
||||
@variable.setter
|
||||
def variable(self, value):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def parser(cls):
|
||||
def createNode(type, variable):
|
||||
node = TypedVariableNode(type.pos)
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos)),
|
||||
IdentifierNode.identifierParser(),
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
#TODO
|
||||
raise RuntimeError("Not implemented yet. There is still required work to correctly build AST related to IdentifierNode")
|
||||
Reference in New Issue
Block a user