xsd_parser/interpreter/
mod.rs

1//! The `interpreter` module contains the schema [`Interpreter`] and all related types.
2
3mod error;
4mod helper;
5mod schema;
6mod state;
7mod variant_builder;
8
9use std::fmt::Debug;
10
11use crate::config::Namespace;
12use crate::schema::xs::ProcessContentsType;
13use crate::schema::{MaxOccurs, Schemas};
14use crate::types::{
15    AnyAttributeInfo, AnyInfo, BuildInInfo, ComplexInfo, GroupInfo, Ident, Module, Name,
16    ReferenceInfo, Type, TypeVariant, Types,
17};
18
19pub use error::Error;
20use tracing::instrument;
21
22use self::helper::{NameExtend, NameFallback, NameUnwrap};
23use self::schema::SchemaInterpreter;
24use self::state::{Node, State};
25use self::variant_builder::VariantBuilder;
26
27/// The [`Interpreter`] is used to interpret the XML schema information.
28///
29/// This structure can be used to interpret the [`Schemas`] structure that was
30/// loaded by the [`Parser`](crate::parser::Parser) to generate the more common
31/// [`Types`] definition out of it.
32#[must_use]
33#[derive(Debug)]
34pub struct Interpreter<'a> {
35    state: State<'a>,
36    schemas: &'a Schemas,
37}
38
39impl<'a> Interpreter<'a> {
40    /// Create a new [`Interpreter`] instance using the passed `schemas` reference.
41    pub fn new(schemas: &'a Schemas) -> Self {
42        let state = State::default();
43
44        Self { state, schemas }
45    }
46
47    /// Add a custom [`Type`] information for the passed `ident`ifier to the
48    /// resulting [`Types`] structure.
49    ///
50    /// # Errors
51    ///
52    /// Returns a suitable [`Error`] if the operation was not successful.
53    #[instrument(err, level = "trace", skip(self))]
54    pub fn with_type<I, T>(mut self, ident: I, type_: T) -> Result<Self, Error>
55    where
56        I: Into<Ident> + Debug,
57        T: Into<Type> + Debug,
58    {
59        self.state.add_type(ident, type_, true)?;
60
61        Ok(self)
62    }
63
64    /// Add a simple type definition to the resulting [`Types`] structure using
65    /// `ident` as identifier for the new type and `type_` as target type for the
66    /// type definition.
67    ///
68    /// # Errors
69    ///
70    /// Returns a suitable [`Error`] if the operation was not successful.
71    #[instrument(err, level = "trace", skip(self))]
72    pub fn with_typedef<I, T>(mut self, ident: I, type_: T) -> Result<Self, Error>
73    where
74        I: Into<Ident> + Debug,
75        T: Into<Ident> + Debug,
76    {
77        self.state
78            .add_type(ident, ReferenceInfo::new(type_), true)?;
79
80        Ok(self)
81    }
82
83    /// Adds the default build-in types to the resulting [`Types`] structure.
84    ///
85    /// # Errors
86    ///
87    /// Returns a suitable [`Error`] if the operation was not successful.
88    #[instrument(err, level = "trace", skip(self))]
89    pub fn with_buildin_types(mut self) -> Result<Self, Error> {
90        macro_rules! add {
91            ($ident:ident, $type:ident) => {
92                self.state
93                    .add_type(Ident::$ident, BuildInInfo::$type, true)?;
94            };
95        }
96
97        add!(U8, U8);
98        add!(U16, U16);
99        add!(U32, U32);
100        add!(U64, U64);
101        add!(U128, U128);
102        add!(USIZE, Usize);
103
104        add!(I8, I8);
105        add!(I16, I16);
106        add!(I32, I32);
107        add!(I64, I64);
108        add!(I128, I128);
109        add!(ISIZE, Isize);
110
111        add!(F32, F32);
112        add!(F64, F64);
113
114        add!(BOOL, Bool);
115        add!(STRING, String);
116
117        Ok(self)
118    }
119
120    /// Adds the type definitions for common XML types (like `xs:string` or `xs:int`)
121    /// to the resulting [`Types`] structure.
122    ///
123    /// # Errors
124    ///
125    /// Returns a suitable [`Error`] if the operation was not successful.
126    #[instrument(err, level = "trace", skip(self))]
127    pub fn with_default_typedefs(mut self) -> Result<Self, Error> {
128        let xs = self
129            .schemas
130            .resolve_namespace(&Some(Namespace::XS))
131            .ok_or_else(|| Error::UnknownNamespace(Namespace::XS.clone()))?;
132
133        macro_rules! add {
134            ($ns:ident, $src:expr, $dst:ident) => {
135                self.state.add_type(
136                    Ident::type_($src).with_ns(Some($ns)),
137                    ReferenceInfo::new(Ident::$dst),
138                    true,
139                )?;
140            };
141        }
142        macro_rules! add_list {
143            ($ns:ident, $src:expr, $dst:ident) => {
144                self.state.add_type(
145                    Ident::type_($src).with_ns(Some($ns)),
146                    ReferenceInfo::new(Ident::$dst)
147                        .min_occurs(0)
148                        .max_occurs(MaxOccurs::Unbounded),
149                    true,
150                )?;
151            };
152        }
153
154        /* Primitive Types */
155
156        add!(xs, "string", STRING);
157        add!(xs, "boolean", BOOL);
158        add!(xs, "decimal", F64);
159        add!(xs, "float", F32);
160        add!(xs, "double", F64);
161
162        /* time related types */
163
164        add!(xs, "duration", STRING);
165        add!(xs, "dateTime", STRING);
166        add!(xs, "time", STRING);
167        add!(xs, "date", STRING);
168        add!(xs, "gYearMonth", STRING);
169        add!(xs, "gYear", STRING);
170        add!(xs, "gMonthDay", STRING);
171        add!(xs, "gMonth", STRING);
172        add!(xs, "gDay", STRING);
173
174        /* Date related types */
175
176        add!(xs, "hexBinary", STRING);
177        add!(xs, "base64Binary", STRING);
178
179        /* URL related types */
180
181        add!(xs, "anyURI", STRING);
182        add!(xs, "QName", STRING);
183        add!(xs, "NOTATION", STRING);
184
185        /* Numeric Types */
186
187        add!(xs, "long", I64);
188        add!(xs, "int", I32);
189        add!(xs, "integer", I32);
190        add!(xs, "short", I16);
191        add!(xs, "byte", I8);
192        add!(xs, "negativeInteger", ISIZE);
193        add!(xs, "nonPositiveInteger", ISIZE);
194
195        add!(xs, "unsignedLong", U64);
196        add!(xs, "unsignedInt", U32);
197        add!(xs, "unsignedShort", U16);
198        add!(xs, "unsignedByte", U8);
199        add!(xs, "positiveInteger", USIZE);
200        add!(xs, "nonNegativeInteger", USIZE);
201
202        /* String Types */
203
204        add!(xs, "normalizedString", STRING);
205        add!(xs, "token", STRING);
206        add!(xs, "language", STRING);
207        add!(xs, "NMTOKEN", STRING);
208        add!(xs, "Name", STRING);
209        add!(xs, "NCName", STRING);
210        add!(xs, "ID", STRING);
211        add!(xs, "IDREF", STRING);
212
213        add_list!(xs, "NMTOKENS", STRING);
214        add_list!(xs, "IDREFS", STRING);
215        add_list!(xs, "ENTITY", STRING);
216        add_list!(xs, "ENTITIES", STRING);
217
218        Ok(self)
219    }
220
221    /// Adds a default type definition for `xs:anyType`.
222    ///
223    /// # Errors
224    ///
225    /// Returns a suitable [`Error`] if the operation was not successful.
226    #[instrument(err, level = "trace", skip(self))]
227    pub fn with_xs_any_type(mut self) -> Result<Self, Error> {
228        let xs = self
229            .schemas
230            .resolve_namespace(&Some(Namespace::XS))
231            .ok_or_else(|| Error::UnknownNamespace(Namespace::XS.clone()))?;
232
233        // content type
234        let content_name = self.state.make_unnamed();
235        let content_ident = Ident::new(content_name).with_ns(Some(xs));
236        let content_variant = TypeVariant::Sequence(GroupInfo {
237            any: Some(AnyInfo {
238                min_occurs: Some(0),
239                max_occurs: Some(MaxOccurs::Unbounded),
240                process_contents: Some(ProcessContentsType::Lax),
241                ..Default::default()
242            }),
243            ..Default::default()
244        });
245        let content_type = Type::new(content_variant);
246        self.state
247            .add_type(content_ident.clone(), content_type, true)?;
248
249        // xs:anyType
250        let ident = Ident::type_("anyType").with_ns(Some(xs));
251        let variant = TypeVariant::ComplexType(ComplexInfo {
252            content: Some(content_ident),
253            min_occurs: 1,
254            max_occurs: MaxOccurs::Bounded(1),
255            any_attribute: Some(AnyAttributeInfo {
256                process_contents: Some(ProcessContentsType::Lax),
257                ..Default::default()
258            }),
259            ..Default::default()
260        });
261        let type_ = Type::new(variant);
262        self.state.add_type(ident, type_, true)?;
263
264        Ok(self)
265    }
266
267    /// Finishes the interpretation of the [`Schemas`] structure and returns
268    /// the [`Types`] structure with the generated type information.
269    ///
270    /// # Errors
271    ///
272    /// Returns a suitable [`Error`] if the operation was not successful.
273    #[instrument(err, level = "trace", skip(self))]
274    pub fn finish(mut self) -> Result<Types, Error> {
275        for (id, info) in self.schemas.namespaces() {
276            let module = Module {
277                name: info
278                    .prefix
279                    .as_ref()
280                    .map(|prefix| Name::new(prefix.to_string())),
281                namespace: info.namespace.clone(),
282            };
283
284            self.state.types.modules.insert(*id, module);
285        }
286
287        for (_id, schema) in self.schemas.schemas() {
288            SchemaInterpreter::process(&mut self.state, schema, self.schemas)?;
289        }
290
291        Ok(self.state.types)
292    }
293}