5 Commits

Author SHA1 Message Date
Bartłomiej Pluta
a1bc422fba Fix accessing properties and methods in identifiers with EQUAL 2019-07-10 16:25:06 +02:00
Bartłomiej Pluta
98d710ac97 Add equal ('==') operator to strings 2019-07-10 16:02:39 +02:00
Bartłomiej Pluta
d6fb101337 Add equal ('==') operator to both identifiers and bools 2019-07-10 15:58:37 +02:00
Bartłomiej Pluta
e008be7952 Do some refactor with multiple left associative operators 2019-07-10 15:26:35 +02:00
Bartłomiej Pluta
0a7d29d4a1 Working proof of concept of multiple left associative operators 2019-07-10 15:02:17 +02:00
17 changed files with 212 additions and 64 deletions

View File

@@ -1,5 +1,5 @@
from smnp.ast.node.expression import ExpressionNode 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.ast.parser import Parser
from smnp.error.syntax import SyntaxException from smnp.error.syntax import SyntaxException
from smnp.token.type import TokenType from smnp.token.type import TokenType
@@ -8,7 +8,7 @@ from smnp.token.type import TokenType
class AccessNode(ExpressionNode): class AccessNode(ExpressionNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
self.children.append(IgnoredNode(pos)) self.children = [ NoneNode(), NoneNode() ]
@property @property
def left(self): def left(self):
@@ -27,30 +27,30 @@ class AccessNode(ExpressionNode):
self[1] = value self[1] = value
@classmethod @classmethod
def _parse(cls, input): def accessParser(cls):
def createNode(left, right): def createNode(left, operator, right):
node = AccessNode(right.pos) node = AccessNode(right.pos)
node.left = left node.left = left
node.right = right node.right = right
return node return node
return Parser.leftAssociativeOperatorParser( return Parser.leftAssociativeOperatorParser(
cls._literalParser(), cls._accessLhs(),
TokenType.DOT, TokenType.DOT,
cls._parseAccessingProperty(), cls._accessRhs(),
createNode=createNode createNode=createNode
)(input) )
@classmethod @classmethod
def _literalParser(cls): def _accessLhs(cls):
pass raise RuntimeError(f"_accessLhs() is not implemented in {cls.__name__} class")
@staticmethod @staticmethod
def _parseAccessingProperty(): def _accessRhs():
from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.identifier import IdentifierNode
return Parser.oneOf( return Parser.oneOf(
IdentifierNode._literalParser(), IdentifierNode.functionCallParser(),
IdentifierNode._functionCallParser(), IdentifierNode.identifierParser(),
exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos()) exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos())
) )

View File

@@ -1,13 +1,32 @@
from smnp.ast.node.access import AccessNode from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode 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 from smnp.token.type import TokenType
class BoolLiteralNode(LiteralNode, AccessNode): class BoolLiteralNode(LiteralNode, AccessNode, RelationOperatorNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
del self.children[1] del self.children[1]
@classmethod @classmethod
def _getTokenType(cls): def _getTokenType(cls):
return TokenType.BOOL return TokenType.BOOL
@classmethod
def _parse(cls, input):
x = Parser.oneOf(
cls.accessParser(),
cls.relationParser(),
cls.literalParser()
)(input)
return x
@classmethod
def _accessLhs(cls):
return cls.literalParser()
@classmethod
def _relationLhs(cls):
return cls.literalParser()

View File

@@ -50,22 +50,17 @@ class ExpressionNode(Node):
@classmethod @classmethod
def _expressionParser(cls): 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.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
from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.string import StringLiteralNode
return Parser.oneOf( return Parser.oneOf(
IntegerLiteralNode.parse, #IntegerLiteralNode.parse,
StringLiteralNode.parse, StringLiteralNode.parse,
NoteLiteralNode.parse, #NoteLiteralNode.parse,
BoolLiteralNode.parse, BoolLiteralNode.parse,
IdentifierNode.parse, IdentifierNode.parse,
MapNode.parse, #MapNode.parse,
ListNode.parse, #ListNode.parse,
TypeNode.parse, #TypeNode.parse,
) )

View File

@@ -2,19 +2,39 @@ from smnp.ast.node.access import AccessNode
from smnp.ast.node.assignment import AssignmentNode from smnp.ast.node.assignment import AssignmentNode
from smnp.ast.node.expression import ExpressionNode from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.invocation import FunctionCallNode, ArgumentsListNode from smnp.ast.node.invocation import FunctionCallNode, ArgumentsListNode
from smnp.ast.node.relation import RelationOperatorNode
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
class IdentifierNode(AccessNode): class IdentifierNode(AccessNode, RelationOperatorNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
del self.children[1] del self.children[1]
@classmethod @classmethod
def _literalParser(cls): def _parse(cls, input):
return Parser.oneOf( return Parser.oneOf(
IdentifierNode._functionCallParser(), cls.relationParser(),
cls.accessParser(),
cls.literalParser()
)(input)
@classmethod
def _accessLhs(cls):
return cls.literalParser()
@classmethod
def _relationLhs(cls):
return Parser.oneOf(
cls.accessParser(),
cls.literalParser()
)
@classmethod
def literalParser(cls):
return Parser.oneOf(
IdentifierNode.functionCallParser(),
IdentifierNode._assignmentParser(), IdentifierNode._assignmentParser(),
IdentifierNode.identifierParser() IdentifierNode.identifierParser()
) )
@@ -35,7 +55,7 @@ class IdentifierNode(AccessNode):
) )
@staticmethod @staticmethod
def _functionCallParser(): def functionCallParser():
def createNode(name, arguments): def createNode(name, arguments):
node = FunctionCallNode(name.pos) node = FunctionCallNode(name.pos)
node.name = name node.name = name

