44 Commits

Author SHA1 Message Date
Bartłomiej Pluta
526412068f Fix 'range' function 2019-07-12 23:25:52 +02:00
Bartłomiej Pluta
439765f442 Move 'flat' function definition to standard library 2019-07-12 23:12:09 +02:00
Bartłomiej Pluta
4c03ca2f86 Fix loop statement 2019-07-12 22:55:46 +02:00
Bartłomiej Pluta
033d864b0f Create evaluator for extend statement 2019-07-12 22:31:14 +02:00
Bartłomiej Pluta
41f385de09 Fix return statement 2019-07-12 22:25:26 +02:00
Bartłomiej Pluta
5512f808f8 Create evaluator for custom functions 2019-07-12 22:19:12 +02:00
Bartłomiej Pluta
cc569b5f19 Create import statement evaluator and update standard library 2019-07-12 22:08:37 +02:00
Bartłomiej Pluta
b31e17d176 Create if-else statement evaluator 2019-07-12 21:58:16 +02:00
Bartłomiej Pluta
95e6a5f95d Create evaluator for relation operators 2019-07-12 21:26:06 +02:00
Bartłomiej Pluta
99dd8bd46e Improve evaluator for sum (concatenating lists and maps) 2019-07-12 21:02:09 +02:00
Bartłomiej Pluta
dc3387c685 Create evaluator for sum (sum, subtraction and string concatenation) 2019-07-12 20:56:42 +02:00
Bartłomiej Pluta
1094c071fb Create evaluator for product (both multiplying and dividing) 2019-07-12 20:45:23 +02:00
Bartłomiej Pluta
13a6dedba6 Create working PoC of loop statement 2019-07-12 20:36:56 +02:00
Bartłomiej Pluta
94128d9f21 Create evaluator for identifier 2019-07-12 19:57:11 +02:00
Bartłomiej Pluta
65fccda989 Create evaluator for power operator 2019-07-12 19:54:29 +02:00
Bartłomiej Pluta
35eb38076f Create evaluator for not operator 2019-07-12 19:45:54 +02:00
Bartłomiej Pluta
a1273896e4 Create evaluator for access operator 2019-07-12 19:40:52 +02:00
Bartłomiej Pluta
94666aca79 Create evaluator for minus operator 2019-07-12 19:21:42 +02:00
Bartłomiej Pluta
6d1351e4a0 Create evaluators for lists and maps 2019-07-12 19:07:12 +02:00
Bartłomiej Pluta
1563045de1 Create evaluator for function call and basic atoms 2019-07-12 18:59:59 +02:00
Bartłomiej Pluta
4394c9a8db Add assertions to map and list items 2019-07-12 18:28:12 +02:00
Bartłomiej Pluta
2bf25da2fa Fix reporting syntax error when parsing only map 2019-07-12 17:55:24 +02:00
Bartłomiej Pluta
df4d737676 Fix oneOf() to reset input cursor after each parser execution 2019-07-12 17:44:12 +02:00
Bartłomiej Pluta
fe8dca4d2c Create asserts for expression and identifier 2019-07-12 17:20:38 +02:00
Bartłomiej Pluta
386c89502a Improve assertions on if/else statement 2019-07-12 17:14:40 +02:00
Bartłomiej Pluta
0c72203551 Create assertions on extend statements 2019-07-12 17:10:47 +02:00
Bartłomiej Pluta
0aad7e52dd Create assertions on import and function definition parsers 2019-07-12 17:00:44 +02:00
Bartłomiej Pluta
b711b6a582 Improve a little bit string tokenizer 2019-07-12 16:52:26 +02:00
Bartłomiej Pluta
c7e90b9fbd Add 'assertExpected' to Parser.oneOf() method 2019-07-12 16:49:25 +02:00
Bartłomiej Pluta
0435bc776e Rename Chain to Unit 2019-07-12 16:00:39 +02:00
Bartłomiej Pluta
916c8c69ef Move list and map parsers to atom 2019-07-12 15:11:36 +02:00
Bartłomiej Pluta
e43b0ad725 Move parentheses in factor before power operator ('**') 2019-07-12 14:51:12 +02:00
Bartłomiej Pluta
1a09a73c91 Improve integer parser 2019-07-12 14:30:49 +02:00
Bartłomiej Pluta
ac8b46b077 Improve 'extend' statement 2019-07-12 14:19:21 +02:00
Bartłomiej Pluta
b7192ea52b Add optional 'as' operator to loop 2019-07-12 14:12:55 +02:00
Bartłomiej Pluta
0cefcd282b Improve minus operator 2019-07-12 00:51:37 +02:00
Bartłomiej Pluta
28f32ea3d0 Perform cleaning code 2019-07-12 00:42:51 +02:00
Bartłomiej Pluta
e71bffcf5d Create 'return' statement 2019-07-12 00:36:26 +02:00
Bartłomiej Pluta
ee91dbec8a Add support for 'extend' statement 2019-07-12 00:28:33 +02:00
Bartłomiej Pluta
f459873574 Rename terminalParser() to terminal() 2019-07-12 00:18:53 +02:00
Bartłomiej Pluta
eb28976704 Enable support for custom functions definition 2019-07-12 00:15:28 +02:00
Bartłomiej Pluta
af3cb7027a Add TypeParser (handling types list - specifiers etc.) 2019-07-11 23:36:52 +02:00
Bartłomiej Pluta
261530eb10 Clean code 2019-07-11 19:51:47 +02:00
Bartłomiej Pluta
5a1d568e8e Refactor ExpressionParser 2019-07-11 19:43:18 +02:00
57 changed files with 1357 additions and 1065 deletions

View File

@@ -1,7 +1,6 @@
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.parser import Parsers 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 Atom(Node): class Atom(Node):
@@ -44,60 +43,48 @@ class TypeLiteral(Atom):
pass pass
@SingletonParser def IntegerParser(input):
def IntegerParser(): return Parser.terminal(TokenType.INTEGER, createNode=IntegerLiteral.withValue)(input)
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(input):
def StringParser(): return Parser.terminal(TokenType.STRING, createNode=StringLiteral.withValue)(input)
return Parsers.terminal(TokenType.STRING, createNode=StringLiteral.withValue)
@SingletonParser def NoteParser(input):
def NoteParser(): return Parser.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)(input)
return Parsers.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)
@SingletonParser def BoolParser(input):
def BoolParser(): return Parser.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)(input)
return Parsers.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)
@SingletonParser def TypeLiteralParser(input):
def TypeParser(): return Parser.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)(input)
return Parsers.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)
@SingletonParser def LiteralParser(input):
def LiteralParser(): return Parser.oneOf(
return Parsers.oneOf( IntegerParser,
IntegerParser(), StringParser,
StringParser(), NoteParser,
NoteParser(), BoolParser,
BoolParser(), TypeLiteralParser,
TypeParser(),
name="literal" name="literal"
) )(input)
@SingletonParser def AtomParser(input):
def AtomParser():
from smnp.ast.node.identifier import IdentifierParser from smnp.ast.node.identifier import IdentifierParser
from smnp.ast.node.list import ListParser
from smnp.ast.node.map import MapParser
return Parsers.oneOf( return Parser.oneOf(
LiteralParser(), LiteralParser,
IdentifierParser(), IdentifierParser,
ListParser,
MapParser,
name="atom" name="atom"
) )(input)

View File

@@ -9,11 +9,9 @@ class Block(Node):
def BlockParser(input): def BlockParser(input):
parser = Parser.loop( return Parser.loop(
Parser.terminalParser(TokenType.OPEN_CURLY), Parser.terminal(TokenType.OPEN_CURLY),
Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"), Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"),
Parser.terminalParser(TokenType.CLOSE_CURLY), Parser.terminal(TokenType.CLOSE_CURLY),
createNode=lambda open, statements, close: Block.withChildren(statements, open.pos) createNode=lambda open, statements, close: Block.withChildren(statements, open.pos)
) )(input)
return Parser(parser, "block", [parser])(input)

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,4 +1,4 @@
from smnp.ast.node.expression import MaxPrecedenceExpressionParser from smnp.ast.node.expression import ExpressionParser
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 StatementParser from smnp.ast.node.statement import StatementParser
@@ -46,23 +46,23 @@ class IfElse(Node):
def IfElseStatementParser(input): def IfElseStatementParser(input):
ifStatementParser = Parser.allOf( ifStatementParser = Parser.allOf(
Parser.terminalParser(TokenType.IF), Parser.terminal(TokenType.IF),
Parser.terminalParser(TokenType.OPEN_PAREN), Parser.terminal(TokenType.OPEN_PAREN),
MaxPrecedenceExpressionParser, ExpressionParser,
Parser.terminalParser(TokenType.CLOSE_PAREN), Parser.terminal(TokenType.CLOSE_PAREN),
StatementParser, StatementParser,
createNode=lambda _, __, condition, ___, ifStatement: IfElse.createNode(ifStatement, condition), createNode=lambda _, __, condition, ___, ifStatement: IfElse.createNode(ifStatement, condition),
name="if statement" name="if statement"
) )
ifElseStatementParser = Parser.allOf( ifElseStatementParser = Parser.allOf(
Parser.terminalParser(TokenType.IF), Parser.terminal(TokenType.IF),
Parser.terminalParser(TokenType.OPEN_PAREN), Parser.terminal(TokenType.OPEN_PAREN, doAssert=True),
MaxPrecedenceExpressionParser, Parser.doAssert(ExpressionParser, "expression"),
Parser.terminalParser(TokenType.CLOSE_PAREN), Parser.terminal(TokenType.CLOSE_PAREN, doAssert=True),
StatementParser, Parser.doAssert(StatementParser, "statement"),
Parser.terminalParser(TokenType.ELSE), Parser.terminal(TokenType.ELSE),
StatementParser, Parser.doAssert(StatementParser, "statement"),
createNode=lambda _, __, condition, ___, ifStatement, ____, elseStatement: IfElse.createNode(ifStatement, condition, elseStatement), createNode=lambda _, __, condition, ___, ifStatement, ____, elseStatement: IfElse.createNode(ifStatement, condition, elseStatement),
name="if-else statement" name="if-else statement"
) )

