correct for second argument when (is)/2 is a tail call

This commit is contained in:
Mark Thom
2020-05-16 20:22:17 -06:00
parent a38fb41e37
commit 05d3b97eae
3 changed files with 92 additions and 60 deletions

View File

@@ -122,31 +122,45 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
*self.var_count.get(var).unwrap() *self.var_count.get(var).unwrap()
} }
fn mark_var_in_non_callable(
&mut self,
name: Rc<Var>,
term_loc: GenContext,
vr: &'a Cell<VarReg>,
code: &mut Code,
) -> RegType {
let mut target = Vec::new();
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
code.extend(target.into_iter().map(Line::Query));
}
vr.get().norm()
}
fn mark_non_callable( fn mark_non_callable(
&mut self, &mut self,
name: Rc<Var>, name: Rc<Var>,
arity: usize, arg: usize,
term_loc: GenContext, term_loc: GenContext,
vr: &'a Cell<VarReg>, vr: &'a Cell<VarReg>,
code: &mut Code, code: &mut Code,
) -> RegType { ) -> RegType {
match self.marker.bindings().get(&name) { match self.marker.bindings().get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t), Some(&VarData::Temp(_, t, _)) if t != 0 => {
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p), RegType::Temp(t)
_ => { }
let mut target = Vec::new(); Some(&VarData::Perm(p)) if p != 0 => {
if let GenContext::Last(_) = term_loc {
self.marker.reset_arg(arity); self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
self.marker temp_v!(arg)
.mark_var(name, Level::Shallow, vr, term_loc, &mut target); } else {
RegType::Perm(p)
if !target.is_empty() {
for query_instr in target {
code.push(Line::Query(query_instr));
}
} }
}
vr.get().norm() _ => {
self.mark_var_in_non_callable(name, term_loc, vr, code)
} }
} }
} }
@@ -365,33 +379,42 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
) -> Result<(), ParserError> { ) -> Result<(), ParserError> {
match ct { match ct {
&InlinedClauseType::CompareNumber(cmp, ..) => { &InlinedClauseType::CompareNumber(cmp, ..) => {
if let &Term::Var(ref vr, ref name) = terms[0].as_ref() { self.marker.reset_arg(2);
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
}
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
}
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
let at_1 =
if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 1, term_loc, vr, code)
)
} else {
at_1.unwrap_or(interm!(1))
};
let at_2 =
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
)
} else {
at_2.unwrap_or(interm!(2))
};
code.append(&mut lcode); code.append(&mut lcode);
code.append(&mut rcode); code.append(&mut rcode);
code.push(compare_number_instr!( code.push(compare_number_instr!(cmp, at_1, at_2));
cmp,
at_1.unwrap_or(interm!(1)),
at_2.unwrap_or(interm!(2))
));
} }
&InlinedClauseType::IsAtom(..) => match terms[0].as_ref() { &InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
&Term::Constant(_, Constant::Char(_)) &Term::Constant(_, Constant::Char(_)) |
| &Term::Constant(_, Constant::EmptyList) &Term::Constant(_, Constant::EmptyList) |
| &Term::Constant(_, Constant::Atom(..)) => { &Term::Constant(_, Constant::Atom(..)) => {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_atom!(r)); code.push(is_atom!(r));
} }
@@ -407,6 +430,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_atomic!(r)); code.push(is_atomic!(r));
} }
@@ -416,6 +440,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_compound!(r)); code.push(is_compound!(r));
} }
@@ -428,6 +453,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_rational!(r)); code.push(is_rational!(r));
} }
@@ -440,6 +466,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_float!(r)); code.push(is_float!(r));
} }
@@ -452,6 +479,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(fail!()); code.push(fail!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_nonvar!(r)); code.push(is_nonvar!(r));
} }
@@ -465,6 +493,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_integer!(r)); code.push(is_integer!(r));
} }
@@ -480,6 +509,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code.push(succeed!()); code.push(succeed!());
} }
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
self.marker.reset_arg(1);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_var!(r)); code.push(is_var!(r));
} }
@@ -494,7 +524,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
term: &'a Term, term: &'a Term,
target_int: usize, target_int: usize,
) -> Result<ArithCont, ArithmeticError> { ) -> Result<ArithCont, ArithmeticError> {
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int); let mut evaluator = ArithmeticEvaluator::new(&self.marker.bindings(), target_int);
evaluator.eval(term) evaluator.eval(term)
} }
@@ -508,23 +538,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
code.append(&mut acode); code.append(&mut acode);
Ok(match terms[0].as_ref() { self.marker.reset_arg(2);
match terms[0].as_ref() {
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
let mut target = vec![]; let mut target = vec![];
self.marker.reset_arg(2); self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
self.marker
.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() { if !target.is_empty() {
code.extend(target.into_iter().map(Line::Query)); code.extend(target.into_iter().map(Line::Query));
} }
if use_default_call_policy {
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
} else {
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
}
} }
&Term::Constant(_, ref c @ Constant::Integer(_)) | &Term::Constant(_, ref c @ Constant::Integer(_)) |
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => { &Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
@@ -534,11 +558,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
temp_v!(1) temp_v!(1)
))); )));
if use_default_call_policy { self.marker.advance_arg();
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
} else {
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
}
} }
&Term::Constant(_, ref c @ Constant::Float(_)) => { &Term::Constant(_, ref c @ Constant::Float(_)) => {
code.push(Line::Query(put_constant!( code.push(Line::Query(put_constant!(
@@ -547,11 +567,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
temp_v!(1) temp_v!(1)
))); )));
if use_default_call_policy { self.marker.advance_arg();
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
} else {
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
}
} }
&Term::Constant(_, ref c @ Constant::Rational(_)) => { &Term::Constant(_, ref c @ Constant::Rational(_)) => {
code.push(Line::Query(put_constant!( code.push(Line::Query(put_constant!(
@@ -560,13 +576,27 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
temp_v!(1) temp_v!(1)
))); )));
if use_default_call_policy { self.marker.advance_arg();
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
} else {
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
}
} }
_ => code.push(fail!()), _ => {
code.push(fail!());
return Ok(());
}
}
let at =
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
ArithmeticTerm::Reg(
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
)
} else {
at.unwrap_or(interm!(1))
};
Ok(if use_default_call_policy {
code.push(is_call_by_default!(temp_v!(1), at));
} else {
code.push(is_call!(temp_v!(1), at));
}) })
} }

View File

@@ -293,7 +293,9 @@ impl<'a> Allocator<'a> for DebrayAllocator {
(pr, true) (pr, true)
} }
r => (r, false), r => {
(r, false)
}
}; };
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var); self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);

View File

@@ -4272,7 +4272,7 @@ impl MachineState {
self.fail = non_quoted_token(once(c)); self.fail = non_quoted_token(once(c));
} }
Addr::Con(h) => { Addr::Con(h) => {
if let HeapCellValue::Atom(atom, _) = &self.heap[h] { if let HeapCellValue::Atom(atom, _) = &self.heap[h] {
self.fail = non_quoted_token(atom.as_str().chars()); self.fail = non_quoted_token(atom.as_str().chars());
} }
} }