29 Commits

Author SHA1 Message Date
Bartłomiej Pluta
49e4c4487e --wip-- [skip ci] 2019-07-11 19:36:25 +02:00
Bartłomiej Pluta
e7674a4834 Create almost working proof of concept with new parsers 2019-07-11 19:10:13 +02:00
Bartłomiej Pluta
ed2c8dc6dd Create base for future parsers 2019-07-11 18:24:05 +02:00
Bartłomiej Pluta
f91e2a75de Create oneOf and allOf parsers 2019-07-11 17:23:39 +02:00
Bartłomiej Pluta
b80710798b Remove unnecessary old code 2019-07-11 10:34:10 +02:00
Bartłomiej Pluta
3e506354cd Add imports statements 2019-07-11 10:23:28 +02:00
Bartłomiej Pluta
610266a9d2 Add 'not' operator 2019-07-11 10:08:18 +02:00
Bartłomiej Pluta
60b54c357d Create if-else statement 2019-07-11 09:32:05 +02:00
Bartłomiej Pluta
a13c87db14 Create if-else expression 2019-07-11 09:16:09 +02:00
Bartłomiej Pluta
101ce862b0 Create statements and block nodes 2019-07-11 00:18:40 +02:00
Bartłomiej Pluta
5a25ec6ffe Little code refactor 2019-07-11 00:12:00 +02:00
Bartłomiej Pluta
3bbacad83b Add support for maps 2019-07-11 00:08:12 +02:00
Bartłomiej Pluta
10c701ecbf Create loop (dash '^') operator (older asterisk '*') 2019-07-10 23:56:21 +02:00
Bartłomiej Pluta
e115c6e33a Fix ARROW operator 2019-07-10 23:21:51 +02:00
Bartłomiej Pluta
18884eb5d9 Add support for assignments, function calls and pure identifiers 2019-07-10 23:19:46 +02:00
Bartłomiej Pluta
24b1012c7c Improve list to make use of max precedence expression parser 2019-07-10 22:49:20 +02:00
Bartłomiej Pluta
175bea6e5c Create expression3 (logic 'and') and expression4 (logic 'or') precedence 2019-07-10 22:46:58 +02:00
Bartłomiej Pluta
3058293b7e Create expression2 precendence level (relation operators) 2019-07-10 22:39:22 +02:00
Bartłomiej Pluta
4018bcddc7 Create expression precendence level 2019-07-10 22:27:44 +02:00
Bartłomiej Pluta
1d573c8c80 Create term precendence level 2019-07-10 22:05:45 +02:00
Bartłomiej Pluta
29820fb2ee Create factor level 2019-07-10 22:00:01 +02:00
Bartłomiej Pluta
9dc8d5a650 Add lists to base items 2019-07-10 21:56:38 +02:00
Bartłomiej Pluta
ab990f3071 Create parser for chain (dot operator) 2019-07-10 21:31:02 +02:00
Bartłomiej Pluta
e31dab52f6 Create parsers for literals (atoms) 2019-07-10 21:23:45 +02:00
Bartłomiej Pluta
66554f6c37 Improve parser to contain name and subparsers 2019-07-10 20:53:36 +02:00
Bartłomiej Pluta
aefa8e8f3c Create simple calc as test draft 2019-07-10 20:14:05 +02:00
Bartłomiej Pluta
76eabbff0e Refactor LeftAssociativeOperatorNode 2019-07-10 17:02:18 +02:00
Bartłomiej Pluta
214eec0e7a Rename 'access.py' to 'operator.py' 2019-07-10 16:55:37 +02:00
Bartłomiej Pluta
88b245dc05 Make access node more generic 2019-07-10 16:51:11 +02:00
42 changed files with 1480 additions and 1029 deletions

View File

@@ -1,56 +0,0 @@
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.parser import Parser
from smnp.error.syntax import SyntaxException
from smnp.token.type import TokenType
class AccessNode(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 _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(),
exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos())
)

View File

@@ -1,28 +0,0 @@
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.none import NoneNode
class AssignmentNode(ExpressionNode):
def __init__(self, pos):
super().__init__(pos)
self.children.append(NoneNode())
@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")

View File

@@ -1,28 +0,0 @@
from smnp.ast.node.none import NoneNode
from smnp.ast.node.statement import StatementNode
class AsteriskNode(StatementNode):
def __init__(self, pos):
super().__init__(pos)
self.children = [NoneNode(), NoneNode()]
@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")

103
smnp/ast/node/atom.py Normal file
View File

@@ -0,0 +1,103 @@
from smnp.ast.node.model import Node
from smnp.ast.parser import Parsers
from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class Atom(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
@classmethod
def withValue(cls, value, pos):
node = cls(pos)
node.value = value
return node
class IntegerLiteral(Atom):
pass
class StringLiteral(Atom):
pass
class NoteLiteral(Atom):
pass
class BoolLiteral(Atom):
pass
class TypeLiteral(Atom):
pass
@SingletonParser
def IntegerParser():
return Parsers.oneOf(
Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
Parsers.allOf(
Parsers.terminal(TokenType.MINUS),
Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
createNode=lambda minus, integer: IntegerLiteral.withValue(-integer.value, minus.pos),
name="negativeInteger"
),
name="int"
)
@SingletonParser
def StringParser():
return Parsers.terminal(TokenType.STRING, createNode=StringLiteral.withValue)
@SingletonParser
def NoteParser():
return Parsers.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)
@SingletonParser
def BoolParser():
return Parsers.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)
@SingletonParser
def TypeParser():
return Parsers.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)
@SingletonParser
def LiteralParser():
return Parsers.oneOf(
IntegerParser(),
StringParser(),
NoteParser(),
BoolParser(),
TypeParser(),
name="literal"
)
@SingletonParser
def AtomParser():
from smnp.ast.node.identifier import IdentifierParser
return Parsers.oneOf(
LiteralParser(),
IdentifierParser(),
name="atom"
)

View File

@@ -1,20 +1,19 @@
from smnp.ast.node.statement import StatementNode from smnp.ast.node.model import Node
from smnp.ast.node.statement import StatementParser
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 BlockNode(StatementNode): class Block(Node):
pass
@classmethod
def _parse(cls, input):
def createNode(start, items, end):
node = BlockNode(start.pos)
node.children = items
return node
return Parser.loop( def BlockParser(input):
Parser.terminalParser(TokenType.OPEN_CURLY), parser = Parser.loop(
Parser.doAssert(StatementNode.parse, f"statement or '{TokenType.CLOSE_CURLY.key}'"), Parser.terminalParser(TokenType.OPEN_CURLY),
Parser.terminalParser(TokenType.CLOSE_CURLY), Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"),
createNode=createNode, Parser.terminalParser(TokenType.CLOSE_CURLY),
)(input) createNode=lambda open, statements, close: Block.withChildren(statements, open.pos)
)
return Parser(parser, "block", [parser])(input)

View File

@@ -1,13 +0,0 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode
from smnp.token.type import TokenType
class BoolLiteralNode(LiteralNode, AccessNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@classmethod
def _getTokenType(cls):
return TokenType.BOOL

32
smnp/ast/node/chain.py Normal file
View File

@@ -0,0 +1,32 @@
from smnp.ast.node.list import ListParser
from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.valuable import Valuable
from smnp.ast.parser import Parsers
from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class Chain(Valuable):
pass
@SingletonParser
def ChainParser():
from smnp.ast.node.atom import AtomParser
itemParser = Parsers.oneOf(
ListParser,
#MapParser,
AtomParser,
name="chainItem"
)
return Parsers.leftAssociativeOperatorParser(
itemParser,
[TokenType.DOT],
itemParser,
lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right)),
name="chain"
)

View File