View File

@@ -1,63 +1,51 @@
from smnp.ast.node.operator import BinaryOperator from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.term import TermParser from smnp.ast.node.term import TermParser
from smnp.ast.node.valuable import Valuable
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 Sum(BinaryOperator):
pass
class Relation(BinaryOperator):
pass
class And(BinaryOperator):
pass
class Or(BinaryOperator):
pass pass
def ExpressionParser(input): def ExpressionParser(input):
return Parser.leftAssociativeOperatorParser( expr1 = Parser.leftAssociativeOperatorParser(
TermParser, TermParser,
[TokenType.PLUS, TokenType.MINUS], [TokenType.PLUS, TokenType.MINUS],
TermParser, TermParser,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right)) lambda left, op, right: Sum.withValues(left, op, right)
)(input) )
expr2 = Parser.leftAssociativeOperatorParser(
expr1,
[TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE],
expr1,
lambda left, op, right: Relation.withValues(left, op, right)
)
def Expression2Parser(input): expr3 = Parser.leftAssociativeOperatorParser(
return Parser.leftAssociativeOperatorParser( expr2,
ExpressionParser,
[TokenType.RELATION],
ExpressionParser,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
)(input)
def Expression3Parser(input):
return Parser.leftAssociativeOperatorParser(
Expression2Parser,
[TokenType.AND], [TokenType.AND],
Expression2Parser, expr2,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right)) lambda left, op, right: And.withValues(left, op, right)
)(input) )
return Parser.leftAssociativeOperatorParser(
def Expression4Parser(input): expr3,
from smnp.ast.node.condition import IfElse
exprParser = Parser.leftAssociativeOperatorParser(
Expression3Parser,
[TokenType.OR], [TokenType.OR],
Expression3Parser, expr3,
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right)) lambda left, op, right: Or.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)
)
return Parser.oneOf(
ifElseExpression,
exprParser,
)(input) )(input)
MaxPrecedenceExpressionParser = Expression4Parser

View File

@@ -1,70 +1,88 @@
# from smnp.ast.node.block import BlockNode from smnp.ast.node.block import Block
# from smnp.ast.node.function import FunctionDefinitionNode from smnp.ast.node.function import FunctionDefinitionParser
# from smnp.ast.node.identifier import IdentifierNode from smnp.ast.node.identifier import IdentifierLiteralParser
# from smnp.ast.node.none import NoneNode from smnp.ast.node.model import Node
# from smnp.ast.node.statement import StatementNode from smnp.ast.node.none import NoneNode
# from smnp.ast.node.type import TypeNode from smnp.ast.node.type import TypeParser
# 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 Extend(Node):
# 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 withValues(cls, pos, type, variable, methods):
# def createNode(extend, type, asKeyword, variable, methods): node = cls(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( def ExtendParser(input):
# Parser.terminalParser(TokenType.EXTEND),
# Parser.doAssert(TypeNode.parse, "type being extended"), simpleExtend = Parser.allOf(
# Parser.terminalParser(TokenType.AS, doAssert=True), Parser.terminal(TokenType.EXTEND),
# Parser.doAssert(IdentifierNode.identifierParser(), "variable name"), TypeParser,
# Parser.doAssert(cls._methodsDeclarationsParser(), "methods declarations"), Parser.terminal(TokenType.AS),
# createNode=createNode IdentifierLiteralParser,
# )(input) Parser.terminal(TokenType.WITH),
# Parser.doAssert(Parser.wrap(FunctionDefinitionParser, lambda method: Block.withChildren([ method ], method.pos)), "method definition"),
# @classmethod createNode=lambda extend, type, _, variable, __, methods: Extend.withValues(extend.pos, type, variable, methods),
# def _methodsDeclarationsParser(cls): name="simple extend"
# def createNode(openBracket, items, closeBracket): )
# node = BlockNode(openBracket.pos)
# node.children = items multiExtend = Parser.allOf(
# return node Parser.terminal(TokenType.EXTEND),
# Parser.doAssert(TypeParser, "type being extended"),
# return Parser.loop( Parser.terminal(TokenType.AS, doAssert=True),
# Parser.terminalParser(TokenType.OPEN_CURLY), Parser.doAssert(IdentifierLiteralParser, "variable name"),
# Parser.doAssert(FunctionDefinitionNode.parse, f"method declaration or '{TokenType.CLOSE_CURLY.key}'"), Parser.doAssert(MethodsDeclarationParser, f"block with methods definitions or '{TokenType.WITH.key}' keyword"),
# Parser.terminalParser(TokenType.CLOSE_CURLY), createNode=lambda extend, type, _, variable, methods: Extend.withValues(extend.pos, type, variable, methods),
# createNode=createNode name="multiple extend"
# ) )
return Parser.oneOf(
simpleExtend,
multiExtend,
name="extend"
)(input)
def MethodsDeclarationParser(input):
return Parser.loop(
Parser.terminal(TokenType.OPEN_CURLY),
Parser.doAssert(FunctionDefinitionParser, f"method definition or '{TokenType.CLOSE_CURLY.key}'"),
Parser.terminal(TokenType.CLOSE_CURLY),
createNode=lambda open, methods, close: Block.withChildren(methods, open.pos),
name="methods block"
)(input)

View File

@@ -1,64 +1,102 @@
from smnp.ast.node.chain import ChainParser 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, UnaryOperator from smnp.ast.node.operator import BinaryOperator, Operator, UnaryOperator
from smnp.ast.node.valuable import Valuable from smnp.ast.node.unit import UnitParser
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 Factor(Valuable):
pass
class NotOperator(UnaryOperator): class NotOperator(UnaryOperator):
pass pass
class Power(BinaryOperator):
pass
class Loop(BinaryOperator): class Loop(BinaryOperator):
def __init__(self, pos):
super().__init__(pos)
self.children.append(NoneNode())
@property
def parameters(self):
return self[3]
@parameters.setter
def parameters(self, value):
self[3] = value
@classmethod
def loop(cls, left, parameters, operator, right):
node = cls(left.pos)
node.left = left
node.parameters = parameters
node.operator = operator
node.right = right
return node
class LoopParameters(Node):
pass pass
def FactorParser(input): def FactorParser(input):
from smnp.ast.node.expression import MaxPrecedenceExpressionParser from smnp.ast.node.expression import ExpressionParser
from smnp.ast.node.statement import StatementParser from smnp.ast.node.statement import StatementParser
from smnp.ast.node.identifier import IdentifierLiteralParser
powerFactor = Parser.leftAssociativeOperatorParser( parentheses = Parser.allOf(
ChainParser, Parser.terminal(TokenType.OPEN_PAREN),
[TokenType.DOUBLE_ASTERISK], Parser.doAssert(ExpressionParser, "expression"),
ChainParser, Parser.terminal(TokenType.CLOSE_PAREN),
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, createNode=lambda open, expr, close: expr,
name="grouping parentheses" name="grouping parentheses"
) )
factorParser = Parser.oneOf( factorOperands = Parser.oneOf(
powerFactor, parentheses,
exprFactor, UnitParser,
name="basic factor" name="factor operands"
)
powerFactor = Parser.leftAssociativeOperatorParser(
factorOperands,
[TokenType.DOUBLE_ASTERISK],
factorOperands,
lambda left, op, right: Power.withValues(left, op, right),
name="power operator"
) )
notOperator = Parser.allOf( notOperator = Parser.allOf(
Parser.terminalParser(TokenType.NOT, Operator.withValue), Parser.terminal(TokenType.NOT, Operator.withValue),
factorParser, powerFactor,
createNode=NotOperator.withValues, createNode=NotOperator.withValues,
name="not" name="not"
) )
loopParameters = Parser.allOf(
Parser.terminal(TokenType.AS),
Parser.oneOf(
Parser.wrap(IdentifierLiteralParser, lambda id: LoopParameters.withChildren([id], id.pos)),
abstractIterableParser(LoopParameters, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, IdentifierLiteralParser)
),
createNode=lambda asKeyword, parameters: parameters,
name="loop parameters"
)
loopFactor = Parser.allOf( loopFactor = Parser.allOf(
factorParser, powerFactor,
Parser.terminalParser(TokenType.DASH, createNode=Operator.withValue), Parser.optional(loopParameters),
Parser.terminal(TokenType.DASH, createNode=Operator.withValue),
StatementParser, StatementParser,
createNode=Loop.withValues, createNode=Loop.loop,
name="dash-loop" name="dash-loop"
) )
return Parser.oneOf( return Parser.oneOf(
loopFactor, loopFactor,
notOperator, notOperator,
factorParser powerFactor,
name="factor"
)(input) )(input)

