From: Mark Thom Date: Fri, 29 Nov 2019 07:44:23 +0000 (-0700) Subject: add copy_term/3 (#232) X-Git-Tag: v0.8.118~36^2~20 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=9c9c484ee4ef858efcdf02b8d58da63ab11f01c5;p=scryer-prolog.git add copy_term/3 (#232) --- diff --git a/README.md b/README.md index d6c31433..63614499 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ The following predicates are built-in to Scryer. * `clause/2` * `compare/3` * `compound/1` -* `copy_term/2` +* `copy_term/{2,3}` * `current_predicate/1` * `current_op/3` * `cyclic_term/1` diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 82bd8cde..a8246405 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -166,6 +166,7 @@ pub enum SystemClauseType { CharCode, CharsToNumber, CodesToNumber, + CopyTermWithoutAttrVars, CheckCutPoint, CopyToLiftedHeap, DeleteAttribute, @@ -264,6 +265,7 @@ impl SystemClauseType { &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), + &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), @@ -392,6 +394,7 @@ impl SystemClauseType { ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), + ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), diff --git a/src/prolog/lib/atts.pl b/src/prolog/lib/atts.pl index 3fc36974..75d01ed5 100644 --- a/src/prolog/lib/atts.pl +++ b/src/prolog/lib/atts.pl @@ -149,3 +149,4 @@ call_residue_vars(Goal, Vars) :- '$get_attr_var_queue_delim'(B), call(Goal), '$get_attr_var_queue_beyond'(B, Vars). + diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 68897044..f900ec8f 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -5,6 +5,12 @@ use std::ops::IndexMut; type Trail = Vec<(Ref, HeapCellValue)>; +#[derive(Clone, Copy)] +pub enum AttrVarPolicy { + DeepCopy, + StripAttributes +} + pub(crate) trait CopierTarget: IndexMut { fn threshold(&self) -> usize; fn push(&mut self, _: HeapCellValue); @@ -13,9 +19,10 @@ pub(crate) trait CopierTarget: IndexMut { fn stack(&mut self) -> &mut AndStack; } -pub(crate) fn copy_term(target: T, addr: Addr) { - let mut copy_term_state = CopyTermState::new(target); - copy_term_state.copy_term_impl(addr); +pub(crate) +fn copy_term(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { + let mut copy_term_state = CopyTermState::new(target, attr_var_policy); + copy_term_state.copy_term_impl(addr); } struct CopyTermState { @@ -23,15 +30,17 @@ struct CopyTermState { scan: usize, old_h: usize, target: T, + attr_var_policy: AttrVarPolicy } impl CopyTermState { - fn new(target: T) -> Self { + fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self { CopyTermState { trail: vec![], scan: 0, old_h: target.threshold(), target, + attr_var_policy } } @@ -41,6 +50,14 @@ impl CopyTermState { &mut self.target[scan] } + fn attr_var_redirect_tag(&self) -> impl Fn(usize) -> Addr { + if let AttrVarPolicy::DeepCopy = self.attr_var_policy { + Addr::AttrVar + } else { + Addr::HeapCell + } + } + fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) { match addr { Addr::HeapCell(h) => { @@ -58,8 +75,10 @@ impl CopyTermState { )); } Addr::AttrVar(h) => { - self.target[threshold] = HeapCellValue::Addr(Addr::AttrVar(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::AttrVar(threshold)); + let redirect_tag = self.attr_var_redirect_tag(); + + self.target[threshold] = HeapCellValue::Addr(redirect_tag(threshold)); + self.target[h] = HeapCellValue::Addr(redirect_tag(threshold)); self.trail .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)))); } @@ -94,10 +113,22 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(ra)); match rd.clone() { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) if h >= self.old_h => { + let redirect_tag = self.attr_var_redirect_tag(); + self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); + } + Addr::HeapCell(h) if h >= self.old_h => { self.target[threshold] = HeapCellValue::Addr(rd) } - ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { + Addr::AttrVar(h) => { + if Addr::AttrVar(h) == rd { + self.reinstantiate_var(Addr::AttrVar(h), threshold); + } else { + let redirect_tag = self.attr_var_redirect_tag(); + self.target[threshold] = HeapCellValue::Addr(redirect_tag(h)); + } + } + ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => { if ra == rd { self.reinstantiate_var(ra, threshold); } else { @@ -121,20 +152,29 @@ impl CopyTermState { let rd = self.target.store(self.target.deref(addr.clone())); match rd.clone() { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { + Addr::AttrVar(h) if h >= self.old_h => { + let redirect_tag = self.attr_var_redirect_tag(); + *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(h)); + self.scan += 1; + } + Addr::HeapCell(h) if h >= self.old_h => { *self.value_at_scan() = HeapCellValue::Addr(rd); self.scan += 1; } Addr::AttrVar(h) if addr == rd => { + let redirect_tag = self.attr_var_redirect_tag(); let threshold = self.target.threshold(); + self.target - .push(HeapCellValue::Addr(Addr::AttrVar(threshold))); + .push(HeapCellValue::Addr(redirect_tag(threshold))); - let list_val = self.target[h + 1].clone(); - self.target.push(list_val); + if let Addr::AttrVar(_) = redirect_tag(threshold) { + let list_val = self.target[h + 1].clone(); + self.target.push(list_val); + } self.reinstantiate_var(addr, threshold); - *self.value_at_scan() = HeapCellValue::Addr(Addr::AttrVar(threshold)); + *self.value_at_scan() = HeapCellValue::Addr(redirect_tag(threshold)); } _ if addr == rd => { let scan = self.scan; @@ -185,8 +225,8 @@ impl CopyTermState { HeapCellValue::Addr(addr) => match addr { Addr::Lis(addr) => self.copy_list(addr), addr @ Addr::AttrVar(_) - | addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) => self.copy_var(addr), + | addr @ Addr::HeapCell(_) + | addr @ Addr::StackCell(..) => self.copy_var(addr), Addr::Str(addr) => self.copy_structure(addr), Addr::Con(_) | Addr::DBRef(_) => self.scan += 1, }, diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index d09b5745..3d451f7d 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -729,7 +729,7 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::CopyTerm => { - machine_st.copy_term(); + machine_st.copy_term(AttrVarPolicy::DeepCopy); return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Eq => { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index f48d77ff..9b913e83 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -2044,6 +2044,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut self.ball.stub), addr, + AttrVarPolicy::DeepCopy, ); } @@ -2941,13 +2942,13 @@ impl MachineState { } } - pub(super) fn copy_term(&mut self) { + pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { let old_h = self.heap.h; let a1 = self[temp_v!(1)].clone(); let a2 = self[temp_v!(2)].clone(); - copy_term(CopyTerm::new(self), a1); + copy_term(CopyTerm::new(self), a1, attr_var_policy); self.unify(Addr::HeapCell(old_h), a2); } diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 7349bdf5..60980406 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -83,3 +83,10 @@ gather_modules_for_attrs(Attrs, Modules, Modules) :- gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :- '$module_of'(Module, Attr), gather_modules_for_attrs(Attrs, Modules, Modules0). + +copy_term(Source, Dest, Goals) :- + term_variables(Source, Vars), + gather_modules(Vars, Modules, _), + call_attribute_goals(Modules, call_query_var_goals, Vars), + '$fetch_attribute_goals'(Goals0), + '$copy_term_without_attr_vars'([Source | Goals0], [Dest | Goals]). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index e168849b..f66ef274 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -353,7 +353,7 @@ impl MachineState { copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); - copy_term(copy_ball_term, copy_target); + copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); threshold + lh_offset + 2 } @@ -867,6 +867,9 @@ impl MachineState { _ => self.fail = true, }; } + &SystemClauseType::CopyTermWithoutAttrVars => { + self.copy_term(AttrVarPolicy::StripAttributes); + } &SystemClauseType::FetchGlobalVar => { let key = self[temp_v!(1)].clone(); @@ -1364,7 +1367,7 @@ impl MachineState { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } &SystemClauseType::FetchAttributeGoals => { - let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + let mut attr_goals = self.attr_var_init.attribute_goals.clone(); attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); self.term_dedup(&mut attr_goals); @@ -1667,6 +1670,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, + AttrVarPolicy::DeepCopy, ); let offset = self[temp_v!(3)].clone(); @@ -1905,7 +1909,7 @@ impl MachineState { ContinueResult::ContinueQuery => ';', ContinueResult::Conclude => '.' }; - + let target = self[temp_v!(1)].clone(); self.unify(Addr::Con(Constant::Char(c)), target); } @@ -1970,6 +1974,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, + AttrVarPolicy::DeepCopy, ); indices.global_variables.insert(key, (ball, None)); @@ -1990,6 +1995,7 @@ impl MachineState { copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value.clone(), + AttrVarPolicy::DeepCopy, ); let stub = ball.copy_and_align(h);