@@ -0,0 +1,74 @@
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode
from smnp.ast.node.statement import StatementParser
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class IfElse(Node):
def __init__(self, pos):
super().__init__(pos)
self.children = [NoneNode(), NoneNode(), NoneNode()]
@property
def condition(self):
return self[0]
@condition.setter
def condition(self, value):
self[0] = value
@property
def ifNode(self):
return self[1]
@ifNode.setter
def ifNode(self, value):
self[1] = value
@property
def elseNode(self):
return self[2]
@elseNode.setter
def elseNode(self, value):
self[2] = value
@classmethod
def createNode(cls, ifNode, condition, elseNode=NoneNode()):
node = cls(ifNode.pos)
node.ifNode = ifNode
node.condition = condition
node.elseNode = elseNode
return node
def IfElseStatementParser(input):
ifStatementParser = Parser.allOf(
Parser.terminalParser(TokenType.IF),
Parser.terminalParser(TokenType.OPEN_PAREN),
MaxPrecedenceExpressionParser,
Parser.terminalParser(TokenType.CLOSE_PAREN),
StatementParser,
createNode=lambda _, __, condition, ___, ifStatement: IfElse.createNode(ifStatement, condition),
name="if statement"
)
ifElseStatementParser = Parser.allOf(
Parser.terminalParser(TokenType.IF),
Parser.terminalParser(TokenType.OPEN_PAREN),
MaxPrecedenceExpressionParser,
Parser.terminalParser(TokenType.CLOSE_PAREN),
StatementParser,
Parser.terminalParser(TokenType.ELSE),
StatementParser,
createNode=lambda _, __, condition, ___, ifStatement, ____, elseStatement: IfElse.createNode(ifStatement, condition, elseStatement),
name="if-else statement"
)
return Parser.oneOf(
ifElseStatementParser,
ifStatementParser,
name="if-else/if statement"
)(input)

View File

@@ -1,71 +1,63 @@
from smnp.ast.node.asterisk import AsteriskNode from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.model import Node from smnp.ast.node.term import TermParser
from smnp.ast.node.none import NoneNode from smnp.ast.node.valuable import Valuable
from smnp.ast.node.statement import StatementNode
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 ExpressionNode(Node): class Expression(Valuable):
def __init__(self, pos): pass
super().__init__(pos, [NoneNode()])
@property
def value(self):
return self[0]
@value.setter def ExpressionParser(input):
def value(self, v): return Parser.leftAssociativeOperatorParser(
self[0] = v TermParser,
[TokenType.PLUS, TokenType.MINUS],
TermParser,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
)(input)
@classmethod def Expression2Parser(input):
def withValue(cls, val, pos): return Parser.leftAssociativeOperatorParser(
node = cls(pos) ExpressionParser,
node.value = val [TokenType.RELATION],
return node ExpressionParser,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
)(input)
@classmethod
def _parse(cls, input):
return Parser.oneOf(
cls._asteriskParser(),
cls._expressionParser(),
)(input)
@classmethod def Expression3Parser(input):
def _asteriskParser(cls): return Parser.leftAssociativeOperatorParser(
def createNode(iterator, asterisk, statement): Expression2Parser,
node = AsteriskNode(asterisk.pos) [TokenType.AND],
node.iterator = iterator Expression2Parser,
node.statement = statement lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
return node )(input)
return Parser.allOf(
cls._expressionParser(),
Parser.terminalParser(TokenType.ASTERISK),
Parser.doAssert(StatementNode.parse, 'statement'),
createNode=createNode
)
@classmethod def Expression4Parser(input):
def _expressionParser(cls): from smnp.ast.node.condition import IfElse
from smnp.ast.node.integer import IntegerLiteralNode exprParser = Parser.leftAssociativeOperatorParser(
from smnp.ast.node.string import StringLiteralNode Expression3Parser,
from smnp.ast.node.note import NoteLiteralNode [TokenType.OR],
from smnp.ast.node.bool import BoolLiteralNode Expression3Parser,
from smnp.ast.node.identifier import IdentifierNode lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
from smnp.ast.node.list import ListNode )
from smnp.ast.node.map import MapNode
from smnp.ast.node.type import TypeNode
return Parser.oneOf( ifElseExpression = Parser.allOf(
IntegerLiteralNode.parse, exprParser,
StringLiteralNode.parse, Parser.terminalParser(TokenType.IF),
NoteLiteralNode.parse, Expression4Parser,
BoolLiteralNode.parse, Parser.terminalParser(TokenType.ELSE),
IdentifierNode.parse, Expression4Parser,
MapNode.parse, createNode=lambda ifNode, _, condition, __, elseNode: IfElse.createNode(ifNode, condition, elseNode)
ListNode.parse, )
TypeNode.parse,
) return Parser.oneOf(
ifElseExpression,
exprParser,
)(input)
MaxPrecedenceExpressionParser = Expression4Parser

View File

@@ -1,70 +1,70 @@
from smnp.ast.node.block import BlockNode # from smnp.ast.node.block import BlockNode
from smnp.ast.node.function import FunctionDefinitionNode # from smnp.ast.node.function import FunctionDefinitionNode
from smnp.ast.node.identifier import IdentifierNode # from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.none import NoneNode # from smnp.ast.node.none import NoneNode
from smnp.ast.node.statement import StatementNode # from smnp.ast.node.statement import StatementNode
from smnp.ast.node.type import TypeNode # from smnp.ast.node.type import TypeNode
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 ExtendNode(StatementNode): # class ExtendNode(StatementNode):
def __init__(self, pos): # def __init__(self, pos):
super().__init__(pos) # super().__init__(pos)
self.children = [NoneNode(), NoneNode(), NoneNode()] # self.children = [NoneNode(), NoneNode(), NoneNode()]
#
@property # @property
def type(self): # def type(self):
return self[0] # return self[0]
#
@type.setter # @type.setter
def type(self, value): # def type(self, value):
self[0] = value # self[0] = value
#
@property # @property
def variable(self): # def variable(self):
return self[1] # return self[1]
#
@variable.setter # @variable.setter
def variable(self, value): # def variable(self, value):
self[1] = value # self[1] = value
#
@property # @property
def methods(self): # def methods(self):
return self[2] # return self[2]
#
@methods.setter # @methods.setter
def methods(self, value): # def methods(self, value):
self[2] = value # self[2] = value
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
def createNode(extend, type, asKeyword, variable, methods): # def createNode(extend, type, asKeyword, variable, methods):
node = ExtendNode(extend.pos) # node = ExtendNode(extend.pos)
node.type = type # node.type = type
node.variable = variable # node.variable = variable
node.methods = methods # node.methods = methods
return node # return node
#
return Parser.allOf( # return Parser.allOf(
Parser.terminalParser(TokenType.EXTEND), # Parser.terminalParser(TokenType.EXTEND),
Parser.doAssert(TypeNode.parse, "type being extended"), # Parser.doAssert(TypeNode.parse, "type being extended"),
Parser.terminalParser(TokenType.AS, doAssert=True), # Parser.terminalParser(TokenType.AS, doAssert=True),
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"), # Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
Parser.doAssert(cls._methodsDeclarationsParser(), "methods declarations"), # Parser.doAssert(cls._methodsDeclarationsParser(), "methods declarations"),
createNode=createNode # createNode=createNode
)(input) # )(input)
#
@classmethod # @classmethod
def _methodsDeclarationsParser(cls): # def _methodsDeclarationsParser(cls):
def createNode(openBracket, items, closeBracket): # def createNode(openBracket, items, closeBracket):
node = BlockNode(openBracket.pos) # node = BlockNode(openBracket.pos)
node.children = items # node.children = items
return node # return node
#
return Parser.loop( # return Parser.loop(
Parser.terminalParser(TokenType.OPEN_CURLY), # Parser.terminalParser(TokenType.OPEN_CURLY),
Parser.doAssert(FunctionDefinitionNode.parse, f"method declaration or '{TokenType.CLOSE_CURLY.key}'"), # Parser.doAssert(FunctionDefinitionNode.parse, f"method declaration or '{TokenType.CLOSE_CURLY.key}'"),
Parser.terminalParser(TokenType.CLOSE_CURLY), # Parser.terminalParser(TokenType.CLOSE_CURLY),
createNode=createNode # createNode=createNode
) # )

64
smnp/ast/node/factor.py Normal file
View File