View File

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

View File

@@ -1,10 +1,11 @@
from smnp.ast.node.atom import Atom from smnp.ast.node.atom import Atom
from smnp.ast.node.expression import ExpressionParser
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.operator import BinaryOperator, Operator from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.parser import Parsers 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 Identifier(Atom):
@@ -48,28 +49,26 @@ class Assignment(BinaryOperator):
pass pass
@SingletonParser def IdentifierLiteralParser(input):
def IdentifierParser(): return Parser.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)(input)
identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)
functionCallParser = Parsers.allOf(
identifierLiteralParser, def IdentifierParser(input):
#abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser), functionCallParser = Parser.allOf(
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments), IdentifierLiteralParser,
name="functionCall" abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, Parser.doAssert(ExpressionParser, "expression")),
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments)
) )
assignmentParser = Parsers.allOf( assignmentParser = Parser.allOf(
identifierLiteralParser, IdentifierLiteralParser,
Parsers.terminal(TokenType.ASSIGN, createNode=Operator.withValue), Parser.terminal(TokenType.ASSIGN, createNode=Operator.withValue),
#MaxPrecedenceExpressionParser, Parser.doAssert(ExpressionParser, "expression"),
createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr), createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr)
name="assignment"
) )
return Parsers.oneOf( return Parser.oneOf(
assignmentParser, assignmentParser,
functionCallParser, functionCallParser,
identifierLiteralParser, IdentifierLiteralParser
name="idExpr" )(input)
)

View File

@@ -1,11 +1,3 @@
# from smnp.ast.node.identifier import Identifier
# from smnp.ast.node.model import Node
# from smnp.ast.node.none import NoneNode
# from smnp.ast.node.string import StringLiteralNode
# from smnp.ast.node.type import TypeNode
# from smnp.ast.parser import Parser
# from smnp.token.type import TokenType
#
from smnp.ast.node.atom import StringParser from smnp.ast.node.atom import StringParser
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
@@ -34,8 +26,8 @@ class Import(Node):
def ImportParser(input): def ImportParser(input):
return Parser.allOf( return Parser.allOf(
Parser.terminalParser(TokenType.IMPORT), Parser.terminal(TokenType.IMPORT),
StringParser, Parser.doAssert(StringParser, "import source as string"),
createNode=lambda imp, source: Import.withValue(source), createNode=lambda imp, source: Import.withValue(source),
name="import" name="import"
)(input) )(input)

View File

@@ -1,11 +1,11 @@
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 AbstractIterable(Node): class AbstractIterable(Node):
def __init__(self, pos): def __init__(self, pos):
@@ -31,74 +31,70 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item
class AbstractIterableTail(AbstractIterable): class AbstractIterableTail(AbstractIterable):
pass pass
def abstractIterableParser(): def abstractIterableParser(input):
return Parsers.oneOf( return Parser.oneOf(
emptyIterable(), emptyIterable,
openIterable(), openIterable
name=name )(input)
)
def emptyIterable(): def emptyIterable(input):
def createNode(open, close): def createNode(open, close):
node = AbstractIterable(open.pos) node = AbstractIterable(open.pos)
node.value = open node.value = open
node.next = close node.next = close
return node return node
return Parsers.allOf( return Parser.allOf(
Parsers.terminal(openTokenType), Parser.terminal(openTokenType),
Parsers.terminal(closeTokenType), Parser.terminal(closeTokenType),
createNode=createNode, createNode=createNode
name=name+"Empty" )(input)
)
def openIterable(): def openIterable(input):
def createNode(open, item, tail): def createNode(open, item, tail):
node = AbstractIterable(open.pos) node = AbstractIterable(open.pos)
node.value = item node.value = item
node.next = tail node.next = tail
return node return node
return Parsers.allOf( return Parser.allOf(
Parsers.terminal(openTokenType), Parser.terminal(openTokenType),
itemParser, itemParser,
abstractIterableTailParser(), abstractIterableTailParser,
createNode=createNode, createNode=createNode
name=name+"Open" )(input)
)
def abstractIterableTailParser(): def abstractIterableTailParser(input):
return Parsers.oneOf( return Parser.oneOf(
closeIterable(), closeIterable,
nextItem(), nextItem,
name=name+"Tail" )(input)
)
def nextItem(): def nextItem(input):
def createNode(comma, item, tail): def createNode(comma, item, tail):
node = AbstractIterableTail(item.pos) node = AbstractIterableTail(item.pos)
node.value = item node.value = item
node.next = tail node.next = tail
return node return node
return Parsers.allOf( return Parser.allOf(
Parsers.terminal(TokenType.COMMA, doAssert=True), Parser.doAssert(Parser.terminal(TokenType.COMMA), f"'{TokenType.COMMA.key}' or '{closeTokenType.key}'"),
itemParser, itemParser,
abstractIterableTailParser(), abstractIterableTailParser,
name=name+"NextItem",
createNode=createNode createNode=createNode
) )(input)
def closeIterable(): def closeIterable(input):
return Parsers.terminal(closeTokenType) return Parser.terminal(closeTokenType)(input)
return abstractIterableParser() return toFlatDesiredNode(iterableNodeType, abstractIterableParser)
#return toFlatDesiredNode(iterableNodeType, abstractIterableParser())
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 +105,7 @@ def toFlatDesiredNode(iterableNodeType, parser):
return ParseResult.FAIL() return ParseResult.FAIL()
return DecoratorParser(wrapper, parser) return Parser(parse, "flat", [parser])
def flattenList(node, output=None): def flattenList(node, output=None):

View File

@@ -1,6 +1,6 @@
from smnp.ast.node.atom import AtomParser
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.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
@@ -8,6 +8,12 @@ class List(Node):
pass pass
def ListParser(): def ListParser(input):
return abstractIterableParser(List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, AtomParser(), name="list") from smnp.ast.node.expression import ExpressionParser
#MaxPrecedenceExpressionParser)(input)
return abstractIterableParser(
List,
TokenType.OPEN_SQUARE,
TokenType.CLOSE_SQUARE,
Parser.doAssert(ExpressionParser, "expression")
)(input)

View File

@@ -1,7 +1,8 @@
from smnp.ast.node.atom import LiteralParser
from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.iterable import abstractIterableParser
from smnp.ast.node.model import Node from smnp.ast.node.model import Node
from smnp.ast.node.operator import BinaryOperator, Operator from smnp.ast.node.operator import BinaryOperator, Operator
from smnp.ast.parser import Parsers from smnp.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
@@ -29,19 +30,21 @@ class Map(Node):
def MapParser(input): def MapParser(input):
from smnp.ast.node.atom import LiteralParser from smnp.ast.node.expression import ExpressionParser
#from smnp.ast.node.expression import MaxPrecedenceExpressionParser
keyParser = LiteralParser keyParser = LiteralParser
#valueParser = MaxPrecedenceExpressionParser valueParser = ExpressionParser
mapEntryParser = Parsers.allOf( mapEntryParser = Parser.allOf(
keyParser, keyParser,
Parsers.terminal(TokenType.ARROW, createNode=Operator.withValue), Parser.terminal(TokenType.ARROW, createNode=Operator.withValue, doAssert=True),
#valueParser, Parser.doAssert(valueParser, "expression"),
createNode=MapEntry.withValues, createNode=MapEntry.withValues
name="mapEntry"
) )
return abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser) return abstractIterableParser(
Map,
TokenType.OPEN_CURLY,
TokenType.CLOSE_CURLY,
mapEntryParser
)(input)

View File

@@ -28,21 +28,6 @@ class Node:
def pop(self, index): def pop(self, index):
return self.children.pop(index) return self.children.pop(index)
@classmethod
def _parse(cls, input):
pass
@classmethod
def parse(cls, input):
result = cls._parse(input)
if result is None:
return ParseResult.FAIL()
if not isinstance(result, ParseResult):
raise RuntimeError(f"_parse() method of '{cls.__name__}' class haven't returned ParseResult object")
return result
def print(self): def print(self):
self._print(first=True) self._print(first=True)

View File

@@ -68,68 +68,7 @@ class BinaryOperator(Node):
node.right = right node.right = right
return node 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): class Operator(Node):
def __init__(self, pos): def __init__(self, pos):
super().__init__(pos) super().__init__(pos)

