Create expression precendence level

This commit is contained in:
Bartłomiej Pluta
2019-07-10 22:27:44 +02:00
parent 1d573c8c80
commit 4018bcddc7
10 changed files with 390 additions and 346 deletions

View File

@@ -1,11 +1,12 @@
from smnp.ast.node.atom import AtomParser from smnp.ast.node.atom import AtomParser
from smnp.ast.node.list import ListParser from smnp.ast.node.list import ListParser
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 Chain(BinaryOperator): class Chain(Valuable):
pass pass
itemParser = Parser.oneOf( itemParser = Parser.oneOf(
@@ -14,5 +15,5 @@ itemParser = Parser.oneOf(
) )
ChainParser = Parser.leftAssociativeOperatorParser(itemParser, [TokenType.DOT], itemParser, ChainParser = Parser.leftAssociativeOperatorParser(itemParser, [TokenType.DOT], itemParser,
lambda left, op, right: Chain.withValues(left, op, right)) lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right)))

View File

@@ -1,71 +1,78 @@
from smnp.ast.node.asterisk import AsteriskNode from smnp.ast.node.operator import BinaryOperator
from smnp.ast.node.model import Node from smnp.ast.node.term import TermParser
from smnp.ast.node.none import NoneNode from smnp.ast.node.valuable import Valuable
from smnp.ast.node.statement import StatementNode
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
from smnp.token.type import TokenType from smnp.token.type import TokenType
class ExpressionNode(Node): class Expression(Valuable):
def __init__(self, pos): pass
super().__init__(pos, [NoneNode()])
@property
def value(self):
return self[0]
@value.setter ExpressionParser = Parser.leftAssociativeOperatorParser(TermParser, [TokenType.PLUS, TokenType.MINUS], TermParser,
def value(self, v): lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right)))
self[0] = v
#
@classmethod # class ExpressionNode(Node):
def withValue(cls, val, pos): # def __init__(self, pos):
node = cls(pos) # super().__init__(pos, [NoneNode()])
node.value = val #
return node # @property
# def value(self):
@classmethod # return self[0]
def _parse(cls, input): #
return Parser.oneOf( #
cls._asteriskParser(), # @value.setter
cls._expressionParser(), # def value(self, v):
)(input) # self[0] = v
#
@classmethod #
def _asteriskParser(cls): # @classmethod
def createNode(iterator, asterisk, statement): # def withValue(cls, val, pos):
node = AsteriskNode(asterisk.pos) # node = cls(pos)
node.iterator = iterator # node.value = val
node.statement = statement # return node
return node #
# @classmethod
return Parser.allOf( # def _parse(cls, input):
cls._expressionParser(), # return Parser.oneOf(
Parser.terminalParser(TokenType.ASTERISK), # cls._asteriskParser(),
Parser.doAssert(StatementNode.parse, 'statement'), # cls._expressionParser(),
createNode=createNode # )(input)
) #
# @classmethod
@classmethod # def _asteriskParser(cls):
def _expressionParser(cls): # def createNode(iterator, asterisk, statement):
from smnp.ast.node.integer import IntegerLiteralNode # node = AsteriskNode(asterisk.pos)
from smnp.ast.node.string import StringLiteralNode # node.iterator = iterator
from smnp.ast.node.note import NoteLiteralNode # node.statement = statement
from smnp.ast.node.bool import BoolLiteralNode # return node
from smnp.ast.node.identifier import IdentifierNode #
from smnp.ast.node.list import List # return Parser.allOf(
from smnp.ast.node.map import MapNode # cls._expressionParser(),
from smnp.ast.node.type import TypeNode # Parser.terminalParser(TokenType.ASTERISK),
# Parser.doAssert(StatementNode.parse, 'statement'),
return Parser.oneOf( # createNode=createNode
IntegerLiteralNode.parse, # )
StringLiteralNode.parse, #
NoteLiteralNode.parse, # @classmethod
BoolLiteralNode.parse, # def _expressionParser(cls):
IdentifierNode.parse, # from smnp.ast.node.integer import IntegerLiteralNode
MapNode.parse, # from smnp.ast.node.string import StringLiteralNode
List.parse, # from smnp.ast.node.note import NoteLiteralNode
TypeNode.parse, # from smnp.ast.node.bool import BoolLiteralNode
) # from smnp.ast.node.identifier import IdentifierNode
# from smnp.ast.node.list import List
# from smnp.ast.node.map import MapNode
# from smnp.ast.node.type import TypeNode
#
# return Parser.oneOf(
# IntegerLiteralNode.parse,
# StringLiteralNode.parse,
# NoteLiteralNode.parse,
# BoolLiteralNode.parse,
# IdentifierNode.parse,
# MapNode.parse,
# List.parse,
# TypeNode.parse,
# )

View File

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

View File