@@ -0,0 +1,64 @@
from smnp.ast.node.chain import ChainParser
from smnp.ast.node.operator import BinaryOperator, Operator, UnaryOperator
from smnp.ast.node.valuable import Valuable
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class Factor(Valuable):
pass
class NotOperator(UnaryOperator):
pass
class Loop(BinaryOperator):
pass
def FactorParser(input):
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
from smnp.ast.node.statement import StatementParser
powerFactor = Parser.leftAssociativeOperatorParser(
ChainParser,
[TokenType.DOUBLE_ASTERISK],
ChainParser,
lambda left, op, right: Factor.withValue(BinaryOperator.withValues(left, op, right)),
name="power operator"
)
exprFactor = Parser.allOf(
Parser.terminalParser(TokenType.OPEN_PAREN),
MaxPrecedenceExpressionParser,
Parser.terminalParser(TokenType.CLOSE_PAREN),
createNode=lambda open, expr, close: expr,
name="grouping parentheses"
)
factorParser = Parser.oneOf(
powerFactor,
exprFactor,
name="basic factor"
)
notOperator = Parser.allOf(
Parser.terminalParser(TokenType.NOT, Operator.withValue),
factorParser,
createNode=NotOperator.withValues,
name="not"
)
loopFactor = Parser.allOf(
factorParser,
Parser.terminalParser(TokenType.DASH, createNode=Operator.withValue),
StatementParser,
createNode=Loop.withValues,
name="dash-loop"
)
return Parser.oneOf(
loopFactor,
notOperator,
factorParser
)(input)

View File

@@ -1,128 +1,128 @@
from smnp.ast.node.block import BlockNode # from smnp.ast.node.block import BlockNode
from smnp.ast.node.expression import ExpressionNode # from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.identifier import IdentifierNode # from smnp.ast.node.identifier import IdentifierNode
from smnp.ast.node.iterable import abstractIterableParser # from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node # from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode # from smnp.ast.node.none import NoneNode
from smnp.ast.node.statement import StatementNode # from smnp.ast.node.statement import StatementNode
from smnp.ast.node.type import TypeNode, TypeSpecifier # from smnp.ast.node.type import TypeNode, TypeSpecifier
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 ArgumentsDeclarationNode(Node): # class ArgumentsDeclarationNode(Node):
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
raise RuntimeError("This class is not supposed to be automatically called") # raise RuntimeError("This class is not supposed to be automatically called")
#
#
class VarargNode(Node): # class VarargNode(Node):
pass # pass
#
#
class ArgumentDefinitionNode(ExpressionNode): # class ArgumentDefinitionNode(ExpressionNode):
def __init__(self, pos): # def __init__(self, pos):
super().__init__(pos) # super().__init__(pos)
self.children.extend([NoneNode(), False]) # self.children.extend([NoneNode(), False])
#
@property # @property
def type(self): # def type(self):
return self[0] # return self[0]
#
@type.setter # @type.setter
def type(self, value): # def type(self, value):
self[0] = value # self[0] = value
#
@property # @property
def variable(self): # def variable(self):
return self[1] # return self[1]
#
@variable.setter # @variable.setter
def variable(self, value): # def variable(self, value):
self[1] = value # self[1] = value
#
@property # @property
def vararg(self): # def vararg(self):
return self[2] # return self[2]
#
@vararg.setter # @vararg.setter
def vararg(self, value): # def vararg(self, value):
self[2] = value # self[2] = value
#
#
@classmethod # @classmethod
def parser(cls): # def parser(cls):
def createNode(type, variable, dots): # def createNode(type, variable, dots):
node = ArgumentDefinitionNode(type.pos) # node = ArgumentDefinitionNode(type.pos)
node.type = type # node.type = type
node.variable = variable # node.variable = variable
node.vararg = isinstance(dots, VarargNode) # node.vararg = isinstance(dots, VarargNode)
return node # return node
#
return Parser.allOf( # return Parser.allOf(
Parser.optional(Parser.oneOf( # Parser.optional(Parser.oneOf(
TypeNode.parse, # TypeNode.parse,
TypeSpecifier.parse # TypeSpecifier.parse
)), # )),
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"), # Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
Parser.optional(Parser.terminalParser(TokenType.DOTS, lambda val, pos: VarargNode(pos))), # Parser.optional(Parser.terminalParser(TokenType.DOTS, lambda val, pos: VarargNode(pos))),
createNode=createNode # createNode=createNode
) # )
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
#TODO # #TODO
raise RuntimeError("Not implemented yet. There is still required work to correctly build AST related to IdentifierNode") # raise RuntimeError("Not implemented yet. There is still required work to correctly build AST related to IdentifierNode")
#
#
#
class FunctionDefinitionNode(StatementNode): # class FunctionDefinitionNode(StatementNode):
def __init__(self, pos): # def __init__(self, pos):
super().__init__(pos) # super().__init__(pos)
self.children = [NoneNode(), NoneNode(), NoneNode()] # self.children = [NoneNode(), NoneNode(), NoneNode()]
#
@property # @property
def name(self): # def name(self):
return self[0] # return self[0]
#
@name.setter # @name.setter
def name(self, value): # def name(self, value):
self[0] = value # self[0] = value
#
@property # @property
def arguments(self): # def arguments(self):
return self[1] # return self[1]
#
@arguments.setter # @arguments.setter
def arguments(self, value): # def arguments(self, value):
self[1] = value # self[1] = value
#
@property # @property
def body(self): # def body(self):
return self[2] # return self[2]
#
@body.setter # @body.setter
def body(self, value): # def body(self, value):
self[2] = value # self[2] = value
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
def createNode(function, name, arguments, body): # def createNode(function, name, arguments, body):
node = FunctionDefinitionNode(function.pos) # node = FunctionDefinitionNode(function.pos)
node.name = name # node.name = name
node.arguments = arguments # node.arguments = arguments
node.body = body # node.body = body
return node # return node
#
return Parser.allOf( # return Parser.allOf(
Parser.terminalParser(TokenType.FUNCTION), # Parser.terminalParser(TokenType.FUNCTION),
Parser.doAssert(IdentifierNode.identifierParser(), "function name"), # Parser.doAssert(IdentifierNode.identifierParser(), "function name"),
Parser.doAssert(cls._argumentsDeclarationParser(), "arguments list"), # Parser.doAssert(cls._argumentsDeclarationParser(), "arguments list"),
Parser.doAssert(BlockNode.parse, "function body"), # Parser.doAssert(BlockNode.parse, "function body"),
createNode=createNode # createNode=createNode
)(input) # )(input)
#
@staticmethod # @staticmethod
def _argumentsDeclarationParser(): # def _argumentsDeclarationParser():
return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, ArgumentDefinitionNode.parser()) # return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, ArgumentDefinitionNode.parser())

View File

@@ -1,53 +1,75 @@
from smnp.ast.node.access import AccessNode from smnp.ast.node.atom import Atom
from smnp.ast.node.assignment import AssignmentNode 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.invocation import FunctionCallNode, ArgumentsListNode from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers
from smnp.token.type import TokenType from smnp.token.type import TokenType
from smnp.util.singleton import SingletonParser
class IdentifierNode(AccessNode): class Identifier(Atom):
pass
class FunctionCall(Node):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
del self.children[1] self.children = [NoneNode(), NoneNode()]
@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 @classmethod
def _literalParser(cls): def withChildren(cls, name, arguments):
return Parser.oneOf( node = cls(name.pos)
IdentifierNode._functionCallParser(), node.name = name
IdentifierNode._assignmentParser(), node.arguments = arguments
IdentifierNode.identifierParser() return node
)
@staticmethod
def _assignmentParser():
def createNode(target, assignment, value):
node = AssignmentNode(assignment.pos)
node.target = target
node.value = value
return node
return Parser.allOf( class ArgumentsList(Node):
IdentifierNode.identifierParser(), pass
Parser.terminalParser(TokenType.ASSIGN),
Parser.doAssert(ExpressionNode.parse, "expression"),
createNode=createNode
)
@staticmethod
def _functionCallParser():
def createNode(name, arguments):
node = FunctionCallNode(name.pos)
node.name = name
node.arguments = arguments
return node
return Parser.allOf( class Assignment(BinaryOperator):
IdentifierNode.identifierParser(), pass
ArgumentsListNode.parse,
createNode=createNode
)
@staticmethod
def identifierParser(): @SingletonParser
return Parser.terminalParser(TokenType.IDENTIFIER, lambda val, pos: IdentifierNode.withValue(val, pos)) def IdentifierParser():
identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)
functionCallParser = Parsers.allOf(
identifierLiteralParser,
#abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser),
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments),
name="functionCall"
)
assignmentParser = Parsers.allOf(
identifierLiteralParser,
Parsers.terminal(TokenType.ASSIGN, createNode=Operator.withValue),
#MaxPrecedenceExpressionParser,
createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr),
name="assignment"
)
return Parsers.oneOf(
assignmentParser,
functionCallParser,
identifierLiteralParser,
name="idExpr"
)

View File