View File

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

View File

@@ -1,32 +1,17 @@
# from smnp.ast.node.expression import ExpressionNode from smnp.ast.node.expression import ExpressionParser
# from smnp.ast.node.none import NoneNode from smnp.ast.node.valuable import Valuable
# from smnp.ast.node.statement import StatementNode from smnp.ast.parser import Parser
# from smnp.ast.parser import Parser from smnp.token.type import TokenType
# from smnp.token.type import TokenType
#
# class Return(Valuable):
# class ReturnNode(StatementNode): pass
# def __init__(self, pos):
# super().__init__(pos)
# self.children.append(NoneNode()) def ReturnParser(input):
# return Parser.allOf(
# @property Parser.terminal(TokenType.RETURN),
# def value(self): Parser.optional(ExpressionParser),
# return self[0] createNode=lambda ret, val: Return.withValue(val, ret.pos),
# name="return"
# @value.setter )(input)
# def value(self, value):
# self[0] = value
#
# @classmethod
# def _parse(cls, input):
# def createNode(ret, value):
# node = ReturnNode(ret.pos)
# node.value = value
# return node
#
# return Parser.allOf(
# Parser.terminalParser(TokenType.RETURN),
# Parser.doAssert(ExpressionNode.parse, "expression"),
# createNode=createNode
# )(input)

View File

@@ -1,4 +1,3 @@
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
@@ -10,25 +9,13 @@ class Statement(Node):
def StatementParser(input): def StatementParser(input):
from smnp.ast.node.block import BlockParser from smnp.ast.node.block import BlockParser
from smnp.ast.node.condition import IfElseStatementParser from smnp.ast.node.condition import IfElseStatementParser
from smnp.ast.node.expression import ExpressionParser
parser = Parser.oneOf( from smnp.ast.node.ret import ReturnParser
return Parser.oneOf(
IfElseStatementParser, IfElseStatementParser,
ExpressionParser,
BlockParser, BlockParser,
MaxPrecedenceExpressionParser ReturnParser,
) name="statement"
)(input)
return Parser(parser, "statement", parser)(input)
# class StatementNode(Node):
#
# @classmethod
# def _parse(cls, input):
# from smnp.ast.node.block import BlockNode
# from smnp.ast.node.expression import ExpressionNode
# from smnp.ast.node.ret import ReturnNode
#
# return Parser.oneOf(
# ExpressionNode.parse,
# BlockNode.parse,
# ReturnNode.parse,
# )(input)

View File

@@ -1,12 +1,17 @@
from smnp.ast.node.factor import FactorParser from smnp.ast.node.factor import FactorParser
from smnp.ast.node.operator import BinaryOperator from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.valuable import Valuable
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 Term(Valuable): class Product(BinaryOperator):
pass pass
TermParser = Parser.leftAssociativeOperatorParser(FactorParser, [TokenType.ASTERISK, TokenType.SLASH], FactorParser,
lambda left, op, right: Term.withValue(BinaryOperator.withValues(left, op, right))) def TermParser(input):
return Parser.leftAssociativeOperatorParser(
FactorParser,
[TokenType.ASTERISK, TokenType.SLASH],
FactorParser,
lambda left, op, right: Product.withValues(left, op, right)
)(input)

View File

@@ -1,63 +1,67 @@
# from smnp.ast.node.iterable import abstractIterableParser from smnp.ast.node.atom import TypeLiteralParser
# 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.node.none import NoneNode
# from smnp.token.type import TokenType from smnp.ast.parser import Parser
# from smnp.type.model import Type from smnp.token.type import TokenType
#
#
# class TypeSpecifier(Node): class Type(Node):
# def __init__(self, pos):
# @classmethod super().__init__(pos)
# def _parse(cls, input): self.children = [NoneNode(), NoneNode()]
# return abstractIterableParser(TypeSpecifier, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE,
# Parser.doAssert(cls._specifierItem(), "type"))(input) @property
# def type(self):
# @classmethod return self[0]
# def _specifierItem(cls):
# return Parser.oneOf( @type.setter
# TypeNode.parse, def type(self, value):
# cls.parse self[0] = value
# )
# @property
# class TypeSpecifiers(Node): def specifiers(self):
# pass return self[1]
#
# @specifiers.setter
# class TypeNode(LeftAssociativeOperatorNode): def specifiers(self, value):
# def __init__(self, pos): self[1] = value
# super().__init__(pos)
# @classmethod
# @property def withValues(cls, pos, type, specifiers=NoneNode()):
# def type(self): node = cls(pos)
# return self[0] node.type = type
# node.specifiers = specifiers
# @type.setter return node
# def type(self, value):
# self[0] = value
# class TypesList(Node):
# @property pass
# def specifiers(self):
# return self[1]
# def TypesListParser(input):
# @specifiers.setter return abstractIterableParser(
# def specifiers(self, value): TypesList,
# self[1] = value TokenType.OPEN_ANGLE,
# TokenType.CLOSE_ANGLE,
# @classmethod TypeParser
# def _parse(cls, input): )(input)
# def createNode(type, specifiers):
# node = TypeNode(type.pos)
# node.type = Type[type.value.upper()] class TypeSpecifiers(Node):
# node.specifiers = specifiers pass
# return node
#
# return Parser.allOf( def TypeParser(input):
# cls._rawTypeParser(), typeWithSpecifier = Parser.allOf(
# Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)), TypeLiteralParser,
# createNode=createNode Parser.many(TypesListParser, createNode=TypeSpecifiers.withChildren),
# )(input) createNode=lambda type, specifiers: Type.withValues(type.pos, type, specifiers),
# name="type with specifiers?"
# @classmethod )
# def _rawTypeParser(cls):
# return Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos)) return Parser.oneOf(
typeWithSpecifier,
TypesListParser,
name="mult. types or type with specifier"
)(input)

36
smnp/ast/node/unit.py Normal file
View File

@@ -0,0 +1,36 @@
from smnp.ast.node.atom import AtomParser
from smnp.ast.node.operator import BinaryOperator, UnaryOperator, Operator
from smnp.ast.parser import Parser
from smnp.token.type import TokenType
class MinusOperator(UnaryOperator):
pass
class Access(BinaryOperator):
pass
def UnitParser(input):
minusOperator = Parser.allOf(
Parser.terminal(TokenType.MINUS, createNode=Operator.withValue),
Parser.doAssert(AtomParser, "atom"),
createNode=MinusOperator.withValues,
name="minus"
)
atom2 = Parser.oneOf(
minusOperator,
AtomParser,
name="atom2"
)
return Parser.leftAssociativeOperatorParser(
atom2,
[TokenType.DOT],
Parser.doAssert(atom2, "atom"),
createNode=lambda left, op, right: Access.withValues(left, op, right),
name="unit"
)(input)

View File

@@ -16,7 +16,7 @@ class Valuable(Node):
self[0] = value self[0] = value
@classmethod @classmethod
def withValue(cls, value): def withValue(cls, value, pos=None):
node = cls(value.pos) node = cls(value.pos if pos is None else pos)
node.value = value node.value = value
return node return node

View File

