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
44 changed files with 1173 additions and 1476 deletions

56
smnp/ast/node/access.py Normal file
View File

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

View File

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

28
smnp/ast/node/asterisk.py Normal file
View File

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

View File

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

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

@@ -0,0 +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, RelationOperatorNode):
def __init__(self, pos):
super().__init__(pos)
del self.children[1]
@classmethod
def _getTokenType(cls):
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

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

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

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

View File

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

View File

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

37
smnp/ast/node/integer.py Normal file
View File

@@ -0,0 +1,37 @@
from smnp.ast.node.expression import ExpressionNode
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class IntegerLiteralNode(ExpressionNode):
def __init__(self, pos):
super().__init__(pos)
#TODO del self.children[1]
# TODO: To Remove
@classmethod
def _parse(cls, input):
return cls._literalParser()(input)
@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

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

View File

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

18
smnp/ast/node/literal.py Normal file
View File

@@ -0,0 +1,18 @@
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,11 +1,19 @@
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.model import Node from smnp.ast.node.none import NoneNode
from smnp.ast.node.operator import BinaryOperator, Operator from smnp.ast.node.note import NoteLiteralNode
from smnp.ast.parser import Parsers 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.token.type import TokenType
class MapEntry(ExpressionNode):
class MapEntry(BinaryOperator): def __init__(self, pos):
super().__init__(pos)
self.children = [NoneNode(), NoneNode()]
@property @property
def key(self): def key(self):
@@ -17,31 +25,39 @@ class MapEntry(BinaryOperator):
@property @property
def value(self): def value(self):
return self[2] return self[1]
@value.setter @value.setter
def value(self, value): def value(self, value):
self[2] = value self[1] = value
class MapNode(AccessNode):
class Map(Node): @classmethod
pass def _literalParser(cls):
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
def MapParser(input): return Parser.allOf(
from smnp.ast.node.atom import LiteralParser cls._keyParser(),
#from smnp.ast.node.expression import MaxPrecedenceExpressionParser Parser.terminalParser(TokenType.ARROW),
keyParser = LiteralParser ExpressionNode.parse,
#valueParser = MaxPrecedenceExpressionParser createNode=createNode
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__, f" (line {self.pos[0]+1}, col {self.pos[1]+1})", sep="") print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, 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

18
smnp/ast/node/note.py Normal file
View File

@@ -0,0 +1,18 @@
from smnp.ast.node.literal import LiteralNode
from smnp.token.type import TokenType
class NoteLiteralNode(LiteralNode):
def __init__(self, pos):
super().__init__(pos)
#TODO del self.children[1]
# TODO: To Remove
@classmethod
def _parse(cls, input):
return cls.literalParser()(input)
@classmethod
def _getTokenType(cls):
return TokenType.NOTE

View File

@@ -1,136 +1,7 @@
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.node.none import NoneNode
class UnaryOperator(Node): class OperatorNode(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): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)
self.children = [None] self.children = [None]
@@ -142,9 +13,3 @@ class Operator(Node):
@value.setter @value.setter
def value(self, value): def value(self, value):
self[0] = value self[0] = value
@classmethod
def withValue(cls, value, pos):
node = cls(pos)
node.value = value
return node

View File

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

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

31
smnp/ast/node/string.py Normal file
View File