@@ -1,16 +1,21 @@
from smnp.ast.node.identifier import IdentifierNode # from smnp.ast.node.identifier import Identifier
# 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
#
from smnp.ast.node.atom import StringParser
from smnp.ast.node.model import Node 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.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
class ImportNode(Node): class Import(Node):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
self.children = [NoneNode(), NoneNode(), NoneNode()] self.children = [None]
@property @property
def source(self): def source(self):
@@ -20,57 +25,17 @@ class ImportNode(Node):
def source(self, value): def source(self, value):
self[0] = 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 @classmethod
def _parse(cls, input): def withValue(cls, value):
return Parser.oneOf( node = cls(value.pos)
cls._literalImportParser(), node.source = value
cls._fileImportParser() return node
)(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( def ImportParser(input):
Parser.terminalParser(TokenType.IMPORT), return Parser.allOf(
TypeNode.parse, Parser.terminalParser(TokenType.IMPORT),
Parser.doAssert(Parser.terminalParser(TokenType.FROM), "'from <source> as <variable name>'"), StringParser,
Parser.doAssert(StringLiteralNode._literalParser(), "source as a string"), createNode=lambda imp, source: Import.withValue(source),
Parser.doAssert(Parser.terminalParser(TokenType.AS), "'as <variable name>'"), name="import"
Parser.doAssert(IdentifierNode.identifierParser(), "variable name"), )(input)
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),
Parser.doAssert(StringLiteralNode._literalParser(), "source as a string"),
createNode=createNode
)

View File

@@ -1,31 +0,0 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class IntegerLiteralNode(AccessNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@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),
Parser.doAssert(cls._positiveIntegerParser(), "integer"),
createNode=createNode
)
@classmethod
def _positiveIntegerParser(cls):
return Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteralNode.withValue(int(val), pos))

View File

@@ -1,40 +0,0 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class ArgumentsListNode(Node):
@classmethod
def _parse(cls, input):
return abstractIterableParser(ArgumentsListNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN,
Parser.doAssert(ExpressionNode.parse, "expression"))(input)
class FunctionCallNode(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")

View File

@@ -1,17 +1,24 @@
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.ignore import IgnoredNode from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.node.model import Node, ParseResult from smnp.ast.node.model import Node, ParseResult
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.parser import Parser from smnp.ast.parser import Parsers, DecoratorParser
from smnp.token.type import TokenType from smnp.token.type import TokenType
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser): def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser, name):
class AbstractIterableTailNode(ExpressionNode):
class AbstractIterable(Node):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
self.children = [NoneNode(), NoneNode()]
self.children.append(NoneNode()) @property
def value(self):
return self[0]
@value.setter
def value(self, value):
self[0] = value
@property @property
def next(self): def next(self):
@@ -21,89 +28,77 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item
def next(self, value): def next(self, value):
self[1] = value self[1] = value
@classmethod class AbstractIterableTail(AbstractIterable):
def _parse(cls, input): pass
return Parser.oneOf(
AbstractIterableTailNode._parser1(),
AbstractIterableTailNode._parser2(),
)(input)
@staticmethod def abstractIterableParser():
def _parser1(): return Parsers.oneOf(
return Parser.terminalParser(closeTokenType) emptyIterable(),
openIterable(),
name=name
)
@staticmethod def emptyIterable():
def _parser2(): def createNode(open, close):
def createNode(comma, expr, iterableTail): node = AbstractIterable(open.pos)
node = AbstractIterableTailNode(expr.pos) node.value = open
node.value = expr node.next = close
node.next = iterableTail return node
return node
return Parser.allOf( return Parsers.allOf(
Parser.terminalParser(TokenType.COMMA, doAssert=True), Parsers.terminal(openTokenType),
itemParser, Parsers.terminal(closeTokenType),
AbstractIterableTailNode.parse, createNode=createNode,
createNode=createNode name=name+"Empty"
) )
class AbstractIterableNode(ExpressionNode): def openIterable():
def __init__(self, pos): def createNode(open, item, tail):
super().__init__(pos) node = AbstractIterable(open.pos)
node.value = item
node.next = tail
return node
self.children.append(NoneNode()) return Parsers.allOf(
Parsers.terminal(openTokenType),
itemParser,
abstractIterableTailParser(),
createNode=createNode,
name=name+"Open"
)
@property def abstractIterableTailParser():
def next(self): return Parsers.oneOf(
return self[1] closeIterable(),
nextItem(),
name=name+"Tail"
)
@next.setter def nextItem():
def next(self, value): def createNode(comma, item, tail):
self[1] = value node = AbstractIterableTail(item.pos)
node.value = item
node.next = tail
return node
@classmethod return Parsers.allOf(
def _parse(cls, input): Parsers.terminal(TokenType.COMMA, doAssert=True),
return Parser.oneOf( itemParser,
AbstractIterableNode._parser1(), abstractIterableTailParser(),
AbstractIterableNode._parser2() name=name+"NextItem",
)(input) createNode=createNode
)
@staticmethod def closeIterable():
def _parser1(): return Parsers.terminal(closeTokenType)
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 return abstractIterableParser()
def _parser2(): #return toFlatDesiredNode(iterableNodeType, abstractIterableParser())
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 toFlatDesiredNode(iterableNodeType, parser):
def parse(input): def wrapper(result):
result = parser(input)
if result.result: if result.result:
value = flattenList(result.node) value = flattenList(result.node)
node = iterableNodeType(result.node.pos) node = iterableNodeType(result.node.pos)
@@ -114,7 +109,7 @@ def toFlatDesiredNode(iterableNodeType, parser):
return ParseResult.FAIL() return ParseResult.FAIL()
return parse return DecoratorParser(wrapper, parser)
def flattenList(node, output=None): def flattenList(node, output=None):

View File

@@ -1,13 +1,13 @@
from smnp.ast.node.access import AccessNode from smnp.ast.node.atom import AtomParser
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.node.model import Node
from smnp.token.type import TokenType from smnp.token.type import TokenType
class ListNode(AccessNode): class List(Node):
pass
@classmethod
def _literalParser(cls): def ListParser():
return abstractIterableParser(ListNode, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, return abstractIterableParser(List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, AtomParser(), name="list")
Parser.doAssert(ExpressionNode.parse, "expression")) #MaxPrecedenceExpressionParser)(input)

View File

@@ -1,18 +0,0 @@
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)

View File

@@ -1,19 +1,11 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.bool import BoolLiteralNode
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.integer import IntegerLiteralNode
from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.none import NoneNode from smnp.ast.node.model import Node
from smnp.ast.node.note import NoteLiteralNode from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.node.string import StringLiteralNode from smnp.ast.parser import Parsers
from smnp.ast.node.type import TypeNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
class MapEntry(ExpressionNode):
def __init__(self, pos): class MapEntry(BinaryOperator):
super().__init__(pos)
self.children = [NoneNode(), NoneNode()]
@property @property
def key(self): def key(self):
@@ -25,39 +17,31 @@ class MapEntry(ExpressionNode):
@property @property
def value(self): def value(self):
return self[1] return self[2]
@value.setter @value.setter
def value(self, value): def value(self, value):
self[1] = value self[2] = value
class MapNode(AccessNode):
@classmethod class Map(Node):
def _literalParser(cls): pass
return abstractIterableParser(MapNode, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, cls._entryParser())
@classmethod
def _entryParser(cls):
def createNode(key, arrow, value):
node = MapEntry(key.pos)
node.key = key
node.value = value
return node
return Parser.allOf( def MapParser(input):
cls._keyParser(), from smnp.ast.node.atom import LiteralParser
Parser.terminalParser(TokenType.ARROW), #from smnp.ast.node.expression import MaxPrecedenceExpressionParser
ExpressionNode.parse, keyParser = LiteralParser
createNode=createNode #valueParser = MaxPrecedenceExpressionParser
)
mapEntryParser = Parsers.allOf(
keyParser,
Parsers.terminal(TokenType.ARROW, createNode=Operator.withValue),
#valueParser,
createNode=MapEntry.withValues,
name="mapEntry"
)
return abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser)
@classmethod
def _keyParser(cls):
return Parser.oneOf(
IntegerLiteralNode._literalParser(),
StringLiteralNode._literalParser(),
NoteLiteralNode._literalParser(),
BoolLiteralNode._literalParser(),
TypeNode.parse
)

View File

