First version of explain. Creating a new parser was a wrong approach. Need to reimplement
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user