handle non-list cases in '', add '' as a built-in (re: issue #31)

This commit is contained in:
Mark Thom
2018-05-01 10:11:27 -06:00
parent 516b67460d
commit 0458a70527
5 changed files with 24 additions and 8 deletions

View File

@@ -537,7 +537,7 @@ impl fmt::Display for Constant {
&Constant::Atom(ref atom) => &Constant::Atom(ref atom) =>
write!(f, "{}", atom), write!(f, "{}", atom),
&Constant::Char(c) => &Constant::Char(c) =>
write!(f, "{}", c as u8), write!(f, "'{}'", c as u8),
&Constant::EmptyList => &Constant::EmptyList =>
write!(f, "[]"), write!(f, "[]"),
&Constant::Number(ref n) => &Constant::Number(ref n) =>

View File

@@ -644,6 +644,7 @@ fn get_builtins() -> Code {
keysort_execute!(), // keysort/2, 484. keysort_execute!(), // keysort/2, 484.
acyclic_term_execute!(), // acyclic_term/1, 485. acyclic_term_execute!(), // acyclic_term/1, 485.
cyclic_term_execute!(), // cyclic_term/1, 486. cyclic_term_execute!(), // cyclic_term/1, 486.
skip_max_list_execute!() // '$skip_max_list', 487.
] ]
} }
@@ -763,6 +764,7 @@ pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
code_dir.insert((clause_name!("keysort"), 2), CodeIndex::from((484, builtin.clone()))); code_dir.insert((clause_name!("keysort"), 2), CodeIndex::from((484, builtin.clone())));
code_dir.insert((clause_name!("acyclic_term"), 1), CodeIndex::from((485, builtin.clone()))); code_dir.insert((clause_name!("acyclic_term"), 1), CodeIndex::from((485, builtin.clone())));
code_dir.insert((clause_name!("cyclic_term"), 1), CodeIndex::from((486, builtin.clone()))); code_dir.insert((clause_name!("cyclic_term"), 1), CodeIndex::from((486, builtin.clone())));
code_dir.insert((clause_name!("$skip_max_list"), 4), CodeIndex::from((487, builtin.clone())));
(code_dir, op_dir) (code_dir, op_dir)
} }
@@ -826,7 +828,8 @@ pub fn builtin_module() -> Module
(clause_name!("sort"), 2), (clause_name!("sort"), 2),
(clause_name!("keysort"), 2), (clause_name!("keysort"), 2),
(clause_name!("acyclic_term"), 1), (clause_name!("acyclic_term"), 1),
(clause_name!("cyclic_term"), 1)]); (clause_name!("cyclic_term"), 1),
(clause_name!("$skip_max_list"), 4)]);
for arity in 0 .. 63 { for arity in 0 .. 63 {
module_decl.exports.push((clause_name!("call"), arity)); module_decl.exports.push((clause_name!("call"), arity));

View File

@@ -1759,7 +1759,8 @@ impl MachineState {
}, },
HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) =>
return CycleSearchResult::PartialOrProperList(steps, hare), return CycleSearchResult::PartialOrProperList(steps, hare),
HeapCellValue::Addr(Addr::HeapCell(hc)) if hc == hare => HeapCellValue::Addr(ref hc @ Addr::HeapCell(_))
if Addr::HeapCell(hare) == self.store(self.deref(hc.clone())) =>
return CycleSearchResult::PartialOrProperList(steps, hare), return CycleSearchResult::PartialOrProperList(steps, hare),
HeapCellValue::Addr(ref sc @ Addr::StackCell(..)) HeapCellValue::Addr(ref sc @ Addr::StackCell(..))
if *sc == self.store(self.deref(sc.clone())) => if *sc == self.store(self.deref(sc.clone())) =>
@@ -1787,7 +1788,7 @@ impl MachineState {
====================================================================================== ======================================================================================
?N, -Xs0 : N = 0, Xs = Xs0. ?N, -Xs0 : N = 0, Xs = Xs0.
?N, +Xs0 : Xs0 is a proper or partial list, Xs0 = [X1, X2, ..., XN | Xs], N = Max, ?N, +Xs0 : Xs0 is a proper or partial list, Xs0 = [X1, X2, ..., XN | Xs], N = Max,
if |Xs0| >= Max, or, Xs = [] and N = |Xs0|. if |Xs0| >= Max, or, Xs = Xs0 and N = |Xs0|.
*/ */
pub(super) fn skip_max_list(&mut self) { pub(super) fn skip_max_list(&mut self) {
let max = self.store(self.deref(self[temp_v!(2)].clone())); let max = self.store(self.deref(self[temp_v!(2)].clone()));
@@ -1814,8 +1815,10 @@ impl MachineState {
self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)), self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)),
CycleSearchResult::PartialOrProperList(n, hc) => CycleSearchResult::PartialOrProperList(n, hc) =>
self.finalize_skip_max_list(n, Addr::HeapCell(hc)), self.finalize_skip_max_list(n, Addr::HeapCell(hc)),
CycleSearchResult::NotList => CycleSearchResult::NotList => {
self.fail = true let xs0 = self[temp_v!(3)].clone();
self.finalize_skip_max_list(0, xs0);
}
} }
} }
} }

View File

@@ -763,6 +763,12 @@ macro_rules! cyclic_term_execute {
) )
} }
macro_rules! skip_max_list_execute {
() => (
Line::Control(ControlInstruction::CallClause(ClauseType::SkipMaxList, 4, 0, true))
)
}
macro_rules! return_from_clause { macro_rules! return_from_clause {
($lco:expr, $machine_st:expr) => {{ ($lco:expr, $machine_st:expr) => {{
if $lco { if $lco {

View File

@@ -1644,4 +1644,8 @@ fn test_queries_on_skip_max_list() {
assert_prolog_failure!(&mut wam, "?- Xs = [a,b|Xs], '$skip_max_list'(3, 5, X, Xs0)."); assert_prolog_failure!(&mut wam, "?- Xs = [a,b|Xs], '$skip_max_list'(3, 5, X, Xs0).");
assert_prolog_failure!(&mut wam, "?- X = [a,b|Y], Y = [c,d|X], '$skip_max_list'(4, 5, X, Xs0)."); assert_prolog_failure!(&mut wam, "?- X = [a,b|Y], Y = [c,d|X], '$skip_max_list'(4, 5, X, Xs0).");
assert_prolog_failure!(&mut wam, "?- X = [a,b|Y], Y = [c,d|X], '$skip_max_list'(4, 3, X, Xs0)."); assert_prolog_failure!(&mut wam, "?- X = [a,b|Y], Y = [c,d|X], '$skip_max_list'(4, 3, X, Xs0).");
// tests on non lists.
assert_prolog_success!(&mut wam, "?- '$skip_max_list'(N, 9, non_list, Xs).",
[["Xs = non_list", "N = 0"]]);
} }