First version of explain. Creating a new parser was a wrong approach. Need to reimplement

This commit is contained in:
2020-04-17 17:24:57 +02:00
parent 6c7c529016
commit d6ea2461a8
43 changed files with 2679 additions and 162 deletions
+150
View File
@@ -0,0 +1,150 @@
from typing import List
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
from core.sheerka.ExecutionContext import ExecutionContext
from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.ExplainParser import ExplanationNode, FilterNode, RecurseDefNode, FormatLNode, FormatDNode
from parsers.ExpressionParser import ExpressionVisitor, IsaNode
from printer.SheerkaPrinter import FormatInstructions
class ExplainExpressionVisitor(ExpressionVisitor):
def __init__(self):
self.instructions = FormatInstructions()
def visit_RecurseDefNode(self, expr_node):
self.instructions.set_recurse("children", expr_node.depth)
def visit_FormatLNode(self, expr_node):
self.instructions.set_format_l(ExecutionContext, expr_node.template)
class ExplainEvaluator(OneReturnValueEvaluator):
NAME = "Explain"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 60)
def get_event_digest(self, sheerka, explanation_node):
if explanation_node.digest and sheerka.sdp.has_result(explanation_node.digest):
return explanation_node.digest
if not explanation_node.digest and not explanation_node.record_digest:
# use a previous digest if found
digest = sheerka.load(self.name, "digest")
if digest is not None:
return digest
start = 0
while True:
events = list(sheerka.sdp.load_events(5, start))
if not events:
break
for event in events:
if not sheerka.sdp.has_result(event.get_digest()):
continue
if not explanation_node.digest or explanation_node.digest == event.message:
# maybe explanation_node.digest is not a real digest, but the command we want to explain
return event.get_digest()
start += 5
if start > 20:
break
return None
@staticmethod
def get_execution_result(sheerka, digest):
if digest is None:
# the test is done here to ease the unit tests
return None
return [sheerka.sdp.load_result(digest)]
@staticmethod
def get_instructions(filter_node: FilterNode):
instructions = FormatInstructions()
for directive in filter_node.directives:
if isinstance(directive, RecurseDefNode):
instructions.set_recurse("children", directive.depth)
elif isinstance(directive, FormatLNode):
instructions.set_format_l(ExecutionContext, directive.template)
elif isinstance(directive, FormatDNode):
instructions.add_format_d(IsaNode(ExecutionContext), directive.properties)
return instructions
@staticmethod
def get_title(filter_node):
return "<title>"
def matches(self, context, return_value):
if not return_value.status:
return False
if not isinstance(return_value.value, ParserResultConcept):
return False
return isinstance(return_value.value.value, ExplanationNode)
def eval(self, context, return_value):
sheerka = context.sheerka
explanation_node = return_value.value.value
if explanation_node.digest and not explanation_node.record_digest:
context.log(f"Deleting recorded digest")
sheerka.delete(context, self.name, "digest")
digest = self.get_event_digest(sheerka, explanation_node)
executions_results = self.get_execution_result(sheerka, digest)
if executions_results is None and not digest:
res = sheerka.new(BuiltinConcepts.ERROR, body=f"No result found (digest={explanation_node.digest})")
else:
# record the digest if needed
if explanation_node.record_digest:
context.log(f"Recording digest '{digest}'")
sheerka.record(context, self.name, "digest", digest)
filter_nodes = explanation_node.expr.filters
global_instructions = self.get_instructions(filter_nodes[0])
if len(filter_nodes) == 1:
filtered = [[]]
self.filter(executions_results, filter_nodes, filtered)
res = sheerka.new(BuiltinConcepts.EXPLANATION,
digest=digest,
command=explanation_node.command,
title="<all>",
body=filtered[0],
instructions=global_instructions)
else:
res = []
filter_nodes = filter_nodes[1:] # remove the first filter_node (which always returns True)
filtered = []
for i in range(len(filter_nodes)):
filtered.append([])
self.filter(executions_results, filter_nodes, filtered)
for i, filter_node in enumerate(filter_nodes):
instructions = global_instructions.clone().merge(self.get_instructions(filter_node))
res.append(sheerka.new(BuiltinConcepts.EXPLANATION,
digest=digest,
command=explanation_node.command,
title=self.get_title(filter_node),
body=filtered[i],
instructions=instructions))
if len(res) == 1:
res = res[0]
return sheerka.ret(self.name, not sheerka.isinstance(res, BuiltinConcepts.ERROR), res, parents=[return_value])
def filter(self, executions_results, filter_nodes: List[FilterNode], res):
for execution_result in executions_results:
for i, filter_node in enumerate(filter_nodes):
if filter_node.expr.eval(execution_result):
res[i].append(execution_result)
if execution_result.children:
self.filter(execution_result.children, filter_nodes, res)
return res