@@ -0,0 +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(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,12 +0,0 @@
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.iterable import abstractIterableParser from smnp.ast.node.access import AccessNode
# from smnp.ast.node.model import Node from smnp.ast.node.iterable import abstractIterableParser
# from smnp.ast.node.operator import LeftAssociativeOperatorNode from smnp.ast.node.model import Node
# 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(LeftAssociativeOperatorNode): class TypeNode(AccessNode):
# 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))

View File

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

@@ -1,290 +1,176 @@
from smnp.ast.node.ignore import IgnoredNode from smnp.ast.node.ignore import IgnoredNode
from smnp.ast.node.model import ParseResult, Node from smnp.ast.node.model import ParseResult, Node
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.node.operator import OperatorNode
from smnp.error.syntax import SyntaxException from smnp.error.syntax import SyntaxException
def parse(input): def parse(input):
from smnp.ast.node.program import ProgramParser from smnp.ast.node.program import Program
return ProgramParser(input).node return Program.parse(input).node
class Parser(object): class Parser:
def __init__(self, name):
self.name = name
def parse(self, input):
result = self._parse(input)
if result is None:
return ParseResult.FAIL()
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:
# a -> A
@staticmethod @staticmethod
def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False): def terminalParser(expectedType, createNode=None, doAssert=False):
return TerminalParser(expectedType, createNode, doAssert) def provideNode(value, pos):
if createNode is None:
return IgnoredNode(pos)
return createNode(value, pos)
@staticmethod def parse(input):
def oneOf(*parsers, name, exception=None): if input.hasCurrent() and input.current().type == expectedType:
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() token = input.current()
input.ahead() input.ahead()
return ParseResult.OK(self.createNode(token.value, token.pos)) return ParseResult.OK(provideNode(token.value, token.pos))
elif self.doAssert: elif doAssert:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else "" found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected '{self.expectedType.key}'{found}", input.currentPos()) raise SyntaxException(f"Expected '{expectedType.key}'{found}", input.currentPos())
return ParseResult.FAIL() return ParseResult.FAIL()
return parse
# oneOf -> a | b | c | ...
class OneOfParser(Parser): @staticmethod
def __init__(self, *parsers, name, exception=None): def oneOf(*parsers, exception=None):
super().__init__(name) def combinedParser(input):
self.parsers = parsers
self.exception = exception
def _parse(self, input):
snap = input.snapshot() snap = input.snapshot()
for parser in self.parsers: for parser in parsers:
value = parser.parse(input) value = parser(input)
if value.result: if value.result:
return value return value
input.reset(snap) # TODO sprawdzic, czy koneiczne !!!!! input.reset(snap)
if self.exception is not None: if exception is not None:
if callable(self.exception): if callable(exception):
raise self.exception(input) raise exception(input)
else: else:
raise self.exception raise 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:
raise RuntimeError("Pass one parser at least")
self.parsers = parsers
self.createNode = createNode
self.exception = exception
def _parse(self, input):
snap = input.snapshot()
parsedItems = []
for parser in self.parsers:
result = parser.parse(input)
if not result.result:
if self.exception is not None:
if callable(self.exception):
raise self.exception(input)
else:
raise self.exception
input.reset(snap) input.reset(snap)
return ParseResult.FAIL() return ParseResult.FAIL()
parsedItems.append(result.node) return combinedParser
node = self.createNode(*parsedItems) # allOf -> a b c ...
@staticmethod
def allOf(*parsers, createNode, exception=None):
if len(parsers) == 0:
raise RuntimeError("Pass one parser at least")
def extendedParser(input):
snap = input.snapshot()
results = []
for parser in parsers:
result = parser(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): 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'") raise RuntimeError("Function 'createNode' haven't returned a Node object. Probably forget to pass 'return'")
return ParseResult.OK(node) 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): return extendedParser
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 ] # leftAssociative -> left | left OP right
self.operatorParser = OneOfParser(*operatorParsers, name="not important") @staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
def _parse(self, input): def parse(input):
snap = input.snapshot() left = leftParser(input)
left = self.leftParser.parse(input) oneAtLeast = False
if left.result: if left.result:
operator = self.operatorParser.parse(input) operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
while operator.result: while operator.result:
right = self.rightParser.parse(input) oneAtLeast = True
left = ParseResult.OK(self.createNode(left.node, operator.node, right.node)) right = rightParser(input)
operator = self.operatorParser.parse(input) 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 left
return ParseResult.FAIL() return ParseResult.FAIL()
return parse
def _grammarRules(self, output): # loop -> start item* end
output.append('\n'.join([f"{self.name} -> {self.leftParser.name} {operator.name.lower()} {self.rightParser.name} | {self.leftParser.name}" for operator in self.operators])) @staticmethod
self.leftParser._grammarRules(output) def loop(startParser, itemParser, endParser, createNode):
self.rightParser._grammarRules(output) def parse(input):
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 ParseResult.OK(NoneNode())
def _grammarRules(self, output):
output.append(f"{self.name} -> {self.parser.name}?")
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
def _parse(self, input):
items = [] items = []
start = self.startParser.parse(input) start = startParser(input)
if start.result: if start.result:
while True: while True:
end = self.endParser.parse(input) end = endParser(input)
if end.result: if end.result:
return ParseResult.OK(self.createNode(start.node, items, end.node)) return ParseResult.OK(createNode(start.node, items, end.node))
item = self.itemParser.parse(input) item = itemParser(input)
if not item.result: if not item.result:
return ParseResult.FAIL() return ParseResult.FAIL()
items.append(item.node) items.append(item.node)
return ParseResult.FAIL() return ParseResult.FAIL()
def _grammarRules(self, output): return parse
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)
@staticmethod
def doAssert(parser, expected):
def parse(input):
result = parser(input)
if not result.result:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ''
raise SyntaxException(f"Expected {expected}{found}", input.currentPos())
return result
return parse
@staticmethod
def optional(parser):
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
return parse
@staticmethod
def many(parser, createNode):
def parse(input):
results = []
snap = input.snapshot()
pos = input.currentPos()
while True:
result = parser(input)
if result.result:
results.append(result.node)
snap = input.snapshot()
else:
input.reset(snap)
return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode())
return parse

