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(StatementNode.parse, f"statement or '{TokenType.CLOSE_CURLY.key}'"),
Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"), Parser.terminalParser(TokenType.CLOSE_CURLY),
Parser.terminalParser(TokenType.CLOSE_CURLY), createNode=createNode,
createNode=lambda open, statements, close: Block.withChildren(statements, open.pos) )(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)
@classmethod
def _parse(cls, input):
return Parser.oneOf(
cls._asteriskParser(),
cls._expressionParser(),
)(input)
def Expression3Parser(input): @classmethod
return Parser.leftAssociativeOperatorParser( def _asteriskParser(cls):
Expression2Parser, def createNode(iterator, asterisk, statement):
[TokenType.AND], node = AsteriskNode(asterisk.pos)
Expression2Parser, node.iterator = iterator
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right)) node.statement = statement
)(input) return node
return Parser.allOf(
cls._expressionParser(),
Parser.terminalParser(TokenType.ASTERISK),
Parser.doAssert(StatementNode.parse, 'statement'),
createNode=createNode
)
def Expression4Parser(input): @classmethod
from smnp.ast.node.condition import IfElse def _expressionParser(cls):
exprParser = Parser.leftAssociativeOperatorParser( from smnp.ast.node.bool import BoolLiteralNode
Expression3Parser,
[TokenType.OR],
Expression3Parser,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
)
ifElseExpression = Parser.allOf( from smnp.ast.node.identifier import IdentifierNode
exprParser, from smnp.ast.node.string import StringLiteralNode
Parser.terminalParser(TokenType.IF), return Parser.oneOf(
Expression4Parser, #IntegerLiteralNode.parse,
Parser.terminalParser(TokenType.ELSE), StringLiteralNode.parse,
Expression4Parser, #NoteLiteralNode.parse,
createNode=lambda ifNode, _, condition, __, elseNode: IfElse.createNode(ifNode, condition, elseNode) BoolLiteralNode.parse,
) IdentifierNode.parse,
#MapNode.parse,
return Parser.oneOf( #ListNode.parse,
ifElseExpression, #TypeNode.parse,
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
# ) )

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(
node.name = name cls.relationParser(),
node.arguments = arguments cls.accessParser(),
return node cls.literalParser()
)(input)
@classmethod
def _accessLhs(cls):
return cls.literalParser()
class ArgumentsList(Node): @classmethod
pass def _relationLhs(cls):
return Parser.oneOf(
cls.accessParser(),
cls.literalParser()
)
@classmethod
def literalParser(cls):
return Parser.oneOf(
IdentifierNode.functionCallParser(),
IdentifierNode._assignmentParser(),
IdentifierNode.identifierParser()
)
class Assignment(BinaryOperator): @staticmethod
pass 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
)
@SingletonParser @staticmethod
def IdentifierParser(): def functionCallParser():
identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue) def createNode(name, arguments):
node = FunctionCallNode(name.pos)
node.name = name
node.arguments = arguments
return node
functionCallParser = Parsers.allOf( return Parser.allOf(
identifierLiteralParser, IdentifierNode.identifierParser(),
#abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser), ArgumentsListNode.parse,
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments), createNode=createNode
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(),
return node 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
def ImportParser(input): return Parser.allOf(
return Parser.allOf( Parser.terminalParser(TokenType.IMPORT),
Parser.terminalParser(TokenType.IMPORT), TypeNode.parse,
StringParser, Parser.doAssert(Parser.terminalParser(TokenType.FROM), "'from <source> as <variable name>'"),
createNode=lambda imp, source: Import.withValue(source), Parser.doAssert(StringLiteralNode.literalParser(), "source as a string"),
name="import" Parser.doAssert(Parser.terminalParser(TokenType.AS), "'as <variable name>'"),
)(input) 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
return node node.next = iterableTail
return node
return Parsers.allOf( return Parser.allOf(
Parsers.terminal(openTokenType), Parser.terminalParser(TokenType.COMMA, doAssert=True),
Parsers.terminal(closeTokenType), itemParser,
createNode=createNode, AbstractIterableTailNode.parse,
name=name+"Empty" createNode=createNode
) )
def openIterable(): class AbstractIterableNode(ExpressionNode):
def createNode(open, item, tail): def __init__(self, pos):
node = AbstractIterable(open.pos) super().__init__(pos)
node.value = item
node.next = tail
return node
return Parsers.allOf( self.children.append(NoneNode())
Parsers.terminal(openTokenType),
itemParser,
abstractIterableTailParser(),
createNode=createNode,
name=name+"Open"
)
def abstractIterableTailParser(): @property
return Parsers.oneOf( def next(self):
closeIterable(), return self[1]
nextItem(),
name=name+"Tail"
)
def nextItem(): @next.setter
def createNode(comma, item, tail): def next(self, value):
node = AbstractIterableTail(item.pos) self[1] = value
node.value = item
node.next = tail
return node
return Parsers.allOf( @classmethod
Parsers.terminal(TokenType.COMMA, doAssert=True), def _parse(cls, input):
itemParser, return Parser.oneOf(
abstractIterableTailParser(), AbstractIterableNode._parser1(),
name=name+"NextItem", AbstractIterableNode._parser2()
createNode=createNode )(input)
)
def closeIterable(): @staticmethod
return Parsers.terminal(closeTokenType) 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
)
return abstractIterableParser() @staticmethod
#return toFlatDesiredNode(iterableNodeType, abstractIterableParser()) 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,
)(input) StatementNode.parse,
exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos)
)(input)
if result.result: root = Program()
root.append(result.node) while input.hasCurrent():
result = parseToken(input)
return ParseResult.OK(root) if result.result:
root.append(result.node)
ProgramParser = Parser(parse, name="program") return ParseResult.OK(root)
# @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 # a -> A
@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()
if not isinstance(result, ParseResult): return parse
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 terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False): def oneOf(*parsers, exception=None):
return TerminalParser(expectedType, createNode, doAssert) def combinedParser(input):
snap = input.snapshot()
for parser in parsers:
value = parser(input)
if value.result:
return value
input.reset(snap)
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 oneOf(*parsers, name, exception=None): def allOf(*parsers, createNode, 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")
self.parsers = parsers def extendedParser(input):
self.createNode = createNode snap = input.snapshot()
self.exception = exception
def _parse(self, input): results = []
snap = input.snapshot()
parsedItems = []
for parser in self.parsers: for parser in parsers:
result = parser.parse(input) 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):
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)
oneAtLeast = False
if left.result:
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
while operator.result:
oneAtLeast = True
right = rightParser(input)
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
if oneAtLeast:
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:
if self.exception is not None: found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ''
if callable(self.exception):
raise self.exception(input)
else:
raise self.exception
input.reset(snap) raise SyntaxException(f"Expected {expected}{found}", input.currentPos())
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 ParseResult.OK(NoneNode()) return parse
def _grammarRules(self, output): @staticmethod
output.append(f"{self.name} -> {self.parser.name}?") def optional(parser):
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
class LoopParser(Parser): return parse
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): @staticmethod
items = [] def many(parser, createNode):
start = self.startParser.parse(input) def parse(input):
if start.result: results = []
snap = input.snapshot()
pos = input.currentPos()
while True: while True:
end = self.endParser.parse(input) result = parser(input)
if end.result: if result.result:
return ParseResult.OK(self.createNode(start.node, items, end.node)) results.append(result.node)
item = self.itemParser.parse(input) snap = input.snapshot()
if not item.result: else:
return ParseResult.FAIL() input.reset(snap)
items.append(item.node) return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode())
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

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