@@ -9,8 +9,15 @@ def parse(input):
return ProgramParser(input).node return ProgramParser(input).node
class Parser(object): class Parser:
def __init__(self, name): def __init__(self, parse, name=None, parsers=None):
if parsers is None:
parsers = []
self.parsers = parsers
self._parse = parse
if name is None:
name = parse.__name__
self.name = name self.name = name
def parse(self, input): def parse(self, input):
@@ -19,27 +26,10 @@ class Parser(object):
return ParseResult.FAIL() return ParseResult.FAIL()
if not isinstance(result, ParseResult): if not isinstance(result, ParseResult):
raise RuntimeError( raise RuntimeError(f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
return result 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): def __call__(self, input):
return self.parse(input) return self.parse(input)
@@ -49,242 +39,186 @@ class Parser(object):
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
# a -> A
class Parsers:
@staticmethod @staticmethod
def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False): def terminal(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)
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())
return ParseResult.FAIL()
return Parser(parse, name=expectedType.name.lower())
# oneOf -> a | b | c | ...
@staticmethod @staticmethod
def oneOf(*parsers, name, exception=None): def oneOf(*parsers, assertExpected=None, exception=None, name="or"):
return OneOfParser(*parsers, name=name, exception=exception) def combinedParser(input):
snap = input.snapshot()
for parser in parsers:
value = parser(input)
if value.result:
return value
input.reset(snap)
if assertExpected is not None:
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
raise SyntaxException(f"Expected {assertExpected}{found}", input.currentPos())
if exception is not None:
if callable(exception):
raise exception(input)
else:
raise exception
input.reset(snap)
return ParseResult.FAIL()
return Parser(combinedParser, name=name, parsers=parsers)
# allOf -> a b c ...
@staticmethod @staticmethod
def allOf(*parsers, createNode, exception=None, name): def allOf(*parsers, createNode, exception=None, name="all"):
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 not result.result:
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
input.reset(snap) input.reset(snap)
return ParseResult.FAIL() return ParseResult.FAIL()
parsedItems.append(result.node) results.append(result.node)
node = self.createNode(*parsedItems) 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 Parser(extendedParser, name=name, parsers=parsers)
def __init__(self, leftParser, operatorTokenTypes, rightParser, createNode, name):
# leftAssociative -> left | left OP right
@staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name="leftAssoc"):
from smnp.ast.node.operator import Operator from smnp.ast.node.operator import Operator
super().__init__(name) def parse(input):
self.leftParser = leftParser operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: Operator.withChildren([val], pos))
self.rightParser = rightParser left = leftParser(input)
self.createNode = createNode if left.result:
self.operators = operatorTokenTypes operator = operatorParser(input)
while operator.result:
right = rightParser(input)
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
operator = operatorParser(input)
return left
operatorParsers = [ TerminalParser(expectedType, createNode=lambda val, pos: Operator.withValue(val, pos)) for expectedType in operatorTokenTypes ] return ParseResult.FAIL()
self.operatorParser = OneOfParser(*operatorParsers, name="not important")
def _parse(self, input): return Parser(parse, name=name, parsers=[leftParser, '|'.join([t.value for t in operatorTokenTypes]), rightParser])
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() @staticmethod
def oneOfTerminals(*tokenTypes, createNode=None):
return Parser.oneOf(*[Parser.terminal(expectedType, createNode=createNode) for expectedType in tokenTypes], name='|'.join([t.value for t in tokenTypes]))
# loop -> start item* end
@staticmethod
def loop(startParser, itemParser, endParser, createNode, name="loop"):
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)
def _grammarRules(self, output): return ParseResult.FAIL()
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)
return Parser(parse, name, parsers=[startParser, itemParser, endParser])
class ManyParser(Parser): @staticmethod
def __init__(self, itemParser, createNode, name): def doAssert(parser, expected, name="!!"):
super().__init__(name) def parse(input):
self.itemParser = itemParser result = parser(input)
self.createNode = createNode
def _parse(self, input): if not result.result:
snap = input.snapshot() found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ''
parsedItems = [] raise SyntaxException(f"Expected {expected}{found}", input.currentPos())
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 Parser(parse, name, parsers=parser)
def _grammarRules(self, output): @staticmethod
output.append(f"{self.name} -> {self.parser.name}?") def optional(parser, name="??"):
def parse(input):
result = parser(input)
if result.result:
return result
return ParseResult.OK(NoneNode())
class LoopParser(Parser): return Parser(parse, name, parsers=[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): @staticmethod
items = [] def epsilon():
start = self.startParser.parse(input) return lambda *args: ParseResult.OK(NoneNode())
if start.result:
@staticmethod
def many(parser, createNode, name="*"):
def parse(input):
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() return Parser(parse, name, parsers=[parser])
def _grammarRules(self, output): @staticmethod
output.append(f"{self.name} -> {self.startParser.name} {self.itemParser.name}* {self.endParser.name}") def wrap(parser, createNode):
self.startParser._grammarRules(output) def parse(input):
self.itemParser._grammarRules(output) result = parser(input)
self.endParser._grammarRules(output) if result.result:
return ParseResult.OK(createNode(result.node))
return result
return parse

View File

@@ -10,6 +10,9 @@ class Sound:
def play(self): def play(self):
sd.play(self.data, self.fs, blocking=True) sd.play(self.data, self.fs, blocking=True)
def __eq__(self, other):
return self.file == other.file and self.data == other.data
def __str__(self): def __str__(self):
return f"sound[{self.file}]" return f"sound[{self.file}]"

View File

@@ -5,7 +5,5 @@ from smnp.program.interpreter import Interpreter
def loadStandardLibrary(): def loadStandardLibrary():
mainSource = resource_string('smnp.library.code', 'main.mus').decode("utf-8") mainSource = resource_string('smnp.library.code', 'main.mus').decode("utf-8")
boolSource = resource_string('smnp.library.code', 'bool.mus').decode("utf-8")
env = Interpreter.interpretString(mainSource) env = Interpreter.interpretString(mainSource)
return Interpreter.interpretString(boolSource, baseEnvironment=env) return env

View File

@@ -1,32 +1,17 @@
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.library.loader import loadStandardLibrary
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=False, execute=True, baseEnvironment=stdLibraryEnv)
# draft() #draft()
#tokens = tokenize(['function a(b...) { x+y}'])
class TestNode(Node): #FunctionDefinitionParser(tokens).node.print()
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,4 +1,4 @@
from smnp.module.iterable.function import combine, flat, map, range, get from smnp.module.iterable.function import combine, map, range, get
functions = [ combine.function, flat.function, map.function, range.function ] functions = [ combine.function, map.function, range.function ]
methods = [ get.function ] methods = [ get.function ]

View File

@@ -1,23 +0,0 @@
from smnp.function.model import Function
from smnp.function.signature import varargSignature
from smnp.type.model import Type
from smnp.type.signature.matcher.type import allTypes
_signature = varargSignature(allTypes())
def _function(env, vararg):
return Type.list(doFlat(vararg, [])).decompose()
def doFlat(input, output=None):
if output is None:
output = []
for item in input:
if item.type == Type.LIST:
doFlat(item.value, output)
else:
output.append(item)
return output
function = Function(_signature, _function, 'flat')

View File

@@ -6,17 +6,17 @@ from smnp.type.signature.matcher.type import ofType
_signature1 = signature(ofType(Type.INTEGER)) _signature1 = signature(ofType(Type.INTEGER))
def _function1(env, upper): def _function1(env, upper):
return Type.list(list(range(upper.value + 1))) return Type.list([ Type.integer(i) for i in range(upper.value + 1)])
_signature2 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER)) _signature2 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER))
def _function2(env, lower, upper): def _function2(env, lower, upper):
return Type.list(list(range(lower.value, upper.value + 1))) return Type.list([ Type.integer(i) for i in range(lower.value, upper.value + 1)])
_signature3 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER), ofType(Type.INTEGER)) _signature3 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER), ofType(Type.INTEGER))
def _function3(env, lower, upper, step): def _function3(env, lower, upper, step):
return Type.list(list(range(lower.value, upper.value + 1, step.value))) return Type.list([ Type.integer(i) for i in range(lower.value, upper.value + 1, step.value)])
_signature4 = signature(ofType(Type.NOTE), ofType(Type.NOTE)) _signature4 = signature(ofType(Type.NOTE), ofType(Type.NOTE))

View File

@@ -1,7 +1,8 @@
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
@@ -17,9 +18,9 @@ class Interpreter:
@staticmethod @staticmethod
def _interpret(lines, printTokens=False, printAst=False, execute=True, baseEnvironment=None): def _interpret(lines, printTokens=False, printAst=False, execute=True, baseEnvironment=None):
#environment = createEnvironment() environment = createEnvironment()
#if baseEnvironment is not None: if baseEnvironment is not None:
# environment.extend(baseEnvironment) environment.extend(baseEnvironment)
try: try:
tokens = tokenize(lines) tokens = tokenize(lines)
@@ -30,10 +31,10 @@ class Interpreter:
if printAst: if printAst:
ast.print() ast.print()
#if execute: 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,10 @@
from smnp.ast.node.block import BlockNode from smnp.ast.node.block import Block
from smnp.ast.node.extend import ExtendNode from smnp.ast.node.condition import IfElse
from smnp.ast.node.function import FunctionDefinitionNode from smnp.ast.node.extend import Extend
from smnp.ast.node.imports import ImportNode from smnp.ast.node.function import FunctionDefinition
from smnp.ast.node.imports import Import
from smnp.ast.node.program import Program from smnp.ast.node.program import Program
from smnp.ast.node.ret import ReturnNode from smnp.ast.node.ret import Return
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.type.model import Type from smnp.type.model import Type
@@ -68,20 +69,27 @@ class EvaluationResult():
def evaluate(node, environment): 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.function import FunctionDefinitionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.extend import ExtendEvaluator from smnp.runtime.evaluators.condition import IfElseStatementEvaluator
from smnp.runtime.evaluators.block import BlockEvaluator from smnp.runtime.evaluators.block import BlockEvaluator
from smnp.runtime.evaluators.imports import ImportEvaluator from smnp.runtime.evaluators.imports import ImportEvaluator
from smnp.runtime.evaluators.function import FunctionDefinitionEvaluator
from smnp.runtime.evaluators.function import ReturnEvaluator from smnp.runtime.evaluators.function import ReturnEvaluator
from smnp.runtime.evaluators.extend import ExtendEvaluator
result = Evaluator.oneOf( result = Evaluator.oneOf(
Evaluator.forNodes(ProgramEvaluator.evaluate, Program), Evaluator.forNodes(ProgramEvaluator.evaluate, Program),
Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode), Evaluator.forNodes(IfElseStatementEvaluator.evaluate, IfElse),
Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode), Evaluator.forNodes(BlockEvaluator.evaluate, Block),
Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode), Evaluator.forNodes(ImportEvaluator.evaluate, Import),
Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode), Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinition),
Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode), Evaluator.forNodes(ReturnEvaluator.evaluate, Return),
Evaluator.forNodes(ExtendEvaluator.evaluate, Extend),
#Evaluator.forNodes(ImportEvaluator.evaluate, ImportNode),
#Evaluator.forNodes(FunctionDefinitionEvaluator.evaluate, FunctionDefinitionNode),
#Evaluator.forNodes(ExtendEvaluator.evaluate, ExtendNode),
#Evaluator.forNodes(BlockEvaluator.evaluate, BlockNode),
#Evaluator.forNodes(ReturnEvaluator.evaluate, ReturnNode),
expressionEvaluator() expressionEvaluator()
)(node, environment) )(node, environment)