@@ -47,7 +47,7 @@ class Node:
self._print(first=True) self._print(first=True)
def _print(self, prefix="", last=True, first=False): def _print(self, prefix="", last=True, first=False):
print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, sep="") print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, f" (line {self.pos[0]+1}, col {self.pos[1]+1})", sep="")
prefix += ' ' if last else '' prefix += ' ' if last else ''
for i, child in enumerate(self.children): for i, child in enumerate(self.children):
last = i == len(self.children) - 1 last = i == len(self.children) - 1

View File

@@ -1,13 +0,0 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode
from smnp.token.type import TokenType
class NoteLiteralNode(LiteralNode, AccessNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@classmethod
def _getTokenType(cls):
return TokenType.NOTE

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

@@ -0,0 +1,150 @@
from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode
class UnaryOperator(Node):
def __init__(self, pos):
super().__init__(pos)
self.children=[NoneNode(), NoneNode()]
@property
def operator(self):
return self[0]
@operator.setter
def operator(self, value):
self[0] = value
@property
def value(self):
return self[1]
@value.setter
def value(self, value):
self[1] = value
@classmethod
def withValues(cls, operator, value):
node = cls(operator.pos)
node.operator = operator
node.value = value
return node
class BinaryOperator(Node):
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 withValues(cls, left, operator, right):
node = cls(operator.pos)
node.left = left
node.operator = operator
node.right = right
return node
#
# class LeftAssociativeOperatorNode(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 _parse(cls, input):
# def createNode(left, operator, right):
# node = LeftAssociativeOperatorNode(right.pos)
# node.left = left
# node.operator = operator
# node.right = right
# return node
#
# return Parser.leftAssociativeOperatorParser(
# cls._lhsParser(),
# TokenType.DOT,
# cls._rhsParser(),
# createNode=createNode
# )(input)
#
# @classmethod
# def _lhsParser(cls):
# raise RuntimeError(f"LHS parser is not implemented in {cls.__name__}")
#
# @staticmethod
# def _rhsParser():
# from smnp.ast.node.identifier import IdentifierNode
#
# return Parser.oneOf(
# # TODO!!!
# IdentifierNode._lhsParser(),
# IdentifierNode._functionCallParser(),
# exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos())
# )
#
#
class Operator(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
@classmethod
def withValue(cls, value, pos):
node = cls(pos)
node.value = value
return node

View File

@@ -1,32 +1,44 @@
from smnp.ast.node.expression import ExpressionNode from smnp.ast.node.imports import ImportParser
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.model import Node, ParseResult
from smnp.ast.node.statement import StatementNode from smnp.ast.node.statement import StatementParser
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
from smnp.error.syntax import SyntaxException
class Program(Node): class Program(Node):
def __init__(self): def __init__(self):
super().__init__((-1, -1)) super().__init__((-1, -1))
@classmethod def parse(input):
def _parse(cls, input): root = Program()
def parseToken(input): while input.hasCurrent():
return Parser.oneOf( result = Parser.oneOf(
FunctionDefinitionNode.parse, # Start Symbol
ExtendNode.parse, ImportParser,
ExpressionNode.parse, StatementParser,
ImportNode.parse, exception=RuntimeError("Nie znam tego wyrazenia")
StatementNode.parse, )(input)
exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos)
)(input)
root = Program() if result.result:
while input.hasCurrent(): root.append(result.node)
result = parseToken(input)
if result.result: return ParseResult.OK(root)
root.append(result.node)
return ParseResult.OK(root) ProgramParser = Parser(parse, name="program")
# @classmethod
# def _parse(cls, input):
# def parseToken(input):
# return Parser.oneOf(
# FunctionDefinitionNode.parse,
# ExtendNode.parse,
# ExpressionNode.parse,
# ImportNode.parse,
# StatementNode.parse,
# exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos)
# )(input)
#
# root = Program()
# while input.hasCurrent():
# result = parseToken(input)
# if result.result:
# root.append(result.node)
# return ParseResult.OK(root)

View File

@@ -1,32 +1,32 @@
from smnp.ast.node.expression import ExpressionNode # from smnp.ast.node.expression import ExpressionNode
from smnp.ast.node.none import NoneNode # from smnp.ast.node.none import NoneNode
from smnp.ast.node.statement import StatementNode # from smnp.ast.node.statement import StatementNode
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 ReturnNode(StatementNode): # class ReturnNode(StatementNode):
def __init__(self, pos): # def __init__(self, pos):
super().__init__(pos) # super().__init__(pos)
self.children.append(NoneNode()) # self.children.append(NoneNode())
#
@property # @property
def value(self): # def value(self):
return self[0] # return self[0]
#
@value.setter # @value.setter
def value(self, value): # def value(self, value):
self[0] = value # self[0] = value
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
def createNode(ret, value): # def createNode(ret, value):
node = ReturnNode(ret.pos) # node = ReturnNode(ret.pos)
node.value = value # node.value = value
return node # return node
#
return Parser.allOf( # return Parser.allOf(
Parser.terminalParser(TokenType.RETURN), # Parser.terminalParser(TokenType.RETURN),
Parser.doAssert(ExpressionNode.parse, "expression"), # Parser.doAssert(ExpressionNode.parse, "expression"),
createNode=createNode # createNode=createNode
)(input) # )(input)

View File

@@ -1,17 +1,34 @@
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
class StatementNode(Node): class Statement(Node):
pass
@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( def StatementParser(input):
ExpressionNode.parse, from smnp.ast.node.block import BlockParser
BlockNode.parse, from smnp.ast.node.condition import IfElseStatementParser
ReturnNode.parse,
)(input) parser = Parser.oneOf(
IfElseStatementParser,
BlockParser,
MaxPrecedenceExpressionParser
)
return Parser(parser, "statement", parser)(input)
# 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(
# ExpressionNode.parse,
# BlockNode.parse,
# ReturnNode.parse,
# )(input)

View File

@@ -1,13 +0,0 @@
from smnp.ast.node.access import AccessNode
from smnp.ast.node.literal import LiteralNode
from smnp.token.type import TokenType
class StringLiteralNode(LiteralNode, AccessNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@classmethod
def _getTokenType(cls):
return TokenType.STRING

12
smnp/ast/node/term.py Normal file
View File

@@ -0,0 +1,12 @@
from smnp.ast.node.factor import FactorParser
from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.valuable import Valuable
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class Term(Valuable):
pass
TermParser = Parser.leftAssociativeOperatorParser(FactorParser, [TokenType.ASTERISK, TokenType.SLASH], FactorParser,
lambda left, op, right: Term.withValue(BinaryOperator.withValues(left, op, right)))

View File

@@ -1,63 +1,63 @@
from smnp.ast.node.access import AccessNode # from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.iterable import abstractIterableParser # from smnp.ast.node.model import Node
from smnp.ast.node.model import Node # from smnp.ast.node.operator import LeftAssociativeOperatorNode
from smnp.ast.parser import Parser # from smnp.ast.parser import Parser
from smnp.token.type import TokenType # from smnp.token.type import TokenType
from smnp.type.model import Type # from smnp.type.model import Type
#
#
class TypeSpecifier(Node): # class TypeSpecifier(Node):
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
return abstractIterableParser(TypeSpecifier, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE, # return abstractIterableParser(TypeSpecifier, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE,
Parser.doAssert(cls._specifierItem(), "type"))(input) # Parser.doAssert(cls._specifierItem(), "type"))(input)
#
@classmethod # @classmethod
def _specifierItem(cls): # def _specifierItem(cls):
return Parser.oneOf( # return Parser.oneOf(
TypeNode.parse, # TypeNode.parse,
cls.parse # cls.parse
) # )
#
class TypeSpecifiers(Node): # class TypeSpecifiers(Node):
pass # pass
#
#
class TypeNode(AccessNode): # class TypeNode(LeftAssociativeOperatorNode):
def __init__(self, pos): # def __init__(self, pos):
super().__init__(pos) # super().__init__(pos)
#
@property # @property
def type(self): # def type(self):
return self[0] # return self[0]
#
@type.setter # @type.setter
def type(self, value): # def type(self, value):
self[0] = value # self[0] = value
#
@property # @property
def specifiers(self): # def specifiers(self):
return self[1] # return self[1]
#
@specifiers.setter # @specifiers.setter
def specifiers(self, value): # def specifiers(self, value):
self[1] = value # self[1] = value
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
def createNode(type, specifiers): # def createNode(type, specifiers):
node = TypeNode(type.pos) # node = TypeNode(type.pos)
node.type = Type[type.value.upper()] # node.type = Type[type.value.upper()]
node.specifiers = specifiers # node.specifiers = specifiers
return node # return node
#
return Parser.allOf( # return Parser.allOf(
cls._rawTypeParser(), # cls._rawTypeParser(),
Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)), # Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)),
createNode=createNode # createNode=createNode
)(input) # )(input)
#
@classmethod # @classmethod
def _rawTypeParser(cls): # def _rawTypeParser(cls):
return Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos)) # return Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos))

