Working on #48 : Fixed first version of ExpressionParser.py
This commit is contained in:
@@ -13,6 +13,9 @@ class ErrorSink:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sink = []
|
self.sink = []
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Errors({self.sink})"
|
||||||
|
|
||||||
def add_error(self, error):
|
def add_error(self, error):
|
||||||
self.sink.append(error)
|
self.sink.append(error)
|
||||||
|
|
||||||
@@ -258,4 +261,3 @@ class BaseParserInputParser(BaseParser):
|
|||||||
by_ids.add(c.id)
|
by_ids.add(c.id)
|
||||||
|
|
||||||
return list_a
|
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.tokenizer import TokenKind
|
||||||
from core.utils import get_text_from_tokens
|
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.FunctionParser import FunctionParser
|
||||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||||
from parsers.RelationalOperatorParser import RelationalOperatorParser
|
from parsers.RelationalOperatorParser import RelationalOperatorParser
|
||||||
from parsers.BaseExpressionParser import ParenthesisNode, NameExprNode, VariableNode, BaseExpressionParser
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionParser(BaseExpressionParser):
|
class ExpressionParser(BaseExpressionParser):
|
||||||
@@ -19,59 +16,15 @@ class ExpressionParser(BaseExpressionParser):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(ExpressionParser.NAME, 60, False, yield_eof=False)
|
super().__init__(ExpressionParser.NAME, 60, False, yield_eof=False)
|
||||||
self.variable_parser = VariableOrNamesParser()
|
self.variable_parser = VariableOrNamesParser()
|
||||||
self.function_parser = FunctionParser()
|
self.function_parser = FunctionParser(expr_parser=self, tokens_parser=self.variable_parser)
|
||||||
self.relational_parser = RelationalOperatorParser(expr_parser=self.variable_parser)
|
self.relational_parser = RelationalOperatorParser(expr_parser=self.function_parser)
|
||||||
self.logical_parser = LogicalOperatorParser(expr_parser=self.relational_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):
|
def parse_input(self, context, parser_input, error_sink):
|
||||||
pos = parser_input.pos
|
return self.logical_parser.parse_input(context, parser_input, error_sink)
|
||||||
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 None
|
def parse_tokens_stop_condition(self, token, parser_input):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class VariableOrNamesParser(BaseExpressionParser):
|
class VariableOrNamesParser(BaseExpressionParser):
|
||||||
@@ -80,44 +33,6 @@ class VariableOrNamesParser(BaseExpressionParser):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(VariableOrNamesParser.NAME, 60, False, yield_eof=False)
|
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):
|
def parse_input(self, context, parser_input, error_sink):
|
||||||
# try to recognize a VariableNode
|
# try to recognize a VariableNode
|
||||||
dots_found = []
|
dots_found = []
|
||||||
@@ -148,3 +63,6 @@ class VariableOrNamesParser(BaseExpressionParser):
|
|||||||
parser_input.as_tokens(),
|
parser_input.as_tokens(),
|
||||||
parts[0],
|
parts[0],
|
||||||
*parts[1:])
|
*parts[1:])
|
||||||
|
|
||||||
|
def parse_tokens_stop_condition(self, token, parser_input):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class FunctionParser(BaseExpressionParser):
|
|||||||
self.sep = sep
|
self.sep = sep
|
||||||
self.longest_concepts_only = longest_concepts_only
|
self.longest_concepts_only = longest_concepts_only
|
||||||
self.expr_parser = kwargs.get("expr_parser", None)
|
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):
|
def function_parser_get_return_value_body(self, context, source, source_code_node):
|
||||||
if source_code_node.error_when_parsing:
|
if source_code_node.error_when_parsing:
|
||||||
@@ -71,7 +72,16 @@ class FunctionParser(BaseExpressionParser):
|
|||||||
return res[0] if len(res) == 1 else res
|
return res[0] if len(res) == 1 else res
|
||||||
|
|
||||||
def parse_input(self, context, parser_input, error_sink):
|
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):
|
def parse_function(self, context, parser_input, error_sink):
|
||||||
|
|
||||||
|
|||||||
@@ -907,19 +907,6 @@ class FN:
|
|||||||
if isinstance(other, FN):
|
if isinstance(other, FN):
|
||||||
return self.first == other.first and self.last == other.last and self.parameters == other.parameters
|
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
|
return False
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import pytest
|
|||||||
from core.builtin_concepts_ids import BuiltinConcepts
|
from core.builtin_concepts_ids import BuiltinConcepts
|
||||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||||
from core.tokenizer import Tokenizer
|
from core.tokenizer import Tokenizer
|
||||||
|
from parsers.BaseExpressionParser import VariableNode
|
||||||
from parsers.BaseParser import ErrorSink
|
from parsers.BaseParser import ErrorSink
|
||||||
from parsers.ExpressionParser import ExpressionParser
|
from parsers.ExpressionParser import ExpressionParser
|
||||||
from parsers.BaseExpressionParser import VariableNode
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
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
|
NEQ, IN, NIN
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +47,10 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
|||||||
("var1 != var2", NEQ(VAR("var1"), VAR("var2"))),
|
("var1 != var2", NEQ(VAR("var1"), VAR("var2"))),
|
||||||
("var1 in (var2.attr2, var3.attr3)", IN(VAR("var1"), EXPR("var2.attr2, var3.attr3"))),
|
("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 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):
|
def test_i_can_parse_input(self, expression, expected):
|
||||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||||
|
|||||||
Reference in New Issue
Block a user