View File

@@ -1,5 +1,4 @@
from smnp.ast.node.identifier import Identifier from smnp.ast.node.identifier import Identifier, FunctionCall
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
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
@@ -20,9 +19,9 @@ class AccessEvaluator(Evaluator):
except KeyError: except KeyError:
raise RuntimeException(f"Unknown property '{right.value}' of type '{left.type.name.lower()}'", right.pos) raise RuntimeException(f"Unknown property '{right.value}' of type '{left.type.name.lower()}'", right.pos)
if type(right) == FunctionCallNode: if type(right) == FunctionCall:
try: try:
arguments = abstractIterableEvaluator(expressionEvaluator(True))(right.arguments, environment) arguments = abstractIterableEvaluator(expressionEvaluator(doAssert=True))(right.arguments, environment)
return environment.invokeMethod(left, right.name.value, arguments) return environment.invokeMethod(left, right.name.value, arguments)
except RuntimeException as e: except RuntimeException as e:
raise updatePos(e, right) raise updatePos(e, right)

View File

@@ -1,4 +1,3 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
@@ -7,11 +6,8 @@ class AssignmentEvaluator(Evaluator):
@classmethod @classmethod
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
target = node.target.value target = node.left.value
if target.startswith("_"): value = expressionEvaluator(doAssert=True)(node.right, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
raise RuntimeException("Declaration and assignation variables with names starting with '_' is not allowed", node.target.pos)
value = expressionEvaluator(doAssert=True)(node.value, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
scopeOfExistingVariable = environment.findVariableScope(target) scopeOfExistingVariable = environment.findVariableScope(target)
if scopeOfExistingVariable is None: if scopeOfExistingVariable is None:
environment.scopes[-1][target] = value environment.scopes[-1][target] = value

View File

@@ -0,0 +1,94 @@
from smnp.ast.node.atom import StringLiteral, IntegerLiteral, NoteLiteral, BoolLiteral, TypeLiteral
from smnp.ast.node.identifier import Identifier
from smnp.ast.node.list import List
from smnp.ast.node.map import Map
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
from smnp.runtime.tools.error import updatePos
from smnp.type.model import Type
class IntegerEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.integer(node.value)
class StringEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.string(node.value)
class NoteEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.note(node.value)
class BoolEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.bool(node.value)
class TypeEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.type(node.value)
class ListEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
list = abstractIterableEvaluator(expressionEvaluator(doAssert=True))(node, environment)
return Type.list(list)
class MapEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
map = {}
exprEvaluator = expressionEvaluator(doAssert=True)
for entry in node.children:
key = exprEvaluator(entry.key, environment).value
if key in map:
raise RuntimeException(f"Duplicated key '{key.stringify()}' found in map", entry.pos)
map[key] = exprEvaluator(entry.value, environment).value
return Type.map(map)
class IdentifierEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
try:
return environment.findVariable(node.value)
except RuntimeException as e:
raise updatePos(e, node)
class AtomEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Evaluator.oneOf(
Evaluator.forNodes(StringEvaluator.evaluate, StringLiteral),
Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteral),
Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteral),
Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteral),
Evaluator.forNodes(TypeEvaluator.evaluate, TypeLiteral),
Evaluator.forNodes(IdentifierEvaluator.evaluate, Identifier),
Evaluator.forNodes(ListEvaluator.evaluate, List),
Evaluator.forNodes(MapEvaluator.evaluate, Map)
)(node, environment).value

View File

@@ -0,0 +1,35 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator, evaluate
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class IfElseEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
condition = expressionEvaluator(doAssert=True)(node.condition, environment).value
if condition.type != Type.BOOL:
raise RuntimeException(f"Only {Type.BOOL.name.lower()} types can be used as conditions in conditional expression", node.condition.pos)
if condition.value:
return expressionEvaluator(doAssert=True)(node.ifNode, environment).value
else:
return expressionEvaluator(doAssert=True)(node.elseNode, environment).value
class IfElseStatementEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
condition = expressionEvaluator(doAssert=True)(node.condition, environment).value
if condition.type != Type.BOOL:
raise RuntimeException(
f"Only {Type.BOOL.name.lower()} types can be used as conditions in conditional expression", node.condition.pos)
if condition.value:
evaluate(node.ifNode, environment)
else:
evaluate(node.elseNode, environment)

View File

@@ -1,15 +1,9 @@
from smnp.ast.node.assignment import AssignmentNode from smnp.ast.node.condition import IfElse
from smnp.ast.node.asterisk import AsteriskNode from smnp.ast.node.expression import Sum, Relation
from smnp.ast.node.bool import BoolLiteralNode from smnp.ast.node.factor import NotOperator, Power, Loop
from smnp.ast.node.identifier import Identifier from smnp.ast.node.identifier import FunctionCall, Assignment
from smnp.ast.node.integer import IntegerLiteralNode from smnp.ast.node.term import Product
from smnp.ast.node.invocation import FunctionCallNode from smnp.ast.node.unit import MinusOperator, Access
from smnp.ast.node.list import List
from smnp.ast.node.map import MapNode
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.type import TypeNode
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.type.model import Type from smnp.type.model import Type
@@ -17,38 +11,38 @@ from smnp.type.model import Type
def expressionEvaluator(doAssert=False): def expressionEvaluator(doAssert=False):
def evaluateExpression(node, environment): def evaluateExpression(node, environment):
from smnp.runtime.evaluators.string import StringEvaluator from smnp.runtime.evaluators.function import FunctionCallEvaluator
from smnp.runtime.evaluators.integer import IntegerEvaluator from smnp.runtime.evaluators.minus import MinusEvaluator
from smnp.runtime.evaluators.note import NoteEvaluator from smnp.runtime.evaluators.atom import AtomEvaluator
from smnp.runtime.evaluators.identifier import IdentifierEvaluator from smnp.runtime.evaluators.access import AccessEvaluator
from smnp.runtime.evaluators.list import ListEvaluator from smnp.runtime.evaluators.negation import NotEvaluator
from smnp.runtime.evaluators.function import FunctionCallEvaluator from smnp.runtime.evaluators.power import PowerEvaluator
from smnp.runtime.evaluators.loop import LoopEvaluator
from smnp.runtime.evaluators.assignment import AssignmentEvaluator
from smnp.runtime.evaluators.product import ProductEvaluator
from smnp.runtime.evaluators.access import AccessEvaluator from smnp.runtime.evaluators.sum import SumEvaluator
from smnp.runtime.evaluators.assignment import AssignmentEvaluator from smnp.runtime.evaluators.relation import RelationEvaluator
from smnp.runtime.evaluators.asterisk import AsteriskEvaluator from smnp.runtime.evaluators.condition import IfElseEvaluator
from smnp.runtime.evaluators.map import MapEvaluator result = Evaluator.oneOf(
from smnp.runtime.evaluators.type import TypeEvaluator Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCall),
from smnp.runtime.evaluators.bool import BoolEvaluator Evaluator.forNodes(MinusEvaluator.evaluate, MinusOperator),
result = Evaluator.oneOf( Evaluator.forNodes(AccessEvaluator.evaluate, Access),
Evaluator.forNodes(FunctionCallEvaluator.evaluate, FunctionCallNode), Evaluator.forNodes(NotEvaluator.evaluate, NotOperator),
Evaluator.forNodes(StringEvaluator.evaluate, StringLiteralNode), Evaluator.forNodes(PowerEvaluator.evaluate, Power),
Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteralNode), Evaluator.forNodes(LoopEvaluator.evaluate, Loop),
Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteralNode), Evaluator.forNodes(AssignmentEvaluator.evaluate, Assignment),
Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteralNode), Evaluator.forNodes(ProductEvaluator.evaluate, Product),
Evaluator.forNodes(TypeEvaluator.evaluate, TypeNode), Evaluator.forNodes(SumEvaluator.evaluate, Sum),
Evaluator.forNodes(IdentifierEvaluator.evaluate, Identifier), Evaluator.forNodes(RelationEvaluator.evaluate, Relation),
Evaluator.forNodes(ListEvaluator.evaluate, List), Evaluator.forNodes(IfElseEvaluator.evaluate, IfElse),
Evaluator.forNodes(AccessEvaluator.evaluate, LeftAssociativeOperatorNode), AtomEvaluator.evaluate
Evaluator.forNodes(AssignmentEvaluator.evaluate, AssignmentNode), )(node, environment)
Evaluator.forNodes(AsteriskEvaluator.evaluate, AsteriskNode),
Evaluator.forNodes(MapEvaluator.evaluate, MapNode)
)(node, environment)
if doAssert and result.result and result.value.type == Type.VOID: if doAssert and result.result and result.value.type == Type.VOID:
raise RuntimeException(f"Expected expression", node.pos) raise RuntimeException(f"Expected expression", node.pos)
return result
return result
return evaluateExpression return evaluateExpression