22
smnp/ast/node/valuable.py Normal file
View File

@@ -0,0 +1,22 @@
from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode
class Valuable(Node):
def __init__(self, pos):
super().__init__(pos)
self.children = [NoneNode()]
@property
def value(self):
return self[0]
@value.setter
def value(self, value):
self[0] = value
@classmethod
def withValue(cls, value):
node = cls(value.pos)
node.value = value
return node

View File

@@ -5,166 +5,286 @@ from smnp.error.syntax import SyntaxException
def parse(input): def parse(input):
from smnp.ast.node.program import Program from smnp.ast.node.program import ProgramParser
return Program.parse(input).node return ProgramParser(input).node
class Parser: class Parser(object):
def __init__(self, name):
# a -> A self.name = name
@staticmethod
def terminalParser(expectedType, createNode=None, doAssert=False):
def provideNode(value, pos):
if createNode is None:
return IgnoredNode(pos)
return createNode(value, pos)
def parse(input):
if input.hasCurrent() and input.current().type == expectedType:
token = input.current()
input.ahead()
return ParseResult.OK(provideNode(token.value, token.pos))
elif doAssert:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected '{expectedType.key}'{found}", input.currentPos())
def parse(self, input):
result = self._parse(input)
if result is None:
return ParseResult.FAIL() return ParseResult.FAIL()
return parse if not isinstance(result, ParseResult):
raise RuntimeError(
f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
return result
def _parse(self, input):
raise RuntimeError(f"_name method of '{self.__class__.__name__}' class is not implemented")
def grammar(self):
rules = []
self._grammarRules(rules)
return "\n".join(self._uniq(rules))
def _uniq(self, seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
def _grammarRules(self, output):
output.append(f"class '{self.__class__.__name__}' does not implement _grammarRules() method")
def __call__(self, input):
return self.parse(input)
def __str__(self):
return self.name
def __repr__(self):
return self.__str__()
class Parsers:
# oneOf -> a | b | c | ...
@staticmethod @staticmethod
def oneOf(*parsers, exception=None): def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
def combinedParser(input): return TerminalParser(expectedType, createNode, doAssert)
snap = input.snapshot()
for parser in parsers:
value = parser(input)
if value.result:
return value
if exception is not None:
if callable(exception):
raise exception(input)
else:
raise exception
input.reset(snap)
return ParseResult.FAIL()
return combinedParser
# allOf -> a b c ...
@staticmethod @staticmethod
def allOf(*parsers, createNode, exception=None): def oneOf(*parsers, name, exception=None):
return OneOfParser(*parsers, name=name, exception=exception)
@staticmethod
def allOf(*parsers, createNode, exception=None, name):
return AllOfParser(*parsers, createNode=createNode, exception=exception, name=name)
@staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name):
return LeftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name)
@staticmethod
def many(itemParser, createNode, name):
return ManyParser(itemParser, createNode, name)
@staticmethod
def optional(parser, name):
return OptionalParser(parser, name)
@staticmethod
def loop(startParser, itemParser, endParser, createNode, name):
return LoopParser(startParser, itemParser, endParser, createNode, name)
class DecoratorParser(Parser):
def __init__(self, wrapper, parser):
super().__init__(parser.name)
self.wrapper = wrapper
self.parser = parser
self._grammarRules = parser._grammarRules
def _parse(self, input):
result = self.parser.parse(input)
return self.wrapper(result)
class TerminalParser(Parser):
def __init__(self, expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
super().__init__(expectedType.name.lower())
self.expectedType = expectedType
self.createNode = createNode
self.doAssert = doAssert
def _grammarRules(self, output):
output.append(f"{self.name} -> '{self.expectedType.value}'")
def _parse(self, input):
if input.isCurrent(self.expectedType):
token = input.current()
input.ahead()
return ParseResult.OK(self.createNode(token.value, token.pos))
elif self.doAssert:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected '{self.expectedType.key}'{found}", input.currentPos())
return ParseResult.FAIL()
class OneOfParser(Parser):
def __init__(self, *parsers, name, exception=None):
super().__init__(name)
self.parsers = parsers
self.exception = exception
def _parse(self, input):
snap = input.snapshot()
for parser in self.parsers:
value = parser.parse(input)
if value.result:
return value
input.reset(snap) # TODO sprawdzic, czy koneiczne !!!!!
if self.exception is not None:
if callable(self.exception):
raise self.exception(input)
else:
raise self.exception
return ParseResult.FAIL()
def _grammarRules(self, output):
output.extend([ f"{self.name} -> {parser.name}" for parser in self.parsers ])
[ parser._grammarRules(output) for parser in self.parsers ]
class AllOfParser(Parser):
def __init__(self, *parsers, createNode, exception=None, name):
super().__init__(name)
if len(parsers) == 0: if len(parsers) == 0:
raise RuntimeError("Pass one parser at least") raise RuntimeError("Pass one parser at least")
def extendedParser(input): self.parsers = parsers
snap = input.snapshot() self.createNode = createNode
self.exception = exception
results = [] def _parse(self, input):
snap = input.snapshot()
parsedItems = []
for parser in parsers: for parser in self.parsers:
result = parser(input) result = parser.parse(input)
if not result.result:
if exception is not None:
if callable(exception):
raise exception(input)
else:
raise exception
input.reset(snap)
return ParseResult.FAIL()
results.append(result.node)
node = createNode(*results)
if not isinstance(node, Node):
raise RuntimeError("Function 'createNode' haven't returned a Node object. Probably forget to pass 'return'")
return ParseResult.OK(node)
return extendedParser
# leftAssociative -> left | left OP right
@staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
def parse(input):
left = leftParser(input)
if left.result:
while Parser.terminalParser(operatorTokenType)(input).result:
right = rightParser(input)
left = ParseResult.OK(createNode(left.node, right.node))
return left
return ParseResult.FAIL()
return parse
# loop -> start item* end
@staticmethod
def loop(startParser, itemParser, endParser, createNode):
def parse(input):
items = []
start = startParser(input)
if start.result:
while True:
end = endParser(input)
if end.result:
return ParseResult.OK(createNode(start.node, items, end.node))
item = itemParser(input)
if not item.result:
return ParseResult.FAIL()
items.append(item.node)
return ParseResult.FAIL()
return parse
@staticmethod
def doAssert(parser, expected):
def parse(input):
result = parser(input)
if not result.result: if not result.result:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else '' if self.exception is not None:
if callable(self.exception):
raise self.exception(input)
else:
raise self.exception
raise SyntaxException(f"Expected {expected}{found}", input.currentPos()) input.reset(snap)
return ParseResult.FAIL()
parsedItems.append(result.node)
node = self.createNode(*parsedItems)
if not isinstance(node, Node):
raise RuntimeError(f"Method 'createNode' of class '{self.__class__.__name__}' haven't returned a Node object. Probably forget to pass 'return'")
return ParseResult.OK(node)
def _grammarRules(self, output):
output.append(self.name + ' -> ' + ' '.join([ parser.name for parser in self.parsers ]))
[ parser._grammarRules(output) for parser in self.parsers ]
class LeftAssociativeOperatorParser(Parser):
def __init__(self, leftParser, operatorTokenTypes, rightParser, createNode, name):
from smnp.ast.node.operator import Operator
super().__init__(name)
self.leftParser = leftParser
self.rightParser = rightParser
self.createNode = createNode
self.operators = operatorTokenTypes
operatorParsers = [ TerminalParser(expectedType, createNode=lambda val, pos: Operator.withValue(val, pos)) for expectedType in operatorTokenTypes ]
self.operatorParser = OneOfParser(*operatorParsers, name="not important")
def _parse(self, input):
snap = input.snapshot()
left = self.leftParser.parse(input)
if left.result:
operator = self.operatorParser.parse(input)
while operator.result:
right = self.rightParser.parse(input)
left = ParseResult.OK(self.createNode(left.node, operator.node, right.node))
operator = self.operatorParser.parse(input)
return left
return ParseResult.FAIL()
def _grammarRules(self, output):
output.append('\n'.join([f"{self.name} -> {self.leftParser.name} {operator.name.lower()} {self.rightParser.name} | {self.leftParser.name}" for operator in self.operators]))
self.leftParser._grammarRules(output)
self.rightParser._grammarRules(output)
class ManyParser(Parser):
def __init__(self, itemParser, createNode, name):
super().__init__(name)
self.itemParser = itemParser
self.createNode = createNode
def _parse(self, input):
snap = input.snapshot()
parsedItems = []
pos = input.currentPos()
while True:
result = self.itemParser.parse(input)
if result.result:
parsedItems.append(result.node)
snap = input.snapshot()
else:
input.reset(snap)
return ParseResult.OK(self.createNode(parsedItems, pos) if len(parsedItems) > 0 else NoneNode())
def _grammarRules(self, output):
output.append(f"{self.name} -> {self.itemParser.name}*")
self.itemParser._grammarRules(output)
class OptionalParser(Parser):
def __init__(self, parser, name):
super().__init__(name)
self.parser = parser
def _parse(self, input):
result = self.parser.parse(input)
if result.result:
return result return result
return parse return ParseResult.OK(NoneNode())
@staticmethod def _grammarRules(self, output):
def optional(parser): output.append(f"{self.name} -> {self.parser.name}?")
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
return parse class LoopParser(Parser):
def __init__(self, startParser, itemParser, endParser, createNode, name):
super().__init__(name)
self.startParser = startParser
self.itemParser = itemParser
self.endParser = endParser
self.createNode = createNode
@staticmethod def _parse(self, input):
def many(parser, createNode): items = []
def parse(input): start = self.startParser.parse(input)
results = [] if start.result:
snap = input.snapshot()
pos = input.currentPos()
while True: while True:
result = parser(input) end = self.endParser.parse(input)
if result.result: if end.result:
results.append(result.node) return ParseResult.OK(self.createNode(start.node, items, end.node))
snap = input.snapshot() item = self.itemParser.parse(input)
else: if not item.result:
input.reset(snap) return ParseResult.FAIL()
return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode()) items.append(item.node)
return ParseResult.FAIL()
def _grammarRules(self, output):
output.append(f"{self.name} -> {self.startParser.name} {self.itemParser.name}* {self.endParser.name}")
self.startParser._grammarRules(output)
self.itemParser._grammarRules(output)
self.endParser._grammarRules(output)
return parse

