From 66f6399b8ada356fb93ff8b58517ce7a5488ecc0 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 29 Aug 2023 16:42:23 -0600 Subject: [PATCH] refine is/2 compilation so errors are thrown when expected without needlessly allocating (#1974, #1984) --- build/instructions_template.rs | 14 +++++++++---- src/codegen.rs | 31 +++++++++++++++++++++-------- src/machine/dispatch.rs | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 3ac76eff8..52fcd8b7a 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -99,6 +99,8 @@ enum BuiltInClauseType { Ground, #[strum_discriminants(strum(props(Arity = "2", Name = "is")))] Is(RegType, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_number")))] + GetNumber(ArithmeticTerm), #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))] KeySort, #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))] @@ -1553,7 +1555,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallFunctor | &Instruction::CallGround | &Instruction::CallKeySort | - &Instruction::CallSort => { + &Instruction::CallSort | + &Instruction::CallGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("call"), [atom(name), fixnum(arity)]) } @@ -1578,7 +1581,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteGround | &Instruction::ExecuteIs(..) | &Instruction::ExecuteKeySort | - &Instruction::ExecuteSort => { + &Instruction::ExecuteSort | + &Instruction::ExecuteGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("execute"), [atom(name), fixnum(arity)]) } @@ -1603,7 +1607,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::DefaultCallGround | &Instruction::DefaultCallIs(..) | &Instruction::DefaultCallKeySort | - &Instruction::DefaultCallSort => { + &Instruction::DefaultCallSort | + &Instruction::DefaultCallGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("call_default"), [atom(name), fixnum(arity)]) } @@ -1628,7 +1633,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::DefaultExecuteGround | &Instruction::DefaultExecuteIs(..) | &Instruction::DefaultExecuteKeySort | - &Instruction::DefaultExecuteSort => { + &Instruction::DefaultExecuteSort | + &Instruction::DefaultExecuteGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) } diff --git a/src/codegen.rs b/src/codegen.rs index f69fa2a9b..4902a6184 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -814,19 +814,34 @@ impl<'b> CodeGenerator<'b> { ); self.marker.mark_safe_var_unconditionally(var_num); + compile_expr!(self, &terms[1], term_loc, code) } else { - if self.marker.in_tail_position { - if self.marker.var_data.allocates { - code.push_back(instr!("deallocate")); + if let Term::Var(ref vr, ref var) = &terms[1] { + let var_num = var.to_var_num().unwrap(); + + // if var is an anonymous variable, insert + // is/2 call so that an instantiation error is + // thrown when the predicate is run. + if self.marker.var_data.records[var_num].num_occurrences > 1 { + self.marker.mark_var::( + var_num, + Level::Shallow, + vr, + term_loc, + code, + ); + + self.marker.mark_safe_var_unconditionally(var_num); + + let at = ArithmeticTerm::Reg(vr.get().norm()); + self.add_call(code, instr!("$get_number", at), call_policy); + + return Ok(()); } - - code.push_back(instr!("proceed")); } - return Ok(()); + compile_expr!(self, &terms[1], term_loc, code) } - - compile_expr!(self, &terms[1], term_loc, code) } &Term::Literal(_, c @ Literal::Integer(_) | c @ Literal::Float(_) | diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 8752522d8..dc55ed861 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -1497,6 +1497,14 @@ impl Machine { try_or_throw!(self.machine_st, self.machine_st.is(r, at)); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + Instruction::DefaultCallGetNumber(at) => { + try_or_throw!(self.machine_st, self.machine_st.get_number(at)); + step_or_fail!(self, self.machine_st.p += 1); + } + Instruction::DefaultExecuteGetNumber(at) => { + try_or_throw!(self.machine_st, self.machine_st.get_number(at)); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallAcyclicTerm => { let addr = self.machine_st.registers[1]; @@ -1965,6 +1973,34 @@ impl Machine { self.machine_st.p = self.machine_st.cp; } } + Instruction::CallGetNumber(at) => { + try_or_throw!(self.machine_st, self.machine_st.get_number(at)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + Instruction::ExecuteGetNumber(at) => { + try_or_throw!(self.machine_st, self.machine_st.get_number(at)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } &Instruction::CallN(arity) => { let pred = self.machine_st.registers[1];