View File

@@ -17,11 +17,11 @@ class ExtendEvaluator(Evaluator):
@classmethod @classmethod
def _typeToMethodSignature(cls, node): def _typeToMethodSignature(cls, node):
if type(node.specifiers) == NoneNode: if type(node.specifiers) == NoneNode:
return signature(ofType(node.type)) return signature(ofType(node.type.value))
elif node.type == Type.LIST: elif node.type.value == Type.LIST:
return signature(listSpecifier(node.specifiers[0])) return signature(listSpecifier(node.specifiers[0]))
elif node.type == Type.MAP: elif node.type.value == Type.MAP:
return signature(mapSpecifier(node.specifiers[0], node.specifiers[1])) return signature(mapSpecifier(node.specifiers[0], node.specifiers[1]))
@classmethod @classmethod

View File

@@ -1,4 +1,3 @@
from smnp.ast.node.none import NoneNode
from smnp.program.interpreter import Interpreter from smnp.program.interpreter import Interpreter
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
@@ -7,13 +6,6 @@ class ImportEvaluator(Evaluator):
@classmethod @classmethod
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
if type(node.type) == NoneNode:
cls._evaluateCodeImport(node, environment)
else:
raise RuntimeError("Importing types is not implemented yet")
@classmethod
def _evaluateCodeImport(cls, node, environment):
source = node.source source = node.source
newEnvironment = Interpreter.interpretFile(source.value) newEnvironment = Interpreter.interpretFile(source.value, baseEnvironment=environment)
environment.extend(newEnvironment) environment.extend(newEnvironment)

View File

@@ -0,0 +1,104 @@
from smnp.ast.node.none import NoneNode
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator, evaluate
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class LoopEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
iterator = expressionEvaluator(doAssert=True)(node.left, environment).value
parameters = [ identifier.value for identifier in node.parameters ] if type(node.parameters) != NoneNode() else []
try:
environment.scopes.append({})
output = {
Type.INTEGER: cls.numberEvaluator,
Type.BOOL: cls.boolEvaluator,
Type.LIST: cls.listEvaluator,
Type.MAP: cls.mapEvaluator
}[iterator.type](node, environment, iterator, parameters)
environment.scopes.pop(-1)
except KeyError:
raise RuntimeException(f"The {iterator.type.name.lower()} type cannot stand as an iterator for loop statement", node.left.pos)
return Type.list(output)
@classmethod
def numberEvaluator(cls, node, environment, evaluatedIterator, parameters):
output = []
if len(parameters) > 1:
raise RuntimeException(f"Loop with numeric iterator can handle only one parameter", node.parameters.pos)
for i in range(evaluatedIterator.value):
if len(parameters) > 0:
environment.scopes[-1][parameters[0]] = Type.integer(i)
output.append(evaluate(node.right, environment).value)
return output
@classmethod
def boolEvaluator(cls, node, environment, evaluatedIterator, parameters):
output = []
if len(parameters) > 0:
raise RuntimeException(f"Loop with logic iterator can't' handle any parameters", node.parameters.pos)
condition = evaluatedIterator
while condition.value:
output.append(evaluate(node.right, environment).value)
condition = expressionEvaluator(doAssert=True)(node.left, environment).value
return output
@classmethod
def listEvaluator(cls, node, environment, evaluatedIterator, parameters):
output = []
if len(parameters) > 2:
raise RuntimeException(f"Loop with list iterator can handle only two parameters", node.parameters.pos)
for i, value in enumerate(evaluatedIterator.value):
if len(parameters) == 1:
environment.scopes[-1][parameters[0]] = value
if len(parameters) == 2:
environment.scopes[-1][parameters[0]] = Type.integer(i)
environment.scopes[-1][parameters[1]] = value
output.append(evaluate(node.right, environment).value)
return output
@classmethod
def mapEvaluator(cls, node, environment, evaluatedIterator, parameters):
output = []
if len(parameters) > 3:
raise RuntimeException(f"Loop with map iterator can handle only three parameters", node.parameters.pos)
i = 0
for key, value in evaluatedIterator.value.items():
if len(parameters) == 1:
environment.scopes[-1][parameters[0]] = value
if len(parameters) == 2:
environment.scopes[-1][parameters[0]] = key
environment.scopes[-1][parameters[1]] = value
if len(parameters) == 3:
environment.scopes[-1][parameters[0]] = Type.integer(i)
environment.scopes[-1][parameters[1]] = key
environment.scopes[-1][parameters[2]] = value
i += 1
output.append(evaluate(node.right, environment).value)
return output

View File

@@ -0,0 +1,31 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator, evaluate
from smnp.type.model import Type
class MinusEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
value = evaluate(node.value, environment).value
try:
return {
Type.INTEGER: cls.evaluateForInteger,
Type.STRING: cls.evaluateForString,
Type.LIST: cls.evaluateForList
}[value.type](value.value)
except KeyError:
raise RuntimeException(f"Type {value.type.name.lower()} does not support '{node.operator.value}' operator", node.pos)
@classmethod
def evaluateForInteger(cls, value):
return Type.integer(-value)
@classmethod
def evaluateForString(cls, value):
return Type.string(value[::-1])
@classmethod
def evaluateForList(cls, value):
return Type.list(value[::-1])

View File

@@ -0,0 +1,16 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class NotEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
value = expressionEvaluator(doAssert=True)(node.value, environment).value
if value.type != Type.BOOL:
raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {Type.BOOL.name.lower()} type", node.value.pos)
return Type.bool(not value.value)

View File

@@ -0,0 +1,20 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class PowerEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value
if left.type != Type.INTEGER:
raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos)
if right.type != Type.INTEGER:
raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.right.pos)
return Type.integer(int(left.value ** right.value))

View File

@@ -0,0 +1,31 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class ProductEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value
if left.type != Type.INTEGER:
raise RuntimeException(
f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos)
if right.type != Type.INTEGER:
raise RuntimeException(
f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.right.pos)
if node.operator.value == "*":
return Type.integer(int(left.value * right.value))
if node.operator.value == "/":
if right.value == 0:
raise RuntimeException("Attempt to divide by 0", node.right.pos)
return Type.integer(int(left.value / right.value))
raise RuntimeError("This line should never be reached")

View File

@@ -0,0 +1,46 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class RelationEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value
if node.operator.value == "==":
return cls.equalOperatorEvaluator(left, node.operator, right)
if node.operator.value == "!=":
return cls.notEqualOperatorEvaluator(left, node.operator, right)
return cls.otherRelationOperatorsEvaluator(left, node.operator, right)
@classmethod
def equalOperatorEvaluator(cls, left, operator, right):
return Type.bool(left.value == right.value)
@classmethod
def notEqualOperatorEvaluator(cls, left, operator, right):
return Type.bool(left.value != right.value)
@classmethod
def otherRelationOperatorsEvaluator(cls, left, operator, right):
if left.type == right.type == Type.INTEGER:
if operator.value == ">":
return Type.bool(left.value > right.value)
if operator.value == ">=":
return Type.bool(left.value >= right.value)
if operator.value == "<":
return Type.bool(left.value < right.value)
if operator.value == "<=":
return Type.bool(left.value < right.value)
raise RuntimeException(f"Operator {operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types", operator.pos)

View File

@@ -0,0 +1,66 @@
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.type.model import Type
class SumEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value
if left.type == right.type == Type.INTEGER:
return cls.integerEvaluator(left, node.operator, right)
if left.type == right.type == Type.STRING:
return cls.stringEvaluator(left, node.operator, right)
if left.type == right.type == Type.LIST:
return cls.listEvaluator(left, node.operator, right)
if left.type == right.type == Type.MAP:
return cls.mapEvaluator(left, node.operator, right)
raise RuntimeException(f"Operator {node.operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types", node.operator.pos)
@classmethod
def integerEvaluator(cls, left, operator, right):
if operator.value == "+":
return Type.integer(left.value + right.value)
if operator.value == "-":
return Type.integer(left.value - right.value)
raise RuntimeError("This line should never be reached")
@classmethod
def stringEvaluator(cls, left, operator, right):
if operator.value == "+":
return Type.string(left.value + right.value)
if operator.value == "-":
raise RuntimeException(f"Operator {operator.value} is not supported by string types", operator.pos)
raise RuntimeError("This line should never be reached")
@classmethod
def listEvaluator(cls, left, operator, right):
if operator.value == "+":
return Type.list(left.value + right.value)
if operator.value == "-":
raise RuntimeException(f"Operator {operator.value} is not supported by list types", operator.pos)
raise RuntimeError("This line should never be reached")
@classmethod
def mapEvaluator(cls, left, operator, right):
if operator.value == "+":
return Type.map({**left.value, **right.value})
if operator.value == "-":
raise RuntimeException(f"Operator {operator.value} is not supported by map types", operator.pos)
raise RuntimeError("This line should never be reached")

