Working proof of concept of multiple left associative operators
This commit is contained in:
@@ -27,7 +27,7 @@ class AccessNode(ExpressionNode):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
def accessParser(cls):
|
||||
def createNode(left, right):
|
||||
node = AccessNode(right.pos)
|
||||
node.left = left
|
||||
@@ -35,22 +35,22 @@ class AccessNode(ExpressionNode):
|
||||
return node
|
||||
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
cls._literalParser(),
|
||||
cls._accessLiteralParser(),
|
||||
TokenType.DOT,
|
||||
cls._parseAccessingProperty(),
|
||||
createNode=createNode
|
||||
)(input)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
pass
|
||||
def _accessLiteralParser(cls):
|
||||
raise RuntimeError(f"_accessLiteralParser() is not implemented in {cls.__name__} class")
|
||||
|
||||
@staticmethod
|
||||
def _parseAccessingProperty():
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
|
||||
return Parser.oneOf(
|
||||
IdentifierNode._literalParser(),
|
||||
IdentifierNode.identifierParser(),
|
||||
IdentifierNode._functionCallParser(),
|
||||
exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos())
|
||||
)
|
||||
|
||||
@@ -1,13 +1,33 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.literal import LiteralNode
|
||||
from smnp.ast.node.relation import RelationOperatorNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class BoolLiteralNode(LiteralNode, AccessNode):
|
||||
class BoolLiteralNode(LiteralNode, AccessNode, RelationOperatorNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
del self.children[1]
|
||||
|
||||
@classmethod
|
||||
def _getTokenType(cls):
|
||||
return TokenType.BOOL
|
||||
return TokenType.BOOL
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
x = Parser.oneOf(
|
||||
|
||||
cls.relationParser(),
|
||||
cls.accessParser(),
|
||||
cls.literalParser()
|
||||
)(input)
|
||||
return x
|
||||
|
||||
@classmethod
|
||||
def _accessLiteralParser(cls):
|
||||
return cls.literalParser()
|
||||
|
||||
@classmethod
|
||||
def _relationLiteralParser(cls):
|
||||
return cls.literalParser()
|
||||
@@ -50,22 +50,15 @@ class ExpressionNode(Node):
|
||||
|
||||
@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.bool import BoolLiteralNode
|
||||
from smnp.ast.node.identifier import IdentifierNode
|
||||
from smnp.ast.node.list import ListNode
|
||||
from smnp.ast.node.map import MapNode
|
||||
from smnp.ast.node.type import TypeNode
|
||||
|
||||
return Parser.oneOf(
|
||||
IntegerLiteralNode.parse,
|
||||
StringLiteralNode.parse,
|
||||
NoteLiteralNode.parse,
|
||||
#IntegerLiteralNode.parse,
|
||||
#StringLiteralNode.parse,
|
||||
#NoteLiteralNode.parse,
|
||||
BoolLiteralNode.parse,
|
||||
IdentifierNode.parse,
|
||||
MapNode.parse,
|
||||
ListNode.parse,
|
||||
TypeNode.parse,
|
||||
#IdentifierNode.parse,
|
||||
#MapNode.parse,
|
||||
#ListNode.parse,
|
||||
#TypeNode.parse,
|
||||
)
|
||||
@@ -56,7 +56,7 @@ class ImportNode(Node):
|
||||
Parser.terminalParser(TokenType.IMPORT),
|
||||
TypeNode.parse,
|
||||
Parser.doAssert(Parser.terminalParser(TokenType.FROM), "'from <source> as <variable name>'"),
|
||||
Parser.doAssert(StringLiteralNode._literalParser(), "source as a string"),
|
||||
Parser.doAssert(StringLiteralNode.literalParser(), "source as a string"),
|
||||
Parser.doAssert(Parser.terminalParser(TokenType.AS), "'as <variable name>'"),
|
||||
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
|
||||
createNode=createNode
|
||||
@@ -71,6 +71,6 @@ class ImportNode(Node):
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminalParser(TokenType.IMPORT),
|
||||
Parser.doAssert(StringLiteralNode._literalParser(), "source as a string"),
|
||||
Parser.doAssert(StringLiteralNode.literalParser(), "source as a string"),
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class IntegerLiteralNode(AccessNode):
|
||||
class IntegerLiteralNode(ExpressionNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
del self.children[1]
|
||||
#TODO del self.children[1]
|
||||
|
||||
|
||||
# TODO: To Remove
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return cls._literalParser()(input)
|
||||
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.expression import ExpressionNode
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class ListNode(AccessNode):
|
||||
class ListNode(ExpressionNode):
|
||||
|
||||
# TODO: To Remove
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return cls._literalParser()(input)
|
||||
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
|
||||
@@ -13,6 +13,6 @@ class LiteralNode(ExpressionNode):
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _literalParser(cls):
|
||||
def literalParser(cls):
|
||||
createNode = lambda val, pos: cls.withValue(cls._processValue(val), pos)
|
||||
return Parser.terminalParser(cls._getTokenType(), createNode)
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.literal import LiteralNode
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class NoteLiteralNode(LiteralNode, AccessNode):
|
||||
class NoteLiteralNode(LiteralNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
del self.children[1]
|
||||
#TODO del self.children[1]
|
||||
|
||||
|
||||
# TODO: To Remove
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return cls.literalParser()(input)
|
||||
|
||||
@classmethod
|
||||
def _getTokenType(cls):
|
||||
|
||||
50
smnp/ast/node/relation.py
Normal file
50
smnp/ast/node/relation.py
Normal file
@@ -0,0 +1,50 @@
|
||||
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 RelationOperatorNode(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 relationParser(cls):
|
||||
def createNode(left, right):
|
||||
node = RelationOperatorNode(right.pos)
|
||||
node.left = left
|
||||
node.right = right
|
||||
return node
|
||||
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
cls._relationLiteralParser(),
|
||||
TokenType.EQUAL,
|
||||
cls._parseRelationProperty(),
|
||||
createNode=createNode
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _relationLiteralParser(cls):
|
||||
raise RuntimeError(f"_relationLiteralParser() is not implemented in {cls.__name__} class")
|
||||
|
||||
@staticmethod
|
||||
def _parseRelationProperty():
|
||||
# TODO doAssert
|
||||
return ExpressionNode.parse
|
||||
@@ -1,12 +1,17 @@
|
||||
from smnp.ast.node.access import AccessNode
|
||||
from smnp.ast.node.literal import LiteralNode
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class StringLiteralNode(LiteralNode, AccessNode):
|
||||
class StringLiteralNode(LiteralNode):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
del self.children[1]
|
||||
#TODO del self.children[1]
|
||||
|
||||
|
||||
# TODO: To Remove
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
return cls.literalParser()(input)
|
||||
|
||||
@classmethod
|
||||
def _getTokenType(cls):
|
||||
|
||||
@@ -41,6 +41,7 @@ class Parser:
|
||||
value = parser(input)
|
||||
if value.result:
|
||||
return value
|
||||
input.reset(snap)
|
||||
|
||||
if exception is not None:
|
||||
if callable(exception):
|
||||
@@ -96,12 +97,15 @@ class Parser:
|
||||
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
|
||||
def parse(input):
|
||||
left = leftParser(input)
|
||||
oneAtLeast = False
|
||||
if left.result:
|
||||
while Parser.terminalParser(operatorTokenType)(input).result:
|
||||
oneAtLeast = True
|
||||
right = rightParser(input)
|
||||
left = ParseResult.OK(createNode(left.node, right.node))
|
||||
|
||||
return left
|
||||
if oneAtLeast:
|
||||
return left
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
|
||||
12
smnp/main.py
12
smnp/main.py
@@ -1,14 +1,14 @@
|
||||
import sys
|
||||
|
||||
from smnp.ast.node.bool import BoolLiteralNode
|
||||
from smnp.error.base import SmnpException
|
||||
from smnp.library.loader import loadStandardLibrary
|
||||
from smnp.program.interpreter import Interpreter
|
||||
from smnp.token.tokenizer import tokenize
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
stdLibraryEnv = loadStandardLibrary()
|
||||
Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, baseEnvironment=stdLibraryEnv)
|
||||
tokens = tokenize([ "true == true == false.not.not" ])
|
||||
BoolLiteralNode.parse(tokens).node.print()
|
||||
#stdLibraryEnv = loadStandardLibrary()
|
||||
#Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, baseEnvironment=None)
|
||||
|
||||
except SmnpException as e:
|
||||
print(e.message())
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
from smnp.ast.node.block import BlockNode
|
||||
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.program import Program
|
||||
from smnp.ast.node.ret import ReturnNode
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.type.model import Type
|
||||
|
||||
@@ -70,18 +65,13 @@ def evaluate(node, environment):
|
||||
from smnp.runtime.evaluators.program import ProgramEvaluator
|
||||
from smnp.runtime.evaluators.expression import expressionEvaluator
|
||||
|
||||
from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator
|
||||
from smnp.runtime.evaluators.extend import ExtendEvaluator
|
||||
from smnp.runtime.evaluators.block import BlockEvaluator
|
||||
from smnp.runtime.evaluators.imports import ImportEvaluator
|
||||
from smnp.runtime.evaluators.function import ReturnEvaluator
|
||||
result = Evaluator.oneOf(
|
||||
Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
|
||||
Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode),
|
||||
Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
|
||||
Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode),
|
||||
Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode),
|
||||
Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode),
|
||||
#Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode),
|
||||
#Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
|
||||
#Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode),
|
||||
#Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode),
|
||||
#Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode),
|
||||
expressionEvaluator()
|
||||
)(node, environment)
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ from smnp.token.tools import defaultTokenizer, separated, regexPatternTokenizer
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
tokenizers = (
|
||||
defaultTokenizer(TokenType.EQUAL),
|
||||
|
||||
# Characters
|
||||
defaultTokenizer(TokenType.OPEN_CURLY),
|
||||
defaultTokenizer(TokenType.CLOSE_CURLY),
|
||||
|
||||
@@ -2,6 +2,7 @@ from enum import Enum
|
||||
|
||||
|
||||
class TokenType(Enum):
|
||||
EQUAL = '=='
|
||||
OPEN_CURLY = '{'
|
||||
CLOSE_CURLY = '}'
|
||||
OPEN_PAREN = '('
|
||||
|
||||
Reference in New Issue
Block a user