66
smnp/calc.py Normal file
View File

@@ -0,0 +1,66 @@
from smnp.ast.node.model import Node
from smnp.ast.parser import Parser
from smnp.token.tokenizer import tokenize
from smnp.token.type import TokenType
class Atom(Node):
def __init__(self, value, pos):
super().__init__(pos)
self.children = [value]
@property
def value(self):
return self[0]
class Operation(Node):
def __init__(self, left, op, right, pos):
super().__init__(pos)
self.children = [left, op, right]
@property
def left(self):
return self[0]
@property
def operator(self):
return self[1]
@property
def right(self):
return self[2]
def atom():
return Parser.oneOfTerminals(TokenType.INTEGER, TokenType.NOTE, TokenType.STRING, createNode=lambda val, pos: Atom(val, pos))
def chain():
return Parser.leftAssociativeOperatorParser(atom(), [TokenType.DOT], atom(), lambda left, op, right: Operation(left, op, right, op.pos), name="chain")
def factor():
return Parser.leftAssociativeOperatorParser(chain(), [TokenType.DOUBLE_ASTERISK], chain(), lambda left, op, right: Operation(left, op, right, op.pos), name="factor")
def term():
return Parser.leftAssociativeOperatorParser(factor(), [TokenType.ASTERISK, TokenType.SLASH], factor(), lambda left, op, right: Operation(left, op, right, op.pos), name="term")
def expr():
return Parser.leftAssociativeOperatorParser(term(), [TokenType.PLUS, TokenType.MINUS], term(), lambda left, op, right: Operation(left, op, right, op.pos), name="expr")
#
def evaluate(node):
if type(node) == Atom:
return node.value
lhs = evaluate(node.left)
rhs = evaluate(node.right)
return {
"+": int(lhs) + int(rhs),
"*": int(lhs) * int(rhs),
"-": int(lhs) - int(rhs),
"/": int(lhs) / int(rhs),
"**": int(lhs) ** int(rhs)
}[node.operator.value]
def draft():
tokens = tokenize(['"fesf fe" + "fsefsef" + "fsefs"'])
e = expr()
node = e(tokens).node
node.print()

View File

@@ -1,14 +1,32 @@
import sys from smnp.ast.node.atom import AtomParser
from smnp.ast.node.chain import ChainParser
from smnp.ast.node.list import ListParser
from smnp.ast.node.model import Node
from smnp.error.base import SmnpException from smnp.error.base import SmnpException
from smnp.library.loader import loadStandardLibrary from smnp.token.tokenizer import tokenize
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=True, printAst=True, execute=False, baseEnvironment=None)
# draft()
class TestNode(Node):
def __init__(self, children):
super().__init__((-1, -1))
self.children = children
tokens = tokenize(['[1, 2]'])
parser = ListParser()
#print(parser.grammar())
res = parser.parse(tokens)
print()
if res.result:
res.node.print()
else:
print("nie sparsowano")
except SmnpException as e: except SmnpException as e:
print(e.message()) print(e.message())

View File

@@ -1,26 +1,25 @@
from smnp.ast.parser import parse from smnp.ast.parser import parse
from smnp.environment.factory import createEnvironment #from smnp.environment.factory import createEnvironment
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.program.FileReader import readLines from smnp.program.FileReader import readLines
from smnp.runtime.evaluator import evaluate
from smnp.token.tokenizer import tokenize from smnp.token.tokenizer import tokenize
class Interpreter: class Interpreter:
@staticmethod @staticmethod
def interpretString(string, printTokens=False, printAst=False, baseEnvironment=None): def interpretString(string, printTokens=False, printAst=False, execute=True, baseEnvironment=None):
return Interpreter._interpret(string.splitlines(), printTokens, printAst, baseEnvironment) return Interpreter._interpret(string.splitlines(), printTokens, printAst, execute, baseEnvironment)
@staticmethod @staticmethod
def interpretFile(file, printTokens=False, printAst=False, baseEnvironment=None): def interpretFile(file, printTokens=False, printAst=False, execute=True, baseEnvironment=None):
return Interpreter._interpret(readLines(file), printTokens, printAst, baseEnvironment) return Interpreter._interpret(readLines(file), printTokens, printAst, execute, baseEnvironment)
@staticmethod @staticmethod
def _interpret(lines, printTokens=False, printAst=False, baseEnvironment=None): def _interpret(lines, printTokens=False, printAst=False, execute=True, baseEnvironment=None):
environment = createEnvironment() #environment = createEnvironment()
if baseEnvironment is not None: #if baseEnvironment is not None:
environment.extend(baseEnvironment) # environment.extend(baseEnvironment)
try: try:
tokens = tokenize(lines) tokens = tokenize(lines)
@@ -31,9 +30,10 @@ class Interpreter:
if printAst: if printAst:
ast.print() ast.print()
evaluate(ast, environment) #if execute:
# evaluate(ast, environment)
return environment #return environment
except RuntimeException as e: except RuntimeException as e:
e.environment = environment #e.environment = environment
raise e raise e

View File