View File

@@ -56,7 +56,7 @@ class ImportNode(Node):
Parser.terminalParser(TokenType.IMPORT), Parser.terminalParser(TokenType.IMPORT),
TypeNode.parse, TypeNode.parse,
Parser.doAssert(Parser.terminalParser(TokenType.FROM), "'from <source> as <variable name>'"), 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(Parser.terminalParser(TokenType.AS), "'as <variable name>'"),
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"), Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
createNode=createNode createNode=createNode
@@ -71,6 +71,6 @@ class ImportNode(Node):
return Parser.allOf( return Parser.allOf(
Parser.terminalParser(TokenType.IMPORT), Parser.terminalParser(TokenType.IMPORT),
Parser.doAssert(StringLiteralNode._literalParser(), "source as a string"), Parser.doAssert(StringLiteralNode.literalParser(), "source as a string"),
createNode=createNode createNode=createNode
) )

View File

@@ -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.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
class IntegerLiteralNode(AccessNode): class IntegerLiteralNode(ExpressionNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(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 @classmethod
def _literalParser(cls): def _literalParser(cls):

View File

@@ -1,11 +1,15 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.expression import ExpressionNode from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
from smnp.token.type import TokenType 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 @classmethod
def _literalParser(cls): def _literalParser(cls):

View File

@@ -13,6 +13,6 @@ class LiteralNode(ExpressionNode):
return value return value
@classmethod @classmethod
def _literalParser(cls): def literalParser(cls):
createNode = lambda val, pos: cls.withValue(cls._processValue(val), pos) createNode = lambda val, pos: cls.withValue(cls._processValue(val), pos)
return Parser.terminalParser(cls._getTokenType(), createNode) return Parser.terminalParser(cls._getTokenType(), createNode)

View File

@@ -1,12 +1,17 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode from smnp.ast.node.literal import LiteralNode
from smnp.token.type import TokenType from smnp.token.type import TokenType
class NoteLiteralNode(LiteralNode, AccessNode): class NoteLiteralNode(LiteralNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(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 @classmethod
def _getTokenType(cls): def _getTokenType(cls):

15
smnp/ast/node/operator.py Normal file
View File

@@ -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

68
smnp/ast/node/relation.py Normal file
View File

@@ -0,0 +1,68 @@
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.none import NoneNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class RelationOperatorNode(ExpressionNode):
def __init__(self, pos):
super().__init__(pos)
self.children = [ NoneNode(), NoneNode(), NoneNode()]
@property
def left(self):
return self[0]
@left.setter
def left(self, value):
self[0] = value
@property
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[2] = value
@classmethod
def relationParser(cls):
def createNode(left, operator, right):
node = RelationOperatorNode(right.pos)
node.left = left
node.operator = operator
node.right = right
return node
return Parser.leftAssociativeOperatorParser(
cls._relationLhs(),
TokenType.EQUAL,
cls._relationRhs(),
createNode=createNode
)
@classmethod
def _relationLhs(cls):
raise RuntimeError(f"_relationLhs() is not implemented in {cls.__name__} class")
@staticmethod
def _relationRhs():
from smnp.ast.node.bool import BoolLiteralNode
from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.string import StringLiteralNode
return Parser.doAssert(Parser.oneOf(
BoolLiteralNode.accessParser(),
BoolLiteralNode.literalParser(),
IdentifierNode.parse,
StringLiteralNode.accessParser(),
StringLiteralNode.literalParser()
), "expression")

View File

@@ -1,13 +1,31 @@
from smnp.ast.node.access import AccessNode from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode 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 from smnp.token.type import TokenType
class StringLiteralNode(LiteralNode, AccessNode): class StringLiteralNode(AccessNode, RelationOperatorNode, LiteralNode):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
del self.children[1] del self.children[1]
@classmethod
def _parse(cls, input):
return Parser.oneOf(
cls.accessParser(),
cls.relationParser(),
cls.literalParser()
)(input)
@classmethod
def _accessLhs(cls):
return cls.literalParser()
@classmethod
def _relationLhs(cls):
return cls.literalParser()
@classmethod @classmethod
def _getTokenType(cls): def _getTokenType(cls):
return TokenType.STRING return TokenType.STRING

View File

@@ -1,6 +1,7 @@
from smnp.ast.node.ignore import IgnoredNode from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.node.model import ParseResult, Node from smnp.ast.node.model import ParseResult, Node
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.node.operator import OperatorNode
from smnp.error.syntax import SyntaxException from smnp.error.syntax import SyntaxException
@@ -41,6 +42,7 @@ class Parser:
value = parser(input) value = parser(input)
if value.result: if value.result:
return value return value
input.reset(snap)
if exception is not None: if exception is not None:
if callable(exception): if callable(exception):
@@ -96,12 +98,16 @@ class Parser:
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode): def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
def parse(input): def parse(input):
left = leftParser(input) left = leftParser(input)
oneAtLeast = False
if left.result: 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) 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, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
return left if oneAtLeast:
return left
return ParseResult.FAIL() return ParseResult.FAIL()

View File

@@ -1,14 +1,13 @@
import sys import sys
from smnp.error.base import SmnpException from smnp.error.base import SmnpException
from smnp.library.loader import loadStandardLibrary
from smnp.program.interpreter import Interpreter from smnp.program.interpreter import Interpreter
def main(): def main():
try: try:
stdLibraryEnv = loadStandardLibrary() #stdLibraryEnv = loadStandardLibrary()
Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, baseEnvironment=stdLibraryEnv) Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, baseEnvironment=None)
except SmnpException as e: except SmnpException as e:
print(e.message()) print(e.message())

