a2x/
context.rs

1//  SPDX-FileCopyrightText: 2025 Greg Heartsfield <scsibug@imap.cc>
2//  SPDX-License-Identifier: GPL-3.0-or-later
3
4//! Configuration and mutable state needed during an ALFA to XACML
5//! conversion.
6use crate::ast::QualifiedName;
7use crate::ast::advice::AdviceDef;
8use crate::ast::attribute::Attribute;
9use crate::ast::category::{Category, standard_categories};
10use crate::ast::constant::Constant;
11use crate::ast::function::Function;
12use crate::ast::import::Import;
13use crate::ast::infix::Infix;
14use crate::ast::obligation::ObligationDef;
15use crate::ast::policy::{Policy, PolicyId};
16use crate::ast::policycombinator::{
17    PolicyCombinator, protected_policycombinators, standard_policycombinators,
18};
19use crate::ast::policyset::{PolicyEntry, PolicySet};
20use crate::ast::rule::RuleDef;
21use crate::ast::rulecombinator::{
22    RuleCombinator, protected_rulecombinators, standard_rulecombinators,
23};
24use crate::ast::std_attributes::standard_attributes;
25use crate::ast::std_functions::standard_functions;
26use crate::ast::std_infix::standard_infix;
27use crate::ast::typedef::{TypeDef, standard_types};
28use crate::ast::{AsAlfa, SrcLoc};
29use crate::errors::{ParseError, SrcError};
30use log::debug;
31use log::info;
32use std::any::type_name;
33use std::cell::RefCell;
34use std::collections::HashMap;
35use std::collections::HashSet;
36use std::fmt::Debug;
37use std::rc::Rc;
38use std::time::Instant;
39
40pub const SYSTEM_NS: &str = "_A2X";
41pub const PROTECTED_NS: &str = "_A2X.PROTECTED";
42
43// A conversion context.  This contains configuration and mutable
44// state that the conversion needs to keep track of.
45
46/// Configuration for conversions.
47#[derive(Debug, PartialEq)]
48pub struct Config {
49    /// Default namespace prefix.
50    pub base_namespace: Option<String>,
51    /// Use built-in functions, attributes, etc.
52    pub enable_builtins: bool,
53    /// Version string to be included in all policies.
54    pub version: Option<String>,
55}
56
57impl Default for Config {
58    fn default() -> Self {
59        Config {
60            base_namespace: None,
61            enable_builtins: true,
62            version: None,
63        }
64    }
65}
66
67impl Config {
68    /// Retrieve the base (default) namespace prefix, if one exists.
69    #[must_use]
70    pub fn get_base_namespace(&self) -> String {
71        self.base_namespace
72            .as_deref()
73            .unwrap_or("https://sr.ht/~gheartsfield/a2x/alfa/ident/")
74            .to_owned()
75    }
76}
77
78/// Store and provide lookup facilities for an ALFA type.
79///
80/// This embodies the default namespace resolution strategy for all
81/// elements that can be referenced from ALFA.
82#[derive(Debug, PartialEq, Default)]
83pub struct Resolver<T> {
84    /// Mapping of fully-qualified names to specific elements.
85    pub elements: RefCell<HashMap<String, Rc<T>>>,
86}
87
88impl<T> Resolver<T>
89where
90    T: QualifiedName,
91    //    T: Spanned,
92    T: Debug,
93{
94    /// Create a new, empty resolver.
95    #[must_use]
96    pub fn new() -> Self {
97        Resolver {
98            elements: RefCell::new(HashMap::new()),
99        }
100    }
101
102    /// Get the (Rust) type name this resolver contains, without any
103    /// parent module names.
104    ///
105    /// This only exists to support log messages.
106    fn short_type_name() -> &'static str {
107        let full_type_name = type_name::<T>();
108        match full_type_name.rfind("::") {
109            Some(pos) => &full_type_name[pos + 2..],
110            None => full_type_name,
111        }
112    }
113
114    /// List all element names
115    pub fn names(&self) -> Vec<String> {
116        self.elements.borrow().keys().cloned().collect()
117    }
118
119    /// List all elements (sorted by key)
120    pub fn elements(&self) -> Vec<Rc<T>> {
121        let map_ref = self.elements.borrow();
122        let mut items: Vec<_> = map_ref.iter().collect();
123        items.sort_by_key(|(k, _v)| *k);
124        items.into_iter().map(|(_k, v)| v.clone()).collect()
125    }
126
127    /// Element insertion
128    ///
129    /// Note, if the element to be registered does not have a
130    /// qualified name (`fully_qualified_name` is `None`, then this
131    /// still returns `Ok`, but does nothing.  Types that have no
132    /// names cannot be looked up, so this seems sensible.
133    ///
134    /// # Errors
135    ///
136    /// Will return `Err` if the registered element duplicates an
137    /// existing symbol.
138    pub fn register(&self, elem: Rc<T>) -> Result<(), ParseError> {
139        // determine the fully-qualified name:
140        if let Some(n) = elem.fully_qualified_name() {
141            // add to map
142            let mut m = self.elements.borrow_mut();
143            let type_name = Resolver::<T>::short_type_name();
144            debug!("registering {type_name}: {n:?}",);
145            if let std::collections::hash_map::Entry::Vacant(e) = m.entry(n.clone()) {
146                e.insert(elem);
147                Ok(())
148            } else {
149                // for duplicate symbols, we could show the location of both.
150                // for now it is sufficient to show the second.
151
152                // but we need to be able to extract a SrcLoc from the <T>.
153
154                //Err(SrcError::err(
155                //    "Duplicate {type_name} definition: '{n}'",
156                //    &format!("second definiton of same name"),
157                //    elem.span().clone()
158                //))
159
160                Err(ParseError::DuplicateSymbol(format!(
161                    "Duplicate {type_name} definition: '{n}'"
162                )))
163            }
164        } else {
165            debug!("ignoring registration of anonymous element");
166            Ok(())
167        }
168    }
169
170    /// Existence check of fully-qualified name
171    pub fn exists_fq(&self, fq_name: &str) -> bool {
172        // check if elements contains this:
173        let e = self.elements.borrow();
174        e.get(fq_name).is_some()
175    }
176
177    fn match_one_and_only(matches: &[Rc<T>]) -> Result<Option<Rc<T>>, ParseError> {
178        if let Some(m) = matches.first() {
179            if matches.len() == 1 {
180                return Ok(Some(m.clone()));
181            }
182            return Err(ParseError::AmbiguousImport(
183                format!(
184                    "symbol {:?} resolved to multiple locations from import statements",
185                    m.fully_qualified_name()
186                )
187                .to_owned(),
188            ));
189        }
190        Ok(None)
191    }
192
193    /// Start from the source namespace, where the reference was made,
194    /// and see if the match exists in the same location.
195    #[must_use]
196    fn lookup_source_namespace(&self, symbol: &str, source_ns: &[String]) -> Option<Rc<T>> {
197        // A symbol is the thing in the text, and may consist of dotted components (foo.bar).
198        // The source_ns is where it was referenced.
199        // imports are the set of import statements in effect where it was referenced.
200
201        // iterate through the 6 namespace resolution rules. End with
202        // SymbolNotFound if we couldn't locate anything.
203
204        // Rule #1: child match: start from the source_namespace,
205        // append symbol, and check for match. (can only be one)
206        {
207            let mut candidate = source_ns.join(".");
208            candidate.push('.');
209            candidate.push_str(symbol);
210            debug!("R1: candidate is {candidate}");
211            // check if elements contains this:
212            let e = self.elements.borrow();
213            //debug!("did a get: {:?}", x);
214            if let Some(k) = e.get(&candidate) {
215                //debug!("R1: Found key {:?}", k);
216                // does the debug for function fail?
217                return Some(k.clone());
218            }
219            debug!("R1: did not find match");
220        }
221        None
222    }
223
224    // Lookup a symbol starting at the root of the namespace.
225    #[must_use]
226    fn lookup_root(&self, symbol: &str) -> Option<Rc<T>> {
227        // Rule #2: root match: attempt to match the full symbol.
228        debug!("R2: candidate to match is [{symbol}]");
229        let e = self.elements.borrow();
230        if let Some(k) = e.get(symbol) {
231            debug!("R2 Found key");
232            return Some(k.clone());
233        } else {
234            debug!("R2 did not find key [{symbol}]");
235        }
236        None
237    }
238
239    // Lookup a symbol against a list of static imports (the import
240    // itself must list the symbol name), assuming the imports are
241    // referencing children of the current namespace.
242    fn lookup_static_import_child(
243        &self,
244        symbol: &str,
245        source_ns: &[String],
246        static_imports: &Vec<Rc<Import>>,
247    ) -> Result<Option<Rc<T>>, ParseError> {
248        // for static-imports, the candidate must be formed by
249        // matching the last element of the import with the
250        // totality of the symbol.
251
252        // We have to look through all possible imports, and
253        // if there are more than one, we throw an error.
254        let mut matches = vec![];
255        for i in static_imports {
256            // last component must match the candidate symbol in scope
257            if let Some(last_component) = i.components.last() {
258                if last_component == symbol {
259                    debug!("R3: checking static import (relative): {i:?}");
260                    let mut candidate = source_ns.join(".");
261                    candidate.push('.');
262                    let c = i.components.join(".");
263                    candidate.push_str(&c);
264                    debug!("R3: candidate is {candidate}");
265                    // check if elements contains this:
266                    let e = self.elements.borrow();
267                    if let Some(k) = e.get(&candidate) {
268                        debug!("R3: Found value {k:?}");
269                        matches.push(k.clone());
270                    }
271                }
272            }
273        }
274        if let Some(m) = Self::match_one_and_only(&matches)? {
275            Ok(Some(m))
276        } else {
277            Ok(None)
278        }
279    }
280
281    // Lookup a symbol against a list of static imports (the import
282    // itself must list the symbol name), assuming the imports are
283    // from the root namespace (fully qualified).
284    fn lookup_static_import_qualified(
285        &self,
286        symbol: &str,
287        static_imports: &Vec<Rc<Import>>,
288    ) -> Result<Option<Rc<T>>, ParseError> {
289        let mut matches = vec![];
290        for i in static_imports {
291            // last component must match the candidate symbol in scope
292            if let Some(last_component) = i.components.last() {
293                if last_component == symbol {
294                    debug!("R4: checking static import (absolute): {i:?}");
295                    let candidate = i.components.join(".");
296                    debug!("R4: candidate is {candidate}");
297                    // check if elements contains this:
298                    let e = self.elements.borrow();
299                    if let Some(k) = e.get(&candidate) {
300                        debug!("R4: Found key {k:?}");
301                        matches.push(k.clone());
302                    }
303                }
304            }
305        }
306        if let Some(m) = Self::match_one_and_only(&matches)? {
307            Ok(Some(m))
308        } else {
309            Ok(None)
310        }
311    }
312
313    // Lookup a symbol against a list of wildcard imports, assuming
314    // the imports are children of the current namespace.
315    fn lookup_wildcard_child(
316        &self,
317        symbol: &str,
318        source_ns: &[String],
319        wildcard_imports: &Vec<Rc<Import>>,
320    ) -> Result<Option<Rc<T>>, ParseError> {
321        let mut matches = vec![];
322        for i in wildcard_imports {
323            // last component must match the candidate symbol in scope
324            debug!("R5: checking wildcard import: {i:?}");
325            // start with the current location
326            let mut candidate = source_ns.join(".");
327            candidate.push('.');
328            // add the import statement
329            let c = i.components.join(".");
330            candidate.push_str(&c);
331            // finish with the symbol
332            candidate.push('.');
333            candidate.push_str(symbol);
334            debug!("R5: candidate is {candidate}");
335            // check if elements contains this:
336            let e = self.elements.borrow();
337            if let Some(k) = e.get(&candidate) {
338                debug!("R5: Found key {k:?}");
339                matches.push(k.clone());
340            }
341        }
342        if let Some(m) = Self::match_one_and_only(&matches)? {
343            Ok(Some(m))
344        } else {
345            Ok(None)
346        }
347    }
348
349    // Lookup a symbol against a list of wildcard imports, assuming
350    // the imports are fully qualified.
351    fn lookup_wildcard_qualified(
352        &self,
353        symbol: &str,
354        wildcard_imports: &Vec<Rc<Import>>,
355    ) -> Result<Option<Rc<T>>, ParseError> {
356        let mut matches = vec![];
357        for i in wildcard_imports {
358            // last component must match the candidate symbol in scope
359            debug!("R6: checking static import: {i:?}");
360            // add the import statement, since we are assuming it is at the root
361            let mut candidate = i.components.join(".");
362            // finish with the symbol
363            candidate.push('.');
364            candidate.push_str(symbol);
365            debug!("R6: candidate is {candidate}");
366            // check if elements contains this:
367            let e = self.elements.borrow();
368            if let Some(k) = e.get(&candidate) {
369                debug!("R6: Found key {k:?}");
370                matches.push(k.clone());
371            }
372        }
373        if let Some(m) = Self::match_one_and_only(&matches)? {
374            Ok(Some(m))
375        } else {
376            Ok(None)
377        }
378    }
379
380    /// Lookup a symbol located in a namespace using a set of imports.
381    ///
382    /// # Arguments
383    /// * `symbol` - A name exactly as it appears in the ALFA source
384    ///   text, including namespace references.
385    /// * `source_ns` - The namespace where the symbol was located.
386    /// * `src_loc` - Source of the symbol reference for error reporting.
387    /// * `imports` - All import statements in effect where the symbol was used.
388    /// # Returns
389    ///
390    /// Reference-counted element found according to namespace
391    /// resolution rules.
392    ///
393    /// # Errors
394    ///
395    /// Will return `Err` if the lookup could not find an element or
396    /// the result was ambiguous.
397    pub fn lookup(
398        &self,
399        symbol: &str,
400        source_ns: &[String],
401        src_loc: Option<&SrcLoc>,
402        imports: Option<&Vec<Rc<Import>>>,
403    ) -> Result<Rc<T>, ParseError> {
404        info!(
405            "doing a lookup of symbol [{}], in namespace [{}]",
406            symbol,
407            source_ns.join(".")
408        );
409        let type_name = Resolver::<T>::short_type_name();
410        // A symbol is the thing in the text, and may consist of dotted components (foo.bar).
411        // The source_ns is where it was referenced.
412        // imports are the set of import statements in effect where it was referenced.
413
414        // iterate through the 6 namespace resolution rules. End with
415        // SymbolNotFound if we couldn't locate anything.
416
417        // Rule #1: child match: start from the source_namespace,
418        // append symbol, and check for match. (can only be one)
419        if let Some(m) = self.lookup_source_namespace(symbol, source_ns) {
420            return Ok(m);
421        }
422        // Rule #2: root match: attempt to match the full symbol.
423        if let Some(m) = self.lookup_root(symbol) {
424            return Ok(m);
425        }
426        // check for import statements
427        if let Some(imports) = imports {
428            // find static imports
429            let (wildcard_imports, static_imports): (Vec<_>, Vec<_>) =
430                imports.iter().map(Rc::clone).partition(|n| n.is_wildcard);
431            info!(
432                "There are {} wildcard imports and {} static imports",
433                wildcard_imports.len(),
434                static_imports.len()
435            );
436            // Rule #3: static-import child match
437            // for static-imports, the candidate must be formed by
438            // matching the last element of the import with the
439            // totality of the symbol.
440
441            // We have to look through all possible imports, and
442            // if there are more than one, we throw an error.
443            if let Some(m) = self.lookup_static_import_child(symbol, source_ns, &static_imports)? {
444                return Ok(m);
445            }
446            // Rule #4: static-import fully-qualified
447            // for static-imports, the candidate must be formed by
448            // matching the last element of the import with the
449            // totality of the symbol.
450            if let Some(m) = self.lookup_static_import_qualified(symbol, &static_imports)? {
451                return Ok(m);
452            }
453            // Rule #5: wildcard-import child match
454            if let Some(m) = self.lookup_wildcard_child(symbol, source_ns, &wildcard_imports)? {
455                return Ok(m);
456            }
457            // Rule #6: wildcard-import fully-qualified
458            if let Some(m) = self.lookup_wildcard_qualified(symbol, &wildcard_imports)? {
459                return Ok(m);
460            }
461        } else {
462            debug!("There were no import statements, so this {type_name} could not be resolved");
463        }
464        Err(SrcError::err_opt(
465            "All referenced symbols must be defined",
466            &format!("this {type_name} could not be resolved"),
467            src_loc,
468        ))
469    }
470}
471
472/// an attribute definition has a URI to identify it, a category URI, and a type URI.
473#[derive(Debug, Clone, PartialEq, Default)]
474pub struct AttributeDefinition {
475    pub uri: String,
476    pub category: String,
477    pub type_uri: String,
478}
479
480/// an attribute value is an attribute def + a stringified value.
481#[derive(Debug, Clone, PartialEq, Default)]
482pub struct AttributeValue {
483    pub attr: AttributeDefinition,
484    pub value: String,
485}
486
487/// a literal is just a type URI + string value.
488#[derive(Debug, Clone, PartialEq, Default)]
489pub struct TypedLiteral {
490    pub type_uri: String,
491    pub value: String,
492}
493
494// We intend for the context to be passed around as an Rc<Context>, so
495// that it can be shared by as many clients as needed.
496/// All shared state needed when parsing an ALFA source file.
497#[derive(Debug, PartialEq)]
498pub struct Context {
499    /// Static configuration
500    pub config: Config,
501    /// Mapping of namespaces to imports.
502    pub imports: RefCell<HashMap<String, Vec<Rc<Import>>>>,
503    /// Next available ID for a policy
504    next_id: RefCell<usize>,
505    /// Mapping of namespaces to the next available policyset ID.
506    policyset_id_mapping: RefCell<HashMap<String, usize>>,
507    /// Mapping of namespaces to the next available policy ID.
508    policy_id_mapping: RefCell<HashMap<String, usize>>,
509    /// Mapping of namespaces to the next available rule ID.
510    rule_id_mapping: RefCell<HashMap<String, usize>>,
511    /// Mapping of fully qualified namespaces to `PolicySet` instances.
512    policyset_resolver: Resolver<PolicySet>,
513    /// Mapping of fully qualified namespaces to `Policy` instances.
514    policy_resolver: Resolver<Policy>,
515    /// Mapping of fully qualified namespaces to `Rule` instances.
516    rule_resolver: Resolver<RuleDef>,
517    /// Mapping of fully qualified namespaces to `RuleCombinator`
518    /// instances.
519    rulecombinator_resolver: Resolver<RuleCombinator>,
520    /// Mapping of fully qualified namespaces to `PolicyCombinator`
521    /// instances.
522    policycombinator_resolver: Resolver<PolicyCombinator>,
523    /// Mapping of fully qualified namespaces to `Function` instances.
524    function_resolver: Resolver<Function>,
525    /// Mapping of fully qualified namespaces to `Infix` instances.
526    infix_resolver: Resolver<Infix>,
527    /// Mapping of fully qualified namespaces to `Attribute` instances.
528    attribute_resolver: Resolver<Attribute>,
529    /// Mapping of fully qualified namespaces to `TypeDef` instances.
530    typedef_resolver: Resolver<TypeDef>,
531    /// Mapping of fully qualified namespaces to `AdviceDef` instances.
532    advice_resolver: Resolver<AdviceDef>,
533    /// Mapping of fully qualified namespaces to `ObligationDef` instances.
534    obligation_resolver: Resolver<ObligationDef>,
535    /// Mapping of fully qualified namespaces to `Category` instances.
536    category_resolver: Resolver<Category>,
537    /// Set of used URIs for identifying policysets, policies, and rules.
538    used_uris: RefCell<HashSet<String>>,
539}
540
541impl Default for Context {
542    fn default() -> Self {
543        Context::new(Config::default())
544    }
545}
546
547impl Context {
548    /// Create a new context, with standard ALFA elements.
549    ///
550    /// # Panics
551    ///
552    /// Will panic if the standard elements cannot be added.  This
553    /// should never happen, since they are all imported from static
554    /// definitions.
555    #[must_use]
556    pub fn new(cfg: Config) -> Self {
557        let mut c = Context {
558            config: cfg,
559            next_id: RefCell::new(0),
560            policy_id_mapping: RefCell::new(HashMap::new()),
561            policyset_id_mapping: RefCell::new(HashMap::new()),
562            rule_id_mapping: RefCell::new(HashMap::new()),
563            policyset_resolver: Resolver::<PolicySet>::new(),
564            policy_resolver: Resolver::<Policy>::new(),
565            rule_resolver: Resolver::<RuleDef>::new(),
566            rulecombinator_resolver: Resolver::<RuleCombinator>::new(),
567            policycombinator_resolver: Resolver::<PolicyCombinator>::new(),
568            function_resolver: Resolver::<Function>::new(),
569            infix_resolver: Resolver::<Infix>::new(),
570            attribute_resolver: Resolver::<Attribute>::new(),
571            typedef_resolver: Resolver::<TypeDef>::new(),
572            advice_resolver: Resolver::<AdviceDef>::new(),
573            obligation_resolver: Resolver::<ObligationDef>::new(),
574            category_resolver: Resolver::<Category>::new(),
575            imports: RefCell::new(HashMap::new()),
576            used_uris: RefCell::new(HashSet::new()),
577        };
578        if c.config.enable_builtins {
579            let start = Instant::now();
580            c.add_standard_defs()
581                .expect("adding standard imports failed");
582
583            let elapsed = start.elapsed().as_micros();
584            info!("Adding built-in alfa elements took {elapsed} microseconds");
585        }
586        // there are a minimal set of ALFA names we must have
587        // available to help with some translations (particular the
588        // "de-conditioning" of policies and policysets that have
589        // conditions).  We call these "protected" because they are
590        // always required to be present for this program to
591        // successfully transform ALFA to XACML.
592        c.add_protected_defs()
593            .expect("adding protected imports failed");
594        c
595    }
596
597    /// Get a new ID for use in identifying alfa elements such as
598    /// unnamed policies. (Deprecated?)
599    pub fn get_fresh_id(&self) -> usize {
600        self.next_id.replace_with(|&mut old| old + 1)
601    }
602
603    /// Get the next ID for a rule at a namespace.
604    pub fn get_next_rule_id(&self, ns: &str) -> usize {
605        // when a rule is defined within a policy, we need to give it
606        // a name, but if it is anonymous, then we need to generate
607        // something.  This provides a unique incrementing number that
608        // is specific to one namespace.
609
610        // what if there is a situation where there is a namespace,
611        // and two anonymous policies with rules under each?.
612
613        let mut rids = self.rule_id_mapping.borrow_mut();
614        *rids
615            .entry(ns.to_owned())
616            .and_modify(|e| *e += 1)
617            .or_insert(0)
618    }
619
620    /// Get the next ID for a policy at a namespace.
621    pub fn get_next_policy_id(&self, ns: &str) -> usize {
622        let mut pids = self.policy_id_mapping.borrow_mut();
623        *pids
624            .entry(ns.to_owned())
625            .and_modify(|e| *e += 1)
626            .or_insert(0)
627    }
628
629    /// Get the next ID for a policyset at a namespace.
630    pub fn get_next_policyset_id(&self, ns: &str) -> usize {
631        let mut pids = self.policyset_id_mapping.borrow_mut();
632        *pids
633            .entry(ns.to_owned())
634            .and_modify(|e| *e += 1)
635            .or_insert(0)
636    }
637
638    /// Add minimal required XACML3 definitions.
639    ///
640    /// These will not be added to the import path, and must always be
641    /// used fully qualified.  We only expect these to be used
642    /// internally, not be externally provided ALFA policies.
643    fn add_protected_defs(&mut self) -> Result<(), ParseError> {
644        info!("adding protected/internal imports under namespace {PROTECTED_NS}");
645        // currently we only need some policy/rule combinators.
646        for p in protected_policycombinators() {
647            self.register_policy_combinator(Rc::new(p))?;
648        }
649        for p in protected_rulecombinators() {
650            self.register_rule_combinator(Rc::new(p))?;
651        }
652        Ok(())
653    }
654
655    /// Add default XACML3 types, categories, and algorithms if requested
656    fn add_standard_defs(&mut self) -> Result<(), ParseError> {
657        info!("adding standard imports under namespace {SYSTEM_NS}");
658        // add the NS into import
659        self.register_import(
660            &[SYSTEM_NS.to_string()],
661            Rc::new(Import {
662                components: vec![SYSTEM_NS.to_string()],
663                is_wildcard: true,
664                src_loc: None,
665            }),
666        );
667        // we'll add a bunch of stuff with a SYSTEM_NS prefix
668        // types
669        for t in standard_types() {
670            self.register_type(Rc::new(t))?;
671        }
672        // rule combinators
673        for r in standard_rulecombinators() {
674            self.register_rule_combinator(Rc::new(r))?;
675        }
676        // policy combinators
677        for r in standard_policycombinators() {
678            self.register_policy_combinator(Rc::new(r))?;
679        }
680        // categories
681        for c in standard_categories() {
682            self.register_category(Rc::new(c))?;
683        }
684        // infix operators
685        for o in standard_infix() {
686            self.register_infix(Rc::new(o))?;
687        }
688        // attributes
689        for a in standard_attributes() {
690            self.register_attribute(Rc::new(a))?;
691        }
692        // functions
693        for f in standard_functions() {
694            self.register_function(Rc::new(f))?;
695        }
696        Ok(())
697    }
698
699    /// Serialize builtins
700    ///
701    /// # Errors
702    ///
703    /// Returns `Err` if writing to output stream fails.
704    pub fn serialize_builtins<W: std::io::Write>(&self, stream: &mut W) -> std::io::Result<()> {
705        // write out namespace.
706        stream.write_all(format!("namespace {SYSTEM_NS} {{\n").as_bytes())?;
707
708        // Categories
709        stream.write_all("\n  /** Categories **/\n\n".as_bytes())?;
710        for c in self.category_resolver.elements() {
711            stream.write_all(c.to_alfa(1).as_bytes())?;
712        }
713        // Type Definitions
714        stream.write_all("\n  /** Type Definitions **/\n\n".as_bytes())?;
715        for n in self.typedef_resolver.elements() {
716            stream.write_all(n.to_alfa(1).as_bytes())?;
717        }
718        // Attributes
719        stream.write_all("\n  /** Attributes **/\n\n".as_bytes())?;
720        for a in self.attribute_resolver.elements() {
721            stream.write_all(a.to_alfa(1).as_bytes())?;
722            // add more space between attributes
723            stream.write_all("\n".as_bytes())?;
724        }
725        // Policy Combinators
726        stream.write_all("\n  /** Policy Combining Algorithms **/\n\n".as_bytes())?;
727        for p in self.policycombinator_resolver.elements() {
728            stream.write_all(p.to_alfa(1).as_bytes())?;
729        }
730        // Rule Combinators
731        stream.write_all("\n  /** Rule Combining Algorithms **/\n\n".as_bytes())?;
732        for r in self.rulecombinator_resolver.elements() {
733            stream.write_all(r.to_alfa(1).as_bytes())?;
734        }
735        // Functions
736        stream.write_all("\n  /** Functions **/\n\n".as_bytes())?;
737        for f in self.function_resolver.elements() {
738            stream.write_all(f.to_alfa(1).as_bytes())?;
739        }
740        // Operators
741        stream.write_all("\n  /** Infix Operators **/\n\n".as_bytes())?;
742        for i in self.infix_resolver.elements() {
743            stream.write_all(i.to_alfa(1).as_bytes())?;
744            // add more space between operators
745            stream.write_all("\n".as_bytes())?;
746        }
747        // close namespace
748        stream.write_all("}\n".as_bytes())?;
749        Ok(())
750    }
751
752    /// Import Insertion
753    pub fn register_import(&self, ns: &[String], rc: Rc<Import>) {
754        let n = ns.join(".");
755        let mut i = self.imports.borrow_mut();
756        // attempt to get a mutable Vec against ns, add rc.
757        if let Some(v) = i.get_mut(&n) {
758            v.push(rc);
759        } else {
760            let import_vec = vec![rc];
761            i.insert(n.to_string(), import_vec);
762        }
763    }
764
765    /// Get imports for a namespace, combining with system default if configured
766    fn get_imports(&self, source_ns: &[String]) -> Option<Vec<Rc<Import>>> {
767        let imports = self.imports.borrow();
768        // get imports from the default system namespace
769        // TODO, only if configuration is set to use defaults
770        let imports_default = imports.get(SYSTEM_NS);
771        // get imports at the given namespace location
772        if let Some(imports_at_ns) = imports.get(&source_ns.join(".")) {
773            let mut i = vec![];
774            i.extend(imports_at_ns.iter().cloned());
775            if let Some(id) = imports_default {
776                i.extend(id.clone());
777            }
778            Some(i)
779        } else {
780            imports_default.cloned()
781        }
782    }
783
784    /// Register rule combinator
785    ///
786    /// # Errors
787    ///
788    /// Returns `Err` if a rule combinator with the same name exists.
789    pub fn register_rule_combinator(&self, elem: Rc<RuleCombinator>) -> Result<(), ParseError> {
790        self.rulecombinator_resolver.register(elem)
791    }
792
793    /// Lookup rule combinator
794    ///
795    /// # Errors
796    ///
797    /// Returns `Err` if the rule combinator does not exist, or is
798    /// ambiguous.
799    pub fn lookup_rule_combinator(
800        &self,
801        symbol: &str,
802        source_ns: &[String],
803        src_loc: Option<&SrcLoc>,
804    ) -> Result<Rc<RuleCombinator>, ParseError> {
805        info!("looking up rule combinator: symbol: {symbol:?}, source: {source_ns:?}");
806        self.rulecombinator_resolver.lookup(
807            symbol,
808            source_ns,
809            src_loc,
810            self.get_imports(source_ns).as_ref(),
811        )
812    }
813
814    /// Register policy combinator
815    ///
816    /// # Errors
817    ///
818    /// Returns `Err` if a policy combinator with the same name exists.
819    pub fn register_policy_combinator(&self, elem: Rc<PolicyCombinator>) -> Result<(), ParseError> {
820        self.policycombinator_resolver.register(elem)
821    }
822
823    /// Lookup policy combinator
824    ///
825    /// # Errors
826    ///
827    /// Returns `Err` if the policy combinator does not exist, or is
828    /// ambiguous.
829    pub fn lookup_policy_combinator(
830        &self,
831        symbol: &str,
832        source_ns: &[String],
833    ) -> Result<Rc<PolicyCombinator>, ParseError> {
834        self.policycombinator_resolver.lookup(
835            symbol,
836            source_ns,
837            None,
838            self.get_imports(source_ns).as_ref(),
839        )
840    }
841
842    /// Register type
843    ///
844    /// # Errors
845    ///
846    /// Returns `Err` if a type with the same name exists.
847    pub fn register_type(&self, elem: Rc<TypeDef>) -> Result<(), ParseError> {
848        self.typedef_resolver.register(elem)
849    }
850
851    /// Lookup type
852    ///
853    /// # Errors
854    ///
855    /// Returns `Err` if the type does not exist, or is ambiguous.
856    pub fn lookup_type(
857        &self,
858        symbol: &str,
859        source_ns: &[String],
860    ) -> Result<Rc<TypeDef>, ParseError> {
861        self.typedef_resolver.lookup(
862            symbol,
863            source_ns,
864            None,
865            self.get_imports(source_ns).as_ref(),
866        )
867    }
868
869    /// Register function
870    ///
871    /// # Errors
872    ///
873    /// Returns `Err` if a function with the same name exists.
874    pub fn register_function(&self, elem: Rc<Function>) -> Result<(), ParseError> {
875        self.function_resolver.register(elem)
876    }
877
878    /// Lookup function
879    ///
880    /// # Errors
881    ///
882    /// Returns `Err` if the function does not exist, or is ambiguous.
883    pub fn lookup_function(
884        &self,
885        symbol: &str,
886        source_ns: &[String],
887    ) -> Result<Rc<Function>, ParseError> {
888        self.function_resolver.lookup(
889            symbol,
890            source_ns,
891            None,
892            self.get_imports(source_ns).as_ref(),
893        )
894    }
895
896    /// Register infix function
897    ///
898    /// # Errors
899    ///
900    /// Returns `Err` if an infix operator with the same name exists.
901    pub fn register_infix(&self, elem: Rc<Infix>) -> Result<(), ParseError> {
902        self.infix_resolver.register(elem)?;
903        Ok(())
904    }
905
906    /// Register advice
907    ///
908    /// # Errors
909    ///
910    /// Returns `Err` if an advice definition with the same name exists.
911    pub fn register_advice(&self, elem: Rc<AdviceDef>) -> Result<(), ParseError> {
912        self.advice_resolver.register(elem)
913    }
914
915    /// Lookup advice
916    ///
917    /// # Errors
918    ///
919    /// Returns `Err` if the advice does not exist, or is ambiguous.
920    pub fn lookup_advice(
921        &self,
922        symbol: &str,
923        source_ns: &[String],
924    ) -> Result<Rc<AdviceDef>, ParseError> {
925        self.advice_resolver.lookup(
926            symbol,
927            source_ns,
928            None,
929            self.get_imports(source_ns).as_ref(),
930        )
931    }
932
933    /// Register obligation
934    ///
935    /// # Errors
936    ///
937    /// Returns `Err` if an obligation with the same name exists.
938    pub fn register_obligation(&self, elem: Rc<ObligationDef>) -> Result<(), ParseError> {
939        self.obligation_resolver.register(elem)
940    }
941
942    /// Lookup obligation
943    ///
944    /// # Errors
945    ///
946    /// Returns `Err` if the obligation does not exist, or is ambiguous.
947    pub fn lookup_obligation(
948        &self,
949        symbol: &str,
950        source_ns: &[String],
951    ) -> Result<Rc<ObligationDef>, ParseError> {
952        self.obligation_resolver.lookup(
953            symbol,
954            source_ns,
955            None,
956            self.get_imports(source_ns).as_ref(),
957        )
958    }
959
960    /// Lookup infix function
961    ///
962    /// # Errors
963    ///
964    /// Returns `Err` if the infix operator does not exist, or is
965    /// ambiguous.
966    pub fn lookup_infix(
967        &self,
968        symbol: &str,
969        source_ns: &[String],
970    ) -> Result<Rc<Infix>, ParseError> {
971        self.infix_resolver.lookup(
972            symbol,
973            source_ns,
974            None,
975            self.get_imports(source_ns).as_ref(),
976        )
977    }
978
979    /// Lookup infix function by its inverse
980    ///
981    /// # Errors
982    ///
983    /// Returns `Err` if the inverse infix operator does not exist, or
984    /// is ambiguous.
985    pub fn lookup_infix_inverse(
986        &self,
987        symbol: &str,
988        source_ns: &[String],
989    ) -> Result<Rc<Infix>, ParseError> {
990        // this could be more efficient if we let the caller provide
991        // the original infix, skipping the first infix_resolver
992        // lookup.
993
994        // first we lookup the regular symbol.
995        let i = self.infix_resolver.lookup(
996            symbol,
997            source_ns,
998            None,
999            self.get_imports(source_ns).as_ref(),
1000        )?;
1001        // Then, we get the inverse operator symbol, looking up from
1002        // the same location as where the original was defined.
1003        if let Some(inv_sym) = &i.inverse {
1004            Ok(self.infix_resolver.lookup(
1005                inv_sym,
1006                source_ns,
1007                None,
1008                self.get_imports(source_ns).as_ref(),
1009            )?)
1010        } else {
1011            // there was no inverse
1012            Err(ParseError::InverseInfixNotFound)
1013        }
1014    }
1015
1016    /// Register policyset
1017    ///
1018    /// # Errors
1019    ///
1020    /// Returns `Err` if a policyset with the same name exists.
1021    pub fn register_policyset(&self, elem: Rc<PolicySet>) -> Result<(), ParseError> {
1022        // we should ensure that there is no *policy* with the exact
1023        // same name.  this would make the resolution of
1024        // policies/policysets by reference under a policyset be
1025        // ambiguous.
1026
1027        // register all the child policies.
1028        for p in &elem.policies {
1029            info!("need to register {p}");
1030            match &p {
1031                PolicyEntry::Ref(_pe) => { // do nothing
1032                }
1033                PolicyEntry::Policy(pe) => {
1034                    debug!("registering policy from policyset");
1035                    self.register_policy(Rc::new(pe.clone()))?;
1036                }
1037                PolicyEntry::PolicySet(pe) => {
1038                    self.register_policyset(Rc::new(pe.clone()))?;
1039                }
1040            }
1041        }
1042        // TODO: prevent collisions from generated and assigned names.
1043
1044        // if the policyset was assigned an ID, record that for
1045        // collision detection.
1046        if let PolicyId::PolicyNameAndId(_, i) = &elem.id {
1047            let mut uu = self.used_uris.borrow_mut();
1048            let unique = uu.insert(i.clone());
1049            if !unique {
1050                return Err(ParseError::DuplicateURI(i.clone()));
1051            }
1052        };
1053        // check if a policy exists in the same namespace with the
1054        // same name.
1055        if let Some(fq) = &elem.fully_qualified_name() {
1056            if self.policy_resolver.exists_fq(fq) {
1057                return Err(ParseError::DuplicatePolicyEntity(fq.clone()));
1058            }
1059        }
1060
1061        self.policyset_resolver.register(elem)
1062    }
1063
1064    /// Lookup policyset
1065    ///
1066    /// # Errors
1067    ///
1068    /// Returns `Err` if a policyset cannot be located.
1069    pub fn lookup_policyset(
1070        &self,
1071        symbol: &str,
1072        source_ns: &[String],
1073    ) -> Result<Rc<PolicySet>, ParseError> {
1074        let p = self.policyset_resolver.lookup(
1075            symbol,
1076            source_ns,
1077            None,
1078            self.get_imports(source_ns).as_ref(),
1079        );
1080        p
1081    }
1082
1083    /// Register policy
1084    ///
1085    /// # Errors
1086    ///
1087    /// Returns `Err` if a policy with the same name exists.
1088    pub fn register_policy(&self, elem: Rc<Policy>) -> Result<(), ParseError> {
1089        // we should ensure that there is no *policyset* with the exact
1090        // same name.  this would make the resolution of
1091        // policies/policysets by reference under a policyset be
1092        // ambiguous.
1093
1094        // TODO: prevent collisions from generated and assigned names.
1095
1096        // if the policyset was assigned an ID, record that for
1097        // collision detection.
1098        if let PolicyId::PolicyNameAndId(_, i) = &elem.id {
1099            let mut uu = self.used_uris.borrow_mut();
1100            let unique = uu.insert(i.clone());
1101            if !unique {
1102                return Err(ParseError::DuplicateURI(i.clone()));
1103            }
1104        };
1105        // check if a policyset exists in the same namespace with the
1106        // same name.
1107        if let Some(fq) = &elem.fully_qualified_name() {
1108            if self.policyset_resolver.exists_fq(fq) {
1109                return Err(ParseError::DuplicatePolicyEntity(fq.clone()));
1110            }
1111        }
1112        self.policy_resolver.register(elem)
1113    }
1114
1115    /// Lookup policy
1116    ///
1117    /// # Errors
1118    ///
1119    /// Returns `Err` if a policy cannot be located.
1120    pub fn lookup_policy(
1121        &self,
1122        symbol: &str,
1123        source_ns: &[String],
1124    ) -> Result<Rc<Policy>, ParseError> {
1125        info!(
1126            "looking up policy with imports: {:?}",
1127            self.get_imports(source_ns)
1128        );
1129        let p = self.policy_resolver.lookup(
1130            symbol,
1131            source_ns,
1132            None,
1133            self.get_imports(source_ns).as_ref(),
1134        );
1135        info!("finished policy resolver");
1136        p
1137    }
1138
1139    /// Register rule
1140    ///
1141    /// # Errors
1142    ///
1143    /// Returns `Err` if a rule with the same name exists.
1144    pub fn register_rule(&self, elem: Rc<RuleDef>) -> Result<(), ParseError> {
1145        self.rule_resolver.register(elem)
1146    }
1147
1148    /// Lookup rule
1149    ///
1150    /// # Errors
1151    ///
1152    /// Returns `Err` if the rule does not exist, or is ambiguous.
1153    pub fn lookup_rule(
1154        &self,
1155        symbol: &str,
1156        source_ns: &[String],
1157        src_loc: Option<&SrcLoc>,
1158    ) -> Result<Rc<RuleDef>, ParseError> {
1159        self.rule_resolver.lookup(
1160            symbol,
1161            source_ns,
1162            src_loc,
1163            self.get_imports(source_ns).as_ref(),
1164        )
1165    }
1166
1167    /// Register attribute
1168    ///
1169    /// # Errors
1170    ///
1171    /// Returns `Err` if an attribute with the same name exists.
1172    pub fn register_attribute(&self, elem: Rc<Attribute>) -> Result<(), ParseError> {
1173        self.attribute_resolver.register(elem)
1174    }
1175
1176    /// Lookup attribute
1177    ///
1178    /// # Errors
1179    ///
1180    /// Returns `Err` if the attribute does not exist, or is
1181    /// ambiguous.
1182    pub fn lookup_attribute(
1183        &self,
1184        symbol: &str,
1185        source_ns: &[String],
1186    ) -> Result<Rc<Attribute>, ParseError> {
1187        self.attribute_resolver.lookup(
1188            symbol,
1189            source_ns,
1190            None,
1191            self.get_imports(source_ns).as_ref(),
1192        )
1193    }
1194
1195    pub fn lookup_attribute_with_loc(
1196        &self,
1197        symbol: &str,
1198        source_ns: &[String],
1199        src_loc: Option<&SrcLoc>,
1200    ) -> Result<Rc<Attribute>, ParseError> {
1201        self.attribute_resolver.lookup(
1202            symbol,
1203            source_ns,
1204            src_loc,
1205            self.get_imports(source_ns).as_ref(),
1206        )
1207    }
1208
1209    /// Register category
1210    ///
1211    /// # Errors
1212    ///
1213    /// Returns `Err` if a category with the same name exists.
1214    pub fn register_category(&self, elem: Rc<Category>) -> Result<(), ParseError> {
1215        self.category_resolver.register(elem)
1216    }
1217
1218    /// Lookup category
1219    ///
1220    /// # Errors
1221    ///
1222    /// Returns `Err` if the category does not exist, or is
1223    /// ambiguous.
1224    pub fn lookup_category(
1225        &self,
1226        symbol: &str,
1227        source_ns: &[String],
1228    ) -> Result<Rc<Category>, ParseError> {
1229        self.category_resolver.lookup(
1230            symbol,
1231            source_ns,
1232            None,
1233            self.get_imports(source_ns).as_ref(),
1234        )
1235    }
1236
1237    /// Convert a constant to a typed literal.  This may involve
1238    /// looking up a type short name.
1239    ///
1240    /// # Errors
1241    ///
1242    /// Returns `Err` if the lookup of a typedef fails.
1243    pub fn constant_to_typedliteral(
1244        &self,
1245        c: Constant,
1246        source_ns: &[String],
1247    ) -> Result<TypedLiteral, ParseError> {
1248        match c {
1249            Constant::String(s) => Ok(TypedLiteral {
1250                type_uri: crate::ast::typedef::STRING_URI.to_string(),
1251                value: s,
1252            }),
1253            Constant::Integer(s) => Ok(TypedLiteral {
1254                type_uri: crate::ast::typedef::INTEGER_URI.to_string(),
1255                value: s,
1256            }),
1257            Constant::Double(s) => Ok(TypedLiteral {
1258                type_uri: crate::ast::typedef::DOUBLE_URI.to_string(),
1259                value: s,
1260            }),
1261            Constant::Boolean(b) => Ok(TypedLiteral {
1262                type_uri: crate::ast::typedef::BOOLEAN_URI.to_string(),
1263                value: b.to_string(),
1264            }),
1265            Constant::Custom(ct, s) => {
1266                // we can only convert a custom-typed constant when we
1267                // know where it came from, so we can use imports appropriately.
1268                let t = self.typedef_resolver.lookup(
1269                    &ct.name,
1270                    source_ns,
1271                    None,
1272                    self.get_imports(source_ns).as_ref(),
1273                )?;
1274                Ok(TypedLiteral {
1275                    type_uri: t.uri.to_string(),
1276                    value: s,
1277                })
1278            }
1279            Constant::Undefined => Err(ParseError::AstConvertError),
1280        }
1281    }
1282}