from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor from . import logger from .terms import ( constant_term, define_equal, define_walrus, define_term, binop, compare, cmdarg_term, command_shell, get_var, ternary_term, run_function, cascade_term, ) class Execuitor(NodeVisitor): """ NodeVisitor that visits each node in a parsed command component, and builds a forward-directional ExecTerm from them. """ def lift_child_log(self, node, visited_children): print(f"NODE: {node} WITH {visited_children}") return self.lift_child(node, visited_children) visit_basicterm = lift_child_log def visit_parenthised(self, node, visited_children): print(f"PARENTH: {visited_children}") _, child, _ = visited_children[0] return child def visit_command(self, node, visited_children): print(f"COMMAND: {visited_children}") _, component, _ = visited_children return command_shell(node.text, component) def visit_bool(self, node, boolterm): (value,) = boolterm[0] if value.text.lower() == "true": return constant_term(node.text, True) elif value.text.lower() == "false": return constant_term(node.text, False) else: raise ValueError(f"Unrecognised bool {value.text}") def visit_test(self, node, testterm): (expr,) = testterm term1, op, term2 = expr return compare(node.text, term1, op.text, term2) def generic_visit(self, node, visited_children): """If we don't have a rule for this node return it as raw text, but evaluatable""" print(f"GENERIC: {node} WITH {visited_children}") return visited_children or node def visit_quoted(self, node, visited_children): return constant_term(node.text, node.text[1:-1]) def visit_keyword(self, node, visited_children): return node.text def visit_word(self, node, visited_children): return node.text def visit_equals(self, node, defineterms): var, _, _, _, term = defineterms return define_equal(node.text, str(var), term) def visit_defines(self, node, defineterms): var, _, _, _, term = defineterms return define_walrus(node.text, str(var), term) def visit_definesterm(self, node, defineterms): var, _, _, _, term = defineterms return define_term(node.text, str(var), term) def visit_numeric(self, node, numeric_term): return constant_term(node.text, int(node.text)) def visit_cmdarg(self, node, visited_children): _, argspec = visited_children return cmdarg_term( node.text, int(argspec.text.strip("$*")), argspec.text.endswith("*") ) def visit_ternary(self, node, visited_children): print(f"TERNARY: {visited_children}") cond, _, arg1, _, arg2 = visited_children return ternary_term(node.text, cond, arg1, arg2) def visit_term(self, node, visited_children): print(f"TERM: {visited_children}") _, value, _ = visited_children (child,) = value return child def visit_component(self, node, visited_children): print(f"COMPONENT: {visited_children}") _, value, _ = visited_children (child,) = value return child def visit_var(self, node, varterm): root, remaining = varterm (root,) = root terms = (root, *(attr for _, attr in remaining)) return get_var(node.text, *terms) def visit_function(self, node, visited_children): print(f"FUNCTION: {node.text}, {visited_children}") func, remaining = visited_children args = (term for _, term in remaining) return run_function(node.text, func, *args) def visit_cascade(self, node, visited_children): print(f"CASCADE: {visited_children}") term, remaining = visited_children terms = (term, *(bterm for _, bterm in remaining)) return cascade_term(node.text, *terms) def visit_binop(self, node, binopterm): (expr,) = binopterm term1, remaining = expr op = remaining[0][0] terms = (term1, *(bterm for _, bterm in remaining)) return binop(node.text, op.text, *terms)