View File

@@ -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.program import Program
from smnp.ast.node.ret import ReturnNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.type.model import Type 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.program import ProgramEvaluator
from smnp.runtime.evaluators.expression import expressionEvaluator 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( result = Evaluator.oneOf(
Evaluator.forNodes(ProgramEvaluator.evaluate, Program), Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode), #Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode),
Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode), #Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode), #Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode),
Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode), #Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode),
Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode), #Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode),
expressionEvaluator() expressionEvaluator()
)(node, environment) )(node, environment)

View File

@@ -11,6 +11,8 @@ from smnp.token.tools import defaultTokenizer, separated, regexPatternTokenizer
from smnp.token.type import TokenType from smnp.token.type import TokenType
tokenizers = ( tokenizers = (
defaultTokenizer(TokenType.EQUAL),
# Characters # Characters
defaultTokenizer(TokenType.OPEN_CURLY), defaultTokenizer(TokenType.OPEN_CURLY),
defaultTokenizer(TokenType.CLOSE_CURLY), defaultTokenizer(TokenType.CLOSE_CURLY),

View File

@@ -2,6 +2,7 @@ from enum import Enum
class TokenType(Enum): class TokenType(Enum):
EQUAL = '=='
OPEN_CURLY = '{' OPEN_CURLY = '{'
CLOSE_CURLY = '}' CLOSE_CURLY = '}'
OPEN_PAREN = '(' OPEN_PAREN = '('