correct (\+)/1 (#2141)

This commit is contained in:
Mark
2023-10-31 23:58:59 -06:00
parent 8f06ef965a
commit dfd9e43405
6 changed files with 88 additions and 18 deletions

View File

@@ -660,6 +660,8 @@ enum InstructionTemplate {
// cut instruction // cut instruction
#[strum_discriminants(strum(props(Arity = "1", Name = "cut")))] #[strum_discriminants(strum(props(Arity = "1", Name = "cut")))]
Cut(RegType), Cut(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "cut_prev")))]
CutPrev(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))] #[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))]
GetLevel(RegType), GetLevel(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "get_prev_level")))] #[strum_discriminants(strum(props(Arity = "1", Name = "get_prev_level")))]
@@ -1333,6 +1335,10 @@ fn generate_instruction_preface() -> TokenStream {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut"), [str(h, 0)], [rt_stub]) functor!(atom!("cut"), [str(h, 0)], [rt_stub])
} }
&Instruction::CutPrev(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut_prev"), [str(h, 0)], [rt_stub])
}
&Instruction::GetLevel(r) => { &Instruction::GetLevel(r) => {
let rt_stub = reg_type_into_functor(r); let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) functor!(atom!("get_level"), [str(h, 0)], [rt_stub])

View File

@@ -950,10 +950,15 @@ impl<'b> CodeGenerator<'b> {
code.push_back(instr!("proceed")); code.push_back(instr!("proceed"));
} }
} }
&QueryTerm::LocalCut(var_num) => { &QueryTerm::LocalCut { var_num, cut_prev } => {
let code = branch_code_stack.code(code); let code = branch_code_stack.code(code);
let r = self.marker.get_binding(var_num); let r = self.marker.get_binding(var_num);
code.push_back(instr!("cut", r));
code.push_back(if cut_prev {
instr!("cut_prev", r)
} else {
instr!("cut", r)
});
if self.marker.in_tail_position { if self.marker.in_tail_position {
if self.marker.var_data.allocates { if self.marker.var_data.allocates {

View File

@@ -202,7 +202,7 @@ pub enum QueryTerm {
// register, clause type, subterms, clause call policy. // register, clause type, subterms, clause call policy.
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy), Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
Fail, Fail,
LocalCut(usize), // var_num LocalCut { var_num: usize, cut_prev: bool }, // var_num
GlobalCut(usize), // var_num GlobalCut(usize), // var_num
GetCutPoint { var_num: usize, prev_b: bool }, GetCutPoint { var_num: usize, prev_b: bool },
GetLevel(usize), // var_num GetLevel(usize), // var_num

View File

@@ -154,8 +154,11 @@ enum TraversalState {
Fail, Fail,
GetCutPoint { var_num: usize, prev_b: bool }, GetCutPoint { var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool }, Cut { var_num: usize, is_global: bool },
CutPrev(usize),
ResetCallPolicy(CallPolicy), ResetCallPolicy(CallPolicy),
Term(Term), Term(Term),
OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
RemoveBranchNum, // pop the current_branch_num and from the root set. RemoveBranchNum, // pop the current_branch_num and from the root set.
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
@@ -171,6 +174,7 @@ pub struct VariableClassifier {
var_num: usize, var_num: usize,
root_set: RootSet, root_set: RootSet,
global_cut_var_num: Option<usize>, global_cut_var_num: Option<usize>,
global_cut_var_num_override: Option<usize>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@@ -252,6 +256,7 @@ impl VariableClassifier {
root_set: RootSet::new(), root_set: RootSet::new(),
var_num: 0, var_num: 0,
global_cut_var_num: None, global_cut_var_num: None,
global_cut_var_num_override: None,
} }
} }
@@ -517,6 +522,12 @@ impl VariableClassifier {
self.probe_in_situ_var(var_num); self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b }); build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
} }
TraversalState::OverrideGlobalCutVar(var_num) => {
self.global_cut_var_num_override = Some(var_num);
}
TraversalState::ResetGlobalCutVarOverride(old_override) => {
self.global_cut_var_num_override = old_override;
}
TraversalState::Cut { var_num, is_global } => { TraversalState::Cut { var_num, is_global } => {
if self.try_set_chunk_at_inlined_boundary() { if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk(); build_stack.add_chunk();
@@ -527,9 +538,18 @@ impl VariableClassifier {
build_stack.push_chunk_term(if is_global { build_stack.push_chunk_term(if is_global {
QueryTerm::GlobalCut(var_num) QueryTerm::GlobalCut(var_num)
} else { } else {
QueryTerm::LocalCut(var_num) QueryTerm::LocalCut { var_num, cut_prev: false }
}); });
} }
TraversalState::CutPrev(var_num) => {
if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::LocalCut { var_num, cut_prev: true });
}
TraversalState::Fail => { TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail); build_stack.push_chunk_term(QueryTerm::Fail);
} }
@@ -684,14 +704,13 @@ impl VariableClassifier {
))); )));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail); state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::Cut { state_stack.push(TraversalState::CutPrev(self.var_num));
var_num: self.var_num, state_stack.push(TraversalState::ResetGlobalCutVarOverride(self.global_cut_var_num_override));
is_global: false,
});
state_stack.push(TraversalState::Term(not_term)); state_stack.push(TraversalState::Term(not_term));
state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
state_stack.push(TraversalState::GetCutPoint { state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num, var_num: self.var_num,
prev_b: true, prev_b: false,
}); });
self.current_chunk_type = ChunkType::Mid; self.current_chunk_type = ChunkType::Mid;
@@ -786,17 +805,23 @@ impl VariableClassifier {
)); ));
} }
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => { Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
if self.global_cut_var_num.is_none() { let (var_num, is_global) =
self.global_cut_var_num = Some(self.var_num); if let Some(var_num) = self.global_cut_var_num_override {
self.var_num += 1; (var_num, false)
} } else if let Some(var_num) = self.global_cut_var_num {
(var_num, true)
} else {
let var_num = self.var_num;
self.probe_in_situ_var(self.global_cut_var_num.unwrap()); self.global_cut_var_num = Some(var_num);
self.var_num += 1;
state_stack.push(TraversalState::Cut { (var_num, true)
var_num: self.global_cut_var_num.unwrap(), };
is_global: true,
}); self.probe_in_situ_var(var_num);
state_stack.push(TraversalState::Cut { var_num, is_global });
} }
Term::Literal(_, Literal::Atom(name)) => { Term::Literal(_, Literal::Atom(name)) => {
if update_chunk_data(self, name, 0) { if update_chunk_data(self, name, 0) {

View File

@@ -1188,6 +1188,21 @@ impl Machine {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::CutPrev(r) => {
let value = self.machine_st[r];
self.machine_st.cut_prev_body(value);
if self.machine_st.fail {
self.machine_st.backtrack();
continue;
}
if (self.machine_st.run_cleaners_fn)(self) {
continue;
}
self.machine_st.p += 1;
}
&Instruction::Allocate(num_cells) => { &Instruction::Allocate(num_cells) => {
self.machine_st.allocate(num_cells); self.machine_st.allocate(num_cells);
} }

View File

@@ -941,6 +941,25 @@ impl MachineState {
} }
); );
} }
#[inline(always)]
pub(super) fn cut_prev_body(&mut self, value: HeapCellValue) {
let b = self.b;
read_heap_cell!(value,
(HeapCellValueTag::CutPoint, b0) => {
let b0 = b0.get_num() as usize;
let b0 = self.stack.index_or_frame(b0).prelude.b;
if b > b0 {
self.b = b0;
}
}
_ => {
self.fail = true;
}
);
}
} }
#[derive(Debug)] #[derive(Debug)]