xsd_parser/interpreter/
mod.rs

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