Working on #48 : Added BaseExprParser and BaseNodeParser.py

This commit is contained in:
2021-03-10 21:09:09 +01:00
parent 998ea160be
commit 9c4991923e
18 changed files with 317 additions and 198 deletions
+84 -66
View File
@@ -7,7 +7,7 @@ from core.sheerka.services.sheerka_service import FailedToCompileError
from core.tokenizer import TokenKind, Tokenizer, Keywords
from core.utils import get_text_from_tokens
from parsers.BaseNodeParser import UnrecognizedTokensNode
from parsers.BaseParser import BaseParser, UnexpectedTokenParsingError, UnexpectedEofParsingError, BaseExprParser
from parsers.BaseParser import UnexpectedTokenParsingError, UnexpectedEofParsingError, BaseExprParser, ErrorSink
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from parsers.expressions import ParenthesisNode, OrNode, AndNode, NotNode, LeftPartNotFoundError, \
ParenthesisMismatchError, NameExprNode, ExprNode, VariableNode, ComparisonNode
@@ -76,6 +76,7 @@ class LogicalOperatorParser(BaseExprParser):
self.and_tokens = list(Tokenizer(" and ", yield_eof=False))
self.and_not_tokens = list(Tokenizer(" and not ", yield_eof=False))
self.not_tokens = list(Tokenizer("not ", yield_eof=False))
self.expr_parser = kwargs.get("expr_parser", None)
@staticmethod
def clean_parenthesis_nodes(nodes):
@@ -101,144 +102,161 @@ class LogicalOperatorParser(BaseExprParser):
False,
sheerka.new(BuiltinConcepts.IS_EMPTY))
if not self.reset_parser(context, parser_input):
return self.sheerka.ret(
error_sink = ErrorSink()
if not self.reset_parser_input(parser_input, error_sink):
return context.sheerka.ret(
self.name,
False,
context.sheerka.new(BuiltinConcepts.ERROR, body=self.error_sink))
context.sheerka.new(BuiltinConcepts.ERROR, body=error_sink.sink))
self.parser_input.next_token()
tree = self.parse_input()
token = self.parser_input.token
tree = self.parse_input(context, parser_input, error_sink)
token = parser_input.token
if token and token.type != TokenKind.EOF:
self.add_error(UnexpectedTokenParsingError(f"Unexpected token '{token}'", token, []))
error_sink.add_error(UnexpectedTokenParsingError(f"Unexpected token '{token}'", token, []))
if isinstance(tree, ParenthesisNode):
tree = tree.node
value = self.get_return_value_body(context.sheerka, self.parser_input.as_text(), tree, tree)
ret = self.sheerka.ret(
self.name,
not self.has_error,
value)
value = self.get_return_value_body(context.sheerka,
parser_input.as_text(),
tree,
tree,
error_sink.sink)
ret = context.sheerka.ret(self.name,
not error_sink.has_error,
value)
return ret
def parse_input(self):
return self.parse_or()
def parse_input(self, context, parser_input, error_sink):
return self.parse_or(context, parser_input, error_sink)
def parse_or(self):
start = self.parser_input.pos
expr = self.parse_and()
token = self.parser_input.token
def parse_or(self, context, parser_input, error_sink):
start = parser_input.pos
expr = self.parse_and(context, parser_input, error_sink)
token = parser_input.token
if token.type != TokenKind.IDENTIFIER or token.value != "or":
return expr
parts = [expr]
while token.type == TokenKind.IDENTIFIER and token.value == "or":
self.parser_input.next_token()
expr = self.parse_and()
parser_input.next_token()
expr = self.parse_and(context, parser_input, error_sink)
if expr is None:
self.add_error(UnexpectedEofParsingError("When parsing 'or'"))
end = self.parser_input.pos
error_sink.add_error(UnexpectedEofParsingError("When parsing 'or'"))
end = parser_input.pos
self.clean_parenthesis_nodes(parts)
return OrNode(start, end, self.parser_input.tokens[start: end + 1], *parts)
return OrNode(start, end, parser_input.tokens[start: end + 1], *parts)
parts.append(expr)
token = self.parser_input.token
token = parser_input.token
end = parts[-1].end
self.clean_parenthesis_nodes(parts)
return OrNode(start, end, self.parser_input.tokens[start: end + 1], *parts)
return OrNode(start, end, parser_input.tokens[start: end + 1], *parts)
def parse_and(self):
start = self.parser_input.pos
expr = self.parse_not()
token = self.parser_input.token
def parse_and(self, context, parser_input, error_sink):
start = parser_input.pos
expr = self.parse_not(context, parser_input, error_sink)
token = parser_input.token
if token.type != TokenKind.IDENTIFIER or token.value != "and":
return expr
parts = [expr]
while token.type == TokenKind.IDENTIFIER and token.value == "and":
self.parser_input.next_token()
expr = self.parse_not()
parser_input.next_token()
expr = self.parse_not(context, parser_input, error_sink)
if expr is None:
self.add_error(UnexpectedEofParsingError("When parsing 'and'"))
end = self.parser_input.pos
error_sink.add_error(UnexpectedEofParsingError("When parsing 'and'"))
end = parser_input.pos
self.clean_parenthesis_nodes(parts)
return AndNode(start, end, self.parser_input.tokens[start: end + 1], *parts)
return AndNode(start, end, parser_input.tokens[start: end + 1], *parts)
parts.append(expr)
token = self.parser_input.token
token = parser_input.token
end = parts[-1].end
self.clean_parenthesis_nodes(parts)
return AndNode(start, end, self.parser_input.tokens[start: end + 1], *parts)
return AndNode(start, end, parser_input.tokens[start: end + 1], *parts)
def parse_not(self):
token = self.parser_input.token
start = self.parser_input.pos
def parse_not(self, context, parser_input, error_sink):
token = parser_input.token
start = parser_input.pos
if token.type == TokenKind.IDENTIFIER and token.value == "not":
self.parser_input.next_token()
parsed = self.parse_not()
parser_input.next_token()
parsed = self.parse_not(context, parser_input, error_sink)
node = parsed.node if isinstance(parsed, ParenthesisNode) else parsed
return NotNode(start,
parsed.end,
self.parser_input.tokens[start: parsed.end + 1],
parser_input.tokens[start: parsed.end + 1],
node)
else:
return self.parse_names()
return self.parse_names(context, parser_input, error_sink)
def parse_names(self):
def parse_names(self, context, parser_input, error_sink):
def stop():
return token.type == TokenKind.EOF or \
paren_count == 0 and token.type == TokenKind.RPAR or \
token.type == TokenKind.IDENTIFIER and token.value in ("and", "or", "not")
token = self.parser_input.token
token = parser_input.token
if token.type == TokenKind.EOF:
return None
if token.type == TokenKind.LPAR:
start = self.parser_input.pos
self.parser_input.next_token()
expr = self.parse_or()
token = self.parser_input.token
start = parser_input.pos
parser_input.next_token()
expr = self.parse_or(context, parser_input, error_sink)
token = parser_input.token
if token.type != TokenKind.RPAR:
self.error_sink.append(
error_sink.add_error(
UnexpectedTokenParsingError(f"Unexpected token '{token}'", token, [TokenKind.RPAR]))
return expr
end = self.parser_input.pos
self.parser_input.next_token()
end = parser_input.pos
parser_input.next_token()
return ParenthesisNode(start, end, None, expr)
buffer = []
paren_count = 0
last_paren = None
start = self.parser_input.pos
start = parser_input.pos
end = parser_input.pos
last_is_whitespace = False
while not stop():
buffer.append(token)
last_is_whitespace = token.type == TokenKind.WHITESPACE
end += 1
if token.type == TokenKind.LPAR:
last_paren = token
paren_count += 1
if token.type == TokenKind.RPAR:
paren_count -= 1
self.parser_input.next_token(False)
token = self.parser_input.token
parser_input.next_token(False)
token = parser_input.token
if len(buffer) == 0:
if last_is_whitespace:
end -= 1
if start == end:
if token.type != TokenKind.RPAR:
self.error_sink.append(LeftPartNotFoundError())
error_sink.add_error(LeftPartNotFoundError())
return None
if paren_count != 0:
self.error_sink.append(ParenthesisMismatchError(last_paren))
error_sink.add_error(ParenthesisMismatchError(last_paren))
return None
if buffer[-1].type == TokenKind.WHITESPACE:
buffer.pop()
end = start + len(buffer) - 1
return NameExprNode(start, end, buffer)
if self.expr_parser:
new_parsing_input = ParserInput(
None,
tokens=parser_input.tokens,
length=parser_input.length,
start=start,
end=end - 1,
yield_oef=False).reset()
new_parsing_input.next_token()
return self.expr_parser.parse_input(context, new_parsing_input, error_sink)
else:
return NameExprNode(start, end - 1, parser_input.tokens[start:end])
def compile_conjunctions(self, context, conjunctions, who):
"""