@@ -1,4 +1,4 @@
from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.identifier import Identifier
from smnp.ast.node.invocation import FunctionCallNode from smnp.ast.node.invocation import FunctionCallNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
@@ -14,7 +14,7 @@ class AccessEvaluator(Evaluator):
left = expressionEvaluator(doAssert=True)(node.left, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult left = expressionEvaluator(doAssert=True)(node.left, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
right = node.right right = node.right
if type(right) == IdentifierNode: if type(right) == Identifier:
try: try:
return left.properties[right.value] return left.properties[right.value]
except KeyError: except KeyError:

View File

@@ -1,4 +1,4 @@
from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.identifier import Identifier
from smnp.runtime.evaluator import evaluate, Evaluator, EvaluationResult from smnp.runtime.evaluator import evaluate, Evaluator, EvaluationResult
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type from smnp.type.model import Type
@@ -40,7 +40,7 @@ class AsteriskEvaluator(Evaluator):
@classmethod @classmethod
def _automaticNamedVariable(cls, iteratorNode, environment, prefix=''): def _automaticNamedVariable(cls, iteratorNode, environment, prefix=''):
if type(iteratorNode) == IdentifierNode: if type(iteratorNode) == Identifier:
return cls._automaticVariableName(environment, prefix, iteratorNode.value, False) return cls._automaticVariableName(environment, prefix, iteratorNode.value, False)
else: else:
return cls._automaticVariableName(environment, prefix, '', True) return cls._automaticVariableName(environment, prefix, '', True)

View File

@@ -1,13 +1,13 @@
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.asterisk import AsteriskNode from smnp.ast.node.asterisk import AsteriskNode
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.identifier import Identifier
from smnp.ast.node.integer import IntegerLiteralNode from smnp.ast.node.integer import IntegerLiteralNode
from smnp.ast.node.invocation import FunctionCallNode from smnp.ast.node.invocation import FunctionCallNode
from smnp.ast.node.list import ListNode from smnp.ast.node.list import List
from smnp.ast.node.map import MapNode from smnp.ast.node.map import MapNode
from smnp.ast.node.note import NoteLiteralNode from smnp.ast.node.note import NoteLiteralNode
from smnp.ast.node.operator import LeftAssociativeOperatorNode
from smnp.ast.node.string import StringLiteralNode from smnp.ast.node.string import StringLiteralNode
from smnp.ast.node.type import TypeNode from smnp.ast.node.type import TypeNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
@@ -37,9 +37,9 @@ def expressionEvaluator(doAssert=False):
Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteralNode), Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteralNode),
Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteralNode), Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteralNode),
Evaluator.forNodes(TypeEvaluator.evaluate, TypeNode), Evaluator.forNodes(TypeEvaluator.evaluate, TypeNode),
Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode), Evaluator.forNodes(IdentifierEvaluator.evaluate, Identifier),
Evaluator.forNodes(ListEvaluator.evaluate, ListNode), Evaluator.forNodes(ListEvaluator.evaluate, List),
Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode), Evaluator.forNodes(AccessEvaluator.evaluate, LeftAssociativeOperatorNode),
Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode), Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode),
Evaluator.forNodes(AsteriskEvaluator.evaluate, AsteriskNode), Evaluator.forNodes(AsteriskEvaluator.evaluate, AsteriskNode),
Evaluator.forNodes(MapEvaluator.evaluate, MapNode) Evaluator.forNodes(MapEvaluator.evaluate, MapNode)

View File

@@ -5,12 +5,19 @@ from smnp.token.tokenizers.comment import commentTokenizer
from smnp.token.tokenizers.identifier import identifierTokenizer from smnp.token.tokenizers.identifier import identifierTokenizer
from smnp.token.tokenizers.keyword import typeTokenizer from smnp.token.tokenizers.keyword import typeTokenizer
from smnp.token.tokenizers.note import noteTokenizer from smnp.token.tokenizers.note import noteTokenizer
from smnp.token.tokenizers.relation import relationOperatorTokenizer
from smnp.token.tokenizers.string import stringTokenizer from smnp.token.tokenizers.string import stringTokenizer
from smnp.token.tokenizers.whitespace import whitespacesTokenizer from smnp.token.tokenizers.whitespace import whitespacesTokenizer
from smnp.token.tools import defaultTokenizer, separated, regexPatternTokenizer from smnp.token.tools import defaultTokenizer, separated, regexPatternTokenizer
from smnp.token.type import TokenType from smnp.token.type import TokenType
tokenizers = ( tokenizers = (
defaultTokenizer(TokenType.ARROW),
# Double-character operators
relationOperatorTokenizer,
defaultTokenizer(TokenType.DOUBLE_ASTERISK),
# Characters # Characters
defaultTokenizer(TokenType.OPEN_CURLY), defaultTokenizer(TokenType.OPEN_CURLY),
defaultTokenizer(TokenType.CLOSE_CURLY), defaultTokenizer(TokenType.CLOSE_CURLY),
@@ -22,9 +29,11 @@ tokenizers = (
defaultTokenizer(TokenType.CLOSE_ANGLE), defaultTokenizer(TokenType.CLOSE_ANGLE),
defaultTokenizer(TokenType.ASTERISK), defaultTokenizer(TokenType.ASTERISK),
defaultTokenizer(TokenType.ASSIGN), defaultTokenizer(TokenType.ASSIGN),
defaultTokenizer(TokenType.ARROW),
defaultTokenizer(TokenType.COMMA), defaultTokenizer(TokenType.COMMA),
defaultTokenizer(TokenType.SLASH),
defaultTokenizer(TokenType.MINUS), defaultTokenizer(TokenType.MINUS),
defaultTokenizer(TokenType.PLUS),
defaultTokenizer(TokenType.DASH),
defaultTokenizer(TokenType.DOTS), defaultTokenizer(TokenType.DOTS),
defaultTokenizer(TokenType.AMP), defaultTokenizer(TokenType.AMP),
defaultTokenizer(TokenType.DOT), defaultTokenizer(TokenType.DOT),
@@ -42,7 +51,12 @@ tokenizers = (
separated(defaultTokenizer(TokenType.EXTEND)), separated(defaultTokenizer(TokenType.EXTEND)),
separated(defaultTokenizer(TokenType.IMPORT)), separated(defaultTokenizer(TokenType.IMPORT)),
separated(defaultTokenizer(TokenType.FROM)), separated(defaultTokenizer(TokenType.FROM)),
separated(defaultTokenizer(TokenType.ELSE)),
separated(defaultTokenizer(TokenType.AND)),
separated(defaultTokenizer(TokenType.NOT)),
separated(defaultTokenizer(TokenType.AS)), separated(defaultTokenizer(TokenType.AS)),
separated(defaultTokenizer(TokenType.IF)),
separated(defaultTokenizer(TokenType.OR)),
# Identifier (couldn't be before keywords!) # Identifier (couldn't be before keywords!)
identifierTokenizer, identifierTokenizer,

View File

@@ -0,0 +1,6 @@
from smnp.token.tools import keywordsTokenizer
from smnp.token.type import TokenType
def relationOperatorTokenizer(input, current, line):
return keywordsTokenizer(TokenType.RELATION, "==", "!=", ">=", "<=", ">", "<")(input, current, line)

View File

@@ -2,6 +2,8 @@ from enum import Enum
class TokenType(Enum): class TokenType(Enum):
RELATION = 'relation'
DOUBLE_ASTERISK = '**'
OPEN_CURLY = '{' OPEN_CURLY = '{'
CLOSE_CURLY = '}' CLOSE_CURLY = '}'
OPEN_PAREN = '(' OPEN_PAREN = '('
@@ -14,10 +16,16 @@ class TokenType(Enum):
ASSIGN = '=' ASSIGN = '='
ARROW = '->' ARROW = '->'
COMMA = ',' COMMA = ','
SLASH = '/'
MINUS = '-' MINUS = '-'
PLUS = '+'
DASH = '^'
DOTS = '...' DOTS = '...'
AMP = '&' AMP = '&'
DOT = '.' DOT = '.'
AND = 'and'
OR = 'or'
NOT = 'not'
INTEGER = 'integer' INTEGER = 'integer'
STRING = 'string' STRING = 'string'
NOTE = 'note' NOTE = 'note'
@@ -28,6 +36,8 @@ class TokenType(Enum):
EXTEND = 'extend' EXTEND = 'extend'
IMPORT = 'import' IMPORT = 'import'
FROM = 'from' FROM = 'from'
ELSE = 'else'
IF = 'if'
AS = 'as' AS = 'as'
IDENTIFIER = 'identifier' IDENTIFIER = 'identifier'
COMMENT = 'comment' COMMENT = 'comment'

0
smnp/util/__init__.py Normal file
View File

14
smnp/util/singleton.py Normal file
View File

@@ -0,0 +1,14 @@
from smnp.ast.parser import Parser
def SingletonParser(function):
def wrapper(*args, **kwargs):
if not hasattr(function, 'instance'):
function.instance = function(*args, **kwargs)
if not isinstance(function.instance, Parser):
raise RuntimeError(f"Function {function.__name__} haven't returned Parser object")
return function.instance
return wrapper