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.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):
@@ -27,30 +27,30 @@ class AccessNode(ExpressionNode):
self[1] = value
@classmethod
def _parse(cls, input):
def createNode(left, right):
def accessParser(cls):
def createNode(left, operator, right):
node = AccessNode(right.pos)
node.left = left
node.right = right
return node
return Parser.leftAssociativeOperatorParser(
cls._literalParser(),
cls._accessLhs(),
TokenType.DOT,
cls._parseAccessingProperty(),
cls._accessRhs(),
createNode=createNode
)(input)
)
@classmethod
def _literalParser(cls):
pass
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._literalParser(),
IdentifierNode._functionCallParser(),
IdentifierNode.functionCallParser(),
IdentifierNode.identifierParser(),
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.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.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
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
from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.string import StringLiteralNode
return Parser.oneOf(
IntegerLiteralNode.parse,
#IntegerLiteralNode.parse,
StringLiteralNode.parse,
NoteLiteralNode.parse,
#NoteLiteralNode.parse,
BoolLiteralNode.parse,
IdentifierNode.parse,
MapNode.parse,
ListNode.parse,
TypeNode.parse,
#MapNode.parse,
#ListNode.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.expression import ExpressionNode
from smnp.ast.node.invocation import FunctionCallNode, ArgumentsListNode
from smnp.ast.node.relation import RelationOperatorNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class IdentifierNode(AccessNode):
class IdentifierNode(AccessNode, RelationOperatorNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@classmethod
def _literalParser(cls):
def _parse(cls, input):
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.identifierParser()
)
@@ -35,7 +55,7 @@ class IdentifierNode(AccessNode):
)
@staticmethod
def _functionCallParser():
def functionCallParser():
def createNode(name, arguments):
node = FunctionCallNode(name.pos)
node.name = name

View File

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

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.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):

View File

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

View File

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

View File

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

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.literal import LiteralNode
from smnp.ast.node.relation import RelationOperatorNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class StringLiteralNode(LiteralNode, AccessNode):
class StringLiteralNode(AccessNode, RelationOperatorNode, LiteralNode):
def __init__(self, pos):
super().__init__(pos)
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
def _getTokenType(cls):
return TokenType.STRING

View File

@@ -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
@@ -41,6 +42,7 @@ class Parser:
value = parser(input)
if value.result:
return value
input.reset(snap)
if exception is not None:
if callable(exception):
@@ -96,12 +98,16 @@ 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:
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))
return left
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
if oneAtLeast:
return left
return ParseResult.FAIL()

View File

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

View File

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

View File

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