View File

@@ -1,66 +0,0 @@
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,32 +1,13 @@
from smnp.ast.node.atom import AtomParser import sys
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.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=True, printAst=True, execute=False, baseEnvironment=None) Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, 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,25 +1,26 @@
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, execute=True, baseEnvironment=None): def interpretString(string, printTokens=False, printAst=False, baseEnvironment=None):
return Interpreter._interpret(string.splitlines(), printTokens, printAst, execute, baseEnvironment) return Interpreter._interpret(string.splitlines(), printTokens, printAst, baseEnvironment)
@staticmethod @staticmethod
def interpretFile(file, printTokens=False, printAst=False, execute=True, baseEnvironment=None): def interpretFile(file, printTokens=False, printAst=False, baseEnvironment=None):
return Interpreter._interpret(readLines(file), printTokens, printAst, execute, baseEnvironment) return Interpreter._interpret(readLines(file), printTokens, printAst, baseEnvironment)
@staticmethod @staticmethod
def _interpret(lines, printTokens=False, printAst=False, execute=True, baseEnvironment=None): def _interpret(lines, printTokens=False, printAst=False, 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)
@@ -30,10 +31,9 @@ class Interpreter:
if printAst: if printAst:
ast.print() ast.print()
#if execute: evaluate(ast, environment)
# 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,9 +1,4 @@
from smnp.ast.node.block import BlockNode
from smnp.ast.node.extend import ExtendNode
from smnp.ast.node.function import FunctionDefinitionNode
from smnp.ast.node.imports import ImportNode
from smnp.ast.node.program import Program from smnp.ast.node.program import Program
from smnp.ast.node.ret import ReturnNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.type.model import Type from smnp.type.model import Type
@@ -70,18 +65,13 @@ def evaluate(node, environment):
from smnp.runtime.evaluators.program import ProgramEvaluator from smnp.runtime.evaluators.program import ProgramEvaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator
from smnp.runtime.evaluators.extend import ExtendEvaluator
from smnp.runtime.evaluators.block import BlockEvaluator
from smnp.runtime.evaluators.imports import ImportEvaluator
from smnp.runtime.evaluators.function import ReturnEvaluator
result = Evaluator.oneOf( result = Evaluator.oneOf(
Evaluator.forNodes(ProgramEvaluator.evaluate, Program), Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode), #Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode),
Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode), #Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode), #Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode),
Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode), #Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode),
Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode), #Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode),
expressionEvaluator() expressionEvaluator()
)(node, environment) )(node, environment)

View File

@@ -1,4 +1,4 @@
from smnp.ast.node.identifier import Identifier from smnp.ast.node.identifier import IdentifierNode
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) == Identifier: if type(right) == IdentifierNode:
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 Identifier from smnp.ast.node.identifier import IdentifierNode
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) == Identifier: if type(iteratorNode) == IdentifierNode:
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 Identifier from smnp.ast.node.identifier import IdentifierNode
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 List from smnp.ast.node.list import ListNode
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, Identifier), Evaluator.forNodes(IdentifierEvaluator.evaluate, IdentifierNode),
Evaluator.forNodes(ListEvaluator.evaluate, List), Evaluator.forNodes(ListEvaluator.evaluate, ListNode),
Evaluator.forNodes(AccessEvaluator.evaluate, LeftAssociativeOperatorNode), Evaluator.forNodes(AccessEvaluator.evaluate, AccessNode),
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,18 +5,13 @@ 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), defaultTokenizer(TokenType.EQUAL),
# Double-character operators
relationOperatorTokenizer,
defaultTokenizer(TokenType.DOUBLE_ASTERISK),
# Characters # Characters
defaultTokenizer(TokenType.OPEN_CURLY), defaultTokenizer(TokenType.OPEN_CURLY),
@@ -29,11 +24,9 @@ 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),
@@ -51,12 +44,7 @@ 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

@@ -1,6 +0,0 @@
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,8 +2,7 @@ from enum import Enum
class TokenType(Enum): class TokenType(Enum):
RELATION = 'relation' EQUAL = '=='
DOUBLE_ASTERISK = '**'
OPEN_CURLY = '{' OPEN_CURLY = '{'
CLOSE_CURLY = '}' CLOSE_CURLY = '}'
OPEN_PAREN = '(' OPEN_PAREN = '('
@@ -16,16 +15,10 @@ 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'
@@ -36,8 +29,6 @@ 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'

View File

View File

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