pub mod error;
pub mod lint;
pub mod parse_error;
pub mod parser;
pub mod source_map;
pub mod tokenizer;
pub use error::{PrologError, ThrownError, format_term};
pub use parse_error::ParseError;
pub use parser::{CallSite, CgClause, Parser, ProgramDirectives};
pub use source_map::SourceMap;
pub use tokenizer::{Token, TokenKind, Tokenizer};
use std::sync::OnceLock;
pub fn stdlib_predicates() -> &'static [(String, usize)] {
static CACHE: OnceLock<Vec<(String, usize)>> = OnceLock::new();
CACHE.get_or_init(|| {
let mut interner = plg_shared::StringInterner::new();
let Ok((clauses, _)) =
Parser::parse_program_with_directives(plg_shared::STDLIB_PL, &mut interner)
else {
return Vec::new();
};
let seen: std::collections::BTreeSet<(String, usize)> = clauses
.iter()
.filter_map(|c| c.head.functor_arity())
.map(|(id, arity)| (interner.resolve(id).to_string(), arity))
.collect();
seen.into_iter().collect()
})
}
#[cfg(test)]
mod tests {
use super::stdlib_predicates;
#[test]
fn stdlib_predicates_include_list_helpers() {
let preds = stdlib_predicates();
for (name, arity) in [("append", 3), ("member", 2), ("length", 2), ("reverse", 2)] {
assert!(
preds.iter().any(|(n, a)| n == name && *a == arity),
"stdlib missing {name}/{arity}"
);
}
}
#[test]
fn stdlib_predicates_is_cached_and_stable() {
let a = stdlib_predicates() as *const _;
let b = stdlib_predicates() as *const _;
assert_eq!(a, b);
}
}