diff --git a/smnp/ast/node/access.py b/smnp/ast/node/access.py index 637a012..bd208a2 100644 --- a/smnp/ast/node/access.py +++ b/smnp/ast/node/access.py @@ -1,5 +1,5 @@ from smnp.ast.node.expression import ExpressionNode -from smnp.ast.node.ignore import IgnoredNode +from smnp.ast.node.none import NoneNode from smnp.ast.parser import Parser from smnp.error.syntax import SyntaxException from smnp.token.type import TokenType @@ -8,7 +8,7 @@ from smnp.token.type import TokenType class AccessNode(ExpressionNode): def __init__(self, pos): super().__init__(pos) - self.children.append(IgnoredNode(pos)) + self.children = [ NoneNode(), NoneNode() ] @property def left(self): @@ -28,29 +28,29 @@ class AccessNode(ExpressionNode): @classmethod def accessParser(cls): - def createNode(left, right): + def createNode(left, operator, right): node = AccessNode(right.pos) node.left = left node.right = right return node return Parser.leftAssociativeOperatorParser( - cls._accessLiteralParser(), + cls._accessLhs(), TokenType.DOT, - cls._parseAccessingProperty(), + cls._accessRhs(), createNode=createNode ) @classmethod - def _accessLiteralParser(cls): - raise RuntimeError(f"_accessLiteralParser() is not implemented in {cls.__name__} class") + def _accessLhs(cls): + raise RuntimeError(f"_accessLhs() is not implemented in {cls.__name__} class") @staticmethod - def _parseAccessingProperty(): + def _accessRhs(): from smnp.ast.node.identifier import IdentifierNode return Parser.oneOf( + IdentifierNode.functionCallParser(), IdentifierNode.identifierParser(), - IdentifierNode._functionCallParser(), exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos()) ) diff --git a/smnp/ast/node/bool.py b/smnp/ast/node/bool.py index 7c8423e..952b257 100644 --- a/smnp/ast/node/bool.py +++ b/smnp/ast/node/bool.py @@ -17,7 +17,6 @@ class BoolLiteralNode(LiteralNode, AccessNode, RelationOperatorNode): @classmethod def _parse(cls, input): x = Parser.oneOf( - cls.relationParser(), cls.accessParser(), cls.literalParser() @@ -25,9 +24,9 @@ class BoolLiteralNode(LiteralNode, AccessNode, RelationOperatorNode): return x @classmethod - def _accessLiteralParser(cls): + def _accessLhs(cls): return cls.literalParser() @classmethod - def _relationLiteralParser(cls): + def _relationLhs(cls): return cls.literalParser() \ No newline at end of file diff --git a/smnp/ast/node/identifier.py b/smnp/ast/node/identifier.py index 0edd0ab..87f6476 100644 --- a/smnp/ast/node/identifier.py +++ b/smnp/ast/node/identifier.py @@ -14,7 +14,7 @@ class IdentifierNode(AccessNode): @classmethod def _literalParser(cls): return Parser.oneOf( - IdentifierNode._functionCallParser(), + IdentifierNode.functionCallParser(), IdentifierNode._assignmentParser(), IdentifierNode.identifierParser() ) @@ -35,7 +35,7 @@ class IdentifierNode(AccessNode): ) @staticmethod - def _functionCallParser(): + def functionCallParser(): def createNode(name, arguments): node = FunctionCallNode(name.pos) node.name = name diff --git a/smnp/ast/node/operator.py b/smnp/ast/node/operator.py new file mode 100644 index 0000000..9afa406 --- /dev/null +++ b/smnp/ast/node/operator.py @@ -0,0 +1,15 @@ +from smnp.ast.node.model import Node + + +class OperatorNode(Node): + def __init__(self, pos): + super().__init__(pos) + self.children = [None] + + @property + def value(self): + return self[0] + + @value.setter + def value(self, value): + self[0] = value diff --git a/smnp/ast/node/relation.py b/smnp/ast/node/relation.py index c7dba25..3b7934b 100644 --- a/smnp/ast/node/relation.py +++ b/smnp/ast/node/relation.py @@ -1,5 +1,5 @@ from smnp.ast.node.expression import ExpressionNode -from smnp.ast.node.ignore import IgnoredNode +from smnp.ast.node.none import NoneNode from smnp.ast.parser import Parser from smnp.token.type import TokenType @@ -7,7 +7,7 @@ from smnp.token.type import TokenType class RelationOperatorNode(ExpressionNode): def __init__(self, pos): super().__init__(pos) - self.children.append(IgnoredNode(pos)) + self.children = [ NoneNode(), NoneNode(), NoneNode()] @property def left(self): @@ -18,33 +18,42 @@ class RelationOperatorNode(ExpressionNode): self[0] = value @property - def right(self): + def operator(self): return self[1] + @operator.setter + def operator(self, value): + self[1] = value + + @property + def right(self): + return self[2] + @right.setter def right(self, value): - self[1] = value + self[2] = value @classmethod def relationParser(cls): - def createNode(left, right): + def createNode(left, operator, right): node = RelationOperatorNode(right.pos) node.left = left + node.operator = operator node.right = right return node return Parser.leftAssociativeOperatorParser( - cls._relationLiteralParser(), + cls._relationLhs(), TokenType.EQUAL, - cls._parseRelationProperty(), + cls._relationRhs(), createNode=createNode ) @classmethod - def _relationLiteralParser(cls): - raise RuntimeError(f"_relationLiteralParser() is not implemented in {cls.__name__} class") + def _relationLhs(cls): + raise RuntimeError(f"_relationLhs() is not implemented in {cls.__name__} class") @staticmethod - def _parseRelationProperty(): + def _relationRhs(): # TODO doAssert return ExpressionNode.parse \ No newline at end of file diff --git a/smnp/ast/parser.py b/smnp/ast/parser.py index 84b6f1a..9351203 100644 --- a/smnp/ast/parser.py +++ b/smnp/ast/parser.py @@ -1,6 +1,7 @@ from smnp.ast.node.ignore import IgnoredNode from smnp.ast.node.model import ParseResult, Node from smnp.ast.node.none import NoneNode +from smnp.ast.node.operator import OperatorNode from smnp.error.syntax import SyntaxException @@ -99,11 +100,12 @@ class Parser: left = leftParser(input) oneAtLeast = False if left.result: - while Parser.terminalParser(operatorTokenType)(input).result: + operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input) + while operator.result: oneAtLeast = True right = rightParser(input) - left = ParseResult.OK(createNode(left.node, right.node)) - + left = ParseResult.OK(createNode(left.node, operator.node, right.node)) + operator = Parser.terminalParser(operatorTokenType)(input) if oneAtLeast: return left