change goal and term expansions, change call/N to use goal expansions

This commit is contained in:
Mark Thom
2019-12-10 21:36:02 -07:00
parent b0fa45cd33
commit 196784bd09
20 changed files with 424 additions and 243 deletions

View File

@@ -134,12 +134,33 @@ impl CodeRepo {
);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::CallN(arity, _, last_call) => {
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
Some(RefOrOwned::Owned(call_clause))
}
&CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::DynamicTransaction(..) => None,
}
}
pub(super)
fn at_end_of_hook(&self, hook: CompileTimeHook, cp: LocalCodePtr) -> bool {
match hook {
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
let len = self.goal_expanders.len();
if len > 0 {
cp == LocalCodePtr::UserGoalExpansion(len - 1)
} else {
true
}
}
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
let len = self.term_expanders.len();
if len > 0 {
cp == LocalCodePtr::UserTermExpansion(len - 1)
} else {
true
}
}
}
}
}

View File

@@ -83,7 +83,7 @@ fn load_module<R: Read>(
// this impromptu definition (namely, its exports) will be filled out later.
let module_decl = ModuleDecl { name: listing_src, exports: vec![] };
let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone());
let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone());
let module_name = module.module_decl.name.clone();
module.is_impromptu_module = true;
@@ -201,6 +201,24 @@ pub fn compile_appendix(
Ok(())
}
fn append_trivial_goal(name: &ClauseName, pred: &mut Predicate)
{
let var = Box::new(Term::Var(Cell::default(), Rc::new(String::from("X"))));
let body = QueryTerm::Clause(
Cell::default(),
ClauseType::from(clause_name!("$at_end_of_expansion"), 0, None),
vec![],
false
);
let rule = Rule {
head: (name.clone(), vec![var.clone(), var], body),
clauses: vec![]
};
pred.0.push(PredicateClause::Rule(rule, 0, 0));
}
impl CodeRepo {
pub fn compile_hook(
&mut self,
@@ -209,13 +227,17 @@ impl CodeRepo {
) -> Result<(), ParserError> {
let key = (hook.name(), hook.arity());
match self.term_dir.get(&key) {
Some(preds) => {
match self.term_dir.get_mut(&key) {
Some(ref mut preds) => {
append_trivial_goal(&key.0, &mut preds.0);
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
let mut code = cg.compile_predicate(&(preds.0).0)?;
compile_appendix(&mut code, &preds.1, false, flags)?;
(preds.0).0.pop();
Ok(match hook {
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
self.term_expanders = code
@@ -225,7 +247,26 @@ impl CodeRepo {
}
})
}
None => Ok(()),
None => Ok(match hook {
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
if self.term_expanders.is_empty() {
let mut preds = Predicate::new();
append_trivial_goal(&key.0, &mut preds);
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
self.term_expanders = cg.compile_predicate(&preds.0)?;
}
}
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
if self.goal_expanders.is_empty() {
let mut preds = Predicate::new();
append_trivial_goal(&key.0, &mut preds);
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
self.goal_expanders = cg.compile_predicate(&preds.0)?;
}
}
})
}
}
}
@@ -649,8 +690,8 @@ impl ListingCompiler {
let idx = code_dir
.entry((name.clone(), arity))
.or_insert(CodeIndex::default());
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
self.localize_self_calls(name, arity, &mut decl_code, p);
code.extend(decl_code.into_iter());
@@ -728,7 +769,7 @@ impl ListingCompiler {
),
);
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
}
fn process_decl(
@@ -749,7 +790,7 @@ impl ListingCompiler {
.code_repo
.compile_hook(hook, flags)
.map_err(SessionError::from);
wam.code_repo.truncate_terms(key, len, queue_len);
result
@@ -940,13 +981,16 @@ fn compile_work_impl(
if let Some(ref mut module) = &mut compiler.module {
// compile the module-level goal and term expansions and store
// their locations to the module's code_dir.
let decls = module.take_local_expansions();
let mut decls = module.take_local_expansions();
if !decls.is_empty() {
append_trivial_goal(&clause_name!("term_expansion"), &mut decls[0].0);
append_trivial_goal(&clause_name!("goal_expansion"), &mut decls[1].0);
results.worker_results.extend(decls.into_iter());
}
}
let module_code = compiler.generate_code(
results.worker_results,
wam,
@@ -999,7 +1043,7 @@ fn compile_work_impl(
wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?;
wam.indices.insert_module(module);
} else {
} else {
add_module_code(wam, module, module_code, indices);
}

View File

@@ -211,6 +211,8 @@ pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
Undefined,
Index(usize),
UserGoalExpansion,
UserTermExpansion
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
@@ -309,7 +311,6 @@ pub enum REPLCodePtr {
#[derive(Clone, PartialEq)]
pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
Local(LocalCodePtr),
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
@@ -320,7 +321,6 @@ impl CodePtr {
pub fn local(&self) -> LocalCodePtr {
match self {
&CodePtr::BuiltInClause(_, ref local)
| &CodePtr::CallN(_, ref local, _)
| &CodePtr::Local(ref local) => local.clone(),
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
&CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
@@ -418,7 +418,7 @@ impl Add<usize> for CodePtr {
| p @ CodePtr::VerifyAttrInterrupt(_)
| p @ CodePtr::DynamicTransaction(..) => p,
CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::CallN(_, local, _) | CodePtr::BuiltInClause(_, local) => {
CodePtr::BuiltInClause(_, local) => {
CodePtr::Local(local + rhs)
}
}
@@ -491,6 +491,19 @@ impl IndexStore {
}
}
pub fn add_term_and_goal_expansion_indices(&mut self) {
self.code_dir.insert((clause_name!("term_expansion"), 2),
CodeIndex(Rc::new(RefCell::new(
(IndexPtr::UserTermExpansion,
clause_name!("user"))
))));
self.code_dir.insert((clause_name!("goal_expansion"), 2),
CodeIndex(Rc::new(RefCell::new(
(IndexPtr::UserGoalExpansion,
clause_name!("user"))
))));
}
#[inline]
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
self.dynamic_code_dir.swap_remove(&(module, name, arity));

View File

@@ -261,6 +261,7 @@ pub struct MachineState {
pub(super) last_call: bool,
pub(crate) heap_locs: HeapVarDict,
pub(crate) flags: MachineFlags,
pub(crate) at_end_of_expansion: LocalCodePtr
}
impl MachineState {
@@ -316,17 +317,17 @@ impl MachineState {
Ok(codes)
}
pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
self.cp.assign_if_local(self.p.clone() + 1);
self.num_of_args = arity;
self.b0 = self.b;
self.p = dir_entry!(p);
self.p = CodePtr::Local(p);
}
pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) {
self.num_of_args = arity;
self.b0 = self.b;
self.p = dir_entry!(p);
self.p = CodePtr::Local(p);
}
pub(super) fn module_lookup(
@@ -342,9 +343,9 @@ impl MachineState {
match idx.0.borrow().0 {
IndexPtr::Index(compiled_tl_index) => {
if last_call {
self.execute_at_index(arity, compiled_tl_index);
self.execute_at_index(arity, dir_entry!(compiled_tl_index));
} else {
self.call_at_index(arity, compiled_tl_index);
self.call_at_index(arity, dir_entry!(compiled_tl_index));
}
return Ok(());
@@ -353,6 +354,24 @@ impl MachineState {
self.fail = true;
return Ok(());
}
IndexPtr::UserTermExpansion => {
if last_call {
self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
} else {
self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
return Ok(());
}
IndexPtr::UserGoalExpansion => {
if last_call {
self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
} else {
self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
return Ok(());
}
_ => {}
}
}
@@ -390,9 +409,9 @@ fn try_in_situ(
) -> CallResult {
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
if last_call {
machine_st.execute_at_index(arity, p);
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p));
} else {
machine_st.call_at_index(arity, p);
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(p));
}
machine_st.p = in_situ_dir_entry!(p);
@@ -619,7 +638,13 @@ pub(crate) trait CallPolicy: Any {
IndexPtr::Undefined =>
return try_in_situ(machine_st, name, arity, indices, false),
IndexPtr::Index(compiled_tl_index) => {
machine_st.call_at_index(arity, compiled_tl_index)
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index))
}
IndexPtr::UserTermExpansion => {
machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
IndexPtr::UserGoalExpansion => {
machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
}
@@ -640,7 +665,13 @@ pub(crate) trait CallPolicy: Any {
IndexPtr::Undefined =>
return try_in_situ(machine_st, name, arity, indices, true),
IndexPtr::Index(compiled_tl_index) => {
machine_st.execute_at_index(arity, compiled_tl_index)
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
}
IndexPtr::UserTermExpansion => {
machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
IndexPtr::UserGoalExpansion => {
machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
}
@@ -834,49 +865,39 @@ pub(crate) trait CallPolicy: Any {
fn call_n(
&mut self,
machine_st: &mut MachineState,
name: ClauseName,
arity: usize,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
) -> CallResult {
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
match ClauseType::from(name.clone(), arity, None) {
ClauseType::CallN => {
machine_st.handle_internal_call_n(arity);
match ClauseType::from(name.clone(), arity, None) {
ClauseType::BuiltIn(built_in) => {
machine_st.setup_built_in_call(built_in.clone());
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
}
ClauseType::Inlined(inlined) => {
machine_st.execute_inlined(&inlined);
if machine_st.fail {
return Ok(());
}
if machine_st.last_call {
machine_st.p = CodePtr::Local(machine_st.cp);
}
}
ClauseType::Op(..) | ClauseType::Named(..) => {
let module = name.owning_module();
machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
self.context_call(machine_st, name, arity, idx, indices)?;
} else {
try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?;
}
ClauseType::BuiltIn(built_in) => {
machine_st.setup_built_in_call(built_in.clone());
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
}
ClauseType::Inlined(inlined) => {
machine_st.execute_inlined(&inlined);
}
ClauseType::Hook(_) | ClauseType::System(_) => {
let name = Addr::Con(Constant::Atom(name, None));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
if machine_st.last_call {
machine_st.p = CodePtr::Local(machine_st.cp);
}
}
ClauseType::Op(..) | ClauseType::Named(..) => {
let module = name.owning_module();
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
self.context_call(machine_st, name, arity, idx, indices)?;
} else {
try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?;
}
}
ClauseType::Hook(_) | ClauseType::System(_) => {
let name = Addr::Con(Constant::Atom(name, None));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
return Err(machine_st
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
}
};
return Err(machine_st
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
}
}
Ok(())
@@ -932,12 +953,13 @@ impl CallPolicy for CWILCallPolicy {
fn call_n(
&mut self,
machine_st: &mut MachineState,
name: ClauseName,
arity: usize,
indices: &mut IndexStore,
parsing_stream: &mut PrologStream,
) -> CallResult {
self.prev_policy
.call_n(machine_st, arity, indices, parsing_stream)?;
.call_n(machine_st, name, arity, indices, parsing_stream)?;
self.increment(machine_st)
}
}
@@ -1093,10 +1115,10 @@ impl SCCCutPolicy {
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
if machine_st.b < b_cutoff {
let (idx, arity) = if machine_st.block < prev_block {
(self.r_c_w_h, 0)
(dir_entry!(self.r_c_w_h), 0)
} else {
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
(self.r_c_wo_h, 1)
(dir_entry!(self.r_c_wo_h), 1)
};
if machine_st.last_call {

View File

@@ -75,6 +75,7 @@ impl MachineState {
last_call: false,
heap_locs: HeapVarDict::new(),
flags: MachineFlags::default(),
at_end_of_expansion: LocalCodePtr::TopLevel(0, 0),
}
}
@@ -105,6 +106,7 @@ impl MachineState {
last_call: false,
heap_locs: HeapVarDict::new(),
flags: MachineFlags::default(),
at_end_of_expansion: LocalCodePtr::TopLevel(0, 0),
}
}
@@ -1988,22 +1990,6 @@ impl MachineState {
}
}
pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
let arity = arity + 1;
let pred = self.registers[1].clone();
for i in 2..arity {
self.registers[i - 1] = self.registers[i].clone();
}
if arity > 1 {
self.registers[arity - 1] = pred;
return;
}
self.fail = true;
}
pub(super) fn set_ball(&mut self) {
self.ball.reset();
@@ -2017,59 +2003,6 @@ impl MachineState {
);
}
pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
let addr = self.store(self.deref(self.registers[arity].clone()));
let (name, narity) = match addr {
Addr::Str(a) => {
let result = self.heap[a].clone();
if let HeapCellValue::NamedStr(narity, name, _) = result {
if narity + arity > 63 {
let representation_error = self.error_form(
MachineError::representation_error(RepFlag::MaxArity),
stub,
);
self.throw_exception(representation_error);
return None;
}
for i in (1 .. arity).rev() {
self.registers[i + narity] = self.registers[i].clone();
}
for i in 1 .. narity + 1 {
self.registers[i] = self.heap[a + i].as_addr(a + i);
}
(name, narity)
} else {
self.fail = true;
return None;
}
}
Addr::Con(Constant::Atom(name, _)) => (name, 0),
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
let instantiation_error =
self.error_form(MachineError::instantiation_error(), stub);
self.throw_exception(instantiation_error);
return None;
}
_ => {
let type_error =
self.error_form(MachineError::type_error(ValidType::Callable, addr), stub);
self.throw_exception(type_error);
return None;
}
};
Some((name, arity + narity - 1))
}
pub(super) fn unwind_stack(&mut self) {
self.b = self.block;
self.truncate_stack();
@@ -3154,10 +3087,6 @@ impl MachineState {
self,
call_policy.call_builtin(self, ct, indices, parsing_stream)
),
&ClauseType::CallN => try_or_fail!(
self,
call_policy.call_n(self, arity, indices, parsing_stream)
),
&ClauseType::Hook(ref hook) => try_or_fail!(self, call_policy.compile_hook(self, hook)),
&ClauseType::Inlined(ref ct) => {
self.execute_inlined(ct);
@@ -3375,6 +3304,7 @@ impl MachineState {
self.mode = MachineMode::Write;
self.registers = vec![Addr::HeapCell(0); MAX_ARITY + 1]; // self.registers[0] is never used.
self.block = 0;
self.at_end_of_expansion = LocalCodePtr::TopLevel(0, 0);
self.ball.reset();
self.heap_locs.clear();

View File

@@ -272,7 +272,8 @@ impl Machine {
self.run_query();
}
pub fn new(prolog_stream: PrologStream) -> Self {
pub fn new(prolog_stream: PrologStream) -> Self
{
let mut wam = Machine {
machine_st: MachineState::new(),
inner_heap: Heap::with_capacity(256 * 256),
@@ -285,6 +286,8 @@ impl Machine {
let atom_tbl = wam.indices.atom_tbl.clone();
wam.indices.add_term_and_goal_expansion_indices();
compile_listing(
&mut wam,
parsing_stream(BUILTINS.as_bytes()),

View File

@@ -108,17 +108,7 @@ impl Module {
let goal_expansions =
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
let mut result = vec![];
if !(term_expansions.0).0.is_empty() {
result.push(term_expansions);
}
if !(goal_expansions.0).0.is_empty() {
result.push(goal_expansions);
}
result
vec![term_expansions, goal_expansions]
}
}

View File

@@ -618,6 +618,9 @@ impl MachineState {
self.p = CodePtr::DynamicTransaction(trans_type, p);
return Ok(());
}
&SystemClauseType::AtEndOfExpansion => {
self.at_end_of_expansion = self.p.local();
}
&SystemClauseType::AtomChars => {
let a1 = self[temp_v!(1)].clone();
@@ -753,13 +756,71 @@ impl MachineState {
let p = self.attr_var_init.project_attrs_loc;
if self.last_call {
self.execute_at_index(2, p);
self.execute_at_index(2, dir_entry!(p));
} else {
self.call_at_index(2, p);
self.call_at_index(2, dir_entry!(p));
}
return Ok(());
}
&SystemClauseType::CallN => {
let (name, arity) = match self.store(self.deref(self[temp_v!(1)].clone())) {
Addr::Str(a) => {
let result = self.heap[a].clone();
if let HeapCellValue::NamedStr(arity, name, _) = result {
if arity > MAX_ARITY {
let stub = MachineError::functor_stub(
clause_name!("$call"),
1,
);
return Err(self.error_form(
MachineError::representation_error(RepFlag::MaxArity),
stub,
));
}
for i in 1 .. arity + 1 {
self.registers[i] = self.heap[a + i].as_addr(a + i);
}
(name, arity)
} else {
unreachable!()
}
}
Addr::Con(Constant::Atom(name, _)) =>
(name, 0),
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
let stub = MachineError::functor_stub(
clause_name!("$call"),
1,
);
return Err(self.error_form(MachineError::instantiation_error(), stub));
}
addr => {
let stub = MachineError::functor_stub(
clause_name!("$call"),
1,
);
return Err(self.error_form(
MachineError::type_error(ValidType::Callable, addr),
stub,
));
}
};
return call_policy.call_n(
self,
name,
arity,
indices,
current_input_stream,
);
}
&SystemClauseType::CharsToNumber => {
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
@@ -991,7 +1052,10 @@ impl MachineState {
match subsection {
Some(dynamic_predicate_info) => {
self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p);
self.execute_at_index(
2,
dir_entry!(dynamic_predicate_info.clauses_subsection_p)
);
return Ok(());
}
None => self.fail = true,
@@ -1626,7 +1690,9 @@ impl MachineState {
self.unify(target, module);
}
_ => self.fail = true,
_ => {
unreachable!()
}
},
_ => self.fail = true,
};
@@ -1925,7 +1991,10 @@ impl MachineState {
match subsection {
Some(dynamic_predicate_info) => {
self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p);
self.execute_at_index(
2,
dir_entry!(dynamic_predicate_info.clauses_subsection_p)
);
return Ok(());
}
_ => unreachable!(),

View File

@@ -343,7 +343,7 @@ impl MachineState {
// this prevents clashes between underscored variable names
// in the same query.
fn reset_with_heap_preservation(&mut self) {
let heap = self.heap.take();
let heap = self.heap.take();
self.reset();
self.heap = heap;
}
@@ -364,6 +364,9 @@ impl MachineState {
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
wam.code_repo.cached_query = code;
self.cp = LocalCodePtr::TopLevel(0, 0);
self.at_end_of_expansion = self.cp;
self.query_stepper(
&mut wam.indices,
&mut wam.policies,
@@ -371,8 +374,8 @@ impl MachineState {
&mut readline::input_stream(),
);
if self.fail {
self.reset_with_heap_preservation();
if self.fail || wam.code_repo.at_end_of_hook(hook, self.at_end_of_expansion) {
self.reset_with_heap_preservation();
None
} else {
let TermWriteResult { var_dict, .. } = term_write_result;
@@ -380,7 +383,7 @@ impl MachineState {
self.heap_locs = var_dict;
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
self.reset_with_heap_preservation();
self.reset_with_heap_preservation();
Some(output.result())
}
}

View File

@@ -693,13 +693,11 @@ impl RelationWorker {
let ct = indices.get_clause_type(name, terms.len(), fixity);
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
}
},
Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(),
ClauseType::CallN,
vec![Box::new(term)],
false,
)),
}
arg @ Term::Var(..) => {
let ct = ClauseType::Named(clause_name!("call"), 1, CodeIndex::default());
Ok(QueryTerm::Clause(Cell::default(), ct, vec![Box::new(arg)], false))
}
_ => Err(ParserError::InadmissibleQueryTerm),
}
}