View File

@@ -0,0 +1,34 @@
from smnp.ast.node.identifier import Identifier, FunctionCall
from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
from smnp.runtime.tools.error import updatePos
class UnitEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return
class AccessEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
right = node.right
if type(right) == Identifier:
try:
return left.properties[right.value]
except KeyError:
raise RuntimeException(f"Unknown property '{right.value}' of type '{left.type.name.lower()}'", right.pos)
if type(right) == FunctionCall:
try:
arguments = abstractIterableEvaluator(expressionEvaluator(doAssert=True))(right.arguments, environment)
return environment.invokeMethod(left, right.name.value, arguments)
except RuntimeException as e:
raise updatePos(e, right)

View File

@@ -1,5 +1,6 @@
from smnp.ast.node import type as ast
from smnp.ast.node.none import NoneNode from smnp.ast.node.none import NoneNode
from smnp.ast.node.type import TypeNode, TypeSpecifier from smnp.ast.node.type import TypesList
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.function.signature import varargSignature, signature from smnp.function.signature import varargSignature, signature
from smnp.runtime.tools.error import updatePos from smnp.runtime.tools.error import updatePos
@@ -16,9 +17,9 @@ def argumentsNodeToMethodSignature(node):
argumentsCount = len(node.children) argumentsCount = len(node.children)
for i, child in enumerate(node.children): for i, child in enumerate(node.children):
matchers = { matchers = {
TypeNode: (lambda c: c.type, typeMatcher), ast.Type: (lambda c: c.type, typeMatcher),
NoneNode: (lambda c: c.type, lambda c: allTypes()), NoneNode: (lambda c: c.type, lambda c: allTypes()),
TypeSpecifier: (lambda c: c, multipleTypeMatcher) TypesList: (lambda c: c, multipleTypeMatcher)
} }
evaluatedMatcher = matchers[type(child.type)][1](matchers[type(child.type)][0](child)) evaluatedMatcher = matchers[type(child.type)][1](matchers[type(child.type)][0](child))
if child.vararg: if child.vararg:
@@ -49,10 +50,10 @@ def multipleTypeMatcher(typeNode):
def typeMatcher(typeNode): def typeMatcher(typeNode):
if type(typeNode.specifiers) == NoneNode: if type(typeNode.specifiers) == NoneNode:
return ofType(typeNode.type) return ofType(typeNode.type.value)
elif typeNode.type == Type.LIST and len(typeNode.specifiers) == 1: elif typeNode.type.value == Type.LIST and len(typeNode.specifiers) == 1:
return listSpecifier(typeNode.specifiers[0]) return listSpecifier(typeNode.specifiers[0])
elif typeNode.type == Type.MAP and len(typeNode.specifiers) == 2: elif typeNode.type.value == Type.MAP and len(typeNode.specifiers) == 2:
return mapSpecifier(typeNode.specifiers[0], typeNode.specifiers[1]) return mapSpecifier(typeNode.specifiers[0], typeNode.specifiers[1])
raise RuntimeException("Unknown type", typeNode.pos) # Todo: Improve pointing position raise RuntimeException("Unknown type", typeNode.pos) # Todo: Improve pointing position

View File

@@ -8,7 +8,7 @@ from smnp.token.tokenizers.note import noteTokenizer
from smnp.token.tokenizers.relation import relationOperatorTokenizer 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, mapValue
from smnp.token.type import TokenType from smnp.token.type import TokenType
tokenizers = ( tokenizers = (
@@ -39,7 +39,7 @@ tokenizers = (
defaultTokenizer(TokenType.DOT), defaultTokenizer(TokenType.DOT),
# Types # Types
separated(regexPatternTokenizer(TokenType.INTEGER, r'\d')), mapValue(separated(regexPatternTokenizer(TokenType.INTEGER, r'\d')), int),
stringTokenizer, stringTokenizer,
noteTokenizer, noteTokenizer,
boolTokenizer, boolTokenizer,
@@ -51,6 +51,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.WITH)),
separated(defaultTokenizer(TokenType.ELSE)), separated(defaultTokenizer(TokenType.ELSE)),
separated(defaultTokenizer(TokenType.AND)), separated(defaultTokenizer(TokenType.AND)),
separated(defaultTokenizer(TokenType.NOT)), separated(defaultTokenizer(TokenType.NOT)),

View File

@@ -3,7 +3,7 @@ from smnp.token.type import TokenType
from smnp.type.model import Type from smnp.type.model import Type
typeTokenizer = separated(keywordsTokenizer(TokenType.TYPE, *[type.name.lower() for type in Type])) typeTokenizer = separated(keywordsTokenizer(TokenType.TYPE, *[type.name.lower() for type in Type], mapKeyword=lambda value: Type[value.upper()]))

View File

@@ -14,7 +14,7 @@ def noteTokenizer(input, current, line):
rawValue = '' rawValue = ''
if input[current] == '@': if input[current] == '@':
rawValue += input[current+consumedChars] rawValue += input[current+consumedChars]
consumedChars += 1 consumedChars += 1 # TODO: Check if next item does even exist
if input[current+consumedChars] in ('C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'A', 'a', 'H', 'h', 'B', 'b'): if input[current+consumedChars] in ('C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'A', 'a', 'H', 'h', 'B', 'b'):
rawValue += input[current + consumedChars] rawValue += input[current + consumedChars]
notePitch = input[current+consumedChars] notePitch = input[current+consumedChars]

View File

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

View File

@@ -13,5 +13,5 @@ def stringTokenizer(input, current, line):
char = input[current + consumedChars] char = input[current + consumedChars]
value += char value += char
consumedChars += 1 consumedChars += 1
return (consumedChars, Token(TokenType.STRING, value[1:len(value)-1], (line, current))) return (consumedChars, Token(TokenType.STRING, value[1:len(value)-1], (line, current), value))
return (0, None) return (0, None)

View File

@@ -16,10 +16,10 @@ def regexPatternTokenizer(type, pattern):
return tokenizer return tokenizer
def keywordsTokenizer(type, *keywords): def keywordsTokenizer(type, *keywords, mapKeyword=lambda x: x):
def tokenizer(input, current, line): def tokenizer(input, current, line):
for keyword in keywords: for keyword in keywords:
result = keywordTokenizer(type, keyword)(input, current, line) result = keywordTokenizer(type, keyword, mapKeyword)(input, current, line)
if result[0] > 0: if result[0] > 0:
return result return result
return (0, None) return (0, None)
@@ -27,10 +27,10 @@ def keywordsTokenizer(type, *keywords):
return tokenizer return tokenizer
def keywordTokenizer(type, keyword): def keywordTokenizer(type, keyword, mapKeyword=lambda x: x):
def tokenizer(input, current, line): def tokenizer(input, current, line):
if len(input) >= current+len(keyword) and input[current:current+len(keyword)] == keyword: if len(input) >= current+len(keyword) and input[current:current+len(keyword)] == keyword:
return (len(keyword), Token(type, keyword, (line, current))) return (len(keyword), Token(type, mapKeyword(keyword), (line, current)))
return (0, None) return (0, None)
return tokenizer return tokenizer
@@ -50,3 +50,14 @@ def separated(tokenizer, end=r"\W"):
return (0, None) return (0, None)
return separated return separated
def mapValue(tokenizer, mapper):
def tokenize(input, current, line):
consumedChars, token = tokenizer(input, current, line)
if consumedChars > 0:
return (consumedChars, Token(token.type, mapper(token.value), token.pos))
return (0, None)
return tokenize

View File

@@ -2,7 +2,7 @@ from enum import Enum
class TokenType(Enum): class TokenType(Enum):
RELATION = 'relation' RELATION = '==, !=, >=, <='
DOUBLE_ASTERISK = '**' DOUBLE_ASTERISK = '**'
OPEN_CURLY = '{' OPEN_CURLY = '{'
CLOSE_CURLY = '}' CLOSE_CURLY = '}'
@@ -36,6 +36,7 @@ class TokenType(Enum):
EXTEND = 'extend' EXTEND = 'extend'
IMPORT = 'import' IMPORT = 'import'
FROM = 'from' FROM = 'from'
WITH = 'with'
ELSE = 'else' ELSE = 'else'
IF = 'if' IF = 'if'
AS = 'as' AS = 'as'

View File

@@ -73,6 +73,7 @@ class Type(Enum):
def void(): def void():
return Value(Type.VOID, None) return Value(Type.VOID, None)
def _failStringify(t): def _failStringify(t):
raise RuntimeException(f"Not able to interpret {t.name}'", None) raise RuntimeException(f"Not able to interpret {t.name}'", None)

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