Working on #48 : Fixed first version of ExpressionParser.py
This commit is contained in:
@@ -13,6 +13,9 @@ class ErrorSink:
|
||||
def __init__(self):
|
||||
self.sink = []
|
||||
|
||||
def __repr__(self):
|
||||
return f"Errors({self.sink})"
|
||||
|
||||
def add_error(self, error):
|
||||
self.sink.append(error)
|
||||
|
||||
@@ -258,4 +261,3 @@ class BaseParserInputParser(BaseParser):
|
||||
by_ids.add(c.id)
|
||||
|
||||
return list_a
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind
|
||||
from core.utils import get_text_from_tokens
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.BaseExpressionParser import NameExprNode, VariableNode, BaseExpressionParser
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||
from parsers.RelationalOperatorParser import RelationalOperatorParser
|
||||
from parsers.BaseExpressionParser import ParenthesisNode, NameExprNode, VariableNode, BaseExpressionParser
|
||||
|
||||
|
||||
class ExpressionParser(BaseExpressionParser):
|
||||
@@ -19,59 +16,15 @@ class ExpressionParser(BaseExpressionParser):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(ExpressionParser.NAME, 60, False, yield_eof=False)
|
||||
self.variable_parser = VariableOrNamesParser()
|
||||
self.function_parser = FunctionParser()
|
||||
self.relational_parser = RelationalOperatorParser(expr_parser=self.variable_parser)
|
||||
self.function_parser = FunctionParser(expr_parser=self, tokens_parser=self.variable_parser)
|
||||
self.relational_parser = RelationalOperatorParser(expr_parser=self.function_parser)
|
||||
self.logical_parser = LogicalOperatorParser(expr_parser=self.relational_parser)
|
||||
|
||||
def parse(self, context, parser_input: ParserInput):
|
||||
"""
|
||||
:param context:
|
||||
:param parser_input:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not isinstance(parser_input, ParserInput):
|
||||
return None
|
||||
|
||||
context.log(f"Parsing '{parser_input}' with {self.NAME}Parser", self.name)
|
||||
sheerka = context.sheerka
|
||||
|
||||
if parser_input.is_empty():
|
||||
return context.sheerka.ret(self.name,
|
||||
False,
|
||||
sheerka.new(BuiltinConcepts.IS_EMPTY))
|
||||
|
||||
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=error_sink.sink))
|
||||
|
||||
node = self.parse_input(context, parser_input, error_sink)
|
||||
if isinstance(node, ParenthesisNode):
|
||||
node = node.node
|
||||
|
||||
value = self.get_return_value_body(context.sheerka, parser_input.as_text(), node, node, error_sink.sink)
|
||||
|
||||
ret = context.sheerka.ret(
|
||||
self.name,
|
||||
not error_sink.has_error,
|
||||
value)
|
||||
|
||||
return ret
|
||||
|
||||
def parse_input(self, context, parser_input, error_sink):
|
||||
pos = parser_input.pos
|
||||
for parser in [self.logical_parser,
|
||||
self.relational_parser,
|
||||
self.variable_parser]: # [self.logical_parser, self.relational_parser, self.function_parser]:
|
||||
parser_input.seek(pos) # reset position
|
||||
res = parser.parse_input(context, parser_input, error_sink)
|
||||
if res and not error_sink.has_error:
|
||||
return res
|
||||
return self.logical_parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
return None
|
||||
def parse_tokens_stop_condition(self, token, parser_input):
|
||||
pass
|
||||
|
||||
|
||||
class VariableOrNamesParser(BaseExpressionParser):
|
||||
@@ -80,44 +33,6 @@ class VariableOrNamesParser(BaseExpressionParser):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(VariableOrNamesParser.NAME, 60, False, yield_eof=False)
|
||||
|
||||
def parse(self, context, parser_input: ParserInput):
|
||||
"""
|
||||
:param context:
|
||||
:param parser_input:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not isinstance(parser_input, ParserInput):
|
||||
return None
|
||||
|
||||
context.log(f"Parsing '{parser_input}' with {self.NAME}Parser", self.name)
|
||||
sheerka = context.sheerka
|
||||
|
||||
if parser_input.is_empty():
|
||||
return context.sheerka.ret(self.name,
|
||||
False,
|
||||
sheerka.new(BuiltinConcepts.IS_EMPTY))
|
||||
|
||||
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=error_sink.sink))
|
||||
|
||||
node = self.parse_input(context, parser_input, error_sink)
|
||||
if isinstance(node, ParenthesisNode):
|
||||
node = node.node
|
||||
|
||||
value = self.get_return_value_body(context.sheerka, parser_input.as_text(), node, node, error_sink.sink)
|
||||
|
||||
ret = context.sheerka.ret(
|
||||
self.name,
|
||||
not error_sink.has_error,
|
||||
value)
|
||||
|
||||
return ret
|
||||
|
||||
def parse_input(self, context, parser_input, error_sink):
|
||||
# try to recognize a VariableNode
|
||||
dots_found = []
|
||||
@@ -148,3 +63,6 @@ class VariableOrNamesParser(BaseExpressionParser):
|
||||
parser_input.as_tokens(),
|
||||
parts[0],
|
||||
*parts[1:])
|
||||
|
||||
def parse_tokens_stop_condition(self, token, parser_input):
|
||||
pass
|
||||
|
||||
@@ -40,6 +40,7 @@ class FunctionParser(BaseExpressionParser):
|
||||
self.sep = sep
|
||||
self.longest_concepts_only = longest_concepts_only
|
||||
self.expr_parser = kwargs.get("expr_parser", None)
|
||||
self.tokens_parser = kwargs.get("tokens_parser", None)
|
||||
|
||||
def function_parser_get_return_value_body(self, context, source, source_code_node):
|
||||
if source_code_node.error_when_parsing:
|
||||
@@ -71,7 +72,16 @@ class FunctionParser(BaseExpressionParser):
|
||||
return res[0] if len(res) == 1 else res
|
||||
|
||||
def parse_input(self, context, parser_input, error_sink):
|
||||
return self.parse_function(context, parser_input, error_sink)
|
||||
# when FunctionParser is used by LexerNode or SheerkaExecute, it must fail if no function is found
|
||||
# when it is used by ExpressionParser, it must default to VariableOrNamesParser
|
||||
pos = parser_input.pos
|
||||
res = self.parse_function(context, parser_input, error_sink)
|
||||
if (not res or error_sink.has_error) and self.tokens_parser:
|
||||
parser_input.seek(pos)
|
||||
error_sink.clear()
|
||||
return self.tokens_parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
return res
|
||||
|
||||
def parse_function(self, context, parser_input, error_sink):
|
||||
|
||||
|
||||
@@ -907,19 +907,6 @@ class FN:
|
||||
if isinstance(other, FN):
|
||||
return self.first == other.first and self.last == other.last and self.parameters == other.parameters
|
||||
|
||||
# if isinstance(other, FunctionNode):
|
||||
# if self.first != other.first.value or self.last != other.last.value:
|
||||
# return False
|
||||
# if len(self.parameters) != len(other.parameters):
|
||||
# return False
|
||||
# for self_parameter, other_parameter in zip(self.parameters, other.parameters):
|
||||
# value = other_parameter.value.value if isinstance(self_parameter[0], str) else other_parameter.value
|
||||
# sep = other_parameter.separator.value if other_parameter.separator else None
|
||||
# if self_parameter[0] != value or self_parameter[1] != sep:
|
||||
# return False
|
||||
#
|
||||
# return True
|
||||
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
|
||||
@@ -3,11 +3,11 @@ import pytest
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from parsers.BaseExpressionParser import VariableNode
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.BaseExpressionParser import VariableNode
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import get_expr_node_from_test_node, VAR, EXPR, AND, OR, NOT, GT, GTE, LT, LTE, EQ, \
|
||||
from tests.parsers.parsers_utils import get_expr_node_from_test_node, VAR, EXPR, FN, AND, NOT, OR, GT, GTE, LT, LTE, EQ, \
|
||||
NEQ, IN, NIN
|
||||
|
||||
|
||||
@@ -47,7 +47,10 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
||||
("var1 != var2", NEQ(VAR("var1"), VAR("var2"))),
|
||||
("var1 in (var2.attr2, var3.attr3)", IN(VAR("var1"), EXPR("var2.attr2, var3.attr3"))),
|
||||
("var1 not in (var2.attr2, var3.attr3)", NIN(VAR("var1"), EXPR("var2.attr2, var3.attr3"))),
|
||||
|
||||
("var1 < var2 and var3 > var4", AND(LT(VAR("var1"), VAR("var2")), GT(VAR("var3"), VAR("var4")))),
|
||||
("func1(one, 1 + 2, func2(3))", FN("func1(", (")", 1), [(VAR("one"), ", "),
|
||||
(EXPR("1 + 2"), ", "),
|
||||
FN("func2(", ")", [EXPR("3")])])),
|
||||
])
|
||||
def test_i_can_parse_input(self, expression, expected):
|
||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||
|
||||
Reference in New Issue
Block a user