@@ -1,12 +1,30 @@
from smnp.ast.node.chain import ChainParser from smnp.ast.node.chain import ChainParser
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 Factor(BinaryOperator): class Factor(Valuable):
pass pass
FactorParser = Parser.leftAssociativeOperatorParser(ChainParser, [TokenType.DOUBLE_ASTERISK], ChainParser, powerFactor = Parser.leftAssociativeOperatorParser(ChainParser, [TokenType.DOUBLE_ASTERISK], ChainParser,
lambda left, op, right: Factor.withValues(left, op, right)) lambda left, op, right: Factor.withValue(BinaryOperator.withValues(left, op, right)))
def exprFactor():
from smnp.ast.node.expression import ExpressionParser
return Parser.allOf(
Parser.terminalParser(TokenType.OPEN_PAREN),
ExpressionParser,
Parser.terminalParser(TokenType.CLOSE_PAREN),
createNode=lambda open, expr, close: expr
)
def FactorParser(input):
return Parser.oneOf(
powerFactor,
exprFactor()
)(input)

View File

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

View File

@@ -1,9 +1,5 @@
from smnp.ast.node.expression import ExpressionNode
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.parser import Parser
from smnp.error.syntax import SyntaxException
from smnp.token.type import TokenType
class BinaryOperator(Node): class BinaryOperator(Node):
@@ -43,68 +39,68 @@ class BinaryOperator(Node):
node.right = right node.right = right
return node return node
#
class LeftAssociativeOperatorNode(ExpressionNode): # class LeftAssociativeOperatorNode(ExpressionNode):
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 left(self): # def left(self):
return self[0] # return self[0]
#
@left.setter # @left.setter
def left(self, value): # def left(self, value):
self[0] = value # self[0] = value
#
@property # @property
def operator(self): # def operator(self):
return self[1] # return self[1]
#
@operator.setter # @operator.setter
def operator(self, value): # def operator(self, value):
self[1] = value # self[1] = value
#
@property # @property
def right(self): # def right(self):
return self[2] # return self[2]
#
@right.setter # @right.setter
def right(self, value): # def right(self, value):
self[2] = value # self[2] = value
#
@classmethod # @classmethod
def _parse(cls, input): # def _parse(cls, input):
def createNode(left, operator, right): # def createNode(left, operator, right):
node = LeftAssociativeOperatorNode(right.pos) # node = LeftAssociativeOperatorNode(right.pos)
node.left = left # node.left = left
node.operator = operator # node.operator = operator
node.right = right # node.right = right
return node # return node
#
return Parser.leftAssociativeOperatorParser( # return Parser.leftAssociativeOperatorParser(
cls._lhsParser(), # cls._lhsParser(),
TokenType.DOT, # TokenType.DOT,
cls._rhsParser(), # cls._rhsParser(),
createNode=createNode # createNode=createNode
)(input) # )(input)
#
@classmethod # @classmethod
def _lhsParser(cls): # def _lhsParser(cls):
raise RuntimeError(f"LHS parser is not implemented in {cls.__name__}") # raise RuntimeError(f"LHS parser is not implemented in {cls.__name__}")
#
@staticmethod # @staticmethod
def _rhsParser(): # def _rhsParser():
from smnp.ast.node.identifier import IdentifierNode # from smnp.ast.node.identifier import IdentifierNode
#
return Parser.oneOf( # return Parser.oneOf(
# TODO!!! # # TODO!!!
IdentifierNode._lhsParser(), # IdentifierNode._lhsParser(),
IdentifierNode._functionCallParser(), # IdentifierNode._functionCallParser(),
exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos()) # 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,5 +1,5 @@
from smnp.ast.node.expression import ExpressionParser
from smnp.ast.node.model import Node, ParseResult from smnp.ast.node.model import Node, ParseResult
from smnp.ast.node.term import TermParser
from smnp.ast.parser import Parser from smnp.ast.parser import Parser
@@ -15,7 +15,7 @@ def parse(input):
#TODO -> temporary (to remove): #TODO -> temporary (to remove):
TermParser ExpressionParser
)(input) )(input)
if result.result: if result.result:

View File

@@ -1,11 +1,12 @@
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(BinaryOperator): class Term(Valuable):
pass pass
TermParser = Parser.leftAssociativeOperatorParser(FactorParser, [TokenType.ASTERISK, TokenType.SLASH], FactorParser, TermParser = Parser.leftAssociativeOperatorParser(FactorParser, [TokenType.ASTERISK, TokenType.SLASH], FactorParser,
lambda left, op, right: Term.withValues(left, op, right)) lambda left, op, right: Term.withValue(BinaryOperator.withValues(left, op, right)))

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

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

View File

@@ -1,8 +1,7 @@
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
@@ -18,9 +17,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)
@@ -31,10 +30,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