patch_prolog_frontend/
lib.rs1pub mod error;
8pub mod lint;
9pub mod parse_error;
10pub mod parser;
11pub mod source_map;
12pub mod tokenizer;
13
14pub use error::{PrologError, ThrownError, format_term};
15pub use parse_error::ParseError;
16pub use parser::{CallSite, CgClause, Parser, ProgramDirectives};
17pub use source_map::SourceMap;
18pub use tokenizer::{Token, TokenKind, Tokenizer};
19
20use std::sync::OnceLock;
21
22pub fn stdlib_predicates() -> &'static [(String, usize)] {
29 static CACHE: OnceLock<Vec<(String, usize)>> = OnceLock::new();
30 CACHE.get_or_init(|| {
31 let mut interner = plg_shared::StringInterner::new();
32 let Ok((clauses, _)) =
33 Parser::parse_program_with_directives(plg_shared::STDLIB_PL, &mut interner)
34 else {
35 return Vec::new();
36 };
37 let seen: std::collections::BTreeSet<(String, usize)> = clauses
38 .iter()
39 .filter_map(|c| c.head.functor_arity())
40 .map(|(id, arity)| (interner.resolve(id).to_string(), arity))
41 .collect();
42 seen.into_iter().collect()
43 })
44}
45
46#[cfg(test)]
47mod tests {
48 use super::stdlib_predicates;
49
50 #[test]
51 fn stdlib_predicates_include_list_helpers() {
52 let preds = stdlib_predicates();
53 for (name, arity) in [("append", 3), ("member", 2), ("length", 2), ("reverse", 2)] {
54 assert!(
55 preds.iter().any(|(n, a)| n == name && *a == arity),
56 "stdlib missing {name}/{arity}"
57 );
58 }
59 }
60
61 #[test]
62 fn stdlib_predicates_is_cached_and_stable() {
63 let a = stdlib_predicates() as *const _;
65 let b = stdlib_predicates() as *const _;
66 assert_eq!(a, b);
67 }
68}