diff --git a/.gitignore b/.gitignore index 979d87e..9d23749 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,8 @@ Cargo.lock /target **/*.rs.bk Cargo.lock + +*.xsd +*.nxsd +*.xml +foo.rs diff --git a/.travis.yml b/.travis.yml index 9869208..0e4819d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,8 @@ rust: - nightly cache: cargo script: - - wget https://www.w3.org/2009/XMLSchema/XMLSchema.xsd - - cargo run --features=bootstrap --bin bootstrap < XMLSchema.xsd > src/generated.rs - - cargo run --bin gen < XMLSchema.xsd > src/generated2.rs + - wget https://www.w3.org/2009/XMLSchema/XMLSchema.xsd -O xml-schema/XMLSchema.xsd + - wget https://www.w3.org/2009/XMLSchema/derived.nxsd -O xml-schema/derived.nxsd - cargo test + - cargo run --package xml-schema --bin gen xml-schema/derived.nxsd xml-schema/XMLSchema.xsd > foo.rs + - diff foo.rs xml-schema/src/parser.rs # Fails if they are different. diff --git a/Cargo.toml b/Cargo.toml index af14aed..2a4bb58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,6 @@ -[package] -name = "xml-schema" -version = "0.1.0" -authors = ["Valentin Lorentz "] +[workspace] -[dependencies] -#quick-xml = "0.12.1" -xmlparser = "0.5.0" -codegen = { git = "https://github.com/carllerche/codegen" } -heck = "0.3.0" - -[dev-dependencies] -pretty_assertions = "^0.4" - -[features] -"bootstrap" = [] - -[[bin]] -name = "bootstrap" -path = "src/bin/bootstrap.rs" -required-features = ["bootstrap"] - -[[bin]] -name = "gen" -path = "src/bin/gen.rs" +members = [ + "xml-schema", + "xml-schema-tests", +] diff --git a/LICENSE b/LICENSE index 94a9ed0..dbbe355 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies @@ -7,17 +7,15 @@ Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to +our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. +software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you @@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. The precise terms and conditions for copying, distribution and modification follow. @@ -72,7 +60,7 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU General Public License. + "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. @@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single +under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General +Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published +GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's +versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see +For more information on this, and how to apply and follow the GNU AGPL, see . - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md index 3743f2a..7b0e4d3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,39 @@ # rust-xml-schema XML Parser generator based on XML schemas. +Project status: pre-alpha + +## Features + +* Self-generating, meaning that all features used by `XMLSchema.xsd` + (XML Schema's definition using XML Schema itself) are supported. + This includes: + * namespaces + * group/choice/sequence/element + * attributes +* Most datatypes (some natively implemented, some generated via `derived.nxsd`) +* Anonymous elements are given a name using a best-effort heuristic -- they + are manually overridable + +## To do + +* simpleContent +* some facets +* anything related to XPath +* assertions +* time data types +* notation +* many other stuff, grep for `TODO`, `unimplemented`, `unwrap`, or `expect` in the code. +* add tests +* check conformance to the XSD specification + ## Regenerating the schema parser ``` -wget https://www.w3.org/2009/XMLSchema/XMLSchema.xsd -cargo run --features=bootstrap --bin bootstrap < XMLSchema.xsd > src/generated.rs -cargo run --bin gen < XMLSchema.xsd > src/generated2.rs +wget https://www.w3.org/2009/XMLSchema/XMLSchema.xsd -O xml-schema/XMLSchema.xsd +wget https://www.w3.org/2009/XMLSchema/derived.nxsd -O xml-schema/derived.nxsd +cargo run --package xml-schema --bin gen xml-schema/derived.nxsd xml-schema/XMLSchema.xsd > foo.rs +cp foo.rs xml-schema/src/parser.rs cargo test ``` diff --git a/src/bin/bootstrap.rs b/src/bin/bootstrap.rs deleted file mode 100644 index 7e9348d..0000000 --- a/src/bin/bootstrap.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::io::stdin; -use std::io::Read; - -extern crate xml_schema; -extern crate codegen; -use xml_schema::parse_xsd; -use xml_schema::round0_parser::*; -use xml_schema::round0_parser_generator::*; - -fn main() { - let mut s = String::new(); - stdin().read_to_string(&mut s).unwrap(); - let doc = parse_xsd(&s); - let mut gen = ParserGenerator::new(&doc); - let mut scope = codegen::Scope::new(); - gen.gen_unqual_module(); - /*for (name, v) in doc.schema.as_ref().unwrap().types.iter() { - println!("{} {:?}", name, v); - }*/ - scope.push_module(gen.nsuri_to_module.remove(doc.schema.as_ref().unwrap().target_namespace).unwrap().1); - println!("#[allow(bad_style)]\n{}\n{}", MACROS, scope.to_string()); - println!("// substs: {:?}", doc.schema.as_ref().unwrap().substitution_groups); -} diff --git a/src/bin/gen.rs b/src/bin/gen.rs deleted file mode 100644 index d4d9a78..0000000 --- a/src/bin/gen.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::io::stdin; -use std::io::Read; - -extern crate xmlparser; -extern crate xml_schema; -extern crate codegen; -use xml_schema::generated::UNQUAL; -use xml_schema::parser_generator::*; -use xml_schema::support::*; - -fn main() { - let mut s = String::new(); - stdin().read_to_string(&mut s).unwrap(); - let tokenizer = xmlparser::Tokenizer::from(&s[..]); - let mut stream = Box::new(InnerStream::new(tokenizer)); - stream.next(); // Eat the declaration - stream.next(); // Eat the DTD start - stream.next(); // Eat comment - stream.next(); // Eat comment - stream.next(); // Eat the DTD end - let doc = UNQUAL::schema_e::parse_xml(&mut stream, &mut (), &()).unwrap(); - let mut gen = ParserGenerator::new(&doc); - let scope = gen.gen(&doc); - //println!("#[allow(bad_style)]\nextern crate xml_schema;use xml_schema::support;\n{}\n{}", MACROS, scope.to_string()); - println!("#[allow(bad_style)]\nuse support;\n{}\n{}", MACROS, scope.to_string()); -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index f50f73d..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![recursion_limit="80"] - -extern crate xmlparser; -extern crate codegen; -extern crate heck; - -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; - -pub mod round0_parser; -pub mod names; -pub mod support; -pub mod round0_parser_generator; - -#[cfg(not(feature="bootstrap"))] -pub mod generated; -#[cfg(not(feature="bootstrap"))] -pub mod parser_generator; -#[cfg(test)] -mod test_generated; -#[cfg(test)] -mod test_generated_schema; -#[cfg(test)] -mod generated2; -#[cfg(test)] -mod test_generated2; - -pub fn parse_xsd(xsd: &str) -> round0_parser::Document { - let mut stream = xmlparser::Tokenizer::from(xsd); - round0_parser::Parser::parse_document(&mut stream) -} - - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - use super::*; - use round0_parser::*; - - const PERSON_XSD: &'static str = r#" - - - - - - - - - - - - "#; - #[test] - fn parse_person_schema() { - let doc = parse_xsd(PERSON_XSD); - - let mut namespaces = HashMap::new(); - namespaces.insert("xs".to_string(), "http://www.w3.org/2001/XMLSchema"); - - let mut elements = HashMap::new(); - elements.insert("person".into(), Element { - min_occurs: None, - max_occurs: None, - name: "person".into(), - attrs: vec![], - mixed: false, - abstract_: false, - type_: Some(ElementType::Sequence(vec![ - (None, None, ElementType::Element(Box::new(Element { - min_occurs: None, - max_occurs: None, - name: "name".into(), - attrs: vec![], - mixed: false, - abstract_: false, - type_: Some(ElementType::String), - }))), - (None, None, ElementType::Element(Box::new(Element { - min_occurs: None, - max_occurs: None, - name: "firstname".into(), - attrs: vec![], - mixed: false, - abstract_: false, - type_: Some(ElementType::String), - }))), - (None, None, ElementType::Element(Box::new(Element { - min_occurs: None, - max_occurs: None, - name: "birthdate".into(), - attrs: vec![], - mixed: false, - abstract_: false, - type_: Some(ElementType::Date), - }))), - ])) - }); - - assert_eq!(doc, Document { - version: Some("1.0"), - encoding: Some("UTF-8"), - standalone: None, - schema: Some(Schema { - namespaces: namespaces, - target_namespace: "foo", - groups: HashMap::new(), - elements: elements, - types: HashMap::new(), - substitution_groups: HashMap::new(), - }), - }); - } -} diff --git a/src/names.rs b/src/names.rs deleted file mode 100644 index 070b396..0000000 --- a/src/names.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::collections::HashMap; - -use support::QName; - -const KEYWORDS: &[&'static str] = &["override"]; -fn escape_keyword(name: &str) -> String { - if KEYWORDS.contains(&name) { - format!("{}_", name) - } - else { - name.to_string() - } -} - -pub(crate) struct NameGenerator(HashMap); - -impl NameGenerator { - pub fn new() -> NameGenerator { - NameGenerator(HashMap::new()) - } - - pub fn gen_name(&mut self, name: String) -> String { - let nb_uses = self.0.get(&name).cloned().unwrap_or(0); - let ret = format!("{}{}", name, "_".repeat(nb_uses)); - self.0.insert(name, nb_uses+1); - ret - } -} - -macro_rules! str_alias { - ($name:ident) => { - #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] - pub struct $name<'input>(&'input str); - impl<'input> $name<'input> { - pub fn new(s: &'input str) -> $name<'input> { - $name(s) - } - pub fn as_str(&self) -> &'input str { - self.0 - } - } - } -} - -#[derive(Debug)] -pub(crate) struct Namespaces<'input> { - pub target_namespace: &'input str, - pub namespaces: HashMap<&'input str, &'input str>, // namespace -> URI - pub module_names: HashMap<&'input str, &'input str>, // URI -> module name - pub default_namespace: &'input str, -} - -impl<'input> Namespaces<'input> { - pub fn new(mut namespaces: HashMap<&'input str, &'input str>, target_namespace: &'input str) -> Namespaces<'input> { - if let Some(uri) = namespaces.insert("xml", "xml") { - panic!("Cannot have a namespaces named \"xml\": {}", uri); - } - if let Some(uri) = namespaces.insert("xmlns", "xmlns") { - panic!("Cannot have a namespaces named \"xmlns\": {}", uri); - } - let mut module_names = HashMap::new(); - for (ns, uri) in namespaces.iter() { - module_names.insert(*uri, *ns); - } - Namespaces { - target_namespace, - namespaces, - default_namespace: target_namespace, - module_names, - } - } - - pub fn expand_prefix(&self, prefix: Option<&'input str>) -> &'input str { - match prefix { - Some(prefix) => self.namespaces.get(prefix).expect(&format!("Unknown prefix: {:?}", prefix)), - None => self.default_namespace, - } - } - pub fn expand_qname(&self, qname: QName<'input>) -> FullName<'input> { - FullName::new(self.expand_prefix(qname.0), qname.1) - } - pub fn parse_qname(&self, s: &'input str) -> FullName<'input> { - self.expand_qname(QName::from(s)) - } - pub fn qname_eq(&self, qname1: QName<'input>, qname2: QName<'input>) -> bool { - qname1.1 == qname2.1 && self.expand_prefix(qname1.0) == self.expand_prefix(qname2.0) - } - - pub fn get_module_name(&self, qname: FullName<'input>) -> &'input str { - let (prefix, _) = qname.as_tuple(); - self.module_names.get(prefix).cloned().unwrap_or("UNQUAL") - } - - pub fn name_from_hint(&self, hint: &NameHint<'input>) -> Option { - if hint.tokens.len() > 0 { - Some(hint.tokens.iter().map(|&s| escape_keyword(s)).collect::>().join("_")) - } - else { - None - } - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct FullName<'input>(&'input str, &'input str); - -impl<'input> FullName<'input> { - pub fn new(ns: &'input str, name: &'input str) -> FullName<'input> { - FullName(ns, name) - } - pub fn as_tuple(&self) -> (&'input str, &'input str) { - (self.0, self.1) - } -} - -#[derive(Debug, Clone)] -pub struct NameHint<'input> { - tokens: Vec<&'input str>, -} -impl<'input> NameHint<'input> { - pub fn new_empty() -> NameHint<'input> { - NameHint { tokens: Vec::new() } - } - pub fn new(s: &'input str) -> NameHint<'input> { - NameHint { tokens: vec![s] } - } - pub fn from_fullname(name: &FullName<'input>) -> NameHint<'input> { - NameHint::new(name.1) - } - pub fn push(&mut self, s: &'input str) { - self.tokens.push(s); - } - pub fn extend(&mut self, other: &NameHint<'input>) { - self.tokens.extend(other.tokens.iter()) - } -} diff --git a/src/parser_generator.rs b/src/parser_generator.rs deleted file mode 100644 index 06e4ccf..0000000 --- a/src/parser_generator.rs +++ /dev/null @@ -1,934 +0,0 @@ -use std::collections::HashMap; -use std::num::ParseIntError; - -use codegen as cg; -use heck::{SnakeCase, CamelCase}; - -use support::*; -use generated::UNQUAL::*; -use names::*; - -const KEYWORDS: &[&'static str] = &["override"]; -fn escape_keyword(name: &str) -> String { - if KEYWORDS.contains(&name) { - format!("{}_", name) - } - else { - name.to_string() - } -} - -pub const MACROS: &'static str = r#" -macro_rules! try_rollback { - ($stream:expr, $tx:expr, $e:expr) => { - match $e { - Some(i) => i, - None => { - $tx.rollback($stream); - return None - } - } - } -} - -macro_rules! impl_enum { - ( $name:ident, $($variant_macro:ident ! ( $($variant_args: tt )* ), )* ) => { - impl<'input> ParseXml<'input> for $name<'input> { - const NODE_NAME: &'static str = concat!("enum ", stringify!($name)); - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - let tx = stream.transaction(); - $( - match $variant_macro!($name, stream, parse_context, parent_context, $($variant_args)*) { - Some(x) => return Some(x), - None => (), // TODO: should we rollback here? - } - )* - - tx.rollback(stream); - None - } - } - } -} - -macro_rules! impl_singleton_variant { - ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Box < $type_name:ident > ) => { - super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name) - }; - ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { - Some(super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name)) - }; - ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ - let mut items = Vec::new(); - while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { - items.push(item); - } - Some($enum_name::$variant_name(items)) - }} -} - -macro_rules! impl_struct_variant { - ( $enum_name:ident, $stream: expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $( ( $field_name:ident, $( $field_args:tt )* ), )* ) => {{ - let mut res = None; - loop { // single run, used for breaking - $( - let $field_name = match impl_struct_variant_field!($stream, $parse_context, $parent_context, $( $field_args )* ) { - Some(e) => e, - None => break, - }; - )* - res = Some($enum_name::$variant_name { - $( - $field_name, - )* - }); - break; - } - res - }} -} - -macro_rules! impl_struct_variant_field { - ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Box < $type_name:ident > ) => { - super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new) - }; - ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { - Some(super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new)) - }; - ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ - let mut items = Vec::new(); - while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { - items.push(item); - } - Some(items) - }} -} - -macro_rules! impl_group_or_sequence { - ( $name:ident, $( ( $field_name:ident, $( $field_args:tt )* ), )* ) => { - impl<'input> ParseXml<'input> for $name<'input> { - const NODE_NAME: &'static str = concat!("group or sequence ", stringify!($name)); - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - let tx = stream.transaction(); - Some($name { - $( - $field_name: impl_element_field!(stream, tx, parse_context, parent_context, $($field_args)*), - )* - }) - } - } - } -} - -macro_rules! impl_element { - ( $struct_name:ident, $name:expr, { $( ( $field_name:ident, $( $field_args:tt )* ), )* }, can_be_empty=$can_be_empty:ident ) => { - impl<'input> ParseXml<'input> for $struct_name<'input> { - const NODE_NAME: &'static str = concat!("element ", stringify!($struct_name)); - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - let tx = stream.transaction(); - let mut tok = stream.next().unwrap(); - loop { - match tok { - Token::Whitespaces(_) => (), - Token::Comment(_) => (), - Token::Text(_) => (), - _ => break, - } - tok = stream.next().unwrap(); - } - match tok { - Token::ElementStart(prefix, name) => { - if name.to_str() == $name { - let mut attrs = HashMap::new(); - loop { - let tok = stream.next().unwrap(); - match tok { - Token::Whitespaces(_) => (), - Token::Comment(_) => (), - Token::Text(_) => (), - Token::Attribute((key_prefix, key_local), value) => { - let key = QName(match key_prefix.to_str() { "" => None, s => Some(s) }, key_local.to_str()); - let old = attrs.insert(key, value.to_str()); assert_eq!(old, None) - }, - Token::ElementEnd(ElementEnd::Open) => { - let ret = Some($struct_name { - ATTRS: attrs, - $( - $field_name: impl_element_field!(stream, tx, parse_context, parent_context, $($field_args)*), - )* - }); - let mut next_tok; - loop { - next_tok = stream.next(); - match next_tok { - Some(Token::Whitespaces(_)) => (), - Some(Token::Comment(_)) => (), - Some(Token::Text(_)) => (), - Some(Token::ElementEnd(ElementEnd::Close(prefix2, name2))) => { - assert_eq!((prefix.to_str(), name.to_str()), (prefix2.to_str(), name2.to_str())); - return ret; - } - _ => panic!(format!("Did not expect token {:?}", next_tok)), - } - } - }, - Token::ElementEnd(ElementEnd::Empty) => { - return gen_empty_element!($can_be_empty, $struct_name, attrs, $($field_name,)*); - }, - Token::ElementEnd(ElementEnd::Close(_, _)) => { - tx.rollback(stream); - return None - }, - _ => panic!(format!("Did not expect token {:?}", tok)), - } - } - } - else { - tx.rollback(stream); - None - } - }, - Token::ElementEnd(ElementEnd::Close(_, _)) => { - tx.rollback(stream); - return None - }, - _ => panic!(format!("Did not expect token {:?}", tok)), - } - } - } - } -} - -macro_rules! gen_empty_element { - ( false, $struct_name:ident, $attrs:expr, $($field_name:ident,)* ) => { - panic!(concat!("Empty element ", stringify!($struct_name))); - }; - ( true, $struct_name:ident, $attrs:expr, $($field_name:ident,)* ) => { - Some($struct_name { - ATTRS: $attrs, - $( - $field_name: Default::default(), // This fails to compile if you told gen_element!() that it can gen_empty_element() whereas there is a field that does not implement Default (ie. not a Vec or an Option) - )* - }) - } -} - -macro_rules! impl_element_field { - ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, $type_name:ident ) => { - try_rollback!($stream, $tx, super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context)) - }; - ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < $type_name:ident > ) => { - super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) - }; - ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ - let mut items = Vec::new(); - while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { - items.push(item); - } - items - }} -} -"#; - -const SCHEMA_URI: &'static str = "http://www.w3.org/2001/XMLSchema"; - -fn parse_max_occurs(s: &str) -> Result { - if s == "unbounded" { - Ok(usize::max_value()) - } - else { - s.parse() - } -} - -#[derive(Debug)] -struct RichType<'input> { - name_hint: NameHint<'input>, - type_: Type<'input>, -} -impl<'input> RichType<'input> { - fn new(name_hint: NameHint<'input>, type_: Type<'input>) -> RichType<'input> { - RichType { name_hint, type_ } - } -} - -#[derive(Debug)] -enum Type<'input> { - Any, - Alias(FullName<'input>), - List(Box>), - Union(Vec>), - Extension(FullName<'input>, Box>), - Element(usize, usize, FullName<'input>), - Group(usize, usize, FullName<'input>), - Choice(usize, usize, String), - Sequence(usize, usize, String), -} - -#[derive(Debug)] -pub struct ParserGenerator<'ast, 'input: 'ast> { - namespaces: Namespaces<'input>, - element_form_default_qualified: bool, - attribute_form_default_qualified: bool, - elements: HashMap, RichType<'input>>, - types: HashMap, RichType<'input>>, - choices: HashMap>>, - sequences: HashMap>>, - groups: HashMap, RichType<'input>>, - attribute_groups: HashMap, &'ast attributeGroup_e<'input>>, -} - -impl<'ast, 'input: 'ast> ParserGenerator<'ast, 'input> { - pub fn new(ast: &'ast schema_e<'input>) -> ParserGenerator<'ast, 'input> { - let mut target_namespace = None; - let mut namespaces = HashMap::new(); - let mut element_form_default_qualified = false; - let mut attribute_form_default_qualified = false; - for (key, &value) in ast.attrs.iter() { - match (key.0, key.1) { - (Some("xml"), "lang") => (), - (Some("xmlns"), ns) => { - let old_value = namespaces.insert(ns, value); - if let Some(old_value) = old_value { - panic!("Namespace {:?} is defined twice ({} and {})", ns, old_value, value); - } - }, - (None, "targetNamespace") => target_namespace = Some(value), - (None, "elementFormDefault") => { - match value { - "qualified" => element_form_default_qualified = true, - "unqualified" => element_form_default_qualified = false, - _ => panic!("Unknown value: elementFormDefault={:?}", value), - } - }, - (None, "attributeFormDefault") => { - match value { - "qualified" => attribute_form_default_qualified = true, - "unqualified" => attribute_form_default_qualified = false, - _ => panic!("Unknown value: attributeFormDefault={:?}", value), - } - }, - (None, "version") => (), - _ => panic!("Unknown attribute {} on .", key), - } - } - let target_namespace = target_namespace.expect("No target namespace."); - ParserGenerator { - namespaces: Namespaces::new(namespaces, target_namespace), - element_form_default_qualified, - attribute_form_default_qualified, - elements: HashMap::new(), - types: HashMap::new(), - groups: HashMap::new(), - choices: HashMap::new(), - sequences: HashMap::new(), - attribute_groups: HashMap::new(), - } - } - - pub fn gen(&mut self, ast: &'ast schema_e<'input>) -> cg::Scope { - self.process_ast(ast); - self.gen_target_scope(ast) - } - - fn gen_target_scope(&mut self, ast: &schema_e<'input>) -> cg::Scope { - let mut scope = cg::Scope::new(); - scope.raw("extern crate xmlparser;"); - scope.raw("pub use std::collections::HashMap;"); - scope.raw("pub use std::marker::PhantomData;"); - scope.raw("pub use support::*;"); - scope.raw("pub use xmlparser::{Token, ElementEnd};"); - self.gen_choices(&mut scope); - self.gen_sequences(&mut scope); - self.gen_elements(&mut scope); - self.gen_groups(&mut scope); - scope - } - - fn process_ast(&mut self, ast: &'ast schema_e<'input>) { - for top_level_item in ast.child.schema_e_inner__extfield0.schema_e_inner__extfield0__seqfield2.0.iter() { - match top_level_item.schemaTop { - schemaTop::redefinable(ref r) => self.process_redefinable(r), - schemaTop::element(ref e) => { self.process_element(e); }, - schemaTop::attribute(_) => unimplemented!("top-level attribute"), - schemaTop::notation(ref e) => self.process_notation(e), - } - } - } - - fn process_notation(&mut self, notation: &'ast notation_e<'input>) { - // TODO - } - - fn process_redefinable(&mut self, r: &'ast redefinable<'input>) { - match r { - redefinable::simpleType(e) => { self.process_simple_type(e); }, - redefinable::complexType(e) => { self.process_complex_type(e); }, - redefinable::group(e) => { self.process_group(e); }, - redefinable::attributeGroup(e) => self.process_attribute_group(e), - } - } - - fn process_group(&mut self, group: &'ast group_e<'input>) -> RichType<'input> { - let mut name = None; - let mut ref_ = None; - let mut max_occurs = 1; - let mut min_occurs = 1; - for (key, &value) in group.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "name") => - name = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "ref") => - ref_ = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "minOccurs") => - min_occurs = value.parse().unwrap(), - (SCHEMA_URI, "maxOccurs") => - max_occurs = parse_max_occurs(value).unwrap(), - _ => panic!("Unknown attribute {} in ", key), - } - } - - if let Some(ref_) = ref_ { - if let Some(name) = name { - panic!(" has both ref={:?} and name={:?}", ref_, name) - } - let (_, field_name) = ref_.as_tuple(); - RichType::new(NameHint::new(field_name), Type::Group(min_occurs, max_occurs, ref_)) - } - else { - let name = name.expect(" has no name or ref."); - - let mut items = Vec::new(); - for particle in ((group.child.0).0).0.particle.0.iter() { - items.push(self.process_particle(particle)); - } - - assert_eq!(items.len(), 1, "{:?}", items); - let type_ = items.remove(0); - - self.groups.insert(name, type_); - RichType::new(NameHint::from_fullname(&name), Type::Group(min_occurs, max_occurs, name)) - } - } - - fn process_attribute_group(&mut self, group: &'ast attributeGroup_e<'input>) { - let mut name = None; - for (key, &value) in group.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "name") => - name = Some(value), - _ => panic!("Unknown attribute {} in ", key), - } - } - let name = name.expect(" has no name."); - self.attribute_groups.insert(self.namespaces.parse_qname(name), group); - } - - fn process_simple_type(&mut self, type_: &'ast simpleType_e<'input>) -> RichType<'input> { - let mut name = None; - for (key, &value) in type_.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "name") => - name = Some(self.namespaces.parse_qname(value)), - _ => panic!("Unknown attribute {} in ", key), - } - } - //let struct_name = self.namespaces.new_type(QName::from(name)); - let ty = match (type_.child.0).0.simpleDerivation { - simpleDerivation::restriction(ref e) => self.process_restriction(e), - simpleDerivation::list(ref e) => self.process_list(e), - simpleDerivation::union(ref e) => self.process_union(e), - }; - - if let Some(name) = name { - self.types.insert(name, ty); - RichType::new(NameHint::from_fullname(&name), Type::Alias(name)) - } - else { - ty - } - } - - fn process_list(&mut self, list: &'ast list_e<'input>) -> RichType<'input> { - let mut item_type = None; - for (key, &value) in list.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "itemType") => item_type = Some(self.namespaces.parse_qname(value)), - _ => panic!("Unknown attribute {} in ", key), - } - } - - let item_type = match (item_type, &list.child.simpleType.0) { - (None, Some(st)) => self.process_simple_type(st), - (Some(n), None) => RichType::new(NameHint::new_empty(), Type::Alias(n)), - (None, None) => RichType::new(NameHint::new_empty(), Type::Any), // TODO - (Some(ref t1), Some(ref t2)) => panic!(" has both an itemType attribute ({:?}) and a child type ({:?}).", t1, t2), - }; - - let mut name_hint = item_type.name_hint.clone(); - name_hint.push("list"); - RichType::new(name_hint, Type::List(Box::new(item_type))) - } - - fn process_union(&mut self, union: &'ast union_e<'input>) -> RichType<'input> { - let mut member_types = Vec::new(); - for (key, &value) in union.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "memberTypes") => { - member_types = value.split(" ").map(|s| { - let name = self.namespaces.parse_qname(s); - let (_, field_name) = name.as_tuple(); - RichType::new(NameHint::new(field_name), Type::Alias(name)) - }).collect() - }, - _ => panic!("Unknown attribute {} in ", key), - } - } - - for t in union.child.simpleType.0.iter() { - member_types.push(self.process_simple_type(t)) - } - - RichType::new(NameHint::new_empty(), Type::Union(member_types)) - } - - fn process_complex_type(&mut self, type_: &'ast complexType_e<'input>) -> RichType<'input> { - let mut name = None; - let mut abstract_ = false; - let mut mixed = false; - for (key, &value) in type_.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "name") => - name = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "abstract") => { - match value { - "true" => abstract_ = true, - "false" => abstract_ = false, - _ => panic!("Invalid value for abstract attribute: {}", value), - } - }, - (SCHEMA_URI, "mixed") => { - match value { - "true" => mixed = true, - "false" => mixed = false, - _ => panic!("Invalid value for mixed attribute: {}", value), - } - }, - _ => panic!("Unknown attribute {} in ", key), - } - } - //let struct_name = self.namespaces.new_type(QName::from(name)); - let ty = match (type_.child.0).0.complexTypeModel { - complexTypeModel::simpleContent(_) => unimplemented!("simpleContent"), - complexTypeModel::complexContent(ref model) => self.process_complex_content(model), - complexTypeModel::complexTypeModel__choicevariant2(ref model) => self.process_other_complex_type_model(model), - }; - - if let Some(name) = name { - self.types.insert(name, ty); - RichType::new(NameHint::from_fullname(&name), Type::Alias(name)) - } - else { - ty - } - } - - fn process_other_complex_type_model(&mut self, model: &'ast complexTypeModel__choicevariant2<'input>) -> RichType<'input> { - RichType::new(NameHint::new_empty(), Type::Any) // TODO - } - - fn process_complex_content(&mut self, model: &'ast complexContent_e<'input>) -> RichType<'input> { - match model.child.complexContent_e_inner__extfield0 { - complexContent_e_inner__extfield0::restriction(ref r) => self.process_restriction(r), - complexContent_e_inner__extfield0::extension(ref e) => self.process_extension(e), - } - } - - fn process_restriction(&mut self, restriction: &'ast restriction_e<'input>) -> RichType<'input> { - let mut base = None; - for (key, &value) in restriction.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "base") => base = Some(value), - _ => panic!("Unknown attribute {} in ", key), - } - } - let base = base.expect(" has no base"); - //match (restriction_e.child.0).0.restrictionType__extfield0. - RichType::new(NameHint::new_empty(), Type::Alias(self.namespaces.parse_qname(base))) // TODO - } - - fn process_type_def_particle(&mut self, particle: &'ast typeDefParticle<'input>) -> RichType<'input> { - match particle { - typeDefParticle::group(e) => self.process_group(e), - typeDefParticle::all(_) => unimplemented!("all"), - typeDefParticle::choice(e) => self.process_choice(e), - typeDefParticle::sequence(e) => self.process_sequence(e), - } - } - fn process_particle(&mut self, particle: &'ast particle<'input>) -> RichType<'input> { - match particle { - particle::element(e) => self.process_element(e), - particle::group(e) => self.process_group(e), - particle::all(_) => unimplemented!("all"), - particle::choice(e) => self.process_choice(e), - particle::sequence(sequence) => self.process_sequence(sequence), - particle::any(e) => self.process_any(e), - } - } - - fn process_any(&mut self, any: &'ast any_e<'input>) -> RichType<'input> { - RichType::new(NameHint::new_empty(), Type::Any) - } - - fn process_sequence(&mut self, sequence: &'ast sequence_e<'input>) -> RichType<'input> { - let mut min_occurs = 1; - let mut max_occurs = 1; - for (key, &value) in sequence.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "minOccurs") => - min_occurs = value.parse().unwrap(), - (SCHEMA_URI, "maxOccurs") => - max_occurs = parse_max_occurs(value).unwrap(), - _ => panic!("Unknown attribute {} in ", key), - } - } - let mut items = Vec::new(); - let mut name_hint = NameHint::new("sequence"); - for particle in (sequence.child.0).0.particle.0.iter() { - let ty = self.process_particle(particle); - name_hint.extend(&ty.name_hint); - items.push(ty); - } - let name = self.namespaces.name_from_hint(&name_hint).unwrap(); - self.sequences.insert(name.clone(), items); - RichType::new(name_hint, Type::Sequence(min_occurs, max_occurs, name)) - } - - fn process_choice(&mut self, choice: &'ast choice_e<'input>) -> RichType<'input> { - let mut min_occurs = 1; - let mut max_occurs = 1; - for (key, &value) in choice.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "minOccurs") => - min_occurs = value.parse().unwrap(), - (SCHEMA_URI, "maxOccurs") => - max_occurs = parse_max_occurs(value).unwrap(), - _ => panic!("Unknown attribute {} in ", key), - } - } - let mut items = Vec::new(); - let mut name_hint = NameHint::new("choice"); - for particle in (choice.child.0).0.particle.0.iter() { - let ty = self.process_particle(particle); - name_hint.extend(&ty.name_hint); - items.push(ty); - } - let name = self.namespaces.name_from_hint(&name_hint).unwrap(); - self.choices.insert(name.clone(), items); - RichType::new(name_hint, Type::Choice(min_occurs, max_occurs, name)) - } - - fn process_extension(&mut self, extension: &'ast extension_e<'input>) -> RichType<'input> { - let mut base = None; - for (key, &value) in extension.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "base") => base = Some(value), - _ => panic!("Unknown attribute {} in ", key), - } - } - let base = base.expect(" has no base"); - let base = self.namespaces.parse_qname(base); - if let Some(ref particle) = extension.child.0.extensionType__extfield0.typeDefParticle.0 { - RichType::new(NameHint::new_empty(), Type::Extension(base, Box::new(self.process_type_def_particle(particle)))) - } - else { - RichType::new(NameHint::new_empty(), Type::Alias(base)) - } - } - - fn process_element(&mut self, element: &'ast element_e<'input>) -> RichType<'input> { - let mut name = None; - let mut ref_ = None; - let mut type_attr = None; - let mut abstract_ = false; - let mut substitution_group = None; - let mut min_occurs = 1; - let mut max_occurs = 1; - for (key, &value) in element.attrs.iter() { - match self.namespaces.expand_qname(*key).as_tuple() { - (SCHEMA_URI, "name") => - name = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "id") => - (), - (SCHEMA_URI, "type") => - type_attr = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "minOccurs") => - min_occurs = value.parse().unwrap(), - (SCHEMA_URI, "maxOccurs") => - max_occurs = parse_max_occurs(value).unwrap(), - (SCHEMA_URI, "abstract") => { - match value { - "true" => abstract_ = true, - "false" => abstract_ = false, - _ => panic!("Invalid value for abstract attribute: {}", value), - } - }, - (SCHEMA_URI, "substitutionGroup") => - substitution_group = Some(self.namespaces.parse_qname(value)), - (SCHEMA_URI, "ref") => - ref_ = Some(self.namespaces.parse_qname(value)), - _ => panic!("Unknown attribute {} in ", key), - } - } - if let Some(ref_) = ref_ { - if let Some(name) = name { - panic!(" has both ref={:?} and name={:?}", ref_, name); - } - let (_, field_name) = ref_.as_tuple(); - RichType::new(NameHint::new(field_name), Type::Element(min_occurs, max_occurs, ref_)) - } - else { - let name = name.expect(" has no name."); - let e = &(element.child.0).0.element__extfield0; - let element__extfield0 { element__extfield0__seqfield0: ref child_type, ref alternative, ref identityConstraint } = e; - let type_ = match (type_attr, &child_type.0) { - (None, Some(ref c)) => match c { - element__extfield0__seqfield0::simpleType(ref e) => self.process_simple_type(e), - element__extfield0__seqfield0::complexType(ref e) => self.process_complex_type(e), - }, - (Some(t), None) => { - let (_, field_name) = t.as_tuple(); - RichType::new(NameHint::new(field_name), Type::Alias(t)) - }, - (None, None) => RichType::new(NameHint::new_empty(), Type::Any), // TODO - (Some(ref t1), Some(ref t2)) => panic!("Element '{:?}' has both a type attribute ({:?}) and a child type ({:?}).", name, t1, t2), - }; - - self.elements.insert(name, type_); - let (_, field_name) = name.as_tuple(); - RichType::new(NameHint::new(field_name), Type::Element(min_occurs, max_occurs, name)) - } - } - - fn gen_choices(&mut self, scope: &mut cg::Scope) { - let mut module = scope.new_module("enums"); - module.vis("pub"); - module.scope().raw("use super::*;"); - // TODO: sort the choices - for (name, items) in self.choices.iter() { - let mut impl_code = Vec::new(); - let enum_name = escape_keyword(&name.to_camel_case()); - impl_code.push(format!("impl_enum!({},", enum_name)); - { - let mut enum_ = module.new_enum(&enum_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); - for (i, item) in items.iter().enumerate() { - let mut fields = Vec::new(); - { - let mut name_gen = NameGenerator::new(); - let writer = &mut |variant_name: &str, type_mod_name: &str, min_occurs, max_occurs, type_name: &str| { - let variant_name = escape_keyword(&name_gen.gen_name(variant_name.to_snake_case())); - let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); - let type_name = escape_keyword(&type_name.to_camel_case()); - fields.push((variant_name, type_mod_name, min_occurs, max_occurs, type_name)); - }; - self.write_type_in_struct_def(writer, &item); - } - let variant_name = self.namespaces.name_from_hint(&item.name_hint) - .unwrap_or(format!("{}{}", name, i)).to_camel_case(); - let variant_name = escape_keyword(&variant_name.to_camel_case()); - let mut variant = enum_.new_variant(&variant_name); - if fields.len() == 1 { - let (_, type_mod_name, min_occurs, max_occurs, type_name) = fields.remove(0); - match (min_occurs, max_occurs) { - (1, 1) => { - variant.tuple(&format!("Box>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); - impl_code.push(format!(" impl_singleton_variant!({}, {}, Box<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); - }, - (0, 1) => { - variant.tuple(&format!("Option>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); - impl_code.push(format!(" impl_singleton_variant!({}, {}, Option<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); - }, - (_, _) => { - variant.tuple(&format!("Vec>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); - impl_code.push(format!(" impl_singleton_variant!({}, {}, Vec<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); - }, - } - } - else { - impl_code.push(format!(" impl_struct_variant!({},", variant_name)); - for (field_name, type_mod_name, min_occurs, max_occurs, type_name) in fields { - match (min_occurs, max_occurs) { - (1, 1) => { - impl_code.push(format!(" ({}, {}, Box<{}>),", field_name, type_mod_name, type_name)); - variant.named(&field_name, &format!("Box>", type_mod_name, type_name)); - }, - (0, 1) => { - impl_code.push(format!(" ({}, {}, Option >),", field_name, type_mod_name, type_name)); - variant.named(&field_name, &format!("Option> >", type_mod_name, type_name)); - }, - (_, _) => { - impl_code.push(format!(" ({}, {}, Vec<{}>),", field_name, type_mod_name, type_name)); - variant.named(&field_name, &format!("Vec >", type_mod_name, type_name)); - }, - } - } - impl_code.push(format!(" ),")); - } - } - } - impl_code.push(");".to_string()); - module.scope().raw(&impl_code.join("\n")); - } - } - - fn gen_sequences(&mut self, scope: &mut cg::Scope) { - let mut module = scope.new_module("sequences"); - module.vis("pub"); - module.scope().raw("use super::*;"); - let mut sequences: Vec<_> = self.sequences.iter().collect(); - - sequences.sort_by_key(|&(n,_)| n); - for (name, sequence) in sequences { - module.vis("pub"); - module.scope().raw("use super::*;"); - self.gen_group_or_sequence(module, name, &sequence.iter().collect()); - } - } - - fn gen_groups(&mut self, scope: &mut cg::Scope) { - let mut groups: Vec<_> = self.groups.iter().collect(); - - groups.sort_by_key(|&(n,_)| n); - for (&name, group) in groups { - let mut module = &mut scope.get_or_new_module(self.namespaces.get_module_name(name)); - module.vis("pub"); - module.scope().raw("use super::*;"); - let (mod_name, struct_name) = name.as_tuple(); - self.gen_group_or_sequence(module, struct_name, &vec![group]); - } - } - - fn gen_group_or_sequence(&self, module: &mut cg::Module, struct_name: &'input str, items: &Vec<&RichType<'input>>) { - let mut impl_code = Vec::new(); - let struct_name = escape_keyword(&struct_name.to_camel_case()); - impl_code.push(format!("impl_group_or_sequence!({},", struct_name)); - { - let mut struct_ = module.new_struct(&struct_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); - let mut name_gen = NameGenerator::new(); - let writer = &mut |name: &str, type_mod_name: &str, min_occurs, max_occurs, type_name: &str| { - let name = escape_keyword(&name_gen.gen_name(name.to_snake_case())); - let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); - let type_name = escape_keyword(&type_name.to_camel_case()); - match (min_occurs, max_occurs) { - (1, 1) => { - struct_.field(&name, &format!("super::{}::{}<'input>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, {}),", name, type_mod_name, type_name)) - }, - (0, 1) => { - struct_.field(&name, &format!("Option>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, Option<{}>),", name, type_mod_name, type_name)) - }, - (_, _) => { - struct_.field(&name, &format!("Vec>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, Vec<{}>),", name, type_mod_name, type_name)) - }, - } - }; - for item in items { - self.write_type_in_struct_def(writer, item); - } - } - impl_code.push(");".to_string()); - module.scope().raw(&impl_code.join("\n")); - } - - fn gen_elements(&mut self, scope: &mut cg::Scope) { - let mut elements: Vec<_> = self.elements.iter().collect(); - - elements.sort_by_key(|&(n,_)| n); - for (&name, element) in elements { - let mut module = &mut scope.get_or_new_module(self.namespaces.get_module_name(name)); - module.vis("pub"); - module.scope().raw("use super::*;"); - self.gen_element(module, name, element); - } - } - - fn gen_element(&self, module: &mut cg::Module, name: FullName<'input>, type_: &RichType<'input>) { - let mut impl_code = Vec::new(); - let (mod_name, tag_name) = name.as_tuple(); - let struct_name = escape_keyword(&tag_name.to_camel_case()); - let mut can_be_empty = true; - impl_code.push(format!("impl_element!({}, \"{}\", {{", struct_name, tag_name)); - { - let mut struct_ = module.new_struct(&struct_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); - struct_.field("ATTRS", "HashMap, &'input str>"); - let mut name_gen = NameGenerator::new(); - let writer = &mut |name: &str, type_mod_name: &str, min_occurs, max_occurs, type_name: &str| { - let name = escape_keyword(&name_gen.gen_name(name.to_snake_case())); - let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); - let type_name = escape_keyword(&type_name.to_camel_case()); - match (min_occurs, max_occurs) { - (1, 1) => { - can_be_empty = false; // TODO: what if all subelements can be empty? - struct_.field(&name, &format!("super::{}::{}<'input>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, {}),", name, type_mod_name, type_name)) - }, - (0, 1) => { - struct_.field(&name, &format!("Option>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, Option<{}>),", name, type_mod_name, type_name)) - }, - (0, _) => { - struct_.field(&name, &format!("Vec>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, Vec<{}>),", name, type_mod_name, type_name)) - }, - (_, _) => { - can_be_empty = false; // TODO: what if all subelements can be empty? - struct_.field(&name, &format!("Vec>", type_mod_name, type_name)); - impl_code.push(format!(" ({}, {}, Vec<{}>),", name, type_mod_name, type_name)) - }, - } - }; - self.write_type_in_struct_def(writer, type_); - } - impl_code.push(format!("}}, can_be_empty={:?});", can_be_empty)); - module.scope().raw(&impl_code.join("\n")); - } - - fn write_type_in_struct_def<'a, F>(&'a self, mut writer: &mut F, rich_type: &'a RichType<'input>) - where F: FnMut(&'a str, &'a str, usize, usize, &'a str), 'ast: 'a { - let RichType { name_hint, type_ } = rich_type; - match &type_ { - Type::Alias(name) => { - let target_type = self.types.get(name).unwrap(); - self.write_type_in_struct_def(writer, target_type) - }, - Type::Sequence(1, 1, name) => { // shortcut, and a lot more readable - let items = self.sequences.get(name).unwrap(); - for item in items { - self.write_type_in_struct_def(writer, item) - } - } - Type::Sequence(min_occurs, max_occurs, name) => { - writer("sequence", "sequences", *min_occurs, *max_occurs, name); - } - Type::Group(min_occurs, max_occurs, name) | - Type::Element(min_occurs, max_occurs, name) => { - let (mod_name, type_name) = name.as_tuple(); - let field_name = type_name; - let mod_name = self.namespaces.module_names.get(mod_name).expect(mod_name); - writer(field_name, mod_name, *min_occurs, *max_occurs, type_name); - }, - Type::Choice(min_occurs, max_occurs, ref name) => { - writer("choice", "enums", *min_occurs, *max_occurs, name); - }, - Type::Extension(base, ext_type) => { - let base_type = &self.types.get(base).unwrap(); - self.write_type_in_struct_def(writer, base_type); - self.write_type_in_struct_def(writer, ext_type); - }, - Type::Any => (), - _ => unimplemented!("writing {:?}", type_), - } - } -} diff --git a/src/round0_parser.rs b/src/round0_parser.rs deleted file mode 100644 index 3eaf3d2..0000000 --- a/src/round0_parser.rs +++ /dev/null @@ -1,1092 +0,0 @@ -use std::marker::PhantomData; -use std::collections::HashMap; -use std::num::ParseIntError; - -use codegen; -use xmlparser::{Token, Tokenizer, Error, StrSpan, ElementEnd}; - -use support::QName; - -#[derive(Debug, PartialEq)] -pub struct Document<'a> { - pub version: Option<&'a str>, - pub encoding: Option<&'a str>, - pub standalone: Option<&'a str>, - pub schema: Option>, -} - -#[derive(Debug, PartialEq)] -pub struct Schema<'a> { - pub target_namespace: &'a str, - pub namespaces: HashMap, - pub elements: HashMap, Element<'a>>, - pub types: HashMap, Option, Vec>, bool, bool, ElementType<'a>)>, // (min_occurs, max_occurs, attrs, mixed, type_) - pub groups: HashMap, Option, Vec>, Option>)>, - pub substitution_groups: HashMap>, -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct Element<'a> { - pub name: QName<'a>, - pub attrs: Vec>, - pub mixed: bool, - pub type_: Option>, // XXX is sometimes None, something about abstract elements facets blah blah blah? - pub min_occurs: Option, - pub max_occurs: Option, - pub abstract_: bool, -} -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum ElementType<'a> { - String, - Date, - Sequence(Vec<(Option, Option, ElementType<'a>)>), - Ref(QName<'a>), - Custom(QName<'a>), - Extension(QName<'a>, Vec<(Option, Option, ElementType<'a>)>), - GroupRef(QName<'a>), - Choice(Vec<(Option, Option, ElementType<'a>)>), - Union(Option>>, Option, Option, ElementType<'a>)>>), - List(List<'a>), - Element(Box>), -} -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum List<'a> { - ComplexList(Option, Option, bool, Box>), // (mixed, inner_type) - SimpleList(QName<'a>), -} -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum Attribute<'a> { - Def { - name: &'a str, - type_: Option>, - default: Option<&'a str>, - }, - Ref(QName<'a>), - GroupRef(QName<'a>), - Any, -} - -fn parse_max_occurs(s: &str) -> Result { - if s == "unbounded" { - Ok(usize::max_value()) - } - else { - s.parse() - } -} - -struct SchemaParseContext<'input> { - main_namespace: &'input str, - substitution_groups: HashMap>, -} - -pub(crate) struct Parser(PhantomData); - -impl<'a, S: Iterator, Error>>> Parser { // To avoid that boilerplate on each function - -fn parse_attributes(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str), mut predicate: P) - -> Result, E> - where P: FnMut(&'a str, &'a str, &'a str) -> Result<(), E> { - loop { - let token = stream.next().expect("Unexpected end while parsing attributes"); - match token { - Ok(Token::Whitespaces(_)) => (), - Ok(Token::Comment(_)) => (), - Ok(Token::Attribute((prefix, local), value)) => predicate(prefix.to_str(), local.to_str(), value.to_str())?, - Ok(Token::ElementEnd(end)) => return Ok(end), - _ => panic!(format!("Unexpected token while parsing attribute in <{}:{}: {:?}", closing_tag.0, closing_tag.1, token)), - } - } -} - - -pub(crate) fn parse_document(stream: &mut S) -> Document<'a> { - let mut root = Document { version: None, encoding: None, standalone: None, schema: None }; - - loop { - let token = stream.next(); - match token { - None => break, - Some(token) => { - match token { - Ok(Token::Whitespaces(_)) => (), - Ok(Token::Comment(_)) => (), - Ok(Token::Declaration(version, encoding, standalone)) => { - assert_eq!(root.version, None); - assert_eq!(version.to_str(), "1.0"); - root.version = Some(version.to_str()); - root.encoding = encoding.map(|s| s.to_str()); - root.standalone = standalone.map(|s| s.to_str()); - }, - Ok(Token::ElementStart(prefix, local)) => { - assert_eq!(local.to_str(), "schema"); - let main_namespace = prefix.to_str(); - let substitution_groups = HashMap::new(); - let mut context = SchemaParseContext { main_namespace, substitution_groups }; - let mut schema = Self::parse_schema(stream, &mut context, (prefix.to_str(), local.to_str())); - schema.substitution_groups = context.substitution_groups; - root.schema = Some(schema); - }, - Ok(Token::DtdStart(_, _)) => (), - Ok(Token::DtdEnd) => (), - _ => panic!(format!("Unexpected token at root: {:?}", token)), - } - } - } - } - - root -} - -fn parse_annotation(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) { - Self::eat_block(stream, context, closing_tag) // TODO -} -fn eat_block(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) { - let mut stack = vec![closing_tag]; - - while stack.len() > 0 { - let token = stream.next().unwrap(); - match token { - Ok(Token::ElementStart(start, end)) => stack.push((start.to_str(), end.to_str())), - Ok(Token::ElementEnd(ElementEnd::Empty)) => { stack.pop(); () }, - Ok(Token::ElementEnd(ElementEnd::Close(start, end))) => { - let expected_tag = stack.pop().unwrap(); // unwrap can't panic, loop invariant - assert_eq!((start.to_str(), end.to_str()), expected_tag); - () - } - Ok(_) => (), - Err(e) => panic!(format!("{:?}", e)), - } - } -} - -fn parse_schema(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> Schema<'a> { - let mut namespaces = HashMap::new(); - let mut target_namespace = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value: &str| { - match (prefix, local) { - ("xmlns", local) => { - namespaces.insert(local.to_string(), value); - Ok(()) - }, - ("", "elementFormDefault") => Ok(()), // TODO - ("", "targetNamespace") => { - assert_eq!(target_namespace, None); - target_namespace = Some(value); - Ok(()) - }, - ("", "version") => Ok(()), // TODO - ("xml", "lang") => Ok(()), // TODO - _ => Err(format!("Unexpected token while parsing attribute in <{}:{}: {}:{}=\"{}\"", closing_tag.0, closing_tag.1, prefix, local, value)) - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open)); - - let mut schema = Schema { - namespaces: namespaces, - elements: HashMap::new(), - types: HashMap::new(), - groups: HashMap::new(), - substitution_groups: HashMap::new(), - target_namespace: target_namespace.expect("Missing targetNamespace"), - }; - - let main_namespace_uri = schema.namespaces.get(context.main_namespace).unwrap().clone(); - assert_eq!(main_namespace_uri, "http://www.w3.org/2001/XMLSchema"); - - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - match local { - "element" if prefix == context.main_namespace => { - let element = Self::parse_root_element(stream2, context, (prefix, local)); - assert_eq!(None, schema.elements.get(&element.name)); - schema.elements.insert(element.name, element); - Ok(()) - }, - "annotation" if prefix == context.main_namespace => { - Self::parse_annotation(stream2, context, (prefix, local)); - Ok(()) - } - "complexType" if prefix == context.main_namespace => { - let (min_occurs, max_occurs, name, attrs, mixed, abstract_, def) = Self::parse_complex_type(stream2, context, (prefix, local)); - let name = name.unwrap(); - assert_eq!(schema.types.get(name), None); - schema.types.insert(name.to_string(), (min_occurs, max_occurs, attrs, mixed, abstract_, def)); - Ok(()) - }, - "simpleType" if prefix == context.main_namespace => { - let (min_occurs, max_occurs, name, attrs, def) = Self::parse_simple_type(stream2, context, (prefix, local)); - let name = name.unwrap(); - assert_eq!(schema.types.get(name), None); - schema.types.insert(name.to_string(), (min_occurs, max_occurs, attrs, false, false, def)); - Ok(()) - }, - "group" if prefix == context.main_namespace => { - let (min_occurs, max_occurs, name, attrs, def) = Self::parse_group_def(stream2, context, (prefix, local)); - assert_eq!(schema.groups.get(name), None); - schema.groups.insert(name.to_string(), (min_occurs, max_occurs, attrs, Some(def))); - Ok(()) - }, - "attributeGroup" if prefix == context.main_namespace => { - let (min_occurs, max_occurs, name, attrs) = Self::parse_attribute_group_def(stream2, context, (prefix, local)); - assert_eq!(schema.groups.get(name), None); - schema.groups.insert(name.to_string(), (min_occurs, max_occurs, attrs, None)); - Ok(()) - }, - "import" if prefix == context.main_namespace => { - Self::eat_block(stream2, context, (prefix, local)); // TODO - Ok(()) - } - "notation" if prefix == context.main_namespace => { - Self::eat_block(stream2, context, (prefix, local)); // TODO - Ok(()) - } - _ => Err(format!("Unexpected tag while parsing schema elements: <{}:{}", prefix, local)), - } - }).unwrap(); - - schema -} -fn parse_children(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str), mut predicate: P) - -> Result<(), E> - where P: FnMut(&mut S, &mut SchemaParseContext, &'a str, &'a str) -> Result<(), E> { - loop { - let token = stream.next().expect("Unexpected end while parsing attributes"); - match token { - Ok(Token::Whitespaces(_)) => (), - Ok(Token::Comment(_)) => (), - Ok(Token::ElementStart(prefix, local)) => predicate(stream, context, prefix.to_str(), local.to_str())?, - Ok(Token::ElementEnd(ElementEnd::Close(prefix, local))) if (prefix.to_str(), local.to_str()) == closing_tag => return Ok(()), - _ => panic!(format!("Unexpected token while parsing <{}:{}'s children: {:?}", closing_tag.0, closing_tag.1, token)), - } - } -} - -fn parse_root_element(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> Element<'a> { - let mut name = None; - let mut type_ = None; - let mut attrs = None; - let mut min_occurs = None; - let mut max_occurs = None; - let mut substitution_group_head = None; - let mut abstract_ = false; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value: &str| - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(QName::from(value)); - Ok(()) - }, - ("", "type") => { - assert_eq!(type_, None); - let id = QName::from(value); - // TODO: handle namespace - type_ = Some(match id.1 { - "string" => ElementType::String, - "date" => ElementType::Date, - _ => ElementType::Custom(id), - }); - Ok(()) - }, - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - ("", "id") => Ok(()), // TODO - ("", "abstract") => Ok(()), // TODO - ("", "substitutionGroup") => { - assert_eq!(substitution_group_head, None); - substitution_group_head = Some(QName::from(value)); - Ok(()) - }, - _ => Err(format!("Unexpected attribute while parsing element: <{}:{}: {}:{}={:?}", closing_tag.0, closing_tag.1, prefix, local, value)) - } - ).unwrap(); - - let (min_occurs, max_occurs, type_, mixed, attrs) = if let ElementEnd::Open = element_end { - let (new_min_occurs, new_max_occurs, newtype, mixed, newattrs) = Self::parse_subelement(stream, context, closing_tag); - let (min_occurs, max_occurs, type_) = match (type_, newtype) { - (Some(t), None) => (min_occurs, max_occurs, Some(t)), - (None, Some(t)) => (new_min_occurs, new_max_occurs, Some(t)), - (None, None) => (min_occurs, max_occurs, None), - (t1, t2) => panic!(format!("Conflict {:?} {:?} {:?}", name, t1, t2)), - }; - let attrs = match (attrs, newattrs) { - (Some(a), None) => a, - (None, Some(a)) => a, - (None, None) => Vec::new(), - _ => panic!("Conflict"), - }; - (min_occurs, max_occurs, type_, mixed, attrs) - } - else { - let type_ = type_.expect(&format!("Element {:?} has no type", name)); - (min_occurs, max_occurs, Some(type_), false, Vec::new()) - }; - - let name = name.expect(&format!("{:?}", type_)); - if let Some(head) = substitution_group_head { - if None == context.substitution_groups.get(head.1) { - context.substitution_groups.insert(head.1.to_string(), Vec::new()); // TODO: namespace - } - context.substitution_groups.get_mut(head.1).unwrap().push(name.1.to_string()); // TODO: namespace - } - - Element { name, attrs, mixed, type_, min_occurs, max_occurs, abstract_ } -} - -fn parse_element(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, ElementType<'a>) { - let mut name = None; - let mut type_ = None; - let mut attrs = None; - let mut min_occurs = None; - let mut max_occurs = None; - let mut abstract_ = false; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value: &str| - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(QName::from(value)); - Ok(()) - }, - ("", "type") => { - assert_eq!(type_, None); - let id = QName::from(value); - // TODO: handle namespace - type_ = Some(match id.1 { - "string" => ElementType::String, - "date" => ElementType::Date, - _ => ElementType::Custom(id), - }); - Ok(()) - }, - ("", "ref") => { - assert_eq!(type_, None); - type_ = Some(ElementType::Ref(QName::from(value))); - assert_eq!(name, None); - Ok(()) - } - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - ("", "id") => Ok(()), // TODO - ("", "abstract") => { - abstract_ = true; - Ok(()) - }, - ("", "substitutionGroup") => Ok(()), // TODO - _ => Err(format!("Unexpected attribute while parsing element: <{}:{}: {:?}", closing_tag.0, closing_tag.1, local)) - } - ).unwrap(); - - let (min_occurs, max_occurs, type_, mixed, attrs) = if let ElementEnd::Open = element_end { - let (new_min_occurs, new_max_occurs, newtype, mixed, newattrs) = Self::parse_subelement(stream, context, closing_tag); - let (min_occurs, max_occurs, type_) = match (type_, newtype) { - (Some(t), None) => (min_occurs, max_occurs, Some(t)), - (None, Some(t)) => (new_min_occurs, new_max_occurs, Some(t)), - (None, None) => (min_occurs, max_occurs, None), - (t1, t2) => panic!(format!("Conflict {:?} {:?} {:?}", name, t1, t2)), - }; - let attrs = match (attrs, newattrs) { - (Some(a), None) => a, - (None, Some(a)) => a, - (None, None) => Vec::new(), - _ => panic!("Conflict"), - }; - (min_occurs, max_occurs, type_, mixed, attrs) - } - else { - let type_ = type_.expect(&format!("Element {:?} has no type", name)); - (min_occurs, max_occurs, Some(type_), false, Vec::new()) - }; - - match name { - Some(name) => (min_occurs, max_occurs, ElementType::Element(Box::new(Element { name, attrs, mixed, type_, min_occurs, max_occurs, abstract_ }))), - None => (min_occurs, max_occurs, type_.unwrap()), - } -} - -fn parse_subelement(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Option>, bool, Option>>) { - let mut type_ = None; - let mut attrs = None; - let mut mixed = None; - let mut min_occurs = None; - let mut max_occurs = None; - let mut abstract_ = false; - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - assert_eq!(prefix, context.main_namespace); - match local { - "complexType" => { - assert_eq!(type_, None); - assert_eq!(attrs, None); - assert_eq!(mixed, None); - assert_eq!(min_occurs, None); - assert_eq!(max_occurs, None); - let (min, max, name, attrs_def, newmixed, abs, def) = Self::parse_complex_type(stream2, context, (prefix, local)); - assert_eq!(name, None); - type_ = Some(def); - attrs = Some(attrs_def); - mixed = Some(newmixed); - min_occurs = Some(min); - max_occurs = Some(max); - abstract_ = abs; - Ok(()) - }, - "simpleType" => { - assert_eq!(type_, None); - assert_eq!(attrs, None); - assert_eq!(min_occurs, None); - assert_eq!(max_occurs, None); - let (min, max, name, attrs_def, def) = Self::parse_simple_type(stream2, context, (prefix, local)); - assert_eq!(name, None); - type_ = Some(def); - attrs = Some(attrs_def); - min_occurs = Some(min); - max_occurs = Some(max); - Ok(()) - }, - "annotation" => { - Self::parse_annotation(stream2, context, (prefix, local)); - Ok(()) - }, - "key" => { - Self::eat_block(stream2, context, (prefix, local)); // TODO - Ok(()) - }, - _ => Err(format!("Unknown element type: {}:{}", prefix, local)), - } - }).unwrap(); - - (min_occurs.unwrap_or(None), max_occurs.unwrap_or(None), type_, mixed.unwrap_or(false), attrs) -} - - -fn parse_complex_type(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Option<&'a str>, Vec>, bool, bool, ElementType<'a>) { - let mut name = None; - let mut mixed = None; - let mut abstract_ = false; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(value); - Ok(()) - }, - ("", "mixed") => { - assert_eq!(mixed, None); - mixed = Some(value); - Ok(()) - } - ("", "abstract") => { - abstract_ = true; - Ok(()) - }, - _ => Err(format!("Unknown attribute for complexType: {:?}", (prefix, local, name))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open)); - let (min_occurs, max_occurs, attributes, type_) = Self::parse_subtype(stream, context, closing_tag).unwrap(); - let mixed = match mixed { None | Some("false") => false, Some("true") => true, _ => panic!(format!("{:?}", mixed)) }; - (min_occurs, max_occurs, name, attributes, mixed, abstract_, type_.expect("complexType has no subtype.")) -} - -fn parse_attribute_group_def(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, &'a str, Vec>) { - let mut name = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(value); - Ok(()) - }, - _ => Err(format!("Unknown attribute for group definition: {:?}", (prefix, local, name))), - } - }); - - assert_eq!(element_end, Ok(ElementEnd::Open)); - let (min_occurs, max_occurs, attrs, items) = Self::parse_subtype(stream, context, closing_tag).unwrap(); - let name = name.expect("AttributeGroup def has no name"); - assert_eq!(items, None); - (min_occurs, max_occurs, name, attrs) -} - -fn parse_attribute_group_ref(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> QName<'a> { - let mut ref_ = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "ref") => { - assert_eq!(ref_, None); - ref_ = Some(QName::from(value)); - Ok(()) - }, - ("", "minOccurs") => Ok(()), // TODO - ("", "maxOccurs") => Ok(()), // TODO - _ => Err(format!("Unknown attribute for group reference: {:?}", (prefix, local, ref_))), - } - }); - - assert_eq!(element_end, Ok(ElementEnd::Empty)); - ref_.expect("AttributeGroup ref has no name") -} - -fn parse_group_def(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, &'a str, Vec>, ElementType<'a>) { - let mut name = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(value); - Ok(()) - }, - _ => Err(format!("Unknown attribute for group definition: {:?}", (prefix, local, name))), - } - }); - - assert_eq!(element_end, Ok(ElementEnd::Open)); - let (min_occurs, max_occurs, attrs, items) = Self::parse_subtype(stream, context, closing_tag).unwrap(); - let name = name.expect("Group def has no name"); - (min_occurs, max_occurs, name, attrs, items.expect("Missing inner element type")) -} - -fn parse_group_ref(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut ref_ = None; - let mut min_occurs = None; - let mut max_occurs = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "ref") => { - assert_eq!(ref_, None); - ref_ = Some(QName::from(value)); - Ok(()) - }, - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for group reference: {:?}", (prefix, local, ref_))), - } - }); - - assert_eq!(element_end, Ok(ElementEnd::Empty)); - let ref_ = ref_.expect("Group ref has no name"); - (min_occurs, max_occurs, Vec::new(), ElementType::GroupRef(ref_)) -} - -fn parse_subtype(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> Result<(Option, Option, Vec>, Option>), String> { - let mut inner: Option<(Option, Option, Vec, ElementType)> = None; - let mut attributes = Vec::new(); - - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - assert_eq!(prefix, context.main_namespace); - match local { - "annotation" => { - Self::parse_annotation(stream2, context, (prefix, local)); - Ok(()) - } - "sequence" => { - assert_eq!(inner, None); - inner = Some(Self::parse_sequence(stream2, context, (prefix, local))); - Ok(()) - } - "choice" => { - assert_eq!(inner, None); - inner = Some(Self::parse_choice(stream2, context, (prefix, local))); - Ok(()) - } - "group" => { - assert_eq!(inner, None); - inner = Some(Self::parse_group_ref(stream2, context, (prefix, local))); - Ok(()) - } - "attributeGroup" => { - attributes.push(Attribute::GroupRef(Self::parse_attribute_group_ref(stream2, context, (prefix, local)))); - Ok(()) - } - "complexContent" => { - assert_eq!(inner, None); - inner = Some(Self::parse_complex_content(stream2, context, (prefix, local))); - Ok(()) - } - "attribute" => { - attributes.push(Self::parse_attribute(stream2, context, (prefix, local))); - Ok(()) - } - "anyAttribute" => { - attributes.push(Self::parse_any_attribute(stream2, context, (prefix, local))); - Ok(()) - } - _ => Err(format!("Unknown subtype: {}:{}", prefix, local)), - } - })?; - - match inner { - Some((min_occurs, max_occurs, attrs, type_)) => { - if attrs.len() > 0 { - assert_eq!(attributes, Vec::new(), "{:?}", type_); - Ok((min_occurs, max_occurs, attrs, Some(type_))) - } - else { - Ok((min_occurs, max_occurs, attributes, Some(type_))) - } - }, - None => Ok((None, None, attributes, None)), - } -} - -fn parse_elements(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Vec>, Vec<(Option, Option, ElementType<'a>)>) { - let mut items = Vec::new(); - let mut attrs = Vec::new(); - - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - assert_eq!(prefix, context.main_namespace); - match local { - "element" => { - items.push(Self::parse_element(stream2, context, (prefix, local))); - Ok(()) - }, - "group" => { - let (min_occurs, max_occurs, a, type_) = Self::parse_group_ref(stream2, context, (prefix, local)); - items.push((min_occurs, max_occurs, type_)); - attrs.extend(a); - Ok(()) - }, - "simpleType" => { - let (min_occurs, max_occurs, name, attrs, type_) = Self::parse_simple_type(stream2, context, (prefix, local)); - let abstract_ = false; // TODO - match name { - Some(name) => items.push((None, None, ElementType::Element(Box::new(Element { name: QName::from(name), attrs, mixed: false, type_: Some(type_), min_occurs, max_occurs, abstract_ })))), - None => items.push((min_occurs, max_occurs, type_)), - } - Ok(()) - }, - "sequence" => { - let (min_occurs, max_occurs, a, type_) = Self::parse_sequence(stream2, context, (prefix, local)); - items.push((min_occurs, max_occurs, type_)); - attrs.extend(a); - Ok(()) - }, - "choice" => { - let (min_occurs, max_occurs, a, type_) = Self::parse_choice(stream2, context, (prefix, local)); - items.push((min_occurs, max_occurs, type_)); - attrs.extend(a); - Ok(()) - } - "extension" => { - let (min_occurs, max_occurs, a, type_) = Self::parse_extension(stream2, context, (prefix, local)); - items.push((min_occurs, max_occurs, type_)); - Ok(()) - }, - "any" => { - let (min_occurs, max_occurs, a, type_) = Self::parse_any(stream2, context, (prefix, local)); - items.push((min_occurs, max_occurs, type_)); - attrs.extend(a); - Ok(()) - }, - "attribute" => { - attrs.push(Self::parse_attribute(stream2, context, (prefix, local))); - Ok(()) - } - "attributeGroup" => { - attrs.push(Self::parse_attribute(stream2, context, (prefix, local))); - Ok(()) - } - "annotation" => { - Self::parse_annotation(stream2, context, (prefix, local)); - Ok(()) - }, - _ => Err(format!("Unknown tag in sequence: {}:{}", prefix, local)), - } - }).unwrap(); - - (attrs, items) -} - -fn parse_sequence(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut min_occurs = None; - let mut max_occurs = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for sequence: {:?}", (prefix, local, value))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open)); - - let (attrs, items) = Self::parse_elements(stream, context, closing_tag); - - (min_occurs, max_occurs, attrs, ElementType::Sequence(items)) -} - -fn parse_choice(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut min_occurs = None; - let mut max_occurs = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for choice: {:?}", (prefix, local, value))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open), "{:?}", closing_tag); - - let (attrs, mut items) = Self::parse_elements(stream, context, closing_tag); - - (min_occurs, max_occurs, attrs, ElementType::Choice(items)) -} - -fn parse_extension(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut base = None; - let mut min_occurs: Option = None; - let mut max_occurs: Option = None; - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "base") => { - assert_eq!(base, None); - base = Some(value); - Ok(()) - }, - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for complexType: {:?}", (prefix, local, value))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open)); - let (attrs, items) = Self::parse_elements(stream, context, closing_tag); - (min_occurs, max_occurs, attrs, ElementType::Extension(QName::from(base.expect("Extension has no base.")), items)) -} - -fn parse_any(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut min_occurs = None; - let mut max_occurs = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "processContents") => Ok(()), // TODO - ("", "namespace") => Ok(()), // TODO - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for any: {:?}", (prefix, local, value))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Empty)); - (min_occurs, max_occurs, Vec::new(), ElementType::Ref(QName(None, "any"))) -} - -fn parse_complex_content(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Vec>, ElementType<'a>) { - let mut type_ = None; - let mut min_occurs = None; - let mut max_occurs = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |_, _, _| Err(())); - assert_eq!(element_end, Ok(ElementEnd::Open)); - - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - assert_eq!(prefix, context.main_namespace); - match local { - "restriction" => { - assert_eq!(type_, None); - let (min, max, t) = Self::parse_restriction(stream2, context, (prefix, local)); - min_occurs = min; - max_occurs = max; - type_ = Some(t); - Ok(()) - }, - "extension" => { - assert_eq!(type_, None); - let (min, max, a, t) = Self::parse_extension(stream2, context, (prefix, local)); - min_occurs = min; - max_occurs = max; - type_ = Some(t); - Ok(()) - }, - _ => Err(format!("Unknown tag in complexContent: {}:{}", prefix, local)), - } - }).unwrap(); - - (min_occurs, max_occurs, Vec::new(), type_.expect("Empty complexContent")) -} - -fn parse_attribute(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> Attribute<'a> { - let mut name = None; - let mut type_ = None; - let mut default = None; - let mut ref_ = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "name") => { - assert_eq!(name, None); - name = Some(value); - Ok(()) - }, - ("", "type") => { - assert_eq!(type_, None); - type_ = Some(QName::from(value)); - Ok(()) - }, - ("", "fixed") => Ok(()), // TODO - ("", "use") => Ok(()), // TODO - ("", "default") => { - assert_eq!(default, None); - default = Some(value); - Ok(()) - }, - ("", "ref") => { - assert_eq!(ref_, None); - ref_ = Some(QName::from(value)); - Ok(()) - }, - _ => Err(format!("Unknown attribute for <{}:{}: {}:{}=\"{}\"", closing_tag.0, closing_tag.1, prefix, local, value)), - } - }); - - match (&element_end, ref_) { - (&Ok(ElementEnd::Empty), Some(ref_)) => { - assert_eq!(name, None); - assert_eq!(type_, None); - Attribute::Ref(ref_) - }, - (&Ok(ElementEnd::Empty), None) => { - let name = name.expect("Attribute has no name."); - Attribute::Def { name, type_: type_.map(ElementType::Ref), default } - }, - (&Ok(ElementEnd::Open), None) => { - let name = name.expect("Attribute has no name."); - let (min_occurs, max_occurs, newtype, mixed, attrs) = Self::parse_subelement(stream, context, closing_tag); - assert_eq!(mixed, false); - assert_eq!(min_occurs, None); - assert_eq!(max_occurs, None); - let (attrs, type_) = match (type_, newtype) { - (Some(t), None) => { - assert_eq!(attrs, None); - (Vec::new(), ElementType::Ref(t)) - }, - (None, Some(t)) => (attrs.unwrap(), t), - _ => panic!("Conflict") - }; - Attribute::Def { name, type_: Some(type_), default } - }, - _ => panic!(format!("<{}:{} did not expect: {:?} {:?}", closing_tag.0, closing_tag.1, element_end, ref_)), - } -} - -fn parse_any_attribute(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> Attribute<'a> { - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "namespace") => Ok(()), // TODO - ("", "processContents") => Ok(()), // TODO - _ => Err(format!("Unknown attribute for <{}:{}: {}:{}=\"{}\"", closing_tag.0, closing_tag.1, prefix, local, value)), - } - }); - - assert_eq!(element_end, Ok(ElementEnd::Empty)); - - Attribute::Any -} - -fn parse_simple_type(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, Option<&'a str>, Vec>, ElementType<'a>) { - let mut type_ = None; - let mut name = None; - let mut min_occurs = None; - let mut max_occurs = None; - let mut attributes = Vec::new(); - - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "name") => { - name = Some(value); - Ok(()) - }, - _ => Err(format!("Unknown attribute for complexType: {:?}", (prefix, local, name))), - } - }); - assert_eq!(element_end, Ok(ElementEnd::Open)); - Self::parse_children(stream, context, closing_tag, |stream2, context, prefix, local| { - assert_eq!(prefix, context.main_namespace); - match local { - "restriction" => { - assert_eq!(type_, None); - let (min, max, t) = Self::parse_restriction(stream2, context, (prefix, local)); - min_occurs = min; - max_occurs = max; - type_ = Some(t); - Ok(()) - }, - "union" => { - assert_eq!(type_, None); - let (min, max, t) = Self::parse_union(stream2, context, (prefix, local)); - min_occurs = min; - max_occurs = max; - type_ = Some(t); - Ok(()) - } - "list" => { - assert_eq!(type_, None); - let (min, max, t) = Self::parse_list(stream2, context, (prefix, local)); - min_occurs = min; - max_occurs = max; - type_ = Some(t); - Ok(()) - } - "attribute" => { - attributes.push(Self::parse_attribute(stream2, context, (prefix, local))); - Ok(()) - }, - "annotation" => { - Self::parse_annotation(stream2, context, (prefix, local)); - Ok(()) - }, - _ => Err(format!("Unknown simpleType type: {}:{}", prefix, local)), - } - }).unwrap(); - - (min_occurs, max_occurs, name, attributes, type_.expect("Missing type for complexType")) -} - -fn parse_restriction(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, ElementType<'a>) { - let mut name = None; - let mut min_occurs = None; - let mut max_occurs = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "base") => { - assert_eq!(name, None); - name = Some(value); - Ok(()) - } - ("", "minOccurs") => { - assert_eq!(min_occurs, None); - min_occurs = Some(value.parse().unwrap()); - Ok(()) - } - ("", "maxOccurs") => { - assert_eq!(max_occurs, None); - max_occurs = Some(parse_max_occurs(value).unwrap()); - Ok(()) - } - _ => Err(format!("Unknown attribute for restriction: {:?}", (prefix, local, name))), - } - }); - - match element_end { - Ok(ElementEnd::Open) => Self::eat_block(stream, context, closing_tag), // TODO - Ok(ElementEnd::Empty) => (), // yeah, it happens sometimes - _ => panic!(format!("{:?}", element_end)), - } - - (min_occurs, max_occurs, ElementType::Custom(QName::from(name.unwrap()))) -} - -fn parse_union(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, ElementType<'a>) { - let mut member_types = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "memberTypes") => { - assert_eq!(member_types, None); - member_types = Some(value); - Ok(()) - } - _ => Err(format!("Unknown attribute for union: {:?}", (prefix, local, member_types))), - } - }); - - let (attrs, items) = match element_end { - Ok(ElementEnd::Empty) => (Vec::new(), None), - Ok(ElementEnd::Open) => { - let (attrs, items) = Self::parse_elements(stream, context, closing_tag); - (attrs, Some(items)) - }, - _ => panic!(format!("{:?}", element_end)), - }; - - let member_types = member_types.map(|s| s.split(" ").map(QName::from).collect()); - (None, None, ElementType::Union(member_types, items)) -} - -fn parse_list(stream: &mut S, context: &mut SchemaParseContext, closing_tag: (&str, &str)) -> (Option, Option, ElementType<'a>) { - let mut item_type = None; - let element_end = Self::parse_attributes(stream, context, closing_tag, |prefix, local, value| { - match (prefix, local) { - ("", "itemType") => { - assert_eq!(item_type, None); - item_type = Some(QName::from(value)); - Ok(()) - }, - _ => Err(format!("Unknown attribute for list: {:?}", (prefix, local, item_type))), - } - }); - if let Ok(ElementEnd::Open) = element_end { - assert_eq!(item_type, None); - let (min_occurs, max_occurs, newtype, mixed, newattrs) = Self::parse_subelement(stream, context, closing_tag); - assert!(newattrs == None || newattrs == Some(Vec::new())); - if let Some(type_) = newtype { - return (None, None, ElementType::List(List::ComplexList(min_occurs, max_occurs, mixed, Box::new(type_)))) - } - } - else { - assert_eq!(element_end, Ok(ElementEnd::Empty)); - } - - let item_type = item_type.unwrap(); - (None, None, ElementType::List(List::SimpleList(item_type))) -} - - -} diff --git a/src/round0_parser_generator.rs b/src/round0_parser_generator.rs deleted file mode 100644 index 5d6074e..0000000 --- a/src/round0_parser_generator.rs +++ /dev/null @@ -1,589 +0,0 @@ -use std::collections::HashMap; - -use codegen as cg; - -use round0_parser::*; -use support::QName; - -const KEYWORDS: &[&'static str] = &["override"]; -fn escape_keyword(name: &str) -> String { - if KEYWORDS.contains(&name) { - format!("{}_", name) - } - else { - name.to_string() - } -} - -pub const MACROS: &'static str = r#" -macro_rules! impl_parsexml_for_element { - ( $element_type:ident, $element_name:expr, $child_type:ident ) => { - impl<'input> ParseXml<'input> for $element_type<'input> { - const NODE_NAME: &'static str = "element (normal) $element_type"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - let tx = stream.transaction(); - let mut tok = stream.next().unwrap(); - loop { - match tok { - Token::Whitespaces(_) => (), - Token::Comment(_) => (), - Token::Text(_) => (), - _ => break, - } - tok = stream.next().unwrap(); - } - match tok { - Token::ElementStart(prefix, name) => { - if name.to_str() == $element_name { - let mut attrs = HashMap::new(); - loop { - let tok = stream.next().unwrap(); - match tok { - Token::Whitespaces(_) => (), - Token::Comment(_) => (), - Token::Text(_) => (), - Token::Attribute((key_prefix, key_local), value) => { - let key = QName(match key_prefix.to_str() { "" => None, s => Some(s) }, key_local.to_str()); - let old = attrs.insert(key, value.to_str()); assert_eq!(old, None) - }, - Token::ElementEnd(ElementEnd::Open) => { - let ret = Some($element_type { - attrs, - child: try_rollback!(stream, tx, $child_type::parse_xml(stream, parse_context, parent_context)), - }); - let mut next_tok; - loop { - next_tok = stream.next(); - match next_tok { - Some(Token::Whitespaces(_)) => (), - Some(Token::Comment(_)) => (), - Some(Token::Text(_)) => (), - Some(Token::ElementEnd(ElementEnd::Close(prefix2, name2))) => { - assert_eq!((prefix.to_str(), name.to_str()), (prefix2.to_str(), name2.to_str())); - return ret; - } - _ => panic!(format!("Did not expect token {:?}", next_tok)), - } - } - }, - Token::ElementEnd(ElementEnd::Empty) => - return Some($element_type { - attrs, - child: $child_type::default(), - }), - Token::ElementEnd(ElementEnd::Close(_, _)) => { - tx.rollback(stream); - return None - }, - _ => panic!(format!("Did not expect token {:?}", tok)), - } - } - } - else { - tx.rollback(stream); - None - } - }, - Token::ElementEnd(ElementEnd::Close(_, _)) => { - tx.rollback(stream); - return None - }, - _ => panic!(format!("Did not expect token {:?}", tok)), - } - } - } - } -} - -macro_rules! impl_parsexml_for_substitution { - ( $element_type:ident, $($variant_name:ident => $variant_type:ident,)* ) => { - impl<'input> ParseXml<'input> for $element_type<'input> { - const NODE_NAME: &'static str = "element (substitution group) $element_type"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - let tx = stream.transaction(); - let mut tok = stream.next().unwrap(); - loop { - match tok { - Token::Whitespaces(_) => (), - Token::Comment(_) => (), - Token::Text(_) => (), - _ => break, - } - tok = stream.next().unwrap(); - } - match tok { - Token::ElementStart(prefix, name) => { - tx.rollback(stream); - $( - match $variant_type::parse_xml(stream, parse_context, parent_context) { - Some(s) => return Some($element_type::$variant_name(s)), - None => (), - } - )* - None - } - Token::ElementEnd(ElementEnd::Close(_, _)) => { - tx.rollback(stream); - return None - }, - _ => panic!(format!("Did not expect token {:?}", tok)), - } - } - } - } -} - -"#; - - -#[derive(Debug)] -pub struct ParserGenerator<'a> { - //document: &'a Document<'a> - schema: &'a Schema<'a>, - target_uri: &'a str, - ns_to_uri: HashMap, - pub nsuri_to_module: HashMap<&'a str, (String, cg::Module)>, - generated_elements: HashMap, String>, - generated_types: HashMap, -} - -impl<'a> ParserGenerator<'a> { - pub fn new(document: &'a Document<'a>) -> ParserGenerator<'a> { - ParserGenerator { - schema: document.schema.as_ref().unwrap(), - target_uri: document.schema.as_ref().unwrap().target_namespace, - ns_to_uri: document.schema.as_ref().unwrap().namespaces.clone(), - nsuri_to_module: HashMap::new(), - generated_elements: HashMap::new(), - generated_types: HashMap::new(), - } - } - - /* - pub fn module(&mut self, uri: Option<&str>) -> &cg::Module { - match (uri, self.nsuri_to_module.get(uri.unwrap_or(self.target_uri))) { - (_, Some(m)) => return m, // We already did the work - (None, None) => (), - (Some(uri), None) if uri == self.target_uri => (), - (Some(uri), None) => panic!(format!("Reference to namespace URI {} but that URI is unknown.", uri)), - } - self.gen_unqual_module() - } - */ - - pub fn gen_unqual_module(&mut self) -> &mut (String, cg::Module) { - { - let mut module = cg::Module::new("UNQUAL"); - module.vis("pub"); - module.scope().raw("use std::collections::HashMap;"); - module.scope().raw("use std::marker::PhantomData;"); - module.scope().raw("use support::*;"); - module.scope().raw("use xmlparser::{Token, ElementEnd};"); - module.scope().raw("macro_rules! try_rollback { ($stream:expr, $tx:expr, $e:expr) => { match $e { Some(i) => i, None => { $tx.rollback($stream); return None } } } }"); - module.scope().raw("\n/////////// types\n"); - self.nsuri_to_module.insert(self.target_uri, ("UNQUAL".to_string(), module)); - } - let mut types: Vec<_> = self.schema.types.iter().collect(); - types.sort_by_key(|&(n,_)| n); - for (name, (min_occurs, max_occurs, attrs, mixed, abstract_, type_tree)) in types { - self.type_occurs(*min_occurs, *max_occurs, &name, &type_tree); - } - self.nsuri_to_module.get_mut(self.target_uri).unwrap().1.scope().raw("\n/////////// elements\n"); - let mut elements: Vec<_> = self.schema.elements.iter().collect(); - elements.sort_by_key(|&(n,_)| n); - for (i, (_name, element)) in elements.iter().enumerate() { - self.element(&element, None); - } - self.nsuri_to_module.get_mut(self.target_uri).unwrap().1.scope().raw("\n/////////// groups\n"); - let mut groups: Vec<_> = self.schema.groups.iter().collect(); - groups.sort_by_key(|&(n,_)| n); - for (name, (min_occurs, max_occurs, attrs, type_tree)) in groups.iter() { - match type_tree { - Some(tt) => { self.type_occurs(*min_occurs, *max_occurs, &name, &tt); }, - None => { self.empty_type(&name); }, - }; - } - self.nsuri_to_module.get_mut(self.target_uri).unwrap() // Won't panic because we inserted it before. - } - - fn id_to_type_name(&self, id: QName) -> String { - match id.0 { - None => id.1.to_string(), - Some(ns) => { - let uri = self.ns_to_uri.get(ns).expect(&format!("Unknown namespace: {:?}", ns)); - let (module_name, _) = self.nsuri_to_module.get(uri).expect("ref to unknown ns URI"); - format!("super::{}::{}", escape_keyword(module_name), escape_keyword(id.1)) - } - } - } - - fn empty_type(&mut self, name: &str) -> String { - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.new_struct(name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field("PhantomData<&'input ()>"); - name.to_string() - } - - fn element(&mut self, element: &Element<'a>, name_override: Option<&str>) -> String { - if let Some(name) = self.generated_elements.get(&element.name) { - return name.to_string(); - } - let Element { name, attrs, mixed, type_, min_occurs, max_occurs, abstract_ } = element; - let type_name = name_override.unwrap_or(name.1); - let type_name = format!("{}_e", type_name); - let uri = match name.0 { - Some(prefix) => self.ns_to_uri.get(prefix).unwrap(), - None => self.target_uri.clone(), - }; - - let (real_name, type_name) = if let Some(substitutes) = self.schema.substitution_groups.get(name.1) { - if substitutes.len() > 0 { - let (_, ref mut module) = self.nsuri_to_module.get_mut(uri).unwrap(); - let (real_name, type_name, default_impl) = { - let mut e = module.new_enum(&type_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); - let mut last_item_name = None; - for substitute in substitutes.iter() { - e.new_variant(substitute).tuple(&format!("{}_e<'input>", substitute)); - last_item_name = Some(substitute.clone()) - } - let last_item_name = last_item_name.unwrap(); - let real_name = type_name.clone(); - let type_name = format!("{}_self", type_name); - let default_impl = format!("impl<'input> Default for {}<'input> {{ fn default() -> {}<'input> {{ {}::{}(Default::default()) }} }}", real_name, real_name, real_name, last_item_name ); // TODO: remove this, that's a temporary hack - (real_name, type_name, default_impl) - }; - module.scope().raw(&format!(r#"impl_parsexml_for_substitution!({}, "#, real_name)); - for substitute in substitutes.iter() { - module.scope().raw(&format!(r#"{} => {}_e,"#, substitute, substitute)); - } - module.scope().raw(&format!(r#");"#)); - module.scope().raw(&default_impl); - (real_name, type_name) - } - else { - (type_name.clone(), type_name) - } - } - else { - (type_name.clone(), type_name) - }; - - - match type_ { - Some(type_) => { - let (_, inner_type_name) = self.type_occurs(*min_occurs, *max_occurs, &format!("{}_inner", type_name), type_); - - - let (_, ref mut module) = self.nsuri_to_module.get_mut(uri).unwrap(); - { - let mut s = module.new_struct(&type_name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").field("pub attrs", &format!("HashMap, &'input str>")).field("pub child", &format!("{}<'input>", inner_type_name)); - } - module.scope().raw(&format!("// ^-- from {:?}", element)); - module.scope().raw(&format!(r#"impl_parsexml_for_element!({}, {:?}, {});"#, - type_name, name.1, inner_type_name)); - } - None => { - let (_, ref mut module) = self.nsuri_to_module.get_mut(uri).unwrap(); - module.new_struct(&type_name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field("PhantomData<&'input ()>"); - module.scope().raw(&format!("// ^-- from {:?}", element)); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "element (empty) {}"; - fn parse_self_xml(stream: &mut Stream<'input>, _parse_context: &mut TParseContext, _parent_context: &TParentContext) -> Option {{ - Some({}(Default::default())) - }} -}}"#, type_name, type_name, type_name)); - } - } - self.generated_elements.insert(element.name, real_name.clone()); - real_name - } - - fn type_occurs(&mut self, min_occurs: Option, max_occurs: Option, name: &str, type_tree: &ElementType<'a>) -> (String, String) { - match (min_occurs, max_occurs) { - (None, None) | (None, Some(1)) | (Some(1), None) | (Some(1), Some(1)) => - self.type_(name, type_tree), - (Some(0), None) | (Some(0), Some(1)) => { - let (field_name, child_typename) = self.type_(name, type_tree); - let name = format!("opt_{}", field_name); - if let Some(type_name) = self.generated_types.get(&name) { - return (field_name, type_name.clone()); - } - self.generated_types.insert(name.clone(), name.clone()); - let mut s = cg::Struct::new(&name); - s.vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field(format!("pub Option<{}<'input>>", child_typename)); - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_struct(s); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "option {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ - Some({}({}::parse_xml(stream, parse_context, parent_context))) - }} -}}"#, name, name, name, child_typename)); - (field_name, name.to_string()) - } - (_, _) => { - let (field_name, child_typename) = self.type_(&name, type_tree); - let name = format!("many_{}", field_name); - if let Some(type_name) = self.generated_types.get(&name) { - return (field_name, type_name.clone()); - } - self.generated_types.insert(name.clone(), name.clone()); - let mut s = cg::Struct::new(&name); - s.vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field(format!("pub Vec<{}<'input>>", child_typename)); - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_struct(s); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "vec {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ - let mut items = Vec::new(); - while let Some(new_item) = {}::parse_xml(stream, parse_context, parent_context) {{ - items.push(new_item); - }} - Some({}(items)) - }} -}}"#, name, name, child_typename, name)); // TODO: validate the size - (field_name, name.to_string()) - } - } - } - fn type_(&mut self, name: &str, type_tree: &ElementType<'a>) -> (String, String) { - match type_tree { - ElementType::String => { - ("string".to_string(), "XmlString".to_string()) - } - ElementType::Date => { - ("date".to_string(), "XmlString".to_string()) - } - ElementType::Sequence(items) => { - let mut s = cg::Struct::new(name); - s.vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input"); - let mut fields = Vec::new(); - for (i, (min_occurs, max_occurs, item)) in items.iter().enumerate() { - match (min_occurs.unwrap_or(1), max_occurs.unwrap_or(1), item) { - (1, 1, ElementType::Element(elem)) => { - let field_name = elem.name.1; - let field_type_name = self.element(elem, None); - s.field(&format!("pub {}", field_name), &format!("{}<'input>", field_type_name)); - fields.push((field_name.to_string(), field_type_name.to_string())); // TODO: namespace - }, - (1, 1, ElementType::GroupRef(ref_name)) => { - let field_name = escape_keyword(ref_name.1); - let field_type_name = escape_keyword(ref_name.1); - s.field(&format!("pub {}", field_name), &format!("{}<'input>", field_type_name)); - fields.push((field_name.to_string(), field_type_name.to_string())); // TODO: namespace - }, - (1, 1, ElementType::Ref(ref_name)) => { - let field_name = escape_keyword(ref_name.1); - let field_type_name = escape_keyword(&format!("{}_e", ref_name.1)); - s.field(&format!("pub {}", field_name), &format!("{}<'input>", field_type_name)); - fields.push((field_name.to_string(), field_type_name.to_string())); // TODO: namespace - }, - _ => { - let element_name = format!("seqfield{}", i); - let (element_name, field_typename) = self.type_occurs(*min_occurs, *max_occurs, &format!("{}__{}", name, element_name), item); - s.field(&format!("pub {}", element_name), &format!("{}<'input>", field_typename)); // TODO: make sure there is no name conflict - fields.push((element_name, field_typename)); - } - } - } - if items.len() == 0 { - s.tuple_field("PhantomData<&'input ()>"); - } - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_struct(s); - module.scope().raw(&format!("// ^-- from {:?}", type_tree)); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "sequence {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ - let tx = stream.transaction(); - Some({} {{ -"#, name, name, name)); - if fields.len() == 0 { - module.scope().raw(&format!(r#" - 0: Default::default() -"#, )); - } - for (item_name, item_typename) in fields.iter() { - module.scope().raw(&format!(r#" - {}: try_rollback!(stream, tx, {}::parse_xml(stream, parse_context, parent_context)), -"#, item_name, item_typename)); - } - module.scope().raw(&format!(r#" - }}) - }} -}}"#, )); - if fields.len() == 1 { - let (element_name, field_typename) = fields.remove(0); - return (element_name, field_typename); - } - (name.to_string(), name.to_string()) - }, - ElementType::Ref(id) => { - let escaped_name = escape_keyword(&format!("{}_e", id.1)); - let mut newid = QName(id.0, &escaped_name); - (id.1.to_string(), self.id_to_type_name(newid)) - }, - ElementType::GroupRef(id) => { - (id.1.to_string(), self.id_to_type_name(*id)) - }, - ElementType::Custom(id_) => { - let type_name = self.id_to_type_name(*id_); - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.new_struct(name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field(format!("pub {}<'input>", type_name)); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "custom {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ - {}::parse_xml(stream, parse_context, parent_context).map({}) - }} -}}"#, name, name, type_name, name)); - (id_.1.to_string(), name.to_string()) - } - ElementType::Extension(base, items) => { - let struct_name = escape_keyword(name); - let mut s = cg::Struct::new(&struct_name); - s.vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input"); - let base_typename = self.id_to_type_name(*base); - s.field("pub BASE", format!("{}<'input>", base_typename)); - let mut fields = Vec::new(); - for (i, (min_occurs, max_occurs, item)) in items.iter().enumerate() { - let element_name = format!("extfield{}", i); - let (element_name, field_typename) = self.type_occurs(*min_occurs, *max_occurs, &format!("{}__{}", name, element_name), item); - s.field(&format!("pub {}", element_name), &format!("{}<'input>", field_typename)); // TODO: make sure there is no name conflict - fields.push((element_name, field_typename)); - } - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_struct(s); - module.scope().raw(&format!("// ^-- from {:?}", type_tree)); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "extension {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ - let tx = stream.transaction(); - Some({} {{ - BASE: try_rollback!(stream, tx, {}::parse_xml(stream, parse_context, parent_context)), -"#, name, name, name, base_typename)); - for (item_name, item_typename) in fields { - module.scope().raw(&format!(r#" - {}: try_rollback!(stream, tx, {}::parse_xml(stream, parse_context, parent_context)), -"#, item_name, item_typename)); - } - module.scope().raw(&format!(r#" - }}) - }} -}} -"#, )); - (name.to_string(), struct_name) - }, - ElementType::Union(member_types, items) => { - let struct_name = escape_keyword(name); - let mut s = cg::Struct::new(&struct_name); - s.vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input"); - if let Some(member_types) = member_types { - for (i, member_type) in member_types.iter().enumerate() { - let member_name = format!("member{}", i); - s.field(&member_name, &format!("{}<'input>", self.id_to_type_name(*member_type))); - } - } - if let Some(items) = items { - for (i, (min_occurs, max_occurs, item)) in items.iter().enumerate() { - let item_name = format!("item{}", i); - let item_type_name = format!("{}__item{}", name, i); - let (item_name, item_type) = self.type_occurs(*min_occurs, *max_occurs, &item_type_name, item); - s.field(&item_name, &format!("{}<'input>", item_type)); - } - } - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_struct(s); - module.scope().raw(&format!("// ^-- from {:?}", type_tree)); - (name.to_string(), struct_name) - }, - ElementType::Choice(items) => { - let enum_name = escape_keyword(name); - let mut e = cg::Enum::new(&enum_name); - e.vis("pub").derive("Debug").derive("PartialEq").generic("'input"); - let mut last_item_name = None; - let mut variants = Vec::new(); - for (i, (min_occurs, max_occurs, item)) in items.iter().enumerate() { - match (min_occurs.unwrap_or(1), max_occurs.unwrap_or(1), item) { - (1, 1, ElementType::Element(elem)) => { - let variant_name = elem.name.1; - let variant_type_name = self.element(elem, None); - e.new_variant(&variant_name).tuple(&format!("Box<{}<'input>>", variant_type_name)); - variants.push((variant_name.to_string(), variant_type_name.to_string())); // TODO: namespace - last_item_name = Some(variant_name.to_string()); - }, - (1, 1, ElementType::GroupRef(ref_name)) => { - let variant_name = escape_keyword(ref_name.1); - let variant_type_name = escape_keyword(ref_name.1); - e.new_variant(&variant_name).tuple(&format!("Box<{}<'input>>", variant_type_name)); - variants.push((variant_name.to_string(), variant_type_name.to_string())); // TODO: namespace - last_item_name = Some(variant_name.to_string()); - }, - (1, 1, ElementType::Ref(ref_name)) => { - let variant_name = escape_keyword(ref_name.1); - let variant_type_name = escape_keyword(&format!("{}_e", ref_name.1)); - e.new_variant(&variant_name).tuple(&format!("Box<{}<'input>>", variant_type_name)); - variants.push((variant_name.to_string(), variant_type_name.to_string())); // TODO: namespace - last_item_name = Some(variant_name.to_string()); - }, - _ => { - let element_name = format!("choicevariant{}", i); - let (element_name, field_typename) = self.type_occurs(*min_occurs, *max_occurs, &format!("{}__{}", name, element_name), item); - e.new_variant(&element_name).tuple(&format!("Box<{}<'input>>", field_typename)); - last_item_name = Some(element_name.clone()); - variants.push((element_name, field_typename)); - } - } - } - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.push_enum(e); - let last_item_name = last_item_name.expect(&format!("enum {} has no variant", enum_name)); - module.scope().raw(&format!("impl<'input> Default for {}<'input> {{ fn default() -> {}<'input> {{ {}::{}(Default::default()) }} }}", enum_name, enum_name, enum_name, last_item_name )); // TODO: remove this, that's a temporary hack - module.scope().raw(&format!("// ^-- from {:?}", type_tree)); - module.scope().raw(&format!(r#" -impl<'input> ParseXml<'input> for {}<'input> {{ - const NODE_NAME: &'static str = "choice {}"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option {{ -"#, enum_name, enum_name)); - for (item_name, item_typename) in variants { - module.scope().raw(&format!(r#" - match {}::parse_xml(stream, parse_context, parent_context) {{ Some(r) => return Some({}::{}(Box::new(r))), None => () }} -"#, item_typename, enum_name, item_name)); - } - module.scope().raw(&format!(r#" - None - }} -}}"#, )); - (name.to_string(), enum_name) - }, - ElementType::List(List::ComplexList(min_occurs, max_occurs, mixed, item_type)) => { - let struct_name = escape_keyword(name); - let (_, type_) = self.type_(&format!("{}__valuetype", name), item_type); - if let Some(type_name) = self.generated_types.get(name) { - return (name.to_string(), type_name.clone()); - } - self.generated_types.insert(name.to_string(), name.to_string()); - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.new_struct(&name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field(&format!("pub Vec<{}<'input>>", type_)); - module.scope().raw(&format!("// ^-- from {:?}", type_tree)); - (name.to_string(), name.to_string()) - }, - ElementType::List(List::SimpleList(item_type)) => { - let type_name = self.id_to_type_name(*item_type); - let name = format!("{}_list", name); - let (_, ref mut module) = self.nsuri_to_module.get_mut(self.target_uri).unwrap(); - module.new_struct(&name).vis("pub").derive("Debug").derive("PartialEq").derive("Default").generic("'input").tuple_field(&format!("pub Vec<{}<'input>>", type_name)); - (name.clone(), name) - }, - ElementType::Element(e) => { - let element_type_name = self.element(e, None); - (e.name.1.to_string(), element_type_name) - } - _ => unimplemented!("{:?}", type_tree), - } - } -} diff --git a/src/support.rs b/src/support.rs deleted file mode 100644 index 8b30970..0000000 --- a/src/support.rs +++ /dev/null @@ -1,216 +0,0 @@ -use std::io::Write; -use std::collections::VecDeque; -use std::fmt; - -use xmlparser::Error as XmlParserError; -use xmlparser::{Token as XmlToken, ElementEnd, StrSpan, Tokenizer}; - -#[derive(Debug, PartialEq)] -pub struct Token<'input>(StrSpan<'input>); - -impl<'input> ParseXml<'input> for Token<'input> { - const NODE_NAME: &'static str = "token"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option> { - match stream.next() { - Some(XmlToken::Text(strspan)) => Some(Token(strspan)), - _ => None, - } - } -} -impl<'input> Default for Token<'input> { - fn default() -> Self { - Token(StrSpan::from_substr("", 0, 0)) - } -} -pub(crate) type token<'input> = Token<'input>; - -#[derive(Debug, PartialEq)] -pub struct NMTOKEN<'input>(StrSpan<'input>); - -impl<'input> ParseXml<'input> for NMTOKEN<'input> { - const NODE_NAME: &'static str = "NMTOKEN"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option> { - match stream.next() { - Some(XmlToken::Text(strspan)) => Some(NMTOKEN(strspan)), - _ => None, - } - } -} -impl<'input> Default for NMTOKEN<'input> { - fn default() -> Self { - NMTOKEN(StrSpan::from_substr("", 0, 0)) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] -pub struct QName<'input>(pub Option<&'input str>, pub &'input str); - -impl<'input> From<&'input str> for QName<'input> { - fn from(s: &'input str) -> QName<'input> { - let mut splitted = s.split(":"); - let v1 = splitted.next().expect(&format!("Empty qname")); - let v2 = splitted.next(); - assert_eq!(splitted.next(), None); - match v2 { - None => QName(None, v1), - Some(v2) => QName(Some(v1), v2), - } - } -} - -impl <'input> QName<'input> { - pub fn from_strspans(prefix: StrSpan<'input>, local: StrSpan<'input>) -> QName<'input> { - match prefix.to_str() { - "" => QName(None, local.to_str()), - p => QName(Some(p), local.to_str()), - } - } -} - -impl<'input> fmt::Display for QName<'input> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - Some(prefix) => write!(f, "{}:{}", prefix, self.1), - None => write!(f, "{}", self.1), - } - } -} - -#[derive(Debug, PartialEq, Default)] -pub struct anyURI<'input>(&'input str); - -#[derive(Debug, PartialEq)] -pub struct anyURI_e<'input>(StrSpan<'input>); -impl<'input> ParseXml<'input> for anyURI_e<'input> { - const NODE_NAME: &'static str = "anyURI_e"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option> { - match stream.next() { - Some(XmlToken::Text(strspan)) => Some(anyURI_e(strspan)), - _ => None, - } - } -} - -#[derive(Debug, PartialEq, Default)] -pub struct nonNegativeInteger<'input>(&'input str); - -#[derive(Debug, PartialEq, Default)] -pub struct SUPPORT_ANY<'input>(Vec>); // TODO: remove, temporary - -#[derive(Debug, PartialEq, Default)] -pub struct any<'input>(Vec>); -impl<'input> ParseXml<'input> for any<'input> { - const NODE_NAME: &'static str = "any"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option> { - let mut tag_stack = Vec::new(); - let mut tokens = Vec::new(); - let tok = stream.next()?; - tokens.push(tok); - match tok { - XmlToken::ElementStart(prefix, name) => tag_stack.push(QName::from_strspans(prefix, name)), - _ => return None, // TODO: put it back in the stream - } - while tag_stack.len() > 0 { - let tok = stream.next().unwrap(); - tokens.push(tok); - match tok { - XmlToken::ElementStart(prefix, name) => tag_stack.push(QName::from_strspans(prefix, name)), - XmlToken::ElementEnd(end) => { - match end { - ElementEnd::Open => (), - ElementEnd::Close(prefix, name) => assert_eq!(QName::from_strspans(prefix, name), tag_stack.pop().unwrap()), - ElementEnd::Empty => { tag_stack.pop(); () }, - } - } - _ => (), - } - } - Some(any(tokens)) - } -} - -#[derive(Debug, PartialEq)] -pub struct XmlString<'input>(StrSpan<'input>); - -impl<'input> ParseXml<'input> for XmlString<'input> { - const NODE_NAME: &'static str = "string"; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option> { - match stream.next() { - Some(XmlToken::Text(strspan)) => Some(XmlString(strspan)), - _ => None, // TODO: put it back in the stream - } - } -} - -impl<'input> Default for XmlString<'input> { - fn default() -> Self { - XmlString(StrSpan::from_substr("", 0, 0)) - } -} - -pub type Stream<'input> = Box>; -pub struct InnerStream<'input> { - pub(crate) index: usize, - tokens: Vec>, -} - -impl<'input> InnerStream<'input> { - pub fn new(tokenizer: Tokenizer<'input>) -> InnerStream<'input> { - InnerStream { index: 0, tokens: tokenizer.into_iter().map(|o| o.unwrap()).collect() } - } - - #[inline] - pub fn transaction(&self) -> Transaction { - Transaction { initial_index: self.index } - } -} - -#[must_use] -pub struct Transaction { - initial_index: usize, -} - -impl Transaction { - #[inline] - pub fn commit(self) { - } - - #[inline] - pub fn rollback(self, stream: &mut InnerStream) { - println!("// Rolling back {} tokens", stream.index - self.initial_index); - ::std::io::stdout().flush().ok().expect("Could not flush stdout"); - stream.index = self.initial_index - } -} - -impl<'input> Iterator for InnerStream<'input> { - type Item = XmlToken<'input>; - fn next(&mut self) -> Option { - let tok = self.tokens.get(self.index); - println!("// Reading {:?}", tok); - ::std::io::stdout().flush().ok().expect("Could not flush stdout"); - match tok { - Some(res) => { - self.index += 1; - Some(res.clone()) - } - None => None - } - } -} - - -pub trait ParseContext { -} // TODO: remove this -pub trait ParseXml<'input>: Sized { - const NODE_NAME: &'static str; - fn parse_self_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option; - fn parse_xml(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &TParentContext) -> Option { - println!("// Entering: {:?}", Self::NODE_NAME); - ::std::io::stdout().flush().ok().expect("Could not flush stdout"); - let ret = Self::parse_self_xml(stream, parse_context, parent_context); - println!("// Leaving: {:?}", Self::NODE_NAME); - ::std::io::stdout().flush().ok().expect("Could not flush stdout"); - ret - } -} diff --git a/src/test_generated.rs b/src/test_generated.rs deleted file mode 100644 index abed7f9..0000000 --- a/src/test_generated.rs +++ /dev/null @@ -1,28 +0,0 @@ - -use xmlparser; - -use parse_xsd; -use round0_parser::*; -use generated::UNQUAL; -use support::*; - -const PERSON_XSD: &'static str = r#" - - - - - - - - - - - "#; - -#[test] -fn generated_parses_person_xsd() { - let tokenizer = xmlparser::Tokenizer::from(PERSON_XSD); - let mut stream = Box::new(InnerStream::new(tokenizer)); - let doc = UNQUAL::schema_e::parse_xml(&mut stream, &mut (), &()); - assert_ne!(doc, None); -} diff --git a/src/test_generated_schema.rs b/src/test_generated_schema.rs deleted file mode 100644 index 112ab41..0000000 --- a/src/test_generated_schema.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::fs::File; -use std::io::Read; - -use xmlparser; - -use parse_xsd; -use generated::UNQUAL; -use parser_generator::ParserGenerator; -use support::*; - -#[test] -fn generated_parses_person_xsd() { - let mut f = File::open("XMLSchema.xsd").unwrap(); - let mut s = String::new(); - f.read_to_string(&mut s).unwrap(); - let tokenizer = xmlparser::Tokenizer::from(&s[..]); - let mut stream = Box::new(InnerStream::new(tokenizer)); - stream.next(); // Eat the declaration - stream.next(); // Eat the DTD start - stream.next(); // Eat comment - stream.next(); // Eat comment - stream.next(); // Eat the DTD end - let doc = UNQUAL::schema_e::parse_xml(&mut stream, &mut (), &()); - assert_ne!(doc, None); -} - -#[test] -fn round1_parser_person_xsd() { - let mut f = File::open("XMLSchema.xsd").unwrap(); - let mut s = String::new(); - f.read_to_string(&mut s).unwrap(); - let tokenizer = xmlparser::Tokenizer::from(&s[..]); - let mut stream = Box::new(InnerStream::new(tokenizer)); - stream.next(); // Eat the declaration - stream.next(); // Eat the DTD start - stream.next(); // Eat comment - stream.next(); // Eat comment - stream.next(); // Eat the DTD end - let doc = UNQUAL::schema_e::parse_xml(&mut stream, &mut (), &()); - assert_ne!(doc, None); - let mut parser_generator = ParserGenerator::new(doc.as_ref().unwrap()); - parser_generator.gen(doc.as_ref().unwrap()).to_string(); -} diff --git a/xml-schema-tests/Cargo.toml b/xml-schema-tests/Cargo.toml new file mode 100644 index 0000000..745e7b4 --- /dev/null +++ b/xml-schema-tests/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "xml-schema-tests" +version = "0.1.0" +authors = ["Valentin Lorentz "] +build = "build.rs" + +[dependencies] +xml-schema = { path = "../xml-schema" } +pretty_assertions = "0.4" + +[build-dependencies] +xml-schema = { path = "../xml-schema" } diff --git a/xml-schema-tests/build.rs b/xml-schema-tests/build.rs new file mode 100644 index 0000000..8cd63fa --- /dev/null +++ b/xml-schema-tests/build.rs @@ -0,0 +1,60 @@ +extern crate xml_schema; + +use std::env; +use std::fs::{File, read_dir}; +use std::io::{Read, Write}; +use std::path::Path; +use std::ffi::OsStr; +use std::env::current_dir; + +use xml_schema::{Processor, ParserGenerator, parse_xsd}; + +fn main() { + let mut in_dir = current_dir().unwrap(); + in_dir.push("src"); + let out_dir = env::var("OUT_DIR").unwrap(); + + println!("cargo:rerun-if-changed=build.rs"); + + for entry in read_dir(in_dir.clone()).expect(&format!("Could not read dir {:?}", in_dir)) { + let in_path = entry.unwrap().path(); + if in_path.extension() != Some(&OsStr::new("xsd")) { + continue; + } + println!("cargo:rerun-if-changed={}", in_path.to_str().unwrap()); + + let mut in_file = + File::open(in_path.clone()) + .expect(&format!("Could not open {:?}", in_path)); + let mut in_xml = String::new(); + in_file + .read_to_string(&mut in_xml) + .expect(&format!("Could not read {:?}", in_path)); + let (document, parse_context) = parse_xsd(&in_xml); + let document = document.expect(&format!("Could not parse {:?}", in_path)); + + let mut proc = Processor::new(&document); + proc.process_ast(&document); + + let renames = Default::default(); + let mut gen = ParserGenerator::new(vec![proc], &parse_context, renames); + let scope = gen.gen_target_scope(); + + let filename = in_path.file_name().unwrap(); + let out_path = + Path::new(&out_dir) + .join(filename) + .with_extension("rs"); + println!("cargo:warning=printing to: {}", out_path.to_str().unwrap()); + let mut out_file = + File::create(out_path.clone()) + .expect(&format!("Could not create {:?}", out_path)); + out_file + .write(b"#[allow(unused_imports)]\nuse xml_schema::support;\n") + .expect(&format!("Could not write in {:?}", out_path)); + out_file + .write(scope.to_string().as_bytes()) + .expect(&format!("Could not write in {:?}", out_path)); + } + println!("cargo:rerun-if-changed={}", in_dir.to_str().unwrap()); +} diff --git a/xml-schema-tests/src/lib.rs b/xml-schema-tests/src/lib.rs new file mode 100644 index 0000000..cd3b63f --- /dev/null +++ b/xml-schema-tests/src/lib.rs @@ -0,0 +1,7 @@ +#[macro_use] +extern crate xml_schema; + +#[macro_use] +extern crate pretty_assertions; + +pub mod po; diff --git a/xml-schema-tests/src/po.rs b/xml-schema-tests/src/po.rs new file mode 100644 index 0000000..3213bae --- /dev/null +++ b/xml-schema-tests/src/po.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/po.rs")); diff --git a/xml-schema-tests/src/po.xsd b/xml-schema-tests/src/po.xsd new file mode 100644 index 0000000..0d2ab06 --- /dev/null +++ b/xml-schema-tests/src/po.xsd @@ -0,0 +1,66 @@ + + + + + Purchase order schema for Example.com. + Copyright 2000 Example.com. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml-schema-tests/tests/po.rs b/xml-schema-tests/tests/po.rs new file mode 100644 index 0000000..4060adc --- /dev/null +++ b/xml-schema-tests/tests/po.rs @@ -0,0 +1,49 @@ +extern crate xml_schema; +extern crate xml_schema_tests; + +use xml_schema::support::{ParseXml, DefaultParseContext, InnerStream, Tokenizer}; +use xml_schema_tests::po; + +const EXAMPLE: &'static str = r#" + + + + Alice Smith + 123 Maple Street + Mill Valley + CA + 90952 + + + Robert Smith + 8 Oak Avenue + Old Town + PA + 95819 + + Hurry, my lawn is going wild! + + + Lawnmower + 1 + 148.95 + Confirm this is electric + + + Baby Monitor + 1 + 39.98 + 1999-05-21 + + + +"#; + +#[test] +fn test_example() { + let tokenizer = Tokenizer::from(EXAMPLE); + let mut stream = Box::new(InnerStream::new(tokenizer)); + let order = po::unqualified::PurchaseOrder::parse_xml(&mut stream, &mut DefaultParseContext::default(), &Default::default()); + let order = order.unwrap(); + assert_eq!(order.attr_order_date.unwrap().0, "1999-10-20"); +} diff --git a/xml-schema/Cargo.toml b/xml-schema/Cargo.toml new file mode 100644 index 0000000..61d267e --- /dev/null +++ b/xml-schema/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "xml-schema" +version = "0.1.0" +authors = ["Valentin Lorentz "] + +[dependencies] +#quick-xml = "0.12.1" +xmlparser = "0.5.0" +codegen = { git = "https://github.com/carllerche/codegen" } +heck = "0.3.0" +bigdecimal = "0.0.12" +num-traits = "0.2.5" + +[[bin]] +name = "gen" +path = "src/bin/gen.rs" diff --git a/xml-schema/src/bigfloat.rs b/xml-schema/src/bigfloat.rs new file mode 100644 index 0000000..3d8b73b --- /dev/null +++ b/xml-schema/src/bigfloat.rs @@ -0,0 +1,184 @@ +use std::fmt::Display; +use std::str::FromStr; +use std::cmp::Ordering; + +use bigdecimal::{BigDecimal, ParseBigDecimalError}; +use num_traits::{Zero, One}; +use std::ops::{Add, Mul}; + +#[derive(Debug, Clone, Hash)] +pub enum BigFloat { + Decimal(BigDecimal), + PlusInfinity, + MinusInfinity, + NaN, +} +impl FromStr for BigFloat { + type Err = ParseBigDecimalError; + + /// https://www.w3.org/TR/xmlschema11-2/#sec-lex-float + /// + /// Make sure to remove all whitespaces before calling this. + fn from_str(s: &str) -> Result { + match s { + "INF" | "+INF" => Ok(BigFloat::PlusInfinity), + "-INF" => Ok(BigFloat::MinusInfinity), + "NaN" => Ok(BigFloat::NaN), + _ => BigDecimal::from_str(s).map(BigFloat::Decimal), + } + } +} +impl PartialEq for BigFloat { + fn eq(&self, rhs: &BigFloat) -> bool { + use self::BigFloat::*; + match (self, rhs) { + (NaN, _) | (_, NaN) => false, + (PlusInfinity, PlusInfinity) => true, + (MinusInfinity, MinusInfinity) => true, + (Decimal(l), Decimal(r)) => l == r, + _ => false, + } + } +} +impl PartialOrd for BigFloat { + fn partial_cmp(&self, rhs: &BigFloat) -> Option { + use self::BigFloat::*; + if self == rhs { + Some(Ordering::Equal) + } + else { + match (self, rhs) { + (NaN, _) | (_, NaN) => None, + (PlusInfinity, _) => Some(Ordering::Less), + (MinusInfinity, _) => Some(Ordering::Greater), + (_, PlusInfinity) => Some(Ordering::Greater), + (_, MinusInfinity) => Some(Ordering::Less), + (Decimal(l), Decimal(r)) => l.partial_cmp(r), + } + } + } +} +impl Display for BigFloat { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> { + use self::BigFloat::*; + match self { + NaN => write!(f, "NaN"), + PlusInfinity => write!(f, "+INF"), // TODO: what's the canonical repr? + MinusInfinity => write!(f, "-INF"), + Decimal(d) => d.fmt(f), + } + } +} + +#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)] +pub struct BigFloatNotNaN(BigFloat); +impl Eq for BigFloatNotNaN {} +impl Ord for BigFloatNotNaN { + fn cmp(&self, rhs: &BigFloatNotNaN) -> Ordering { + self.0.partial_cmp(&rhs.0).expect("NaN") + } +} +impl From for BigFloatNotNaN { + fn from(d: BigDecimal) -> BigFloatNotNaN { + BigFloatNotNaN(BigFloat::Decimal(d)) + } +} +impl From for BigFloatNotNaN { + fn from(f: BigFloat) -> BigFloatNotNaN { + if f == BigFloat::NaN { + panic!("NaN"); + } + BigFloatNotNaN(f) + } +} +impl FromStr for BigFloatNotNaN { + type Err = ParseBigDecimalError; + + /// https://www.w3.org/TR/xmlschema11-2/#sec-lex-float + /// + /// Make sure to remove all whitespaces before calling this. + fn from_str(s: &str) -> Result { + match s { + "INF" | "+INF" => Ok(BigFloatNotNaN(BigFloat::PlusInfinity)), + "-INF" => Ok(BigFloatNotNaN(BigFloat::MinusInfinity)), + "NaN" => Err(ParseBigDecimalError::Other("NaN".to_string())), + _ => Ok(BigFloatNotNaN::from(BigDecimal::from_str(s)?)), + } + } +} +impl Add for BigFloatNotNaN { + type Output = BigFloatNotNaN; + fn add(self, rhs: BigFloatNotNaN) -> BigFloatNotNaN { + use self::BigFloat::*; + match (self.0, rhs.0) { + (NaN, _) | (_, NaN) => panic!("NaN"), + (PlusInfinity, MinusInfinity) => panic!("+inf + -inf"), + (MinusInfinity, PlusInfinity) => panic!("-inf + +inf"), + (PlusInfinity, _) | (_, PlusInfinity) => BigFloatNotNaN(PlusInfinity), + (MinusInfinity, _) | (_, MinusInfinity) => BigFloatNotNaN(MinusInfinity), + (Decimal(f), Decimal(r)) => BigFloatNotNaN(Decimal(f + r)), + } + } +} +impl Mul for BigFloatNotNaN { + type Output = BigFloatNotNaN; + fn mul(self, rhs: BigFloatNotNaN) -> BigFloatNotNaN { + use self::BigFloat::*; + match (self.0, rhs.0) { + (NaN, _) | (_, NaN) => panic!("NaN"), + (PlusInfinity, MinusInfinity) | (MinusInfinity, PlusInfinity) => BigFloatNotNaN(MinusInfinity), + (PlusInfinity, PlusInfinity) | (MinusInfinity, MinusInfinity) => BigFloatNotNaN(PlusInfinity), + (PlusInfinity, Decimal(d)) | (Decimal(d), PlusInfinity) => { + if BigDecimal::is_zero(&d) { + panic!("+inf * 0") + } + else if d > BigDecimal::zero() { + BigFloatNotNaN(PlusInfinity) + } + else { + BigFloatNotNaN(MinusInfinity) + } + }, + (MinusInfinity, Decimal(d)) | (Decimal(d), MinusInfinity) => { + if BigDecimal::is_zero(&d) { + panic!("-inf * 0") + } + else if d > BigDecimal::zero() { + BigFloatNotNaN(MinusInfinity) + } + else { + BigFloatNotNaN(PlusInfinity) + } + }, + (Decimal(l), Decimal(r)) => BigFloatNotNaN(Decimal(l * r)), + } + } +} +impl Zero for BigFloatNotNaN { + fn zero() -> BigFloatNotNaN { + BigFloatNotNaN(BigFloat::Decimal(BigDecimal::zero())) + } + fn is_zero(&self) -> bool { + match self { + BigFloatNotNaN(BigFloat::Decimal(d)) => d.is_zero(), + _ => false, + } + } +} +impl One for BigFloatNotNaN { + fn one() -> BigFloatNotNaN { + BigFloatNotNaN(BigFloat::Decimal(BigDecimal::one())) + } + fn is_one(&self) -> bool { + match self { + BigFloatNotNaN(BigFloat::Decimal(d)) => d.is_one(), + _ => false, + } + } +} +impl Display for BigFloatNotNaN { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> { + self.0.fmt(f) + } +} + diff --git a/xml-schema/src/bin/gen.rs b/xml-schema/src/bin/gen.rs new file mode 100644 index 0000000..9e4fcfb --- /dev/null +++ b/xml-schema/src/bin/gen.rs @@ -0,0 +1,63 @@ +use std::env::args_os; +use std::fs::File; +use std::io::Read; +use std::collections::HashMap; + +extern crate xmlparser; +extern crate xml_schema; +extern crate codegen; +use xml_schema::processor::*; +use xml_schema::parser_generator::*; +use xml_schema::parse_xsd_with_visitor; + +const RENAMES: &[(&'static str, &'static str)] = &[ + ("SequenceDefaultOpenContentAnnotation", "AnnotatedOpenContent"), + ("sequence_default_open_content_annotation", "open_content"), + ("ChoiceSimpleTypeComplexType", "Type"), + ("choice_simple_type_complex_type", "type_"), + ("SequenceOpenContentTypeDefParticleAttrDeclsAssertions", "CompleteContentModel"), + ("ChoiceAttributeAttributeGroup", "AttrOrAttrGroup"), + ("choice_attribute_attribute_group", "attribute"), + ("SequenceSelectorField", "UniquenessSpec"), + ("sequence_selector_field", "uniqueness_spec"), + //("ChoiceRestrictionExtension", "ContentDef"), + //("choice_restriction_extension", "content_def"), + ("ChoiceAppinfoDocumentation", "AnnotationContent"), + ("choice_appinfo_documentation", "annotation_content"), + ]; + +fn main() { + let mut inputs = Vec::new(); + for arg in args_os().skip(1) { + let mut s = String::new(); + let mut file = File::open(&arg).expect(&format!("Could not open {:?}", arg)); + file.read_to_string(&mut s).expect(&format!("Could not read {:?}", arg)); + inputs.push((arg, s)); + } + + let inputs2 = inputs.iter().map(|(arg, s)| (arg, &s[..])); + + let mut parse_context = XsdParseContext::default(); + + let mut documents = Vec::new(); + for (filename, input) in inputs2 { + documents.push((filename, parse_xsd_with_visitor(input, &mut parse_context).unwrap())); + } + + let mut processors = Vec::new(); + for (filename, document) in &documents { + println!("// Input: {:?}", filename); + let mut proc = Processor::new(document); + proc.process_ast(document); + processors.push(proc); + } + + let mut renames = HashMap::new(); + for (from_, to_) in RENAMES { + renames.insert(from_.to_string(), to_.to_string()); + } + + let mut gen = ParserGenerator::new(processors, &parse_context, renames); + let scope = gen.gen_target_scope(); + println!("#[allow(unused_imports)]\nuse support;\n{}", scope.to_string()); +} diff --git a/xml-schema/src/lib.rs b/xml-schema/src/lib.rs new file mode 100644 index 0000000..a80376d --- /dev/null +++ b/xml-schema/src/lib.rs @@ -0,0 +1,41 @@ +#![recursion_limit="80"] + +pub extern crate xmlparser; +extern crate codegen; +extern crate heck; +extern crate num_traits; +extern crate bigdecimal; + +#[macro_use] pub mod macros; +pub mod xml_utils; +pub mod names; +pub mod support; +pub mod primitives; +pub mod bigfloat; + +pub mod parser; +pub mod processor; +pub mod parser_generator; + +#[cfg(test)] +mod test_parser; +#[cfg(test)] +mod test_parser_schema; + +use support::{ParseXml, InnerStream, ParseContext, ParentContext}; + +pub use processor::Processor; +pub use parser_generator::{XsdParseContext, ParserGenerator}; + +pub fn parse_xsd<'input>(xsd: &'input str) -> (Option>, XsdParseContext) { + let mut visitor = XsdParseContext::default(); + let ast = parse_xsd_with_visitor(xsd, &mut visitor); + (ast, visitor) +} + +pub fn parse_xsd_with_visitor<'input, TParseContext: ParseContext<'input>>(xsd: &'input str, visitor: &mut TParseContext) -> Option> { + let tokenizer = xmlparser::Tokenizer::from(xsd); + let mut stream = Box::new(InnerStream::new(tokenizer)); + parser::xs::Schema::parse_xml(&mut stream, visitor, &ParentContext::default()) +} + diff --git a/xml-schema/src/macros.rs b/xml-schema/src/macros.rs new file mode 100644 index 0000000..17bb25f --- /dev/null +++ b/xml-schema/src/macros.rs @@ -0,0 +1,509 @@ +#[macro_export] +macro_rules! use_xsd_types { + () => { + pub use $crate::parser::xs; + } +} + +#[macro_export] +macro_rules! try_rollback { + ($stream:expr, $tx:expr, $e:expr) => { + match $e { + Some(i) => i, + None => { + $tx.rollback($stream); + return None + } + } + } +} + +#[macro_export] +macro_rules! impl_enum { + ( $name:ident, $($variant_macro:ident ! ( $($variant_args: tt )* ), )* ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXml<'input> for $name<'input> { + const NODE_NAME: &'static str = concat!("enum ", stringify!($name)); + + fn parse_empty>(parse_context: &mut TParseContext, parent_context: &ParentContext<'input>) -> Option { + $( + match $variant_macro!($name, __empty_element, parse_context, parent_context, $($variant_args)*) { + Some(x) => return Some(x), + None => (), + } + )* + None + } + + fn parse_self_xml<'b, TParseContext: ParseContext<'input>>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &'b ParentContext<'input>) -> Option { + let tx = stream.transaction(); + $( + match $variant_macro!($name, stream, parse_context, parent_context, $($variant_args)*) { + Some(x) => return Some(x), + None => (), // TODO: should we rollback here? + } + )* + + tx.rollback(stream); + None + } + } + } +} + +// TODO: deduplicate the empty and non-empty cases +macro_rules! impl_singleton_variant { + // empty element; call parse_empty_xml + ( $enum_name:ident, __empty_element, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Box < $type_name:ident > ) => { + super::$type_mod_name::$type_name::parse_empty($parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name) + }; + ( $enum_name:ident, __empty_element, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { + Some(super::$type_mod_name::$type_name::parse_empty($parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name)) + }; + ( $enum_name:ident, __empty_element, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ + // TODO: Should it be vec![], or vec![super::$type_mod_name::$type_name::parse_empty(...)]? + let mut items = Vec::new(); + Some($enum_name::$variant_name(items)) + }}; + + // non-empty element; call parse_xml + ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Box < $type_name:ident > ) => { + super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name) + }; + ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { + Some(super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new).map($enum_name::$variant_name)) + }; + ( $enum_name:ident, $stream:expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ + let mut items = Vec::new(); + while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { + items.push(item); + } + Some($enum_name::$variant_name(items)) + }} +} + +// TODO: deduplicate the empty and non-empty cases +macro_rules! impl_struct_variant { + ( $enum_name:ident, __empty_element, $parse_context:expr, $parent_context:expr, $variant_name:ident, ) => {{ + // empty variant + Some(Default::default()) + }}; + ( $enum_name:ident, __empty_element, $parse_context:expr, $parent_context:expr, $variant_name:ident, $( ( $field_name:ident, $( $field_args:tt )* ), )* ) => {{ + let mut res = None; + loop { // single run, used for breaking + $( + let $field_name = match impl_struct_variant_field!(__empty_element, $parse_context, $parent_context, $( $field_args )* ) { + Some(e) => e, + None => break, + }; + )* + res = Some($enum_name::$variant_name { + $( + $field_name, + )* + }); + break; + } + res + }}; + + ( $enum_name:ident, $stream: expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, ) => {{ + // empty variant + None + }}; + ( $enum_name:ident, $stream: expr, $parse_context:expr, $parent_context:expr, $variant_name:ident, $( ( $field_name:ident, $( $field_args:tt )* ), )* ) => {{ + let mut res = None; + loop { // single run, used for breaking + $( + let $field_name = match impl_struct_variant_field!($stream, $parse_context, $parent_context, $( $field_args )* ) { + Some(e) => e, + None => break, + }; + )* + res = Some($enum_name::$variant_name { + $( + $field_name, + )* + }); + break; + } + res + }} +} + +// TODO: deduplicate the empty and non-empty cases +macro_rules! impl_struct_variant_field { + ( __empty_element, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Box < $type_name:ident > ) => { + super::$type_mod_name::$type_name::parse_empty($parse_context, $parent_context).map(Box::new) + }; + ( __empty_element, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { + Some(super::$type_mod_name::$type_name::parse_empty($parse_context, $parent_context).map(Box::new)) + }; + ( __empty_element, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ + // TODO: Should it be vec![], or vec![super::$type_mod_name::$type_name::parse_empty(...)]? + let mut items = Vec::new(); + Some(items) + }}; + + + ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Box < $type_name:ident > ) => { + super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new) + }; + ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < Box < $type_name:ident > > ) => { + Some(super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context).map(Box::new)) + }; + ( $stream: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident > ) => {{ + let mut items = Vec::new(); + while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { + items.push(item); + } + Some(items) + }} +} + +#[macro_export] +macro_rules! impl_group_or_sequence { + ( $name:ident, ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXml<'input> for $name<'input> { + const NODE_NAME: &'static str = concat!("empty group or sequence ", stringify!($name)); + + fn parse_empty>(parse_context: &mut TParseContext, parent_context: &ParentContext<'input>) -> Option { + Some($name(Default::default())) + } + + fn parse_self_xml<'b, TParseContext: ParseContext<'input>>(stream: &mut Stream<'input>, _parse_context: &mut TParseContext, _parent_context: &'b ParentContext<'input>) -> Option { + None + } + } + }; + ( $name:ident, $( ( $field_name:ident, $( $field_args:tt )* ), )* ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXml<'input> for $name<'input> { + const NODE_NAME: &'static str = concat!("group or sequence ", stringify!($name)); + + #[allow(unused_variables)] + fn parse_empty>(parse_context: &mut TParseContext, parent_context: &ParentContext<'input>) -> Option { + Some($name { + $( + $field_name: impl_empty_element_field!(parse_context, parent_context, $($field_args)*), + )* + }) + } + + #[allow(unused_variables)] + fn parse_self_xml<'b, TParseContext: ParseContext<'input>>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &'b ParentContext<'input>) -> Option { + let tx = stream.transaction(); + Some($name { + $( + $field_name: impl_element_field!(stream, tx, parse_context, parent_context, $($field_args)*), + )* + }) + } + } + } +} + +#[macro_export] +macro_rules! impl_element { + ( $struct_name:ident, $namespace:expr, $name:expr, attributes = { $( ($attr_prefix:expr, $attr_local:expr) => $attr_name:ident : $use:ident, )* }, fields = { $( ( $field_name:ident, $( $field_args:tt )* ), )* } ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXml<'input> for $struct_name<'input> { + const NODE_NAME: &'static str = concat!("element ", stringify!($struct_name)); + + fn parse_empty>(_parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>) -> Option { + None + } + + #[allow(unused_variables)] + fn parse_self_xml<'b, TParseContext: ParseContext<'input>>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &'b ParentContext<'input>) -> Option { + use $crate::support::{XmlToken,ElementEnd}; + let mut parent_context: ParentContext<'input> = parent_context.clone(); + let tx = stream.transaction(); + let mut tok = stream.next().unwrap(); + loop { + match tok { + XmlToken::Whitespaces(_) => (), + XmlToken::Comment(_) => (), + XmlToken::Text(_) => (), + _ => break, + } + tok = stream.next().unwrap(); + } + match tok { + XmlToken::ElementStart(element_prefix, name) => { + if name.to_str() == $name { + let mut attrs = HashMap::new(); + $( + let mut $attr_name = None; + )* + loop { + let tok = stream.next().unwrap(); + match tok { + XmlToken::Whitespaces(_) => (), + XmlToken::Comment(_) => (), + XmlToken::Text(_) => (), + XmlToken::Attribute((key_prefix, key_local), value) => { + let key_prefix = key_prefix.to_str(); + let key_local = key_local.to_str(); + let value = value.to_str(); + match (key_prefix, key_local) { + ("xmlns", l) => { + parent_context.namespaces.insert(l, value); + parse_context.on_xmlns(Some(l), value); + //continue; // TODO: uncomment + }, + ("", "xmlns") => { + parent_context.namespaces.insert("", value); + parse_context.on_xmlns(None, value); + //continue; // TODO: uncomment + } + _ => (), + } + let key_namespace = match key_prefix { + "" => parent_context.namespaces.get(element_prefix.to_str()).cloned(), + _ => parent_context.namespaces.get(key_prefix).cloned(), + }; + let key = FullName::new(key_namespace, key_local); + let old = attrs.insert(key, value); assert_eq!(old, None); + match (key_prefix, key_local) { + $( + (_, $attr_local) => { // TODO: match the namespace too + match ParseXmlStr::parse_xml_str(value, parse_context, &parent_context, &Facets::default()) { + Some(("", value)) => { + $attr_name = Some(value) + // TODO: check for duplicates + }, + Some((out, _)) => + panic!("Unmatched data at the end of {}={:?}: {:?}", $attr_local, value, out), + None => + panic!("Could not parse {}={:?}.", $attr_local, value), + } + }, + )* + _ => (), // TODO: unknown attribute + } + }, + XmlToken::ElementEnd(ElementEnd::Open) => { + let element_ns: &'input str = match element_prefix.to_str() { + "" => { + parent_context.namespaces.get("").cloned().unwrap_or("") + }, + p => { + parent_context.namespaces.get(p) + .expect(&format!("unknown namespace {:?}", element_prefix.to_str())).clone() + }, + }; + if element_ns != $namespace { // This can't be checked on the ElementStart, because we have to check for xmlns first. + return None + } + let ret = Some($struct_name { + attrs, + $( + $attr_name: extract_attribute!($attr_name, $attr_local, $use), + )* + $( + $field_name: impl_element_field!(stream, tx, parse_context, &parent_context, $($field_args)*), + )* + }); + let mut next_tok; + loop { + next_tok = stream.next(); + match next_tok { + Some(XmlToken::Whitespaces(_)) => (), + Some(XmlToken::Comment(_)) => (), + Some(XmlToken::Text(_)) => (), + Some(XmlToken::ElementEnd(ElementEnd::Close(prefix2, name2))) => { + assert_eq!((element_prefix.to_str(), name.to_str()), (prefix2.to_str(), name2.to_str())); + return ret; + } + _ => panic!(format!("Expected closing tag for {}:{}, got {:?}", element_prefix, name, next_tok)), + } + } + }, + XmlToken::ElementEnd(ElementEnd::Empty) => { + let element_ns: &'input str = parent_context.namespaces.get(element_prefix.to_str()).expect(&format!("unknown namespace {:?}", element_prefix.to_str())).clone(); + if element_ns != $namespace { // This can't be checked on the ElementStart, because we have to check for xmlns first. + return None + } + return Some($struct_name { + attrs, + $( + $attr_name: extract_attribute!($attr_name, $attr_local, $use), + )* + $( + $field_name: impl_empty_element_field!(parse_context, &parent_context, $($field_args)*), + )* + }); + }, + XmlToken::ElementEnd(ElementEnd::Close(_, _)) => { + tx.rollback(stream); + return None + }, + _ => panic!(format!("Expected element end for {}:{}, got {:?}", element_prefix, name, tok)), + } + } + } + else { + tx.rollback(stream); + None + } + }, + XmlToken::ElementEnd(ElementEnd::Close(_, _)) => { + tx.rollback(stream); + return None + }, + _ => panic!(format!("Expected element start for {}, got {:?}", Self::NODE_NAME, tok)), + } + } + } + } +} + +#[macro_export] +macro_rules! extract_attribute { + ( $attr_name:ident, $attr_local:expr, required ) => { + $attr_name.expect(&format!("Missing attribute {}", $attr_local)) + }; + ( $attr_name:ident, $attr_local:expr, optional ) => { + $attr_name + }; +} + +#[macro_export] +macro_rules! impl_element_field { + ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, $type_name:ident ) => { + try_rollback!($stream, $tx, super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context)) + }; + ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < $type_name:ident > ) => { + super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) + }; + ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident ; min=$min:expr ; max=$max:expr ; > ) => {{ + let mut items = Vec::new(); + let min: usize = $min; + let max: usize = $max; + while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { + items.push(item); + if items.len() > max { + return None; + } + } + if items.len() < min { + return None; + } + items + }}; + ( $stream: expr, $tx: expr, $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident ; min=$min:expr ; > ) => {{ + let mut items = Vec::new(); + let min: usize = $min; + while let Some(item) = super::$type_mod_name::$type_name::parse_xml($stream, $parse_context, $parent_context) { + items.push(item); + } + if items.len() < min { + return None; + } + items + }}; +} + + +#[macro_export] +macro_rules! impl_empty_element_field { + ( $parse_context:expr, $parent_context:expr, $type_mod_name:ident, $type_name:ident ) => { + match super::$type_mod_name::$type_name::parse_empty($parse_context, $parent_context) { + Some(default) => default, + None => return None, + } + }; + ( $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Option < $type_name:ident > ) => { + None + }; + ( $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident ; min=$min:expr ; max=$max:expr ; > ) => {{ + Vec::new() + }}; + ( $parse_context:expr, $parent_context:expr, $type_mod_name:ident, Vec < $type_name:ident ; min=$min:expr ; > ) => {{ + Vec::new() + }}; +} + +#[macro_export] +macro_rules! impl_union { + ( $name:ident, { $($variant_macro:ident ! ( $($variant_args: tt )* ), )* } ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXmlStr<'input> for $name<'input> { + const NODE_NAME: &'static str = concat!("union ", stringify!($name)); + + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Self)> { + $( + match $variant_macro!($name, input, parse_context, parent_context, facets, $($variant_args)*) { + Some((o, x)) => return Some((o, x)), + None => (), + } + )* + + None + } + } + } +} + +macro_rules! impl_union_variant { + ( $name:ident, $input:expr, $parse_context:expr, $parent_context:expr, $facets:expr, $variant_name:ident) => { + ParseXmlStr::parse_xml_str($input, $parse_context, $parent_context, $facets) + .map(|(o, x)| (o, $name::$variant_name(x))) + } +} + +#[macro_export] +macro_rules! impl_list { + ( $name:ident, $item_type_mod_name:ident :: $item_type:ident ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXmlStr<'input> for $name<'input> { + const NODE_NAME: &'static str = concat!("list ", stringify!($name)); + + #[allow(unused_variables)] + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Self)> { + let mut input = input; + let mut items = Vec::new(); + while let Some((output, item)) = ParseXmlStr::parse_xml_str(input, parse_context, parent_context, facets) { + items.push(item); + if output.len() == 0 { + return Some(("", $name(items))); + } + if &output[0..1] != " " { + return None; + } + input = &output[1..]; + } + None + } + } + } +} + +#[macro_export] +macro_rules! impl_simpletype_restriction { + ( $name:ident, Facets { $( $facet_name:ident : $facet_value:expr , )* } ) => { + #[allow(unused_imports)] + use $crate::support::*; + impl<'input> ParseXmlStr<'input> for $name<'input> { + const NODE_NAME: &'static str = stringify!($name); + + #[allow(unused_variables)] + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Self)> { + let mut facets = facets.clone(); + $( + facets.$facet_name = $facet_value.or(facets.$facet_name); + )* + let (output, v) = ParseXmlStr::parse_xml_str(input, parse_context, parent_context, &facets)?; + Some((output, $name(v))) + } + } + } +} diff --git a/xml-schema/src/names.rs b/xml-schema/src/names.rs new file mode 100644 index 0000000..e8e688a --- /dev/null +++ b/xml-schema/src/names.rs @@ -0,0 +1,95 @@ +use std::collections::HashMap; +use std::fmt; + +use primitives::QName; + +const KEYWORDS: &[&'static str] = &["override"]; +fn escape_keyword(name: &str) -> String { + if KEYWORDS.contains(&name) { + format!("{}_", name) + } + else { + name.to_string() + } +} + +pub(crate) struct NameGenerator(HashMap); + +impl NameGenerator { + pub fn new() -> NameGenerator { + NameGenerator(HashMap::new()) + } + + pub fn gen_name(&mut self, name: String) -> String { + let nb_uses = self.0.get(&name).cloned().unwrap_or(1); + let ret = if nb_uses > 1 { + format!("{}{}", name, nb_uses) + } + else { + name.to_string() + }; + self.0.insert(name, nb_uses+1); + ret + } +} + +pub fn name_from_hint<'input>(hint: &NameHint<'input>) -> Option { + if hint.tokens.len() > 0 { + Some(hint.tokens.iter().map(|&s| escape_keyword(s)).collect::>().join("_")) + } + else { + None + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct FullName<'input>(Option<&'input str>, &'input str); + +impl<'input> FullName<'input> { + pub fn new(ns: Option<&'input str>, name: &'input str) -> FullName<'input> { + FullName(ns, name) + } + pub fn namespace(&self) -> Option<&'input str> { + self.0 + } + pub fn local_name(&self) -> &'input str { + self.1 + } +} + +impl<'input> FullName<'input> { + pub fn from_qname(qn: &QName<'input>, default_namespace: Option<&'input str>) -> FullName<'input> { + FullName(qn.namespace.or(default_namespace), qn.local_name) + } +} + +impl<'input> fmt::Display for FullName<'input> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Some(prefix) => write!(f, "{}:{}", prefix, self.1), + None => write!(f, "{}", self.1), + } + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct NameHint<'input> { + tokens: Vec<&'input str>, +} +impl<'input> NameHint<'input> { + pub fn new_empty() -> NameHint<'input> { + NameHint { tokens: Vec::new() } + } + pub fn new(s: &'input str) -> NameHint<'input> { + NameHint { tokens: vec![s] } + } + pub fn from_fullname(name: &FullName<'input>) -> NameHint<'input> { + NameHint::new(name.1) + } + pub fn push(&mut self, s: &'input str) { + self.tokens.push(s); + } + pub fn extend(&mut self, other: &NameHint<'input>) { + self.tokens.extend(other.tokens.iter()) + } +} diff --git a/xml-schema/src/parser.rs b/xml-schema/src/parser.rs new file mode 100644 index 0000000..40677bf --- /dev/null +++ b/xml-schema/src/parser.rs @@ -0,0 +1,2808 @@ +// Input: "xml-schema/derived.nxsd" +// Input: "xml-schema/XMLSchema.xsd" +#[allow(unused_imports)] +use support; +pub use std::collections::HashMap; + +pub use std::marker::PhantomData; + +pub mod unqualified { + //! None + + #[allow(unused_imports)] + use super::*; +} + +pub mod xs { + //! Some("http://www.w3.org/2001/XMLSchema") + + #[allow(unused_imports)] + use super::*; + + pub type Entities<'input> = restrictions::RestrictAnySimpleType<'input>; + + pub type Entity<'input> = restrictions::RestrictNcName<'input>; + + pub type Id<'input> = restrictions::RestrictNcName<'input>; + + pub type Idref<'input> = restrictions::RestrictNcName<'input>; + + pub type Idrefs<'input> = restrictions::RestrictAnySimpleType<'input>; + + pub type Nmtoken<'input> = restrictions::RestrictToken2<'input>; + + pub type Nmtokens<'input> = restrictions::RestrictAnySimpleType<'input>; + + pub type Name<'input> = restrictions::RestrictToken3<'input>; + + pub type Byte<'input> = restrictions::RestrictShort<'input>; + + pub type DateTimeStamp<'input> = restrictions::RestrictDateTime<'input>; + + pub type DayTimeDuration<'input> = restrictions::RestrictDuration2<'input>; + + pub type Int<'input> = restrictions::RestrictLong<'input>; + + pub type Integer<'input> = restrictions::RestrictDecimal<'input>; + + pub type Language<'input> = restrictions::RestrictToken<'input>; + + pub type Long<'input> = restrictions::RestrictInteger2<'input>; + + pub type NegativeInteger<'input> = restrictions::RestrictNonPositiveInteger<'input>; + + pub type NonPositiveInteger<'input> = restrictions::RestrictInteger<'input>; + + pub type NormalizedString<'input> = restrictions::RestrictString<'input>; + + pub type Short<'input> = restrictions::RestrictInt<'input>; + + pub type UnsignedByte<'input> = restrictions::RestrictUnsignedShort<'input>; + + pub type UnsignedInt<'input> = restrictions::RestrictUnsignedLong<'input>; + + pub type UnsignedLong<'input> = restrictions::RestrictNonNegativeInteger<'input>; + + pub type UnsignedShort<'input> = restrictions::RestrictUnsignedInt<'input>; + + pub type YearMonthDuration<'input> = restrictions::RestrictDuration<'input>; + + pub type AllNni<'input> = unions::UnionNonNegativeIntegerNmtoken<'input>; + + pub type BasicNamespaceList<'input> = lists::UnionAnyUriTokenList<'input>; + + pub type BlockSet<'input> = unions::UnionTokenDerivationControlList<'input>; + + pub type DerivationControl<'input> = restrictions::EnumerationSubstitutionExtensionRestrictionListUnion<'input>; + + pub type DerivationSet<'input> = unions::UnionTokenReducedDerivationControlList<'input>; + + pub type FormChoice<'input> = restrictions::EnumerationQualifiedUnqualified<'input>; + + pub type FullDerivationSet<'input> = unions::UnionTokenTypeDerivationControlList<'input>; + + pub type NamespaceList<'input> = unions::UnionSpecialNamespaceListBasicNamespaceList<'input>; + + pub type Public<'input> = restrictions::RestrictToken4<'input>; + + pub type QnameList<'input> = lists::UnionQNameTokenList<'input>; + + pub type QnameListA<'input> = lists::UnionQNameTokenList<'input>; + + pub type ReducedDerivationControl<'input> = restrictions::EnumerationExtensionRestriction<'input>; + + pub type SimpleDerivationSet<'input> = unions::UnionTokenDerivationControlList<'input>; + + pub type SpecialNamespaceList<'input> = restrictions::EnumerationAnyOther<'input>; + + pub type TypeDerivationControl<'input> = restrictions::EnumerationExtensionRestrictionListUnion<'input>; + + pub type XpathDefaultNamespace<'input> = unions::UnionAnyUriToken<'input>; + + /// Only elements allowed inside + #[derive(Debug, PartialEq)] + pub struct All<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub all_model: super::xs::AllModel<'input>, + } + + impl_element!(All, "http://www.w3.org/2001/XMLSchema", "all", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (all_model, xs, AllModel), + }); + + #[derive(Debug, PartialEq)] + pub struct Annotation<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub annotation_content: Vec>, + } + + impl_element!(Annotation, "http://www.w3.org/2001/XMLSchema", "annotation", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation_content, enums, Vec), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Any<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_not_q_name: Option>, + pub attr_namespace: Option>, + pub attr_not_namespace: Option>, + pub attr_process_contents: Option>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + } + + impl_element!(Any, "http://www.w3.org/2001/XMLSchema", "any", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "notQName") => attr_not_q_name: optional, + ("http://www.w3.org/2001/XMLSchema", "namespace") => attr_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "notNamespace") => attr_not_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "processContents") => attr_process_contents: optional, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct AnyAttribute<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_not_q_name: Option>, + pub attr_namespace: Option>, + pub attr_not_namespace: Option>, + pub attr_process_contents: Option>, + pub annotation: Option>, + } + + impl_element!(AnyAttribute, "http://www.w3.org/2001/XMLSchema", "anyAttribute", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "notQName") => attr_not_q_name: optional, + ("http://www.w3.org/2001/XMLSchema", "namespace") => attr_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "notNamespace") => attr_not_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "processContents") => attr_process_contents: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Appinfo<'input> { + pub attrs: HashMap, &'input str>, + pub attr_source: Option>, + pub sequence_any: Vec>, + } + + impl_element!(Appinfo, "http://www.w3.org/2001/XMLSchema", "appinfo", attributes = { + ("http://www.w3.org/2001/XMLSchema", "source") => attr_source: optional, + }, fields = { + (sequence_any, sequences, Vec), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Assertion<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_test: Option>, + pub attr_xpath_default_namespace: Option>, + pub annotation: Option>, + } + + impl_element!(Assertion, "http://www.w3.org/2001/XMLSchema", "assertion", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "test") => attr_test: optional, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Attribute<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_type: Option>, + pub attr_default: Option>, + pub attr_fixed: Option>, + pub attr_inheritable: Option>, + pub attr_name: support::NcName<'input>, + pub annotation: Option>, + pub local_simple_type: Option>, + } + + impl_element!(Attribute, "http://www.w3.org/2001/XMLSchema", "attribute", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "type") => attr_type: optional, + ("http://www.w3.org/2001/XMLSchema", "default") => attr_default: optional, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + ("http://www.w3.org/2001/XMLSchema", "inheritable") => attr_inheritable: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + }, fields = { + (annotation, xs, Option), + (local_simple_type, inline_elements, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct AttributeGroup<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: support::NcName<'input>, + pub annotation: Option>, + pub attr_decls: super::xs::AttrDecls<'input>, + } + + impl_element!(AttributeGroup, "http://www.w3.org/2001/XMLSchema", "attributeGroup", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + }, fields = { + (annotation, xs, Option), + (attr_decls, xs, AttrDecls), + }); + + /// group type for the three kinds of group + #[derive(Debug, PartialEq)] + pub struct Choice<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + pub nested_particle: Vec>, + } + + impl_element!(Choice, "http://www.w3.org/2001/XMLSchema", "choice", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + (nested_particle, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct ComplexContent<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_mixed: Option>, + pub annotation: Option>, + pub choice_restriction_extension: super::enums::ChoiceRestrictionExtension<'input>, + } + + impl_element!(ComplexContent, "http://www.w3.org/2001/XMLSchema", "complexContent", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "mixed") => attr_mixed: optional, + }, fields = { + (annotation, xs, Option), + (choice_restriction_extension, enums, ChoiceRestrictionExtension), + }); + + #[derive(Debug, PartialEq)] + pub struct ComplexType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: support::NcName<'input>, + pub attr_mixed: Option>, + pub attr_abstract: Option>, + pub attr_final: Option>, + pub attr_block: Option>, + pub attr_default_attributes_apply: Option>, + pub annotation: Option>, + pub complex_type_model: super::xs::ComplexTypeModel<'input>, + } + + impl_element!(ComplexType, "http://www.w3.org/2001/XMLSchema", "complexType", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + ("http://www.w3.org/2001/XMLSchema", "mixed") => attr_mixed: optional, + ("http://www.w3.org/2001/XMLSchema", "abstract") => attr_abstract: optional, + ("http://www.w3.org/2001/XMLSchema", "final") => attr_final: optional, + ("http://www.w3.org/2001/XMLSchema", "block") => attr_block: optional, + ("http://www.w3.org/2001/XMLSchema", "defaultAttributesApply") => attr_default_attributes_apply: optional, + }, fields = { + (annotation, xs, Option), + (complex_type_model, xs, ComplexTypeModel), + }); + + #[derive(Debug, PartialEq)] + pub struct DefaultOpenContent<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_applies_to_empty: Option>, + pub attr_mode: Option>, + pub annotation: Option>, + pub any_wildcard: super::inline_elements::AnyWildcard<'input>, + } + + impl_element!(DefaultOpenContent, "http://www.w3.org/2001/XMLSchema", "defaultOpenContent", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "appliesToEmpty") => attr_applies_to_empty: optional, + ("http://www.w3.org/2001/XMLSchema", "mode") => attr_mode: optional, + }, fields = { + (annotation, xs, Option), + (any_wildcard, inline_elements, AnyWildcard), + }); + + #[derive(Debug, PartialEq)] + pub struct Documentation<'input> { + pub attrs: HashMap, &'input str>, + pub attr_source: Option>, + pub sequence_any: Vec>, + } + + impl_element!(Documentation, "http://www.w3.org/2001/XMLSchema", "documentation", attributes = { + ("http://www.w3.org/2001/XMLSchema", "source") => attr_source: optional, + }, fields = { + (sequence_any, sequences, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct Element<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_type: Option>, + pub attr_substitution_group: Option>, + pub attr_default: Option>, + pub attr_fixed: Option>, + pub attr_nillable: Option>, + pub attr_abstract: Option>, + pub attr_final: Option>, + pub attr_block: Option>, + pub attr_name: support::NcName<'input>, + pub annotation: Option>, + pub type_: Option>, + pub alternative_alt_type: Vec>, + pub identity_constraint: Vec>, + } + + impl_element!(Element, "http://www.w3.org/2001/XMLSchema", "element", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "type") => attr_type: optional, + ("http://www.w3.org/2001/XMLSchema", "substitutionGroup") => attr_substitution_group: optional, + ("http://www.w3.org/2001/XMLSchema", "default") => attr_default: optional, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + ("http://www.w3.org/2001/XMLSchema", "nillable") => attr_nillable: optional, + ("http://www.w3.org/2001/XMLSchema", "abstract") => attr_abstract: optional, + ("http://www.w3.org/2001/XMLSchema", "final") => attr_final: optional, + ("http://www.w3.org/2001/XMLSchema", "block") => attr_block: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + }, fields = { + (annotation, xs, Option), + (type_, enums, Option), + (alternative_alt_type, inline_elements, Vec), + (identity_constraint, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct Enumeration<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::AnySimpleType<'input>, + pub annotation: Option>, + } + + impl_element!(Enumeration, "http://www.w3.org/2001/XMLSchema", "enumeration", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct ExplicitTimezone<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: restrictions::EnumerationOptionalRequiredProhibited<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(ExplicitTimezone, "http://www.w3.org/2001/XMLSchema", "explicitTimezone", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub enum Facet<'input> { + FacetHead(Box>), + MinExclusive(Box>), + MinInclusive(Box>), + MaxExclusive(Box>), + MaxInclusive(Box>), + TotalDigits(Box>), + FractionDigits(Box>), + Length(Box>), + MinLength(Box>), + MaxLength(Box>), + Enumeration(Box>), + WhiteSpace(Box>), + Pattern(Box>), + Assertion(Box>), + ExplicitTimezone(Box>), + } + + impl_enum!(Facet, + impl_singleton_variant!(FacetHead, xs, Box), + impl_singleton_variant!(MinExclusive, xs, Box), + impl_singleton_variant!(MinInclusive, xs, Box), + impl_singleton_variant!(MaxExclusive, xs, Box), + impl_singleton_variant!(MaxInclusive, xs, Box), + impl_singleton_variant!(TotalDigits, xs, Box), + impl_singleton_variant!(FractionDigits, xs, Box), + impl_singleton_variant!(Length, xs, Box), + impl_singleton_variant!(MinLength, xs, Box), + impl_singleton_variant!(MaxLength, xs, Box), + impl_singleton_variant!(Enumeration, xs, Box), + impl_singleton_variant!(WhiteSpace, xs, Box), + impl_singleton_variant!(Pattern, xs, Box), + impl_singleton_variant!(Assertion, xs, Box), + impl_singleton_variant!(ExplicitTimezone, xs, Box), + ); + + /// An abstract element, representing facets in general. The facets defined by this spec are substitutable for this element, and implementation-defined facets should also name this as a substitution-group head. + #[derive(Debug, PartialEq)] + pub struct FacetHead<'input> { + pub attrs: HashMap, &'input str>, + } + + impl_element!(FacetHead, "http://www.w3.org/2001/XMLSchema", "facet", attributes = { + }, fields = { + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Field<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_xpath: restrictions::RestrictToken4<'input>, + pub attr_xpath_default_namespace: Option>, + pub annotation: Option>, + } + + impl_element!(Field, "http://www.w3.org/2001/XMLSchema", "field", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "xpath") => attr_xpath: required, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct FractionDigits<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::NonNegativeInteger<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(FractionDigits, "http://www.w3.org/2001/XMLSchema", "fractionDigits", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Group<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: support::NcName<'input>, + pub annotation: Option>, + pub choice_all_choice_sequence: super::enums::ChoiceAllChoiceSequence<'input>, + } + + impl_element!(Group, "http://www.w3.org/2001/XMLSchema", "group", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + }, fields = { + (annotation, xs, Option), + (choice_all_choice_sequence, enums, ChoiceAllChoiceSequence), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Import<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_namespace: Option>, + pub attr_schema_location: Option>, + pub annotation: Option>, + } + + impl_element!(Import, "http://www.w3.org/2001/XMLSchema", "import", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "namespace") => attr_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "schemaLocation") => attr_schema_location: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Include<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_schema_location: support::AnyUri<'input>, + pub annotation: Option>, + } + + impl_element!(Include, "http://www.w3.org/2001/XMLSchema", "include", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "schemaLocation") => attr_schema_location: required, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Key<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: Option>, + pub attr_ref: Option>, + pub annotation: Option>, + pub uniqueness_spec: Option>, + } + + impl_element!(Key, "http://www.w3.org/2001/XMLSchema", "key", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: optional, + }, fields = { + (annotation, xs, Option), + (uniqueness_spec, sequences, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Keyref<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: Option>, + pub attr_ref: Option>, + pub attr_refer: Option>, + pub annotation: Option>, + pub uniqueness_spec: Option>, + } + + impl_element!(Keyref, "http://www.w3.org/2001/XMLSchema", "keyref", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: optional, + ("http://www.w3.org/2001/XMLSchema", "refer") => attr_refer: optional, + }, fields = { + (annotation, xs, Option), + (uniqueness_spec, sequences, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Length<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::NonNegativeInteger<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(Length, "http://www.w3.org/2001/XMLSchema", "length", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// itemType attribute and simpleType child are mutually exclusive, but one or other is required + /// itemType attribute and simpleType child are mutually exclusive, but one or other is required + #[derive(Debug, PartialEq)] + pub struct List<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_item_type: Option>, + pub annotation: Option>, + pub local_simple_type: Option>, + } + + impl_element!(List, "http://www.w3.org/2001/XMLSchema", "list", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "itemType") => attr_item_type: optional, + }, fields = { + (annotation, xs, Option), + (local_simple_type, inline_elements, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct MaxExclusive<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::AnySimpleType<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MaxExclusive, "http://www.w3.org/2001/XMLSchema", "maxExclusive", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct MaxInclusive<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::AnySimpleType<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MaxInclusive, "http://www.w3.org/2001/XMLSchema", "maxInclusive", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct MaxLength<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::NonNegativeInteger<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MaxLength, "http://www.w3.org/2001/XMLSchema", "maxLength", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct MinExclusive<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::AnySimpleType<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MinExclusive, "http://www.w3.org/2001/XMLSchema", "minExclusive", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct MinInclusive<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::AnySimpleType<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MinInclusive, "http://www.w3.org/2001/XMLSchema", "minInclusive", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct MinLength<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::NonNegativeInteger<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(MinLength, "http://www.w3.org/2001/XMLSchema", "minLength", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Notation<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: support::NcName<'input>, + pub attr_public: Option>, + pub attr_system: Option>, + pub annotation: Option>, + } + + impl_element!(Notation, "http://www.w3.org/2001/XMLSchema", "notation", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + ("http://www.w3.org/2001/XMLSchema", "public") => attr_public: optional, + ("http://www.w3.org/2001/XMLSchema", "system") => attr_system: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct OpenContent<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_mode: Option>, + pub annotation: Option>, + pub any_wildcard: Option>, + } + + impl_element!(OpenContent, "http://www.w3.org/2001/XMLSchema", "openContent", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "mode") => attr_mode: optional, + }, fields = { + (annotation, xs, Option), + (any_wildcard, inline_elements, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Override<'input> { + pub attrs: HashMap, &'input str>, + pub attr_schema_location: support::AnyUri<'input>, + pub attr_id: Option>, + pub annotation: Option>, + pub schema_top: Vec>, + } + + impl_element!(Override, "http://www.w3.org/2001/XMLSchema", "override", attributes = { + ("http://www.w3.org/2001/XMLSchema", "schemaLocation") => attr_schema_location: required, + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation, xs, Option), + (schema_top, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct Pattern<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::XmlString<'input>, + pub annotation: Option>, + } + + impl_element!(Pattern, "http://www.w3.org/2001/XMLSchema", "pattern", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Redefine<'input> { + pub attrs: HashMap, &'input str>, + pub attr_schema_location: support::AnyUri<'input>, + pub attr_id: Option>, + pub choice_annotation_redefinable: Vec>, + } + + impl_element!(Redefine, "http://www.w3.org/2001/XMLSchema", "redefine", attributes = { + ("http://www.w3.org/2001/XMLSchema", "schemaLocation") => attr_schema_location: required, + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (choice_annotation_redefinable, enums, Vec), + }); + + /// base attribute and simpleType child are mutually exclusive, but one or other is required + /// base attribute and simpleType child are mutually exclusive, but one or other is required + #[derive(Debug, PartialEq)] + pub struct Restriction<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_base: Option>, + pub annotation: Option>, + pub simple_restriction_model: super::xs::SimpleRestrictionModel<'input>, + } + + impl_element!(Restriction, "http://www.w3.org/2001/XMLSchema", "restriction", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "base") => attr_base: optional, + }, fields = { + (annotation, xs, Option), + (simple_restriction_model, xs, SimpleRestrictionModel), + }); + + #[derive(Debug, PartialEq)] + pub struct Schema<'input> { + pub attrs: HashMap, &'input str>, + pub attr_target_namespace: Option>, + pub attr_version: Option>, + pub attr_final_default: Option>, + pub attr_block_default: Option>, + pub attr_attribute_form_default: Option>, + pub attr_element_form_default: Option>, + pub attr_default_attributes: Option>, + pub attr_xpath_default_namespace: Option>, + pub attr_id: Option>, + pub composition: Vec>, + pub open_content: Option>, + pub sequence_schema_top_annotation: Vec>, + } + + impl_element!(Schema, "http://www.w3.org/2001/XMLSchema", "schema", attributes = { + ("http://www.w3.org/2001/XMLSchema", "targetNamespace") => attr_target_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "version") => attr_version: optional, + ("http://www.w3.org/2001/XMLSchema", "finalDefault") => attr_final_default: optional, + ("http://www.w3.org/2001/XMLSchema", "blockDefault") => attr_block_default: optional, + ("http://www.w3.org/2001/XMLSchema", "attributeFormDefault") => attr_attribute_form_default: optional, + ("http://www.w3.org/2001/XMLSchema", "elementFormDefault") => attr_element_form_default: optional, + ("http://www.w3.org/2001/XMLSchema", "defaultAttributes") => attr_default_attributes: optional, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (composition, xs, Vec), + (open_content, sequences, Option), + (sequence_schema_top_annotation, sequences, Vec), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Selector<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_xpath: restrictions::RestrictToken4<'input>, + pub attr_xpath_default_namespace: Option>, + pub annotation: Option>, + } + + impl_element!(Selector, "http://www.w3.org/2001/XMLSchema", "selector", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "xpath") => attr_xpath: required, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// group type for the three kinds of group + #[derive(Debug, PartialEq)] + pub struct Sequence<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + pub nested_particle: Vec>, + } + + impl_element!(Sequence, "http://www.w3.org/2001/XMLSchema", "sequence", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + (nested_particle, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct SimpleContent<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub annotation: Option>, + pub choice_restriction_extension: super::enums::ChoiceRestrictionExtension<'input>, + } + + impl_element!(SimpleContent, "http://www.w3.org/2001/XMLSchema", "simpleContent", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation, xs, Option), + (choice_restriction_extension, enums, ChoiceRestrictionExtension), + }); + + #[derive(Debug, PartialEq)] + pub struct SimpleType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_final: Option>, + pub attr_name: support::NcName<'input>, + pub annotation: Option>, + pub simple_derivation: super::xs::SimpleDerivation<'input>, + } + + impl_element!(SimpleType, "http://www.w3.org/2001/XMLSchema", "simpleType", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "final") => attr_final: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: required, + }, fields = { + (annotation, xs, Option), + (simple_derivation, xs, SimpleDerivation), + }); + + #[derive(Debug, PartialEq)] + pub struct TotalDigits<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: support::PositiveInteger<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(TotalDigits, "http://www.w3.org/2001/XMLSchema", "totalDigits", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// memberTypes attribute must be non-empty or there must be at least one simpleType child + /// memberTypes attribute must be non-empty or there must be at least one simpleType child + #[derive(Debug, PartialEq)] + pub struct Union<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_member_types: Option>, + pub annotation: Option>, + pub local_simple_type: Vec>, + } + + impl_element!(Union, "http://www.w3.org/2001/XMLSchema", "union", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "memberTypes") => attr_member_types: optional, + }, fields = { + (annotation, xs, Option), + (local_simple_type, inline_elements, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct Unique<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_name: Option>, + pub attr_ref: Option>, + pub annotation: Option>, + pub uniqueness_spec: Option>, + } + + impl_element!(Unique, "http://www.w3.org/2001/XMLSchema", "unique", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: optional, + }, fields = { + (annotation, xs, Option), + (uniqueness_spec, sequences, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct WhiteSpace<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_value: restrictions::EnumerationPreserveReplaceCollapse<'input>, + pub attr_fixed: Option>, + pub annotation: Option>, + } + + impl_element!(WhiteSpace, "http://www.w3.org/2001/XMLSchema", "whiteSpace", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "value") => attr_value: required, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct AllModel<'input> { + pub annotation: Option>, + pub choice_element_any_group: Vec>, + } + + impl_group_or_sequence!(AllModel, + (annotation, xs, Option), + (choice_element_any_group, enums, Vec), + ); + + #[derive(Debug, PartialEq)] + pub struct Assertions<'input> { + pub assertion: Vec>, + } + + impl_group_or_sequence!(Assertions, + (assertion, inline_elements, Vec), + ); + + #[derive(Debug, PartialEq)] + pub struct AttrDecls<'input> { + pub attribute: Vec>, + pub any_attribute: Option>, + } + + impl_group_or_sequence!(AttrDecls, + (attribute, enums, Vec), + (any_attribute, xs, Option), + ); + + #[derive(Debug, PartialEq)] + pub enum ComplexTypeModel<'input> { + SimpleContent(Box>), + ComplexContent(Box>), + CompleteContentModel { + open_content: Option> >, + type_def_particle: Option> >, + attr_decls: Box>, + assertions: Box>, + } + , + } + + impl_enum!(ComplexTypeModel, + impl_singleton_variant!(SimpleContent, xs, Box), + impl_singleton_variant!(ComplexContent, xs, Box), + impl_struct_variant!(CompleteContentModel, + (open_content, xs, Option >), + (type_def_particle, xs, Option >), + (attr_decls, xs, Box), + (assertions, xs, Box), + ), + ); + + #[derive(Debug, PartialEq)] + pub enum Composition<'input> { + Include(Box>), + Import(Box>), + Redefine(Box>), + Override(Box>), + Annotation(Box>), + } + + impl_enum!(Composition, + impl_singleton_variant!(Include, xs, Box), + impl_singleton_variant!(Import, xs, Box), + impl_singleton_variant!(Redefine, xs, Box), + impl_singleton_variant!(Override, xs, Box), + impl_singleton_variant!(Annotation, xs, Box), + ); + + /// The three kinds of identity constraints, all with type of or derived from 'keybase'. + #[derive(Debug, PartialEq)] + pub enum IdentityConstraint<'input> { + Unique(Box>), + Key(Box>), + Keyref(Box>), + } + + impl_enum!(IdentityConstraint, + impl_singleton_variant!(Unique, xs, Box), + impl_singleton_variant!(Key, xs, Box), + impl_singleton_variant!(Keyref, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum NestedParticle<'input> { + Element(Box>), + Group(Box>), + Choice(Box>), + Sequence(Box>), + Any(Box>), + } + + impl_enum!(NestedParticle, + impl_singleton_variant!(Element, inline_elements, Box), + impl_singleton_variant!(Group, inline_elements, Box), + impl_singleton_variant!(Choice, xs, Box), + impl_singleton_variant!(Sequence, xs, Box), + impl_singleton_variant!(Any, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum Particle<'input> { + Element(Box>), + Group(Box>), + All(Box>), + Choice(Box>), + Sequence(Box>), + Any(Box>), + } + + impl_enum!(Particle, + impl_singleton_variant!(Element, inline_elements, Box), + impl_singleton_variant!(Group, inline_elements, Box), + impl_singleton_variant!(All, xs, Box), + impl_singleton_variant!(Choice, xs, Box), + impl_singleton_variant!(Sequence, xs, Box), + impl_singleton_variant!(Any, xs, Box), + ); + + /// This group is for the elements which can self-redefine (see below). + #[derive(Debug, PartialEq)] + pub enum Redefinable<'input> { + SimpleType(Box>), + ComplexType(Box>), + Group(Box>), + AttributeGroup(Box>), + } + + impl_enum!(Redefinable, + impl_singleton_variant!(SimpleType, xs, Box), + impl_singleton_variant!(ComplexType, xs, Box), + impl_singleton_variant!(Group, xs, Box), + impl_singleton_variant!(AttributeGroup, xs, Box), + ); + + /// This group is for the elements which occur freely at the top level of schemas. All of their types are based on the "annotated" type by extension. + #[derive(Debug, PartialEq)] + pub enum SchemaTop<'input> { + Redefinable(Box>), + Element(Box>), + Attribute(Box>), + Notation(Box>), + } + + impl_enum!(SchemaTop, + impl_singleton_variant!(Redefinable, xs, Box), + impl_singleton_variant!(Element, xs, Box), + impl_singleton_variant!(Attribute, xs, Box), + impl_singleton_variant!(Notation, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum SimpleDerivation<'input> { + Restriction(Box>), + List(Box>), + Union(Box>), + } + + impl_enum!(SimpleDerivation, + impl_singleton_variant!(Restriction, xs, Box), + impl_singleton_variant!(List, xs, Box), + impl_singleton_variant!(Union, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub struct SimpleRestrictionModel<'input> { + pub local_simple_type: Option>, + pub choice_facet_any: Vec>, + } + + impl_group_or_sequence!(SimpleRestrictionModel, + (local_simple_type, inline_elements, Option), + (choice_facet_any, enums, Vec), + ); + + /// 'complexType' uses this + #[derive(Debug, PartialEq)] + pub enum TypeDefParticle<'input> { + Group(Box>), + All(Box>), + Choice(Box>), + Sequence(Box>), + } + + impl_enum!(TypeDefParticle, + impl_singleton_variant!(Group, inline_elements, Box), + impl_singleton_variant!(All, xs, Box), + impl_singleton_variant!(Choice, xs, Box), + impl_singleton_variant!(Sequence, xs, Box), + ); +} + +pub mod hfp { + //! Some("http://www.w3.org/2001/XMLSchema-hasFacetAndProperty") + + #[allow(unused_imports)] + use super::*; +} + +pub mod enums { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] + pub enum ChoiceAllChoiceSequence<'input> { + All(Box>), + Choice(Box>), + Sequence(Box>), + } + + impl_enum!(ChoiceAllChoiceSequence, + impl_singleton_variant!(All, xs, Box), + impl_singleton_variant!(Choice, xs, Box), + impl_singleton_variant!(Sequence, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceAllChoiceSequence2<'input> { + All(Box>), + Choice(Box>), + Sequence(Box>), + } + + impl_enum!(ChoiceAllChoiceSequence2, + impl_singleton_variant!(All, inline_elements, Box), + impl_singleton_variant!(Choice, inline_elements, Box), + impl_singleton_variant!(Sequence, inline_elements, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceAnnotationRedefinable<'input> { + Annotation(Box>), + Redefinable(Box>), + } + + impl_enum!(ChoiceAnnotationRedefinable, + impl_singleton_variant!(Annotation, xs, Box), + impl_singleton_variant!(Redefinable, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum AnnotationContent<'input> { + Appinfo(Box>), + Documentation(Box>), + } + + impl_enum!(AnnotationContent, + impl_singleton_variant!(Appinfo, xs, Box), + impl_singleton_variant!(Documentation, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum AttrOrAttrGroup<'input> { + Attribute(Box>), + AttributeGroup(Box>), + } + + impl_enum!(AttrOrAttrGroup, + impl_singleton_variant!(Attribute, inline_elements, Box), + impl_singleton_variant!(AttributeGroup, inline_elements, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceElementAnyGroup<'input> { + Element(Box>), + Any(Box>), + Group(Box>), + } + + impl_enum!(ChoiceElementAnyGroup, + impl_singleton_variant!(Element, inline_elements, Box), + impl_singleton_variant!(Any, xs, Box), + impl_singleton_variant!(Group, inline_elements, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceFacetAny<'input> { + Facet(Box>), + Any(Box>), + } + + impl_enum!(ChoiceFacetAny, + impl_singleton_variant!(Facet, xs, Box), + impl_singleton_variant!(Any, support, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceRestrictionExtension<'input> { + Restriction(Box>), + Extension(Box>), + } + + impl_enum!(ChoiceRestrictionExtension, + impl_singleton_variant!(Restriction, inline_elements, Box), + impl_singleton_variant!(Extension, inline_elements, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceRestrictionExtension2<'input> { + Restriction(Box>), + Extension(Box>), + } + + impl_enum!(ChoiceRestrictionExtension2, + impl_singleton_variant!(Restriction, inline_elements, Box), + impl_singleton_variant!(Extension, inline_elements, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum ChoiceSequenceOpenContentTypeDefParticleSimpleRestrictionModel<'input> { + SequenceOpenContentTypeDefParticle { + open_content: Option> >, + type_def_particle: Box>, + } + , + SimpleRestrictionModel(Box>), + } + + impl_enum!(ChoiceSequenceOpenContentTypeDefParticleSimpleRestrictionModel, + impl_struct_variant!(SequenceOpenContentTypeDefParticle, + (open_content, xs, Option >), + (type_def_particle, xs, Box), + ), + impl_singleton_variant!(SimpleRestrictionModel, xs, Box), + ); + + #[derive(Debug, PartialEq)] + pub enum Type<'input> { + SimpleType(Box>), + ComplexType(Box>), + } + + impl_enum!(Type, + impl_singleton_variant!(SimpleType, inline_elements, Box), + impl_singleton_variant!(ComplexType, inline_elements, Box), + ); +} + +pub mod restrictions { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] pub struct RestrictNcName<'input>(pub support::NcName<'input>); + + impl_simpletype_restriction!(RestrictNcName, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictName<'input>(pub xs::Name<'input>); + + impl_simpletype_restriction!(RestrictName, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("[\\i-[:]][\\c-[:]]*"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictAnySimpleType<'input>(pub support::AnySimpleType<'input>); + + impl_simpletype_restriction!(RestrictAnySimpleType, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: Some(1), + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictDateTime<'input>(pub support::DateTime<'input>); + + impl_simpletype_restriction!(RestrictDateTime, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: Some("required"), + }); + + #[derive(Debug, PartialEq)] pub struct RestrictDecimal<'input>(pub support::Decimal<'input>); + + impl_simpletype_restriction!(RestrictDecimal, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: Some(0), + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("[\\-+]?[0-9]+"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictDuration<'input>(pub support::Duration<'input>); + + impl_simpletype_restriction!(RestrictDuration, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("[^DT]*"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictDuration2<'input>(pub support::Duration<'input>); + + impl_simpletype_restriction!(RestrictDuration2, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("[^YM]*(T.*)?"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictInt<'input>(pub xs::Int<'input>); + + impl_simpletype_restriction!(RestrictInt, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("-32768").unwrap()), + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("32767").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictInteger<'input>(pub xs::Integer<'input>); + + impl_simpletype_restriction!(RestrictInteger, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("0").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictInteger2<'input>(pub xs::Integer<'input>); + + impl_simpletype_restriction!(RestrictInteger2, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("-9223372036854775808").unwrap()), + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("9223372036854775807").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictInteger3<'input>(pub xs::Integer<'input>); + + impl_simpletype_restriction!(RestrictInteger3, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("0").unwrap()), + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictLong<'input>(pub xs::Long<'input>); + + impl_simpletype_restriction!(RestrictLong, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("-2147483648").unwrap()), + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("2147483647").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictNonNegativeInteger<'input>(pub support::NonNegativeInteger<'input>); + + impl_simpletype_restriction!(RestrictNonNegativeInteger, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("18446744073709551615").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictNonNegativeInteger2<'input>(pub support::NonNegativeInteger<'input>); + + impl_simpletype_restriction!(RestrictNonNegativeInteger2, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("1").unwrap()), + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictNonPositiveInteger<'input>(pub xs::NonPositiveInteger<'input>); + + impl_simpletype_restriction!(RestrictNonPositiveInteger, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("-1").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictNormalizedString<'input>(pub xs::NormalizedString<'input>); + + impl_simpletype_restriction!(RestrictNormalizedString, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: Some("collapse"), + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictShort<'input>(pub xs::Short<'input>); + + impl_simpletype_restriction!(RestrictShort, Facets { + min_exclusive: None, + min_inclusive: Some(BigFloatNotNaN::from_str("-128").unwrap()), + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("127").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictString<'input>(pub support::XmlString<'input>); + + impl_simpletype_restriction!(RestrictString, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: Some("replace"), + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictToken<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(RestrictToken, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictToken2<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(RestrictToken2, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("\\c+"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictToken3<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(RestrictToken3, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: Some("\\i\\c*"), + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictUnsignedInt<'input>(pub xs::UnsignedInt<'input>); + + impl_simpletype_restriction!(RestrictUnsignedInt, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("65535").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictUnsignedLong<'input>(pub xs::UnsignedLong<'input>); + + impl_simpletype_restriction!(RestrictUnsignedLong, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("4294967295").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictUnsignedShort<'input>(pub xs::UnsignedShort<'input>); + + impl_simpletype_restriction!(RestrictUnsignedShort, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: Some(BigFloatNotNaN::from_str("255").unwrap()), + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationInterleaveSuffix<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationInterleaveSuffix, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["interleave", "suffix"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationNoneInterleaveSuffix<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationNoneInterleaveSuffix, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["none", "interleave", "suffix"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationOptionalRequiredProhibited<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationOptionalRequiredProhibited, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["optional", "required", "prohibited"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationPreserveReplaceCollapse<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationPreserveReplaceCollapse, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["preserve", "replace", "collapse"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationProhibitedOptionalRequired<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationProhibitedOptionalRequired, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["prohibited", "optional", "required"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationQualifiedUnqualified<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationQualifiedUnqualified, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["qualified", "unqualified"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationSkipLaxStrict<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationSkipLaxStrict, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["skip", "lax", "strict"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationSubstitutionExtensionRestrictionListUnion<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(EnumerationSubstitutionExtensionRestrictionListUnion, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["substitution", "extension", "restriction", "list", "union"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct Unbounded<'input>(pub xs::Nmtoken<'input>); + + impl_simpletype_restriction!(Unbounded, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["unbounded"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct Enumeration01<'input>(pub xs::AllNni<'input>); + + impl_simpletype_restriction!(Enumeration01, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["0", "1"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictBasicNamespaceList<'input>(pub xs::BasicNamespaceList<'input>); + + impl_simpletype_restriction!(RestrictBasicNamespaceList, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: Some(1), + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationExtensionRestriction<'input>(pub xs::DerivationControl<'input>); + + impl_simpletype_restriction!(EnumerationExtensionRestriction, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["extension", "restriction"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationExtensionRestrictionListUnion<'input>(pub xs::DerivationControl<'input>); + + impl_simpletype_restriction!(EnumerationExtensionRestrictionListUnion, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["extension", "restriction", "list", "union"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationExtensionRestrictionSubstitution<'input>(pub xs::DerivationControl<'input>); + + impl_simpletype_restriction!(EnumerationExtensionRestrictionSubstitution, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["extension", "restriction", "substitution"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationListUnionRestrictionExtension<'input>(pub xs::DerivationControl<'input>); + + impl_simpletype_restriction!(EnumerationListUnionRestrictionExtension, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["list", "union", "restriction", "extension"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct Enumeration012<'input>(pub support::NonNegativeInteger<'input>); + + impl_simpletype_restriction!(Enumeration012, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["0", "1"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct RestrictToken4<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(RestrictToken4, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: None, + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationAnyOther<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(EnumerationAnyOther, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["##any", "##other"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationDefaultNamespaceTargetNamespaceLocal<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(EnumerationDefaultNamespaceTargetNamespaceLocal, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["##defaultNamespace", "##targetNamespace", "##local"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct Defined<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(Defined, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["##defined"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationDefinedDefinedSibling<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(EnumerationDefinedDefinedSibling, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["##defined", "##definedSibling"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct EnumerationTargetNamespaceLocal<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(EnumerationTargetNamespaceLocal, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["##targetNamespace", "##local"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); + + #[derive(Debug, PartialEq)] pub struct All<'input>(pub support::Token<'input>); + + impl_simpletype_restriction!(All, Facets { + min_exclusive: None, + min_inclusive: None, + max_exclusive: None, + max_inclusive: None, + total_digits: None, + fraction_digits: None, + length: None, + min_length: None, + max_length: None, + enumeration: Some(vec!["#all"]), + white_space: None, + pattern: None, + assertion: None, + explicit_timezone: None, + }); +} + +pub mod lists { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] + pub struct QNameList<'input>(pub Vec>); + + impl_list!(QNameList, support::QName); + + #[derive(Debug, PartialEq)] + pub struct DerivationControlList<'input>(pub Vec>); + + impl_list!(DerivationControlList, restrictions::EnumerationExtensionRestrictionSubstitution); + + #[derive(Debug, PartialEq)] + pub struct DerivationControlList2<'input>(pub Vec>); + + impl_list!(DerivationControlList2, restrictions::EnumerationListUnionRestrictionExtension); + + #[derive(Debug, PartialEq)] + pub struct ReducedDerivationControlList<'input>(pub Vec>); + + impl_list!(ReducedDerivationControlList, xs::ReducedDerivationControl); + + #[derive(Debug, PartialEq)] + pub struct TypeDerivationControlList<'input>(pub Vec>); + + impl_list!(TypeDerivationControlList, xs::TypeDerivationControl); + + #[derive(Debug, PartialEq)] + pub struct UnionQNameTokenList<'input>(pub Vec>); + + impl_list!(UnionQNameTokenList, unions::UnionQNameToken); + + #[derive(Debug, PartialEq)] + pub struct UnionAnyUriTokenList<'input>(pub Vec>); + + impl_list!(UnionAnyUriTokenList, unions::UnionAnyUriToken); +} + +pub mod unions { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] + pub enum UnionQNameToken<'input> { + QName(support::QName<'input>), + Token(restrictions::Defined<'input>), + } + + impl_union!(UnionQNameToken, { + impl_union_variant!(QName), + impl_union_variant!(Token), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionQNameToken2<'input> { + QName(support::QName<'input>), + Token(restrictions::EnumerationDefinedDefinedSibling<'input>), + } + + impl_union!(UnionQNameToken2, { + impl_union_variant!(QName), + impl_union_variant!(Token), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionAnyUriToken<'input> { + AnyUri(support::AnyUri<'input>), + Token(restrictions::EnumerationDefaultNamespaceTargetNamespaceLocal<'input>), + } + + impl_union!(UnionAnyUriToken, { + impl_union_variant!(AnyUri), + impl_union_variant!(Token), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionAnyUriToken2<'input> { + AnyUri(support::AnyUri<'input>), + Token(restrictions::EnumerationTargetNamespaceLocal<'input>), + } + + impl_union!(UnionAnyUriToken2, { + impl_union_variant!(AnyUri), + impl_union_variant!(Token), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionNonNegativeIntegerNmtoken<'input> { + NonNegativeInteger(support::NonNegativeInteger<'input>), + Nmtoken(restrictions::Unbounded<'input>), + } + + impl_union!(UnionNonNegativeIntegerNmtoken, { + impl_union_variant!(NonNegativeInteger), + impl_union_variant!(Nmtoken), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionSpecialNamespaceListBasicNamespaceList<'input> { + SpecialNamespaceList(xs::SpecialNamespaceList<'input>), + BasicNamespaceList(xs::BasicNamespaceList<'input>), + } + + impl_union!(UnionSpecialNamespaceListBasicNamespaceList, { + impl_union_variant!(SpecialNamespaceList), + impl_union_variant!(BasicNamespaceList), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionTokenDerivationControlList<'input> { + Token(restrictions::All<'input>), + DerivationControlList(lists::DerivationControlList<'input>), + } + + impl_union!(UnionTokenDerivationControlList, { + impl_union_variant!(Token), + impl_union_variant!(DerivationControlList), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionTokenReducedDerivationControlList<'input> { + Token(restrictions::All<'input>), + ReducedDerivationControlList(lists::ReducedDerivationControlList<'input>), + } + + impl_union!(UnionTokenReducedDerivationControlList, { + impl_union_variant!(Token), + impl_union_variant!(ReducedDerivationControlList), + }); + + #[derive(Debug, PartialEq)] + pub enum UnionTokenTypeDerivationControlList<'input> { + Token(restrictions::All<'input>), + TypeDerivationControlList(lists::TypeDerivationControlList<'input>), + } + + impl_union!(UnionTokenTypeDerivationControlList, { + impl_union_variant!(Token), + impl_union_variant!(TypeDerivationControlList), + }); +} + +pub mod sequences { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] + pub struct SequenceAny<'input> { + pub any: super::support::Any<'input>, + } + + impl_group_or_sequence!(SequenceAny, + (any, support, Any), + ); + + #[derive(Debug, PartialEq)] + pub struct AnnotatedOpenContent<'input> { + pub default_open_content: super::xs::DefaultOpenContent<'input>, + pub annotation: Vec>, + } + + impl_group_or_sequence!(AnnotatedOpenContent, + (default_open_content, xs, DefaultOpenContent), + (annotation, xs, Vec), + ); + + /// This choice is added simply to make this a valid restriction per the REC + #[derive(Debug, PartialEq)] + pub struct SequenceOpenContentTypeDefParticle<'input> { + pub open_content: Option>, + pub type_def_particle: super::xs::TypeDefParticle<'input>, + } + + impl_group_or_sequence!(SequenceOpenContentTypeDefParticle, + (open_content, xs, Option), + (type_def_particle, xs, TypeDefParticle), + ); + + #[derive(Debug, PartialEq)] + pub struct SequenceSchemaTopAnnotation<'input> { + pub schema_top: super::xs::SchemaTop<'input>, + pub annotation: Vec>, + } + + impl_group_or_sequence!(SequenceSchemaTopAnnotation, + (schema_top, xs, SchemaTop), + (annotation, xs, Vec), + ); + + #[derive(Debug, PartialEq)] + pub struct UniquenessSpec<'input> { + pub selector: super::xs::Selector<'input>, + pub field: Vec>, + } + + impl_group_or_sequence!(UniquenessSpec, + (selector, xs, Selector), + (field, xs, Vec), + ); +} + +pub mod inline_elements { + #[allow(unused_imports)] + use super::*; + + #[derive(Debug, PartialEq)] + pub struct All<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub all_model: super::xs::AllModel<'input>, + } + + impl_element!(All, "http://www.w3.org/2001/XMLSchema", "all", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (all_model, xs, AllModel), + }); + + /// This type is used for 'alternative' elements. + #[derive(Debug, PartialEq)] + pub struct AlternativeAltType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_test: Option>, + pub attr_type: Option>, + pub attr_xpath_default_namespace: Option>, + pub annotation: Option>, + pub type_: Option>, + } + + impl_element!(AlternativeAltType, "http://www.w3.org/2001/XMLSchema", "alternative", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "test") => attr_test: optional, + ("http://www.w3.org/2001/XMLSchema", "type") => attr_type: optional, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + }, fields = { + (annotation, xs, Option), + (type_, enums, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct AnyWildcard<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_namespace: Option>, + pub attr_not_namespace: Option>, + pub attr_process_contents: Option>, + pub annotation: Option>, + } + + impl_element!(AnyWildcard, "http://www.w3.org/2001/XMLSchema", "any", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "namespace") => attr_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "notNamespace") => attr_not_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "processContents") => attr_process_contents: optional, + }, fields = { + (annotation, xs, Option), + }); + + /// This type is extended by all types which allow annotation other than itself + #[derive(Debug, PartialEq)] + pub struct Assertion<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_test: Option>, + pub attr_xpath_default_namespace: Option>, + pub annotation: Option>, + } + + impl_element!(Assertion, "http://www.w3.org/2001/XMLSchema", "assert", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "test") => attr_test: optional, + ("http://www.w3.org/2001/XMLSchema", "xpathDefaultNamespace") => attr_xpath_default_namespace: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct Attribute<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_type: Option>, + pub attr_use: Option>, + pub attr_default: Option>, + pub attr_fixed: Option>, + pub attr_form: Option>, + pub attr_target_namespace: Option>, + pub attr_inheritable: Option>, + pub attr_name: Option>, + pub attr_ref: Option>, + pub annotation: Option>, + pub local_simple_type: Option>, + } + + impl_element!(Attribute, "http://www.w3.org/2001/XMLSchema", "attribute", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "type") => attr_type: optional, + ("http://www.w3.org/2001/XMLSchema", "use") => attr_use: optional, + ("http://www.w3.org/2001/XMLSchema", "default") => attr_default: optional, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + ("http://www.w3.org/2001/XMLSchema", "form") => attr_form: optional, + ("http://www.w3.org/2001/XMLSchema", "targetNamespace") => attr_target_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "inheritable") => attr_inheritable: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: optional, + }, fields = { + (annotation, xs, Option), + (local_simple_type, inline_elements, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct AttributeGroupRef<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_ref: support::QName<'input>, + pub annotation: Option>, + } + + impl_element!(AttributeGroupRef, "http://www.w3.org/2001/XMLSchema", "attributeGroup", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: required, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct ChoiceSimpleExplicitGroup<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub annotation: Option>, + pub nested_particle: Vec>, + } + + impl_element!(ChoiceSimpleExplicitGroup, "http://www.w3.org/2001/XMLSchema", "choice", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation, xs, Option), + (nested_particle, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct LocalComplexType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_mixed: Option>, + pub attr_default_attributes_apply: Option>, + pub annotation: Option>, + pub complex_type_model: super::xs::ComplexTypeModel<'input>, + } + + impl_element!(LocalComplexType, "http://www.w3.org/2001/XMLSchema", "complexType", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "mixed") => attr_mixed: optional, + ("http://www.w3.org/2001/XMLSchema", "defaultAttributesApply") => attr_default_attributes_apply: optional, + }, fields = { + (annotation, xs, Option), + (complex_type_model, xs, ComplexTypeModel), + }); + + #[derive(Debug, PartialEq)] + pub struct LocalElement<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_type: Option>, + pub attr_default: Option>, + pub attr_fixed: Option>, + pub attr_nillable: Option>, + pub attr_block: Option>, + pub attr_form: Option>, + pub attr_target_namespace: Option>, + pub attr_name: Option>, + pub attr_ref: Option>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + pub type_: Option>, + pub alternative_alt_type: Vec>, + pub identity_constraint: Vec>, + } + + impl_element!(LocalElement, "http://www.w3.org/2001/XMLSchema", "element", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "type") => attr_type: optional, + ("http://www.w3.org/2001/XMLSchema", "default") => attr_default: optional, + ("http://www.w3.org/2001/XMLSchema", "fixed") => attr_fixed: optional, + ("http://www.w3.org/2001/XMLSchema", "nillable") => attr_nillable: optional, + ("http://www.w3.org/2001/XMLSchema", "block") => attr_block: optional, + ("http://www.w3.org/2001/XMLSchema", "form") => attr_form: optional, + ("http://www.w3.org/2001/XMLSchema", "targetNamespace") => attr_target_namespace: optional, + ("http://www.w3.org/2001/XMLSchema", "name") => attr_name: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: optional, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + (type_, enums, Option), + (alternative_alt_type, inline_elements, Vec), + (identity_constraint, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct ExtensionType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_base: support::QName<'input>, + pub annotation: Option>, + pub open_content: Option>, + pub type_def_particle: Option>, + pub attr_decls: super::xs::AttrDecls<'input>, + pub assertions: super::xs::Assertions<'input>, + } + + impl_element!(ExtensionType, "http://www.w3.org/2001/XMLSchema", "extension", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "base") => attr_base: required, + }, fields = { + (annotation, xs, Option), + (open_content, xs, Option), + (type_def_particle, xs, Option), + (attr_decls, xs, AttrDecls), + (assertions, xs, Assertions), + }); + + /// No typeDefParticle group reference + #[derive(Debug, PartialEq)] + pub struct SimpleExtensionType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_base: support::QName<'input>, + pub annotation: Option>, + pub attr_decls: super::xs::AttrDecls<'input>, + pub assertions: super::xs::Assertions<'input>, + } + + impl_element!(SimpleExtensionType, "http://www.w3.org/2001/XMLSchema", "extension", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "base") => attr_base: required, + }, fields = { + (annotation, xs, Option), + (attr_decls, xs, AttrDecls), + (assertions, xs, Assertions), + }); + + #[derive(Debug, PartialEq)] + pub struct Group<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_ref: support::QName<'input>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + } + + impl_element!(Group, "http://www.w3.org/2001/XMLSchema", "group", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: required, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct GroupRef<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_ref: support::QName<'input>, + pub attr_min_occurs: Option>, + pub attr_max_occurs: Option>, + pub annotation: Option>, + } + + impl_element!(GroupRef, "http://www.w3.org/2001/XMLSchema", "group", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "ref") => attr_ref: required, + ("http://www.w3.org/2001/XMLSchema", "minOccurs") => attr_min_occurs: optional, + ("http://www.w3.org/2001/XMLSchema", "maxOccurs") => attr_max_occurs: optional, + }, fields = { + (annotation, xs, Option), + }); + + #[derive(Debug, PartialEq)] + pub struct ComplexRestrictionType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_base: support::QName<'input>, + pub annotation: Option>, + pub sequence_open_content_type_def_particle: Option>, + pub attr_decls: super::xs::AttrDecls<'input>, + pub assertions: super::xs::Assertions<'input>, + } + + impl_element!(ComplexRestrictionType, "http://www.w3.org/2001/XMLSchema", "restriction", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "base") => attr_base: required, + }, fields = { + (annotation, xs, Option), + (sequence_open_content_type_def_particle, sequences, Option), + (attr_decls, xs, AttrDecls), + (assertions, xs, Assertions), + }); + + #[derive(Debug, PartialEq)] + pub struct SimpleRestrictionType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub attr_base: support::QName<'input>, + pub annotation: Option>, + pub simple_restriction_model: Option>, + pub attr_decls: super::xs::AttrDecls<'input>, + pub assertions: super::xs::Assertions<'input>, + } + + impl_element!(SimpleRestrictionType, "http://www.w3.org/2001/XMLSchema", "restriction", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + ("http://www.w3.org/2001/XMLSchema", "base") => attr_base: required, + }, fields = { + (annotation, xs, Option), + (simple_restriction_model, xs, Option), + (attr_decls, xs, AttrDecls), + (assertions, xs, Assertions), + }); + + #[derive(Debug, PartialEq)] + pub struct SequenceSimpleExplicitGroup<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub annotation: Option>, + pub nested_particle: Vec>, + } + + impl_element!(SequenceSimpleExplicitGroup, "http://www.w3.org/2001/XMLSchema", "sequence", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation, xs, Option), + (nested_particle, xs, Vec), + }); + + #[derive(Debug, PartialEq)] + pub struct LocalSimpleType<'input> { + pub attrs: HashMap, &'input str>, + pub attr_id: Option>, + pub annotation: Option>, + pub simple_derivation: super::xs::SimpleDerivation<'input>, + } + + impl_element!(LocalSimpleType, "http://www.w3.org/2001/XMLSchema", "simpleType", attributes = { + ("http://www.w3.org/2001/XMLSchema", "id") => attr_id: optional, + }, fields = { + (annotation, xs, Option), + (simple_derivation, xs, SimpleDerivation), + }); +} diff --git a/xml-schema/src/parser_generator.rs b/xml-schema/src/parser_generator.rs new file mode 100644 index 0000000..ebed18a --- /dev/null +++ b/xml-schema/src/parser_generator.rs @@ -0,0 +1,796 @@ +use std::collections::{HashMap, HashSet}; + +use codegen as cg; +use heck::{SnakeCase, CamelCase}; + +use support::{ParseContext, Facets}; +use primitives::PRIMITIVE_TYPES; +use processor::*; +use names::*; + +#[derive(Default)] +pub struct XsdParseContext<'input> { + namespaces: HashMap<&'input str, &'input str>, +} +impl<'input> ParseContext<'input> for XsdParseContext<'input> { + fn on_xmlns(&mut self, name: Option<&'input str>, uri: &'input str) { + match name { + None => (), + Some(ns) => { self.namespaces.insert(uri, ns); }, + } + } +} + +const KEYWORDS: &[&'static str] = &["override"]; +fn escape_keyword(name: &str) -> String { + if KEYWORDS.contains(&name) { + format!("{}_", name) + } + else { + name.to_string() + } +} + +#[derive(Debug)] +pub struct ParserGenerator<'ast, 'input: 'ast> { + processors: Vec>, + module_names: HashMap, String>, // URI -> module name + primitive_types: HashMap<&'static str, RichType<'input, Type<'input>>>, + simple_restrictions: HashMap<(FullName<'input>, Facets<'input>), String>, + renames: HashMap, + self_gen: bool, +} + +impl<'ast, 'input: 'ast> ParserGenerator<'ast, 'input> { + pub fn new(processors: Vec>, parse_context: &XsdParseContext<'input>, renames: HashMap) -> ParserGenerator<'ast, 'input> { + let mut module_names = HashMap::new(); + module_names.insert(None, "unqualified".to_string()); + let mut name_gen = NameGenerator::new(); + + let mut primitive_types = HashMap::new(); + for (name, type_name) in PRIMITIVE_TYPES { + primitive_types.insert(*name, RichType::new(NameHint::new(name), Type::Simple(SimpleType::Primitive(name, type_name)), Documentation::new())); + } + + for (&uri, ns) in parse_context.namespaces.iter() { + if Some(&ns.to_string()) != module_names.get(&Some(uri)) { + module_names.insert(Some(uri), name_gen.gen_name(ns.to_string())); + } + } + + let mut self_gen = false; + for proc in &processors { + if proc.target_namespace == Some(&SCHEMA_URI) { + self_gen = true; + } + } + ParserGenerator { + processors, renames, module_names, primitive_types, self_gen, + simple_restrictions: HashMap::new(), + } + } + + pub fn get_module_name(&self, qname: FullName<'input>) -> String { + if qname.namespace() == Some(SCHEMA_URI) { + for (name, _) in PRIMITIVE_TYPES { + if *name == qname.local_name() { + return "support".to_string(); + } + } + } + self.module_names.get(&qname.namespace()).expect(&format!("{:?}", qname.namespace())).clone() + } + + pub fn gen_target_scope(&mut self) -> cg::Scope { + let mut scope = cg::Scope::new(); + scope.raw("pub use std::collections::HashMap;"); + scope.raw("pub use std::marker::PhantomData;"); + self.create_modules(&mut scope); + self.gen_choices(&mut scope); + self.gen_simple_types(&mut scope); + self.gen_lists(&mut scope); + self.gen_unions(&mut scope); + self.gen_sequences(&mut scope); + self.gen_elements(&mut scope); + self.gen_inline_elements(&mut scope); + self.gen_groups(&mut scope); + scope + } + + fn create_modules(&mut self, scope: &mut cg::Scope) { + let mut modules: Vec<_> = self.module_names.iter().collect(); + modules.sort(); + for (&uri, mod_name) in modules { + if !self.self_gen && uri == Some(SCHEMA_URI) { + scope.raw(&format!("#[allow(unused_imports)]\npub use xml_schema::parser::xs as {};", mod_name)); + } + else { + let mut module = scope.new_module(mod_name); + module.vis("pub"); + module.scope().raw(&format!("//! {:?}", uri)); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + } + } + } + + fn gen_choices(&self, scope: &mut cg::Scope) { + let module = scope.new_module("enums"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + let mut name_gen = NameGenerator::new(); + for proc in &self.processors { + let mut choices: Vec<_> = proc.choices.iter().collect(); + choices.sort_by_key(|&(t,names)| (t, names.iter().collect::>())); + for (ref choice, ref names) in choices { + for name in names.iter() { + let enum_name = escape_keyword(&name.to_camel_case()); + let enum_name = name_gen.gen_name(enum_name); + self.gen_choice(module.scope(), &enum_name, choice, &Documentation::new()); + } + } + } + } + fn gen_choice(&self, scope: &mut cg::Scope, enum_name: &String, items: &Vec>>, doc: &Documentation<'input>) { + let mut impl_code = Vec::new(); + let enum_name = self.renames.get(enum_name).unwrap_or(enum_name); + impl_code.push(format!("impl_enum!({},", enum_name)); + { + let enum_ = scope.new_enum(&enum_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + for (i, item) in items.iter().enumerate() { + let mut fields = Vec::new(); + let mut doc = doc.clone(); + { + let mut name_gen = NameGenerator::new(); + let field_writer = &mut |field_name: String, type_mod_name: String, min_occurs, max_occurs, type_name: String| { + let field_name = escape_keyword(&name_gen.gen_name(field_name.to_snake_case())); + let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); + let type_name = escape_keyword(&type_name.to_camel_case()); + fields.push((field_name, type_mod_name, min_occurs, max_occurs, type_name)); + }; + let doc_writer = &mut |doc2: &Documentation<'input>| doc.extend(doc2); + self.write_type_in_struct_def(field_writer, &mut Some(doc_writer), &item.type_); + } + enum_.doc(&doc.to_string()); + let variant_name = name_from_hint(&item.name_hint) + .unwrap_or(format!("{}{}", enum_name, i)).to_camel_case(); + let variant_name = escape_keyword(&variant_name.to_camel_case()); + let variant_name = self.renames.get(&variant_name).unwrap_or(&variant_name); + let mut variant = enum_.new_variant(&variant_name); + if fields.len() == 1 { + let (_, type_mod_name, min_occurs, max_occurs, type_name) = fields.remove(0); + match (min_occurs, max_occurs) { + (1, 1) => { + variant.tuple(&format!("Box>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); + impl_code.push(format!(" impl_singleton_variant!({}, {}, Box<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); + }, + (0, 1) => { + variant.tuple(&format!("Option>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); + impl_code.push(format!(" impl_singleton_variant!({}, {}, Option<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); + }, + (_, _) => { + variant.tuple(&format!("Vec>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); + impl_code.push(format!(" impl_singleton_variant!({}, {}, Vec<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); + }, + } + } + else { + impl_code.push(format!(" impl_struct_variant!({},", variant_name)); + for (field_name, type_mod_name, min_occurs, max_occurs, type_name) in fields { + match (min_occurs, max_occurs) { + (1, 1) => { + impl_code.push(format!(" ({}, {}, Box<{}>),", field_name, type_mod_name, type_name)); + variant.named(&field_name, &format!("Box>", type_mod_name, type_name)); + }, + (0, 1) => { + impl_code.push(format!(" ({}, {}, Option >),", field_name, type_mod_name, type_name)); + variant.named(&field_name, &format!("Option> >", type_mod_name, type_name)); + }, + (_, _) => { + impl_code.push(format!(" ({}, {}, Vec<{}>),", field_name, type_mod_name, type_name)); + variant.named(&field_name, &format!("Vec >", type_mod_name, type_name)); + }, + } + } + impl_code.push(format!(" ),")); + } + } + } + impl_code.push(");".to_string()); + scope.raw(&impl_code.join("\n")); + } + fn gen_unions(&self, scope: &mut cg::Scope) { + let module = scope.new_module("unions"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + let mut name_gen = NameGenerator::new(); + for proc in &self.processors { + let mut unions: Vec<_> = proc.unions.iter().collect(); + unions.sort_by_key(|&(items, names)| (items, names.iter().collect::>())); + for (ref items, ref names) in unions { + for name in names.iter() { + let enum_name = escape_keyword(&name.to_camel_case()); + let enum_name = name_gen.gen_name(enum_name); + let mut impl_code = Vec::new(); + impl_code.push(format!("impl_union!({}, {{", enum_name)); + { + let enum_ = module.new_enum(&enum_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + for item in items.iter() { + let RichType { name_hint, attrs, type_, doc } = item; + let variant_name = name_from_hint(name_hint).unwrap().to_camel_case(); + if let Some((type_mod_name, type_name)) = self.get_simple_type_name(type_) { + enum_.new_variant(&variant_name).tuple(&format!("{}::{}<'input>", type_mod_name, type_name)); + impl_code.push(format!(" impl_union_variant!({}),", variant_name)); + } + } + } + impl_code.push(format!("}});")); + module.scope().raw(&impl_code.join("\n")); + } + } + } + } + + fn gen_lists(&self, scope: &mut cg::Scope) { + let module = scope.new_module("lists"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + let mut name_gen = NameGenerator::new(); + for proc in &self.processors { + let mut lists: Vec<_> = proc.lists.iter().collect(); + lists.sort_by_key(|&(item_type, names)| (item_type, names.iter().collect::>())); + for (ref item_type, ref names) in lists { + for name in names.iter() { + let name = escape_keyword(&name.to_camel_case()); + let struct_name = name_gen.gen_name(name); + if let Some((type_mod_name, type_name)) = self.get_simple_type_name(&item_type.type_) { + { + let struct_ = module.new_struct(&struct_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + struct_.tuple_field(&format!("pub Vec<{}::{}<'input>>", type_mod_name, type_name)); + } + module.scope().raw(&format!("impl_list!({}, {}::{});", struct_name, type_mod_name, type_name)); + } + } + } + } + } + + fn get_simple_type_name(&self, ty: &SimpleType<'input>) -> Option<(String, String)> { + let (type_mod_name, type_name) = match ty { + SimpleType::Alias(name) => { + if name.namespace() == Some(&SCHEMA_URI) { + for (prim_name, prim_type_name) in PRIMITIVE_TYPES { + if *prim_name == name.local_name() { + return Some(("support".to_string(), prim_type_name.to_string())); + } + } + } + let type_mod_name = self.get_module_name(*name); + let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); + let type_name = escape_keyword(&name.local_name().to_camel_case()); + (type_mod_name, type_name) + }, + SimpleType::Restriction(name, facets) => { + ("restrictions".to_string(), self.simple_restrictions.get(&(name.clone(), facets.clone())).unwrap().to_string()) + } + SimpleType::Primitive(field_name, type_name) => { + ("support".to_string(), type_name.to_string()) + }, + SimpleType::Union(type_name) => { + let type_name = escape_keyword(&type_name.to_camel_case()); + ("unions".to_string(), type_name) + }, + SimpleType::List(name) => { + let type_name = escape_keyword(&name.to_camel_case()); + ("lists".to_string(), type_name) + }, + SimpleType::Empty => { + return None + }, + }; + Some((type_mod_name, type_name)) + } + + fn gen_simple_types(&mut self, scope: &mut cg::Scope) { + self.gen_simple_restrictions(scope); + let mut name_gen = NameGenerator::new(); + for proc in &self.processors { + let mut types: Vec<_> = proc.simple_types.iter().collect(); + types.sort_by_key(|&(n,_)| n); + for (&qname, (ref ty, ref doc)) in types { + let mod_name = self.get_module_name(qname); + if mod_name == "support" { + // Implemented as a primitive, skip it. + continue; + } + let scope = scope.get_module_mut(&mod_name) + .expect(&mod_name).scope(); + let name = escape_keyword(&qname.local_name().to_camel_case()); + let name = name_gen.gen_name(name); + if let Some((type_mod_name, type_name)) = self.get_simple_type_name(&ty.type_) { + scope.raw(&format!("pub type {}<'input> = {}::{}<'input>;", name, type_mod_name, type_name)); + } + else { + panic!("{:?}", ty) + } + } + } + } + + fn gen_simple_restrictions(&mut self, scope: &mut cg::Scope) { + let mut name_gen = NameGenerator::new(); + let module = scope.new_module("restrictions"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + + for proc in &self.processors { + let mut simple_restrictions: Vec<_> = proc.simple_restrictions.iter().collect(); + + simple_restrictions.sort(); + for (base_name, facets) in simple_restrictions { + if self.simple_restrictions.get(&(*base_name, facets.clone())).is_some() { + continue; + } + let name = match &facets.enumeration { + Some(items) => { + if items.len() == 1 { + format!("{}", items[0]) + } + else { + format!("enumeration_{}", items.join("_")) + } + }, + None => format!("Restrict_{}", base_name.local_name()), + }; + let name = name.to_camel_case(); + let name = name_gen.gen_name(name.clone()); + self.simple_restrictions.insert((base_name.clone(), facets.clone()), name.clone()); + let (base_mod_name, base_type_name) = self.get_simple_type_name(&SimpleType::Alias(*base_name)).unwrap(); // TODO + module.scope().raw(&format!("#[derive(Debug, PartialEq)] pub struct {}<'input>(pub {}::{}<'input>);", name, base_mod_name, base_type_name)); + let mut s = Vec::new(); + let f = &mut |n: &Option<_>| { + match n.as_ref() { + None => "None".to_string(), + Some(f) => format!("Some(BigFloatNotNaN::from_str(\"{}\").unwrap())", f), + } + }; + s.push(format!("min_exclusive: {},", f(&facets.min_exclusive))); + s.push(format!("min_inclusive: {},", f(&facets.min_inclusive))); + s.push(format!("max_exclusive: {},", f(&facets.max_exclusive))); + s.push(format!("max_inclusive: {},", f(&facets.max_inclusive))); + s.push(format!("total_digits: {:?},", facets.total_digits)); + s.push(format!("fraction_digits: {:?},", facets.fraction_digits)); + s.push(format!("length: {:?},", facets.length)); + s.push(format!("min_length: {:?},", facets.min_length)); + s.push(format!("max_length: {:?},", facets.max_length)); + match &facets.enumeration { + Some(items) => s.push(format!("enumeration: Some(vec![{}]),", items.iter().map(|i| format!("{:?}", i)).collect::>().join(", "))), + None => s.push("enumeration: None,".to_string()), + } + s.push(format!("white_space: {:?},", facets.white_space)); + s.push(format!("pattern: {:?},", facets.pattern)); + s.push(format!("assertion: {:?},", facets.assertion)); + s.push(format!("explicit_timezone: {:?},", facets.explicit_timezone)); + module.scope().raw(&format!("impl_simpletype_restriction!({}, Facets {{\n {}\n}});", name, s.join("\n "))); + } + } + } + + fn gen_sequences(&mut self, scope: &mut cg::Scope) { + let module = scope.new_module("sequences"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + + for proc in &self.processors { + let mut sequences: Vec<_> = proc.sequences.iter().collect(); + + sequences.sort_by_key(|&(i,(n,_))| (n.iter().collect::>(), i)); + for (sequence, (names, doc)) in sequences { + for name in names.iter() { + self.gen_group_or_sequence(module, name, &sequence.iter().collect(), doc); + } + } + } + } + + fn gen_groups(&mut self, scope: &mut cg::Scope) { + for proc in &self.processors { + let mut groups: Vec<_> = proc.groups.iter().collect(); + + groups.sort_by_key(|&(n,_)| n); + for (&name, group) in groups { + let mod_name = self.get_module_name(name); + let mut module = scope.get_module_mut(&mod_name).unwrap(); + let struct_name = name.local_name(); + if let Type::InlineChoice(ref items) = group.type_ { + self.gen_choice(module.scope(), &struct_name.to_string().to_camel_case(), items, &group.doc); + } + else if let Type::InlineSequence(ref items) = group.type_ { + self.gen_group_or_sequence(module, struct_name, &items.iter().collect(), &group.doc); + } + else { + self.gen_group_or_sequence(module, struct_name, &vec![group], &group.doc); + } + } + } + } + + fn gen_fields(&self, empty_struct: &mut bool, struct_: &mut cg::Struct, impl_code: &mut Vec, doc: &mut Documentation<'input>, name_gen: &mut NameGenerator, type_: &Type<'input>) { + let field_writer = &mut |name: String, type_mod_name: String, min_occurs, max_occurs, type_name: String| { + *empty_struct = false; + let name = escape_keyword(&name_gen.gen_name(name.to_snake_case())); + let name = self.renames.get(&name).unwrap_or(&name); + let type_mod_name = escape_keyword(&type_mod_name.to_snake_case()); + let type_name = escape_keyword(&type_name.to_camel_case()); + let type_name = self.renames.get(&type_name).unwrap_or(&type_name); + match (min_occurs, max_occurs) { + (1, 1) => { + struct_.field(&format!("pub {}", name), &format!("super::{}::{}<'input>", type_mod_name, type_name)); + impl_code.push(format!(" ({}, {}, {}),", name, type_mod_name, type_name)) + }, + (0, 1) => { + struct_.field(&format!("pub {}", name), &format!("Option>", type_mod_name, type_name)); + impl_code.push(format!(" ({}, {}, Option<{}>),", name, type_mod_name, type_name)) + }, + (_, ::std::usize::MAX) => { + struct_.field(&format!("pub {}", name), &format!("Vec>", type_mod_name, type_name)); + impl_code.push(format!(" ({}, {}, Vec<{}; min={};>),", name, type_mod_name, type_name, min_occurs)) + }, + (_, _) => { + struct_.field(&format!("pub {}", name), &format!("Vec>", type_mod_name, type_name)); + impl_code.push(format!(" ({}, {}, Vec<{}; min={}; max={};>),", name, type_mod_name, type_name, min_occurs, max_occurs)) + }, + } + }; + let doc_writer = &mut |doc2| doc.extend(doc2); + self.write_type_in_struct_def(field_writer, &mut Some(doc_writer), &type_); + } + + fn gen_group_or_sequence(&self, module: &mut cg::Module, struct_name: &'input str, items: &Vec<&RichType<'input, Type<'input>>>, doc: &Documentation<'input>) { + let mut impl_code = Vec::new(); + let struct_name = escape_keyword(&struct_name.to_camel_case()); + let struct_name = self.renames.get(&struct_name).unwrap_or(&struct_name); + impl_code.push(format!("impl_group_or_sequence!({},", struct_name)); + { + let mut empty_struct = true; + let struct_ = module.new_struct(&struct_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + let mut name_gen = NameGenerator::new(); + let mut doc = doc.clone(); + { + for item in items { + self.gen_fields(&mut empty_struct, struct_, &mut impl_code, &mut doc, &mut name_gen, &item.type_); + } + } + struct_.doc(&doc.to_string()); + if empty_struct { + struct_.tuple_field(&format!("pub ::std::marker::PhantomData<&'input ()>")); + } + } + impl_code.push(");".to_string()); + module.scope().raw(&impl_code.join("\n")); + } + + fn gen_inline_elements(&mut self, scope: &mut cg::Scope) { + let module = scope.new_module("inline_elements"); + module.vis("pub"); + module.scope().raw("#[allow(unused_imports)]\nuse super::*;"); + for proc in &self.processors { + let mut elements: Vec<_> = proc.inline_elements.iter().collect(); + + elements.sort_by_key(|&((ns,n,_,_),(n2,_))| (ns, n, n2.iter().collect::>())); + for ((namespace, tag_name, attrs, element), (struct_names, doc)) in elements { + // struct_names is always non-empty. + + let mut struct_names: Vec<_> = struct_names.iter().map(|s| s.to_camel_case()).collect(); + + // Sort them to get the shortest one, and alias all the others to this one + struct_names.sort_by_key(|n| n.len()); // TODO: just use a min_by_key + for alias in &struct_names[1..] { + module.scope().raw(&format!("pub type {}<'input> = {}<'input>;", alias, struct_names[0])); + } + + let tag_name = FullName::new(*namespace, tag_name); + self.gen_element(module, &struct_names[0], &tag_name, attrs, element, doc); + } + } + } + + fn gen_elements(&mut self, scope: &mut cg::Scope) { + for proc in &self.processors { + let mut elements: Vec<_> = proc.elements.iter().collect(); + + elements.sort_by_key(|&(n,_)| n); + for (&name, element) in elements { + let mod_name = self.get_module_name(name); + let mut module = scope.get_module_mut(&mod_name).expect(&mod_name); + let head_local_name = format!("{}_head", name.local_name()); + let mut substitutions = Vec::new(); + substitutions.push(FullName::new(name.namespace(), &head_local_name)); + for proc in &self.processors { + if let Some(members) = proc.substitution_groups.get(&name) { + substitutions.extend(members); + } + } + if substitutions.len() > 1 { + let enum_name = escape_keyword(&name.local_name().to_camel_case()); + self.gen_substitution_enum(module.scope(), &enum_name, &substitutions); + let struct_name = escape_keyword(&head_local_name.to_camel_case()); + self.gen_element(module, &struct_name, &name, &element.attrs, &element.type_, &element.doc); + } + else { + let struct_name = escape_keyword(&name.local_name().to_camel_case()); + self.gen_element(module, &struct_name, &name, &element.attrs, &element.type_, &element.doc); + } + } + } + } + + fn gen_substitution_enum(&self, scope: &mut cg::Scope, enum_name: &str, substitutions: &Vec>) { + let mut impl_code = Vec::new(); + impl_code.push(format!("impl_enum!({},", enum_name)); + let mut name_gen = NameGenerator::new(); + { + let enum_ = scope.new_enum(&enum_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + for &substitution in substitutions { + let variant_name = escape_keyword(&name_gen.gen_name(substitution.local_name().to_camel_case())); + let type_mod_name = escape_keyword(&self.get_module_name(substitution).to_snake_case()); + let type_name = escape_keyword(&substitution.local_name().to_camel_case()); + let mut variant = enum_.new_variant(&variant_name); + variant.tuple(&format!("Box>", escape_keyword(&type_mod_name), escape_keyword(&type_name))); + impl_code.push(format!(" impl_singleton_variant!({}, {}, Box<{}>),", variant_name, escape_keyword(&type_mod_name), escape_keyword(&type_name))); + } + impl_code.push(");".to_string()); + } + scope.raw(&impl_code.join("\n")); + } + + fn gen_attrs(&self, struct_: &mut cg::Struct, impl_code: &mut Vec, name_gen: &mut NameGenerator, attrs: &Attrs<'input>, seen_attrs: &mut HashMap, AttrUse>, generated_attrs: &mut HashSet>, inherited: bool) { + for (attr_name, use_, attr_type) in &attrs.named { + if generated_attrs.contains(attr_name) { + continue; + } + let default_type = SimpleType::Primitive(SCHEMA_URI, "AnySimpleType"); + let type_ = attr_type.as_ref().unwrap_or(&default_type); + let (type_mod_name, type_name) = self.get_simple_type_name(&type_).unwrap(); + let use_ = if inherited { + *seen_attrs.get(attr_name).unwrap_or(use_) + } + else { + *use_ + }; + seen_attrs.insert(attr_name.clone(), use_); + generated_attrs.insert(attr_name.clone()); + match use_ { + AttrUse::Optional => { + let field_name = name_gen.gen_name(format!("attr_{}", attr_name.local_name()).to_snake_case()); + struct_.field(&format!("pub {}", field_name), &format!("Option<{}::{}<'input>>", type_mod_name, type_name)); + impl_code.push(format!(" ({:?}, {:?}) => {}: optional,", attr_name.namespace().unwrap_or(""), attr_name.local_name(), field_name)); + }, + AttrUse::Required => { + let field_name = name_gen.gen_name(format!("attr_{}", attr_name.local_name()).to_snake_case()); + struct_.field(&format!("pub {}", field_name), &format!("{}::{}<'input>", type_mod_name, type_name)); + impl_code.push(format!(" ({:?}, {:?}) => {}: required,", attr_name.namespace().unwrap_or(""), attr_name.local_name(), field_name)); + }, + AttrUse::Prohibited => (), + } + } + for group_name in &attrs.group_refs { + let mut found = false; + for processor in self.processors.iter() { + if let Some(attrs) = processor.attribute_groups.get(group_name) { + self.gen_attrs(struct_, impl_code, name_gen, attrs, seen_attrs, generated_attrs, false); + found = true; + break; + } + } + if !found { + panic!("unknown attribute group: {:?}", group_name); + } + } + } + + fn gen_element(&self, module: &mut cg::Module, struct_name: &str, tag_name: &FullName<'input>, attrs: &Attrs<'input>, type_: &Type<'input>, doc: &Documentation<'input>) { + let mut impl_code = Vec::new(); + impl_code.push(format!("impl_element!({}, {:?}, \"{}\", attributes = {{", + struct_name, tag_name.namespace().unwrap_or(""), tag_name.local_name())); + { + let struct_ = module.new_struct(&struct_name).vis("pub").derive("Debug").derive("PartialEq").generic("'input"); + let mut empty_struct = false; + struct_.field("pub attrs", "HashMap, &'input str>"); + let mut name_gen = NameGenerator::new(); + let mut doc = doc.clone(); + let mut generated_attrs = HashSet::new(); + let mut seen_attrs = HashMap::new(); + + let attrs = self.compute_attrs(&type_, attrs); + self.gen_attrs(struct_, &mut impl_code, &mut name_gen, &attrs, &mut seen_attrs, &mut generated_attrs, false); + { + let field_writer = &mut |_, _, _, _, _| (); + let doc_writer = &mut |_| (); + self.write_type_in_struct_def(field_writer, &mut Some(doc_writer), &type_); + } + impl_code.push(format!("}}, fields = {{")); + self.gen_fields(&mut empty_struct, struct_, &mut impl_code, &mut doc, &mut name_gen, type_); + struct_.doc(&doc.to_string()); + } + impl_code.push(format!("}});")); + module.scope().raw(&impl_code.join("\n")); + } + + fn get_type(&self, name: &FullName<'input>) -> &RichType<'input, Type<'input>> { + if name.namespace() == Some(SCHEMA_URI) { + if let Some(type_) = self.primitive_types.get(name.local_name()) { + return type_; + } + } + let mut type_ = None; + for proc in &self.processors { + if proc.target_namespace != name.namespace() { + continue; + } + type_ = proc.types.get(name); + if type_.is_some() { + break; + } + } + let type_ = type_.expect(&format!("Unknown type name: {:?}", name)); + type_ + } + + fn write_type_in_struct_def<'a, F, H>(&'a self, + field_writer: &mut F, + doc_writer: &mut Option<&mut H>, + type_: &'a Type<'input>, + ) where + F: FnMut(String, String, usize, usize, String), + H: FnMut(&'a Documentation<'input>), + 'ast: 'a { + let mut doc_non_writer: Option<&mut H> = None; + match &type_ { + Type::Alias(name) => { + let target_type = self.get_type(name); + if let Some(ref mut f) = doc_writer { + f(&target_type.doc); + } + self.write_type_in_struct_def(field_writer, doc_writer, &target_type.type_); + }, + Type::InlineSequence(items) => { + for item in items { + self.write_type_in_struct_def(field_writer, &mut doc_non_writer, &item.type_); + } + } + Type::Sequence(min_occurs, max_occurs, name) => { + field_writer(name.to_string(), "sequences".to_string(), *min_occurs, *max_occurs, name.to_string()); + } + Type::Element(min_occurs, max_occurs, name) => { + field_writer(name.to_string(), "inline_elements".to_string(), *min_occurs, *max_occurs, name.to_string()); + } + Type::Group(min_occurs, max_occurs, name) | + Type::ElementRef(min_occurs, max_occurs, name) => { + let field_name = name.local_name(); + let mod_name = self.get_module_name(*name); + field_writer(field_name.to_string(), mod_name.to_string(), *min_occurs, *max_occurs, name.local_name().to_string()); + }, + Type::Choice(min_occurs, max_occurs, ref name) => { + field_writer(name.to_string(), "enums".to_string(), *min_occurs, *max_occurs, name.to_string()); + }, + Type::Extension(base, ext_type) => { + let base_type = &self.get_type(base); + self.write_type_in_struct_def(field_writer, &mut doc_non_writer, &base_type.type_); + self.write_type_in_struct_def(field_writer, doc_writer, &ext_type.type_); + }, + Type::Restriction(base, ext_type) => { + if let Some(ref mut f) = doc_writer { + f(&ext_type.doc); + } + let base_type = &self.get_type(base); + // TODO: do something with the base's type + self.write_type_in_struct_def(field_writer, doc_writer, &ext_type.type_); + }, + Type::Empty => (), // TODO ? + Type::Any => { + field_writer("any".to_string(), "support".to_string(), 1, 1, "Any".to_string()) + }, + Type::Simple(type_) => { + let (type_mod_name, type_name) = self.get_simple_type_name(&type_).unwrap(); + field_writer(type_name.clone(), type_mod_name, 1, 1, type_name); + } + _ => unimplemented!("writing {:?}", type_), + } + } + + fn compute_attrs(&self, type_: &Type<'input>, own_attrs: &Attrs<'input>) -> Attrs<'input> { + match type_ { + Type::Alias(name) => { + let target_type = self.get_type(name); + let target_attrs = self.compute_attrs(&target_type.type_, &target_type.attrs); + self.extend_attrs(&target_attrs, own_attrs) + }, + Type::InlineSequence(_) | + Type::Sequence(_, _, _) | + Type::Element(_, _, _) | + Type::Group(_, _, _) | + Type::ElementRef(_, _, _) | + Type::Choice(_, _, _) | + Type::Empty | + Type::Any => { + own_attrs.clone() + } + Type::Extension(base, ext_type) => { + let base_type = &self.get_type(&base); + let base_attrs = self.compute_attrs(&base_type.type_, &base_type.attrs); + let own_attrs = self.extend_attrs(own_attrs, &ext_type.attrs); // XXX + self.extend_attrs(&base_attrs, &own_attrs) + }, + Type::Restriction(base, ext_type) => { + let base_type = &self.get_type(&base); + let base_attrs = self.compute_attrs(&base_type.type_, &base_type.attrs); + let own_attrs = self.extend_attrs(own_attrs, &ext_type.attrs); // XXX + self.restrict_attrs(&base_attrs, &own_attrs) + }, + Type::Simple(type2) => { + own_attrs.clone() + } + _ => unimplemented!("writing {:?}", type_), + } + } + + pub fn extend_attrs(&self, base: &Attrs<'input>, other: &Attrs<'input>) -> Attrs<'input> { + let mut other_named = HashMap::new(); + for (name, attr_use, type_) in other.named.iter() { + other_named.insert(name.clone(), (*attr_use, type_)); + } + let mut seen = HashSet::new(); + let mut named: Vec<_> = base.named.iter().map(|(name, attr_use, type_)| { + seen.insert(name); + match other_named.get(name) { + None => (name.clone(), *attr_use, (*type_).clone()), + Some((attr_use, type_)) => (name.clone(), *attr_use, (*type_).clone()), + } + }).collect(); + + let mut other_refs = HashMap::new(); + for (name, attr_use, ref_) in other.refs.iter() { + other_refs.insert((name.clone(), ref_.clone()), *attr_use); + } + let mut refs: Vec<_> = base.refs.iter().map(|(name, attr_use, ref_)| { + if let Some(name) = name { + seen.insert(name); + } + match other_refs.get(&(*name, *ref_)) { + None => (name.clone(), *attr_use, (*ref_).clone()), + Some(attr_use) => (name.clone(), *attr_use, (*ref_).clone()), + } + }).collect(); + + for (name, attr_use, type_) in other.named.iter() { + if !seen.contains(name) { + named.push((name.clone(), *attr_use, type_.clone())); + } + } + for (name, attr_use, ref_) in other.refs.iter() { + match name { + Some(name) => { + if !seen.contains(name) { + refs.push((Some(name.clone()), *attr_use, ref_.clone())); + } + }, + None => (), // TODO + } + } + + let mut group_refs = base.group_refs.clone(); + let seen_refs: HashSet<_> = base.group_refs.iter().collect(); + for group_ref in other.group_refs.iter() { + if !seen_refs.contains(group_ref) { + group_refs.push(*group_ref); + } + } + + let res = Attrs { named, refs, group_refs, any_attributes: other.any_attributes }; + res + } + + pub fn restrict_attrs(&self, base: &Attrs<'input>, other: &Attrs<'input>) -> Attrs<'input> { + self.extend_attrs(base, other) // XXX + } +} diff --git a/xml-schema/src/primitives.rs b/xml-schema/src/primitives.rs new file mode 100644 index 0000000..580e6ac --- /dev/null +++ b/xml-schema/src/primitives.rs @@ -0,0 +1,467 @@ +use std::cmp::max; +use std::str::FromStr; +use std::marker::PhantomData; +use std::fmt; + +use bigdecimal::BigDecimal; +use num_traits::{Zero, One}; + +use xmlparser::{Token as XmlToken, ElementEnd, StrSpan}; + +use support::{ParseXml, ParseXmlStr, Stream, ParseContext, ParentContext, Facets, BigFloatNotNaN}; +use xml_utils::*; + +macro_rules! return_split { + ( $input:expr, $position:expr, $pred:expr, $validator:ident !, $facets:expr) => {{ + let input = $input; + let pos = $position; + let parsed = &input[0..pos]; + $validator!(parsed, $facets); + return Some((&input[pos..], $pred(parsed))) + }} +} + +macro_rules! validate_str { + ( $s:expr, $facets:expr) => {{ + let facets = $facets; + let s: &&str = &$s; + if let Some(ref enumeration) = facets.enumeration { + if !enumeration.contains(s) { + panic!("Expected one of {:?}, got {:?}", enumeration, s); + } + } + if let Some(ref length) = facets.length { + if s.len() != *length { + panic!("{:?} has length != {}", s, length); + } + } + if let Some(ref min_length) = facets.min_length { + if s.len() < *min_length { + panic!("{:?} has length < {}", s, min_length); + } + } + if let Some(ref max_length) = facets.max_length { + if s.len() > *max_length { + panic!("{:?} has length > {}", s, max_length); + } + } + }} +} + +macro_rules! validate_int { + ( $n:expr, $facets:expr) => {{ + let n: BigDecimal = $n.into(); + validate_decimal!(n, $facets); + }} +} +macro_rules! validate_decimal { + ( $n:expr, $facets:expr) => {{ + let facets = $facets; + let n: BigFloatNotNaN = $n.into(); + if let Some(ref min_exclusive) = facets.min_exclusive { + if n <= *min_exclusive { + panic!("{} is <= {}", n, min_exclusive); + } + } + if let Some(ref min_inclusive) = facets.min_inclusive { + if n < *min_inclusive { + panic!("{} is < {}", n, min_inclusive); + } + } + if let Some(ref max_exclusive) = facets.max_exclusive { + if n >= *max_exclusive { + panic!("{} is >= {}", n, max_exclusive); + } + } + if let Some(ref max_inclusive) = facets.max_inclusive { + if n > *max_inclusive { + panic!("{} is > {}", n, max_inclusive); + } + } + }} +} + +pub const PRIMITIVE_TYPES: &[(&'static str, &'static str)] = &[ + ("anySimpleType", "AnySimpleType"), + ("token", "Token"), + ("QName", "QName"), + ("string", "XmlString"), + ("positiveInteger", "PositiveInteger"), + ("anyURI", "AnyUri"), + ("boolean", "Boolean"), + ("NCName", "NcName"), + ("nonNegativeInteger", "NonNegativeInteger"), + ("dateTime", "DateTime"), + ("date", "Date"), + ("duration", "Duration"), + ("decimal", "Decimal"), + ]; + +pub type DateTime<'input> = Token<'input>; // TODO +pub type Date<'input> = Token<'input>; // TODO +pub type Duration<'input> = Token<'input>; // TODO + +/// https://www.w3.org/TR/xmlschema11-2/#token +#[derive(Debug, PartialEq)] +pub struct Token<'input>(pub &'input str); + +impl<'input> ParseXmlStr<'input> for Token<'input> { + const NODE_NAME: &'static str = "token"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Token<'input>)> { + if input.len() == 0 { + return None; + } + let mut iter = input.char_indices().peekable(); + while let Some((i, c)) = iter.next() { + match (i, c) { + (0, ' ') => return None, + (_, ' ') => { + // If this space is followed by a whitespace, split before both + match iter.peek() { + Some((_, ' ')) | Some((_, '\r')) | Some((_, '\n')) | + Some((_, '\t')) => return_split!(input, i, Token, validate_str!, facets), + Some((_, _)) => (), + None => return_split!(input, i, Token, validate_str!, facets), + } + } + (_, '\r') | (_, '\n') | (_, '\t') => return_split!(input, i, Token, validate_str!, facets), + _ => (), + } + } + validate_str!(input, facets); + Some(("", Token(input))) + } +} +impl<'input> Default for Token<'input> { + fn default() -> Self { + Token("") + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +pub struct QName<'input> { + pub namespace: Option<&'input str>, + pub local_name: &'input str, +} +impl<'input> ParseXmlStr<'input> for QName<'input> { + const NODE_NAME: &'static str = "QName"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, QName<'input>)> { + if input.len() == 0 { + return None; + } + let f = &mut |prefix, local| QName { + namespace: parent_context.namespaces.get(prefix).cloned(), + local_name: local + }; + let mut i1 = 0; + for (i, c) in input.char_indices() { + if c == ':' { + i1 = i; + } + else if c == ' ' { // TODO + if i == 0 || i <= i1+1 { + return None; + } + if i1 > 0 { + return Some((&input[i..], f(&input[0..i1+1], &input[i1+1..i+1]))) + } + else { + return Some((&input[i..], f("", &input[0..i+1]))) + } + } + } + if i1 > 0 { + return Some(("", f(&input[0..i1], &input[i1+1..]))) + } + else { + return Some(("", f("", input))) + } + } +} + +impl<'input> From<&'input str> for QName<'input> { + fn from(s: &'input str) -> QName<'input> { + let mut splitted = s.split(":"); + let v1 = splitted.next().expect(&format!("Empty qname")); + let v2 = splitted.next(); + assert_eq!(splitted.next(), None); + match v2 { + None => QName { namespace: None, local_name: v1 }, + Some(v2) => QName { namespace: Some(v1), local_name: v2 }, + } + } +} + +impl <'input> QName<'input> { + pub fn from_strspans(prefix: StrSpan<'input>, local: StrSpan<'input>) -> QName<'input> { + match prefix.to_str() { + "" => QName { namespace: None, local_name: local.to_str() }, + p => QName { namespace: Some(p), local_name: local.to_str() }, + } + } +} + +impl<'input> fmt::Display for QName<'input> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.namespace { + Some(ns) => write!(f, "{}:{}", ns, self.local_name), + None => write!(f, "{}", self.local_name), + } + } +} + +#[derive(Debug, PartialEq, Default)] +pub struct AnyUri<'input>(pub &'input str); +impl<'input> ParseXmlStr<'input> for AnyUri<'input> { + const NODE_NAME: &'static str = "AnyUri"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, AnyUri<'input>)> { + if input.len() == 0 { + return None; + } + for (i, c) in input.char_indices() { + if c == ' ' { // TODO + if i == 0 { + return None; + } + return Some((&input[i..], AnyUri(&input[0..i]))) + } + } + Some(("", AnyUri(input))) + } +} + +#[derive(Debug, PartialEq)] +pub struct AnyURIElement<'input>(StrSpan<'input>); +impl<'input> ParseXml<'input> for AnyURIElement<'input> { + const NODE_NAME: &'static str = "AnyURIElement"; + fn parse_self_xml>(stream: &mut Stream<'input>, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>) -> Option> { + match stream.next() { + Some(XmlToken::Text(strspan)) => Some(AnyURIElement(strspan)), + _ => None, + } + } +} + +#[derive(Debug, PartialEq, Default)] +pub struct Integer<'input>(pub i64, PhantomData<&'input ()>); +impl<'input> ParseXmlStr<'input> for Integer<'input> { + const NODE_NAME: &'static str = "Integer"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Integer<'input>)> { + let mut iter = input.char_indices(); + let mut n: i64 = 0; + let mut multiplier = 1; + let c = iter.next()?.1; + match c { + '+' => multiplier = 1, + '-' => multiplier = -1, + '0'..='9' => n = (c as i64) - ('0' as i64), + _ => return None, + } + + if c == '+' || c == '-' { + let c = iter.next()?.1; + match c { + '0'..='9' => n = (c as i64) - ('0' as i64), + _ => return None, + } + } + + for (i,c) in iter { + match c { + '0'..='9' => n = n * 10 + ((c as i64) - ('0' as i64)), + _ => { + let res = multiplier * n; + validate_int!(res, facets); + return Some((&input[i..], Integer(res, PhantomData::default()))); + } + } + } + + let res = multiplier * n; + validate_int!(res, facets); + Some(("", Integer(res, PhantomData::default()))) + } +} + +#[derive(Debug, PartialEq)] +pub struct NonNegativeInteger<'input>(pub u64, PhantomData<&'input ()>); +impl<'input> ParseXmlStr<'input> for NonNegativeInteger<'input> { + const NODE_NAME: &'static str = "NonNegativeInteger"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets) -> Option<(&'input str, NonNegativeInteger<'input>)> { + let min = max(BigFloatNotNaN::zero(), facets.min_inclusive.clone().unwrap_or(BigFloatNotNaN::zero())); + let mut facets = facets.clone(); + facets.min_inclusive = Some(min); + let (output, n) = Integer::parse_self_xml_str(input, parse_context, parent_context, &facets)?; + Some((output, NonNegativeInteger(n.0 as u64, PhantomData::default()))) + } +} + +#[derive(Debug, PartialEq)] +pub struct PositiveInteger<'input>(pub u64, PhantomData<&'input ()>); +impl<'input> ParseXmlStr<'input> for PositiveInteger<'input> { + const NODE_NAME: &'static str = "PositiveInteger"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets) -> Option<(&'input str, PositiveInteger<'input>)> { + let min = max(BigFloatNotNaN::one(), facets.min_inclusive.clone().unwrap_or(BigFloatNotNaN::zero())); + let mut facets = facets.clone(); + facets.min_inclusive = Some(min); + let (output, n) = NonNegativeInteger::parse_self_xml_str(input, parse_context, parent_context, &facets)?; + Some((output, PositiveInteger(n.0, PhantomData::default()))) + } +} + +#[derive(Debug, PartialEq, Default)] +pub struct Decimal<'input>(pub BigDecimal, PhantomData<&'input ()>); +impl<'input> ParseXmlStr<'input> for Decimal<'input> { + const NODE_NAME: &'static str = "Decimal"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Decimal<'input>)> { + for (i, c) in input.char_indices() { + if c == ' ' { // TODO + let res = match BigDecimal::from_str(&input[0..i]) { + Ok(res) => res, + Err(_) => return None, + }; + validate_decimal!(res.clone(), facets); + return Some((&input[i..], Decimal(res, PhantomData::default()))) + } + } + let res = match BigDecimal::from_str(input) { + Ok(res) => res, + Err(_) => return None, + }; + validate_decimal!(res.clone(), facets); + Some(("", Decimal(res, PhantomData::default()))) + } +} + +#[derive(Debug, PartialEq, Default)] +pub struct Any<'input>(pub Vec>); +impl<'input> ParseXml<'input> for Any<'input> { + const NODE_NAME: &'static str = "Any"; + fn parse_self_xml>(stream: &mut Stream<'input>, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>) -> Option> { + let mut tag_stack = Vec::new(); + let mut tokens = Vec::new(); + loop { + let tx = stream.transaction(); + let tok = stream.next()?; + match tok { + XmlToken::Whitespaces(_) => (), + XmlToken::Comment(_) => (), + XmlToken::Text(_) => (), + XmlToken::ElementStart(prefix, name) => { + tag_stack.push(QName::from_strspans(prefix, name)); + tokens.push(tok); + break + }, + _ => { + tx.rollback(stream); + if tokens.len() > 0 { + return Some(Any(tokens)); + } + else { + return None; + } + } + } + tokens.push(tok); + } + while tag_stack.len() > 0 { + let tok = stream.next().unwrap(); + tokens.push(tok); + match tok { + XmlToken::ElementStart(prefix, name) => tag_stack.push(QName::from_strspans(prefix, name)), + XmlToken::ElementEnd(end) => { + match end { + ElementEnd::Open => (), + ElementEnd::Close(prefix, name) => assert_eq!(QName::from_strspans(prefix, name), tag_stack.pop().unwrap()), + ElementEnd::Empty => { tag_stack.pop(); () }, + } + } + _ => (), + } + } + Some(Any(tokens)) + } +} + +/// https://www.w3.org/TR/xmlschema11-2/#string +#[derive(Debug, PartialEq)] +pub struct XmlString<'input>(pub &'input str); + +impl<'input> ParseXmlStr<'input> for XmlString<'input> { + const NODE_NAME: &'static str = "XmlString"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, XmlString<'input>)> { + for (i, c) in input.char_indices() { + if !is_xml_char(c) { + return_split!(input, i, XmlString, validate_str!, facets); + } + } + Some(("", XmlString(input))) + } +} + +impl<'input> Default for XmlString<'input> { + fn default() -> Self { + XmlString("") + } +} + +/// https://www.w3.org/TR/xmlschema11-2/#anySimpleType +#[derive(Debug, PartialEq)] +pub struct AnySimpleType<'input>(pub &'input str); + +impl<'input> ParseXmlStr<'input> for AnySimpleType<'input> { + const NODE_NAME: &'static str = "AnySimpleType"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, AnySimpleType<'input>)> { + Some(("", AnySimpleType(input))) + } +} + +impl<'input> Default for AnySimpleType<'input> { + fn default() -> Self { + AnySimpleType("") + } +} + + +/// https://www.w3.org/TR/xmlschema11-2/#NCName +#[derive(Debug, PartialEq)] +pub struct NcName<'input>(pub &'input str); + +impl<'input> ParseXmlStr<'input> for NcName<'input> { + const NODE_NAME: &'static str = "NcName"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, NcName<'input>)> { + let mut iter = input.char_indices(); + let c = iter.next()?.1; + if c == ':' || !is_name_start_char(c) { return None }; + + for (i, c) in iter { + if c == ':' || !is_name_char(c) { + return_split!(input, i, NcName, validate_str!, facets); + } + } + + Some(("", NcName(input))) + } +} + +#[derive(Debug, PartialEq, Default)] +pub struct Boolean<'input>(bool, PhantomData<&'input ()>); +impl<'input> ParseXmlStr<'input> for Boolean<'input> { + const NODE_NAME: &'static str = "Boolean"; + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, _parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Boolean<'input>)> { + if input.len() >= 1 { + match &input[0..1] { + "0" => return Some((&input[1..], Boolean(false, PhantomData::default()))), + "1" => return Some((&input[1..], Boolean(true, PhantomData::default()))), + _ => (), + } + } + if input.len() >= 4 && &input[0..4] == "true" { + return Some((&input[4..], Boolean(true, PhantomData::default()))) + } + if input.len() >= 5 && &input[0..4] == "false" { + return Some((&input[5..], Boolean(false, PhantomData::default()))) + } + None + } +} diff --git a/xml-schema/src/processor.rs b/xml-schema/src/processor.rs new file mode 100644 index 0000000..b433294 --- /dev/null +++ b/xml-schema/src/processor.rs @@ -0,0 +1,951 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::collections::{HashMap, HashSet}; + +use xmlparser::Token as XmlToken; +use xmlparser::{TextUnescape, XmlSpace}; + +use parser::*; +use names::*; +use support::Facets; +use primitives::{QName,NcName,AnyUri,NonNegativeInteger}; + +pub const SCHEMA_URI: &'static str = "http://www.w3.org/2001/XMLSchema"; + +fn parse_min_occurs(x: &Option) -> usize { + match x { + None => 1, + Some(n) => n.0 as usize, + } +} +fn parse_max_occurs(x: &Option) -> usize { + match x { + None => 1, + Some(unions::UnionNonNegativeIntegerNmtoken::NonNegativeInteger(n)) => n.0 as usize, + Some(unions::UnionNonNegativeIntegerNmtoken::Nmtoken(restrictions::Unbounded(_))) => usize::max_value(), + } +} + +fn vec_concat_opt(vector: &Vec, value: Option) -> Vec{ + let mut vector2: Vec = vector.clone(); + if let Some(v) = value { + vector2.push(v); + } + vector2 +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[must_use] +pub struct Documentation<'input>(Vec<&'input str>); +impl<'input> Documentation<'input> { + pub fn new() -> Documentation<'input> { + Documentation(Vec::new()) + } + pub fn extend(&mut self, v: &Documentation<'input>) { + self.0.extend(v.0.iter()); + } +} + +impl<'input> ToString for Documentation<'input> { + fn to_string(&self) -> String { + self.0.iter().map(|doc| TextUnescape::unescape(doc, XmlSpace::Default)).collect::>().join("\n") + } +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AttrUse { + Prohibited, + Required, + Optional, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Attrs<'input> { + pub named: Vec<(FullName<'input>, AttrUse, Option>)>, + pub refs: Vec<(Option>, AttrUse, FullName<'input>)>, + pub group_refs: Vec>, + pub any_attributes: bool, +} +impl<'input> Attrs<'input> { + pub fn new() -> Attrs<'input> { + Attrs { named: Vec::new(), refs: Vec::new(), group_refs: Vec::new(), any_attributes: false } + } + fn extend(&mut self, other: Attrs<'input>) { + let Attrs { named, refs, group_refs, any_attributes } = other; + self.named.extend(named); + self.refs.extend(refs); + self.group_refs.extend(group_refs); + self.any_attributes |= any_attributes; + } +} + +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct RichType<'input, T: Debug + Hash + PartialEq + Eq + PartialOrd + Ord> { + pub name_hint: NameHint<'input>, + pub attrs: Attrs<'input>, + pub type_: T, + pub doc: Documentation<'input>, +} +impl<'input, T: Debug + Hash + PartialEq + Eq + PartialOrd + Ord> RichType<'input, T> { + pub fn new(name_hint: NameHint<'input>, type_: T, doc: Documentation<'input>) -> RichType<'input, T> { + RichType { name_hint, attrs: Attrs::new(), type_, doc } + } +} +impl<'input> RichType<'input, Type<'input>> { + fn add_attrs(mut self, new_attrs: Attrs<'input>) -> RichType<'input, Type<'input>> { + self.attrs.extend(new_attrs); + self + } +} + +impl<'input> RichType<'input, SimpleType<'input>> { + pub fn into_complex(self) -> RichType<'input, Type<'input>> { + let RichType { name_hint, attrs, type_, doc } = self; + RichType { name_hint, attrs, type_: Type::Simple(type_), doc } + } +} + +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Type<'input> { + Any, + Empty, + Alias(FullName<'input>), + Extension(FullName<'input>, Box>>), + Restriction(FullName<'input>, Box>>), + ElementRef(usize, usize, FullName<'input>), + Element(usize, usize, String), + Group(usize, usize, FullName<'input>), + Choice(usize, usize, String), + InlineChoice(Vec>>), + Sequence(usize, usize, String), + InlineSequence(Vec>>), + Simple(SimpleType<'input>), +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum SimpleType<'input> { + Primitive(&'static str, &'static str), + Alias(FullName<'input>), + Restriction(FullName<'input>, Facets<'input>), + List(String), + Union(String), + Empty, +} + +#[derive(Debug)] +pub struct Processor<'ast, 'input: 'ast> { + pub target_namespace: Option<&'input str>, + pub element_form_default_qualified: bool, + pub attribute_form_default_qualified: bool, + pub elements: HashMap, RichType<'input, Type<'input>>>, + pub types: HashMap, RichType<'input, Type<'input>>>, + pub simple_types: HashMap, (RichType<'input, SimpleType<'input>>, Documentation<'input>)>, + pub choices: HashMap>>, HashSet>, + pub sequences: HashMap>>, (HashSet, Documentation<'input>)>, + pub groups: HashMap, RichType<'input, Type<'input>>>, + pub attribute_groups: HashMap, Attrs<'input>>, + pub inline_elements: HashMap<(Option<&'input str>, &'input str, Attrs<'input>, Type<'input>), (HashSet, Documentation<'input>)>, + + pub lists: HashMap>, HashSet>, + pub unions: HashMap>>, HashSet>, + pub simple_restrictions: HashSet<(FullName<'input>, Facets<'input>)>, + pub substitution_groups: HashMap, Vec>>, + _phantom: PhantomData<&'ast ()>, // Sometimes I need 'ast when prototyping +} + +impl<'ast, 'input: 'ast> Processor<'ast, 'input> { + pub fn new(ast: &'ast xs::Schema<'input>) -> Processor<'ast, 'input> { + let target_namespace = ast.attr_target_namespace.as_ref().map(|t| t.0); + let element_form_default_qualified = match ast.attr_element_form_default.as_ref().map(|x| ((x.0).0).0) { + Some("qualified") => true, + Some("unqualified") | None => false, + _ => unreachable!(), + }; + let attribute_form_default_qualified = match ast.attr_attribute_form_default.as_ref().map(|x| ((x.0).0).0) { + Some("qualified") => true, + Some("unqualified") | None => false, + _ => unreachable!(), + }; + Processor { + target_namespace, + element_form_default_qualified, + attribute_form_default_qualified, + elements: HashMap::new(), + types: HashMap::new(), + groups: HashMap::new(), + choices: HashMap::new(), + lists: HashMap::new(), + unions: HashMap::new(), + sequences: HashMap::new(), + attribute_groups: HashMap::new(), + inline_elements: HashMap::new(), + simple_types: HashMap::new(), + simple_restrictions: HashSet::new(), + substitution_groups: HashMap::new(), + _phantom: PhantomData::default(), + } + } + + pub fn process_ast(&mut self, ast: &'ast xs::Schema<'input>) { + for top_level_item in ast.sequence_schema_top_annotation.iter() { + match top_level_item.schema_top { + xs::SchemaTop::Redefinable(ref r) => self.process_redefinable(r, false), + xs::SchemaTop::Element(ref e) => { self.process_toplevel_element(e); }, + xs::SchemaTop::Attribute(_) => unimplemented!("top-level attribute"), + xs::SchemaTop::Notation(ref e) => self.process_notation(e), + } + } + } + + fn process_notation(&mut self, notation: &'ast xs::Notation<'input>) { + // TODO + } + + fn process_redefinable(&mut self, r: &'ast xs::Redefinable<'input>, inlinable: bool) { + match r { + xs::Redefinable::SimpleType(ref e) => { self.process_simple_type(e); }, + xs::Redefinable::ComplexType(e) => { self.process_complex_type(e, inlinable); }, + xs::Redefinable::Group(e) => { self.process_named_group(e); }, + xs::Redefinable::AttributeGroup(e) => self.process_attribute_group(e), + } + } + + fn process_annotation(&self, annotation: &Vec<&'ast xs::Annotation<'input>>) -> Documentation<'input> { + let strings = annotation.iter().flat_map(|xs::Annotation { ref attrs, ref attr_id, ref annotation_content }| { + annotation_content.iter().filter_map(|c| { + match c { + enums::AnnotationContent::Appinfo(_) => None, + enums::AnnotationContent::Documentation(e) => { + let xs::Documentation { ref attrs, ref attr_source, ref sequence_any } = **e; + Some(sequence_any.iter().flat_map(|sequences::SequenceAny { any }| { + any.0.iter().filter_map(|tok| { + match tok { + XmlToken::Text(s) => Some(s.to_str()), + _ => None, + } + }) + })) + }, + } + }) + }).flat_map(|v| v).collect(); + Documentation(strings) + } + + fn process_group_ref(&mut self, + group_ref: &'ast inline_elements::GroupRef<'input>, + ) -> RichType<'input, Type<'input>> { + let inline_elements::GroupRef { ref attrs, ref attr_id, ref attr_ref, ref attr_min_occurs, ref attr_max_occurs, ref annotation } = group_ref; + let ref_ = attr_ref; + let min_occurs = parse_min_occurs(attr_min_occurs); + let max_occurs = parse_max_occurs(attr_max_occurs); + + let ref_ = FullName::from_qname(ref_, self.target_namespace); + RichType::new( + NameHint::new(ref_.local_name()), + Type::Group(min_occurs, max_occurs, ref_), + self.process_annotation(&annotation.iter().collect()), + ) + } + + fn process_named_group(&mut self, + group: &'ast xs::Group<'input>, + ) -> RichType<'input, Type<'input>> { + let xs::Group { ref attrs, ref attr_id, ref attr_name, ref annotation, choice_all_choice_sequence: ref content } = group; + let name = attr_name; + let max_occurs = 1; + let min_occurs = 1; + + let mut type_ = match content { + enums::ChoiceAllChoiceSequence::All(_) => unimplemented!("all"), + enums::ChoiceAllChoiceSequence::Choice(e) => self.process_choice(e, true), + enums::ChoiceAllChoiceSequence::Sequence(e) => self.process_sequence(e, true), + }; + + type_.doc.extend(&self.process_annotation(&annotation.iter().collect())); + let doc = type_.doc.clone(); + + let name = FullName::new(self.target_namespace, name.0); + self.groups.insert(name, type_); + RichType::new( + NameHint::from_fullname(&name), + Type::Group(min_occurs, max_occurs, name), + doc, + ) + } + + fn process_attribute_group(&mut self, group: &'ast xs::AttributeGroup<'input>) { + let name = &group.attr_name; + let attrs = self.process_attr_decls(&group.attr_decls); + let name = FullName::new(self.target_namespace, name.0); + self.attribute_groups.insert(name, attrs); + } + + fn process_local_simple_type(&mut self, + simple_type: &'ast inline_elements::LocalSimpleType<'input>, + ) -> RichType<'input, SimpleType<'input>> { + let inline_elements::LocalSimpleType { ref attrs, ref attr_id, ref annotation, ref simple_derivation } = simple_type; + //let struct_name = self.namespaces.new_type(QName::from(name)); + let annotation: Vec<_> = annotation.iter().collect(); + match simple_derivation { + xs::SimpleDerivation::Restriction(e) => self.process_simple_restriction(e, annotation.clone()), + xs::SimpleDerivation::List(ref e) => self.process_list(e, annotation.clone()), + xs::SimpleDerivation::Union(ref e) => self.process_union(e, annotation.clone()), + } + } + + fn process_simple_type(&mut self, + simple_type: &'ast xs::SimpleType<'input>, + ) -> RichType<'input, SimpleType<'input>> { + let xs::SimpleType { ref attrs, ref attr_id, ref attr_name, ref attr_final, ref annotation, ref simple_derivation } = simple_type; + let annotation: Vec<_> = annotation.iter().collect(); + let name = attr_name; + let name = FullName::new(self.target_namespace, name.0); + //let struct_name = self.namespaces.new_type(QName::from(name)); + let ty = match simple_derivation { + xs::SimpleDerivation::Restriction(e) => + self.process_simple_restriction(e, annotation.clone()), + xs::SimpleDerivation::List(ref e) => self.process_list(e, annotation.clone()), + xs::SimpleDerivation::Union(ref e) => self.process_union(e, annotation.clone()), + }; + + let doc = self.process_annotation(&annotation); + self.simple_types.insert(name, (ty, doc.clone())); + RichType::new( + NameHint::from_fullname(&name), + SimpleType::Alias(name), + doc, + ) + } + + fn process_list(&mut self, + list: &'ast xs::List<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, SimpleType<'input>> { + let item_type = list.attr_item_type; + let item_type = item_type.as_ref().map(|n| FullName::from_qname(n, self.target_namespace)); + + let item_type = match (item_type, &list.local_simple_type) { + (None, Some(st)) => { + let mut ty = self.process_local_simple_type(st); + ty.doc.extend(&self.process_annotation(&annotation)); + ty + }, + (Some(n), None) => { + RichType::new( + NameHint::new(n.local_name()), + SimpleType::Alias(n), + self.process_annotation(&annotation), + ) + }, + (None, None) => panic!(" with no itemType or child type."), + (Some(ref t1), Some(ref t2)) => panic!(" has both an itemType attribute ({:?}) and a child type ({:?}).", t1, t2), + }; + + let mut name_hint = item_type.name_hint.clone(); + name_hint.push("list"); + let doc = self.process_annotation(&annotation); + let name = name_from_hint(&name_hint).unwrap(); + self.lists.entry(item_type) + .or_insert(HashSet::new()) + .insert(name.clone()); + RichType::new( + name_hint, + SimpleType::List(name), + doc, + ) + } + + fn process_union(&mut self, + union: &'ast xs::Union<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, SimpleType<'input>> { + let default_vec = Vec::new(); + let mut name_hint = NameHint::new("union"); + let member_types = union.attr_member_types.as_ref().map(|l| &l.0).unwrap_or(&default_vec); + let mut member_types: Vec<_> = member_types.iter().map(|name| { + let name = FullName::from_qname(name, self.target_namespace); + name_hint.push(name.local_name()); + RichType::new( + NameHint::new(name.local_name()), + SimpleType::Alias(name), + self.process_annotation(&annotation), + ) + }).collect(); + + for t in union.local_simple_type.iter() { + let ty = self.process_local_simple_type(t); + name_hint.extend(&ty.name_hint); + member_types.push(ty) + } + + let doc = self.process_annotation(&annotation); + let name = name_from_hint(&name_hint).unwrap(); + self.unions.entry(member_types) + .or_insert(HashSet::new()) + .insert(name.clone()); + RichType::new( + name_hint, + SimpleType::Union(name), + doc, + ) + } + + fn process_complex_type(&mut self, + complex_type: &'ast xs::ComplexType<'input>, + inlinable: bool, + ) -> RichType<'input, Type<'input>> { + let xs::ComplexType { ref attrs, ref attr_id, ref attr_name, ref attr_mixed, ref attr_abstract, ref attr_final, ref attr_block, ref attr_default_attributes_apply, ref annotation, ref complex_type_model } = complex_type; + let name = attr_name; + //let struct_name = self.namespaces.new_type(QName::from(name)); + let mut ty = match complex_type_model { + xs::ComplexTypeModel::SimpleContent(_) => unimplemented!("simpleContent"), + xs::ComplexTypeModel::ComplexContent(ref model) => + self.process_complex_content(model, false), + xs::ComplexTypeModel::CompleteContentModel { ref open_content, ref type_def_particle, ref attr_decls, ref assertions } => + self.process_complete_content_model(open_content, type_def_particle, attr_decls, assertions, inlinable), + }; + ty.doc.extend(&self.process_annotation(&annotation.iter().collect())); + + let doc = ty.doc.clone(); + let name = FullName::new(self.target_namespace, name.0); + self.types.insert(name, ty); + RichType::new( + NameHint::from_fullname(&name), + Type::Alias(name), + doc, + ) + } + + fn process_local_complex_type(&mut self, + complex_type: &'ast inline_elements::LocalComplexType<'input>, + attr_name: Option<&'ast NcName<'input>>, + annotation: Vec<&'ast xs::Annotation<'input>>, + inlinable: bool, + ) -> RichType<'input, Type<'input>> { + let inline_elements::LocalComplexType { ref attrs, ref attr_id, ref attr_mixed, ref attr_default_attributes_apply, annotation: ref annotation2, ref complex_type_model } = complex_type; + let name = attr_name; + //let struct_name = self.namespaces.new_type(QName::from(name)); + let mut ty = match complex_type_model { + xs::ComplexTypeModel::SimpleContent(_) => unimplemented!("simpleContent"), + xs::ComplexTypeModel::ComplexContent(ref model) => + self.process_complex_content(model, false), + xs::ComplexTypeModel::CompleteContentModel { ref open_content, ref type_def_particle, ref attr_decls, ref assertions } => + self.process_complete_content_model(open_content, type_def_particle, attr_decls, assertions, inlinable), + }; + ty.doc.extend(&self.process_annotation(&vec_concat_opt(&annotation, annotation2.as_ref()))); + + if let Some(name) = name { + let doc = ty.doc.clone(); + let name = FullName::new(self.target_namespace, name.0); + self.types.insert(name, ty); + RichType::new( + NameHint::from_fullname(&name), + Type::Alias(name), + doc, + ) + } + else { + ty + } + } + + fn process_complete_content_model(&mut self, + open_content: &'ast Option>>, + type_def_particle: &'ast Option>>, + attr_decls: &'ast xs::AttrDecls<'input>, + assertions: &'ast xs::Assertions<'input>, + inlinable: bool, + ) -> RichType<'input, Type<'input>> { + let ty = match type_def_particle.as_ref() { + Some(type_def_particle) => self.process_type_def_particle(type_def_particle, inlinable), + None => RichType::new( + NameHint::new("empty_particle"), + Type::Empty, + Documentation::new() + ), + }; + ty.add_attrs(self.process_attr_decls(attr_decls)) + } + + fn process_complex_content(&mut self, model: &'ast xs::ComplexContent<'input>, inlinable: bool) -> RichType<'input, Type<'input>> { + let xs::ComplexContent { ref attrs, ref attr_id, ref attr_mixed, ref annotation, ref choice_restriction_extension } = model; + let annotation = annotation.iter().collect(); + match choice_restriction_extension { + enums::ChoiceRestrictionExtension::Restriction(ref r) => { + let inline_elements::ComplexRestrictionType { + ref attrs, ref attr_id, ref attr_base, annotation: ref annotation2, + ref sequence_open_content_type_def_particle, + ref attr_decls, ref assertions + } = **r; + let ty = match sequence_open_content_type_def_particle { + Some(sequences::SequenceOpenContentTypeDefParticle { open_content, type_def_particle }) => + self.process_complex_restriction(attr_base, type_def_particle, vec_concat_opt(&annotation, annotation2.as_ref())), + None => { + RichType::new( + NameHint::new("empty_extension"), + Type::Empty, + self.process_annotation(&vec_concat_opt(&annotation, annotation2.as_ref())), + ) + }, + }; + ty.add_attrs(self.process_attr_decls(attr_decls)) + }, + enums::ChoiceRestrictionExtension::Extension(ref e) => { + let inline_elements::ExtensionType { + ref attrs, ref attr_base, ref attr_id, annotation: ref annotation2, ref open_content, + ref type_def_particle, ref attr_decls, ref assertions + } = **e; + let ty = match type_def_particle { + Some(type_def_particle) => + self.process_extension(attrs, attr_base, type_def_particle, vec_concat_opt(&annotation, annotation2.as_ref()), inlinable), + None => self.process_trivial_extension(attrs, attr_base, vec_concat_opt(&annotation, annotation2.as_ref())), + }; + ty.add_attrs(self.process_attr_decls(attr_decls)) + }, + } + } + + fn process_complex_restriction(&mut self, + attr_base: &'ast QName<'input>, + type_def_particle: &'ast xs::TypeDefParticle<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, Type<'input>> { + // TODO: use the base + let ty = self.process_type_def_particle(type_def_particle, false); + let base = FullName::from_qname(attr_base, self.target_namespace); + RichType::new( + NameHint::new_empty(), + Type::Restriction(base, Box::new(ty)), + self.process_annotation(&annotation), + ) + } + + fn process_facets(&mut self, facet_list: &Vec>) -> Facets<'input> { + let mut facets = Facets::default(); + use parser::xs::Facet::*; + for facet_or_any in facet_list { + match facet_or_any { + enums::ChoiceFacetAny::Facet(e) => { + match **e { + FacetHead(_) => panic!("abstract element"), + MinExclusive(ref e) => facets.min_exclusive = Some(e.attr_value.0.parse().expect("invalid minexclusive")), + MinInclusive(ref e) => facets.min_inclusive = Some(e.attr_value.0.parse().expect("invalid mininclusive")), + MaxExclusive(ref e) => facets.max_exclusive = Some(e.attr_value.0.parse().expect("invalid maxexclusive")), + MaxInclusive(ref e) => facets.max_inclusive = Some(e.attr_value.0.parse().expect("invalid maxinclusive")), + TotalDigits(ref e) => facets.total_digits = Some(e.attr_value.0), + FractionDigits(ref e) => facets.fraction_digits = Some(e.attr_value.0), + Length(ref e) => facets.length = Some(e.attr_value.0 as usize), + MinLength(ref e) => facets.min_length = Some(e.attr_value.0 as usize), + MaxLength(ref e) => facets.max_length = Some(e.attr_value.0 as usize), + Enumeration(ref e) => facets.enumeration.get_or_insert(Vec::new()).push(e.attr_value.0), + WhiteSpace(ref e) => facets.white_space = Some(((e.attr_value.0).0).0), + Pattern(ref e) => facets.pattern = Some(e.attr_value.0), + Assertion(ref e) => unimplemented!("assertion facet"), + ExplicitTimezone(ref e) => facets.explicit_timezone = Some(((e.attr_value.0).0).0), + }; + }, + enums::ChoiceFacetAny::Any(_) => (), // TODO (probably just whitespaces) + } + } + facets + } + + fn process_simple_restriction(&mut self, + restriction: &'ast xs::Restriction<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, SimpleType<'input>> { + let xs::Restriction { ref attrs, ref attr_id, ref attr_base, annotation: ref annotation2, ref simple_restriction_model } = restriction; + let base = attr_base; + let base = base.unwrap_or(QName { namespace: Some(SCHEMA_URI), local_name: "anySimpleType" }); + let xs::SimpleRestrictionModel { ref local_simple_type, ref choice_facet_any } = simple_restriction_model; + let facets = self.process_facets(choice_facet_any); + + let base = FullName::from_qname(&base, self.target_namespace); + + self.simple_restrictions.insert((base, facets.clone())); + + match local_simple_type { + Some(inline_elements::LocalSimpleType { ref attrs, ref attr_id, annotation: ref annotation2, ref simple_derivation }) => { + RichType::new( + NameHint::new(base.local_name()), + SimpleType::Restriction(base, facets), + self.process_annotation(&vec_concat_opt(&annotation, annotation2.as_ref())), + ) + }, + None => { + RichType::new( + NameHint::new(base.local_name()), + SimpleType::Restriction(base, facets), + self.process_annotation(&annotation), + ) + }, + } + } + + fn process_type_def_particle(&mut self, particle: &'ast xs::TypeDefParticle<'input>, inlinable: bool) -> RichType<'input, Type<'input>> { + match particle { + xs::TypeDefParticle::Group(e) => self.process_group_ref(e), + xs::TypeDefParticle::All(_) => unimplemented!("all"), + xs::TypeDefParticle::Choice(e) => self.process_choice(e, inlinable), + xs::TypeDefParticle::Sequence(e) => self.process_sequence(e, inlinable), + } + } + + fn process_nested_particle(&mut self, + particle: &'ast xs::NestedParticle<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + inlinable: bool + ) -> RichType<'input, Type<'input>> { + let mut ty = match particle { + xs::NestedParticle::Element(e) => self.process_local_element(e), + xs::NestedParticle::Group(e) => self.process_group_ref(e), + xs::NestedParticle::Choice(e) => self.process_choice(e, inlinable), + xs::NestedParticle::Sequence(e) => self.process_sequence(e, inlinable), + xs::NestedParticle::Any(e) => self.process_any(e, Vec::new()), + }; + + ty.doc.extend(&self.process_annotation(&annotation)); + ty + } + + fn process_any(&mut self, + any: &'ast xs::Any<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, Type<'input>> { + RichType::new( + NameHint::new("any"), + Type::Any, + self.process_annotation(&annotation), + ) + } + + fn process_sequence(&mut self, + seq: &'ast xs::Sequence<'input>, + inlinable: bool, + ) -> RichType<'input, Type<'input>> { + let xs::Sequence { ref attrs, ref attr_id, ref attr_min_occurs, ref attr_max_occurs, ref annotation, ref nested_particle } = seq; + let particles = nested_particle; + let min_occurs = parse_min_occurs(attr_min_occurs); + let max_occurs = parse_max_occurs(attr_max_occurs); + let mut items = Vec::new(); + let mut name_hint = NameHint::new("sequence"); + if min_occurs == 1 && max_occurs == 1 && inlinable && particles.len() == 1 { + self.process_nested_particle(particles.get(0).unwrap(), annotation.iter().collect(), inlinable) + } + else { + for particle in particles.iter() { + let ty = self.process_nested_particle(particle, vec![], false); + name_hint.extend(&ty.name_hint); + items.push(ty); + } + let doc = self.process_annotation(&annotation.iter().collect()); + if min_occurs == 1 && max_occurs == 1 { + RichType::new( + name_hint, + Type::InlineSequence(items), + doc, + ) + } + else { + let name = name_from_hint(&name_hint).unwrap(); + let (names, docs) = self.sequences.entry(items) + .or_insert((HashSet::new(), Documentation::new())); + names.insert(name.clone()); + docs.extend(&doc); + RichType::new( + name_hint, + Type::Sequence(min_occurs, max_occurs, name), + doc, + ) + } + } + } + + fn process_choice(&mut self, + choice: &'ast xs::Choice<'input>, + inlinable: bool + ) -> RichType<'input, Type<'input>> { + let xs::Choice { ref attrs, ref attr_id, ref attr_min_occurs, ref attr_max_occurs, ref annotation, ref nested_particle } = choice; + let particles = nested_particle; + let min_occurs = parse_min_occurs(attr_min_occurs); + let max_occurs = parse_max_occurs(attr_max_occurs); + let mut items = Vec::new(); + let mut name_hint = NameHint::new("choice"); + if particles.len() == 1 { + let particle = particles.get(0).unwrap(); + let RichType { name_hint, attrs, type_, doc } = + self.process_nested_particle(particle, annotation.iter().collect(), inlinable); + match (min_occurs, max_occurs, type_) { + (_, _, Type::Element(1, 1, e)) => return RichType { + name_hint, attrs, type_: Type::Element(min_occurs, max_occurs, e), doc }, + (_, _, Type::Group(1, 1, e)) => return RichType { + name_hint, attrs, type_: Type::Group(min_occurs, max_occurs, e), doc }, + (_, _, Type::Choice(1, 1, e)) => return RichType { + name_hint, attrs, type_: Type::Choice(min_occurs, max_occurs, e), doc }, + (_, _, Type::Sequence(1, 1, e)) => return RichType { + name_hint, attrs, type_: Type::Sequence(min_occurs, max_occurs, e), doc }, + (1, 1, type_) => return RichType { name_hint, attrs, type_, doc }, + (_, _, type_) => { + let name = name_from_hint(&name_hint).unwrap(); + let items = vec![RichType { name_hint: name_hint.clone(), attrs: Attrs::new(), type_, doc: doc.clone() }]; + let (names, docs) = self.sequences.entry(items) + .or_insert((HashSet::new(), Documentation::new())); + names.insert(name.clone()); + docs.extend(&doc); + let type_ = Type::Sequence(min_occurs, max_occurs, name); + return RichType { name_hint, attrs, type_, doc } + }, + } + } + else { + for particle in particles.iter() { + let ty = self.process_nested_particle(particle, vec![], false); + name_hint.extend(&ty.name_hint); + items.push(ty); + } + } + let doc = self.process_annotation(&annotation.iter().collect()); + match (min_occurs, max_occurs, inlinable) { + (1, 1, true) => { + RichType::new( + name_hint, + Type::InlineChoice(items), + doc, + ) + }, + (_, _, _) => { + let name = name_from_hint(&name_hint).unwrap(); + self.choices.entry(items) + .or_insert(HashSet::new()) + .insert(name.clone()); + RichType::new( + name_hint, + Type::Choice(min_occurs, max_occurs, name), + doc, + ) + } + } + } + + fn process_trivial_extension(&mut self, + attrs: &'ast HashMap, &'input str>, + attr_base: &'ast QName<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + ) -> RichType<'input, Type<'input>> { + let base = FullName::from_qname(&attr_base, self.target_namespace); + RichType::new( + NameHint::new_empty(), + Type::Alias(base), + self.process_annotation(&annotation), + ) + } + + fn process_extension(&mut self, + attrs: &'ast HashMap, &'input str>, + attr_base: &'ast QName<'input>, + type_def_particle: &'ast xs::TypeDefParticle<'input>, + annotation: Vec<&'ast xs::Annotation<'input>>, + inlinable: bool, + ) -> RichType<'input, Type<'input>> { + let base = FullName::from_qname(attr_base, self.target_namespace); + RichType::new( + NameHint::new_empty(), + Type::Extension(base, Box::new(self.process_type_def_particle(type_def_particle, inlinable))), + self.process_annotation(&annotation), + ) + } + + fn process_toplevel_element(&mut self, element: &'ast xs::Element<'input>) { + let name = FullName::new(self.target_namespace, element.attr_name.0); + let type_attr: Option> = element.attr_type; + let substitution_group = &element.attr_substitution_group; + let xs::Element { ref attrs, ref attr_id, ref attr_name, ref attr_type, ref attr_substitution_group, ref attr_default, ref attr_fixed, ref attr_nillable, ref attr_abstract, ref attr_final, ref attr_block, ref annotation, type_: ref child_type, ref alternative_alt_type, ref identity_constraint } = element; + let annotation = annotation.iter().collect(); + if let Some(heads) = attr_substitution_group { + for head in &heads.0 { + let head = FullName::from_qname(head, self.target_namespace); + self.substitution_groups.entry(head) + .or_insert(Vec::new()) + .push(name.clone()); + } + } + let type_ = match (type_attr, &child_type) { + (None, Some(ref c)) => match c { + enums::Type::SimpleType(ref e) => { + let mut ty = self.process_local_simple_type(e); + ty.doc.extend(&self.process_annotation(&annotation)); + ty.into_complex() + }, + enums::Type::ComplexType(ref e) => { + self.process_local_complex_type(e, Some(attr_name), annotation, false) + }, + }, + (Some(t), None) => { + let t = FullName::from_qname(&t, self.target_namespace); + RichType::new( + NameHint::new(t.local_name()), + Type::Alias(t.into()), + self.process_annotation(&annotation), + ) + }, + (None, None) => { + RichType::new( + NameHint::new("empty"), + Type::Empty, + self.process_annotation(&annotation), + ) + }, + (Some(ref t1), Some(ref t2)) => panic!("Toplevel element '{:?}' has both a type attribute ({:?}) and a child type ({:?}).", name, t1, t2), + }; + + self.elements.insert(name, type_); + } + + fn process_local_element(&mut self, + element: &'ast inline_elements::LocalElement<'input>, + ) -> RichType<'input, Type<'input>> { + let inline_elements::LocalElement { ref attrs, ref attr_id, ref attr_name, ref attr_ref, ref attr_min_occurs, ref attr_max_occurs, ref attr_type, ref attr_default, ref attr_fixed, ref attr_nillable, ref attr_block, ref attr_form, ref attr_target_namespace, ref annotation, ref type_, ref alternative_alt_type, ref identity_constraint } = element; + let annotation = annotation.iter().collect(); + let name = attr_name; + let type_attr = attr_type; + let min_occurs = parse_min_occurs(attr_min_occurs); + let max_occurs = parse_max_occurs(attr_max_occurs); + + if let Some(ref_) = attr_ref { + if let Some(name) = name { + panic!(" has both ref={:?} and name={:?}", ref_, name); + } + let ref_ = FullName::from_qname(ref_, self.target_namespace); + RichType::new( + NameHint::new(ref_.local_name()), + Type::ElementRef(min_occurs, max_occurs, ref_), + self.process_annotation(&annotation), + ) + } + else { + let name = name.as_ref().expect(" has no name.").0; + + // https://www.w3.org/TR/xmlschema11-1/#dcl.elt.local + let qualified_form = match attr_form.as_ref().map(|x| ((x.0).0).0) { + Some("qualified") => true, + Some("unqualified") => false, + None => self.element_form_default_qualified, + _ => unreachable!(), + }; + let namespace = match (attr_target_namespace, qualified_form) { + (Some(AnyUri(target_namespace)), _) => Some(*target_namespace), + (None, true) => self.target_namespace, + (None, false) => None, + }; + + match (type_attr, &type_) { + (None, Some(ref c)) => { + let mut t = match c { + enums::Type::SimpleType(ref e) => { + let mut ty = self.process_local_simple_type(e); + ty.doc.extend(&self.process_annotation(&annotation)); + ty.into_complex() + }, + enums::Type::ComplexType(ref e) => { + self.process_local_complex_type(e, None, annotation, false) + }, + }; + let mut name_hint = NameHint::new(name); + name_hint.extend(&t.name_hint); + let struct_name = name_from_hint(&name_hint).unwrap(); + let (elems, doc) = self.inline_elements.entry((namespace, name, t.attrs, t.type_)) + .or_insert((HashSet::new(), Documentation::new())); + elems.insert(struct_name.clone()); + t.doc.extend(doc); + RichType::new( + NameHint::new(name), + Type::Element(min_occurs, max_occurs, struct_name), + t.doc, + ) + }, + (Some(t), None) => { + let name_hint1 = NameHint::new(t.local_name); + let mut name_hint2 = NameHint::new(name); + name_hint2.push(t.local_name); + // TODO: move this heuristic in names.rs + let name_hint = if t.local_name.to_lowercase().contains(&name.to_lowercase()) { + name_hint1 + } + else { + name_hint2 + }; + let struct_name = name_from_hint(&name_hint).unwrap(); + let mut doc = self.process_annotation(&annotation); + let t = FullName::from_qname(t, self.target_namespace); + let (elems, doc2) = self.inline_elements.entry((namespace, name, Attrs::new(), Type::Alias(t))) + .or_insert((HashSet::new(), Documentation::new())); + elems.insert(struct_name.clone()); + doc.extend(doc2); + RichType::new( + NameHint::new(name), + Type::Element(min_occurs, max_occurs, struct_name), + doc, + ) + }, + (None, None) => { + RichType::new( + NameHint::new("empty"), + Type::Empty, + self.process_annotation(&annotation), + ) + }, + (Some(ref t1), Some(ref t2)) => panic!("Element '{:?}' has both a type attribute ({:?}) and a child type ({:?}).", name, t1, t2), + } + } + } + + fn process_attr_decls(&mut self, attr_decls: &'ast xs::AttrDecls<'input>) -> Attrs<'input> { + let mut attrs = Attrs::new(); + for attr_decl in &attr_decls.attribute { + match attr_decl { + enums::AttrOrAttrGroup::Attribute(e) => { + let name = e.attr_name.as_ref().map(|ncn| FullName::new(self.target_namespace, ncn.0)); + let mut type_attr: Option> = e.attr_type; + let use_ = match e.attr_use.as_ref().map(|x| ((x.0).0).0) { + Some("prohibited") => AttrUse::Prohibited, + Some("required") => AttrUse::Required, + Some("optional") => AttrUse::Optional, + None => AttrUse::Optional, // TODO + Some(s) => panic!("Unknown attribute value use={:?}", s), + }; + match (name, e.attr_ref, type_attr, &e.local_simple_type) { + (Some(name), None, Some(t), None) => { + let t = FullName::from_qname(&t, self.target_namespace); + attrs.named.push((name, use_, Some(SimpleType::Alias(t)))); + }, + (Some(name), None, None, Some(t)) => { + let t = self.process_local_simple_type(t); + attrs.named.push((name, use_, Some(t.type_))); + }, + (Some(name), None, None, None) => + attrs.named.push((name, use_, None)), + (None, None, None, None) => + panic!("no attribute on ."), + (_, _, Some(ref t1), Some(ref t2)) => + panic!(" has both a type attribute ({:?}) and a child type ({:?}).", t1, t2), + (None, None, Some(_), None) | (None, None, None, Some(_)) => + panic!(" has a type but no name."), + (_, Some(_), Some(_), None) | (_, Some(_), None, Some(_)) => + panic!(" has a type and a ref."), + (_, Some(ref_), None, None) => (), // TODO + } + }, + enums::AttrOrAttrGroup::AttributeGroup(e) => { + attrs.group_refs.push(FullName::from_qname(&e.attr_ref, self.target_namespace)); + }, + } + } + if attr_decls.any_attribute.is_some() { + attrs.any_attributes = true; + } + attrs + } + + +} diff --git a/xml-schema/src/support.rs b/xml-schema/src/support.rs new file mode 100644 index 0000000..f19141a --- /dev/null +++ b/xml-schema/src/support.rs @@ -0,0 +1,177 @@ +use std::marker::PhantomData; +use std::collections::HashMap; +pub use std::str::FromStr; + +pub use xmlparser::{Token as XmlToken, Tokenizer, ElementEnd}; + +pub use primitives::*; // TODO: remove the pub? +pub use names::FullName; + +pub use bigfloat::BigFloatNotNaN; + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct Facets<'input> { + pub min_exclusive: Option, + pub min_inclusive: Option, + pub max_exclusive: Option, + pub max_inclusive: Option, + pub total_digits: Option, + pub fraction_digits: Option, + pub length: Option, + pub min_length: Option, + pub max_length: Option, + pub enumeration: Option>, + pub white_space: Option<&'input str>, + pub pattern: Option<&'input str>, + pub assertion: Option<&'input str>, + pub explicit_timezone: Option<&'input str>, +} + +#[derive(Debug,PartialEq)] +pub struct List<'input, Item>(Vec, PhantomData<&'input ()>); + +pub type Stream<'input> = Box>; +pub struct InnerStream<'input> { + pub(crate) index: usize, + passed_prelude: bool, + tokens: Vec>, +} + +impl<'input> InnerStream<'input> { + pub fn new(tokenizer: Tokenizer<'input>) -> InnerStream<'input> { + InnerStream { index: 0, passed_prelude: false, tokens: tokenizer.into_iter().map(|o| o.unwrap()).collect() } + } + + #[inline] + pub fn transaction(&self) -> Transaction { + Transaction { initial_index: self.index } + } +} + +#[must_use] +pub struct Transaction { + initial_index: usize, +} + +impl Transaction { + #[inline] + pub fn commit(self) { + } + + #[inline] + pub fn rollback(self, stream: &mut InnerStream) { + //println!("// Rolling back {} tokens", stream.index - self.initial_index); + stream.index = self.initial_index + } +} + +impl<'input> Iterator for InnerStream<'input> { + type Item = XmlToken<'input>; + fn next(&mut self) -> Option { + if !self.passed_prelude { + self.passed_prelude = true; + loop { + let tok = self.next().unwrap(); + match tok { + XmlToken::EntityDeclaration(_, _) | + XmlToken::Declaration(_, _, _) | + XmlToken::DtdStart(_, _) | + XmlToken::Comment(_) => (), + XmlToken::DtdEnd => break, + _ => { + return Some(tok); + } + } + } + } + let tok = self.tokens.get(self.index); + //println!("// Reading {:?}", tok); + match tok { + Some(res) => { + self.index += 1; + Some(res.clone()) + } + None => None + } + } +} + + +#[derive(Clone)] +pub struct ParentContext<'input> { + pub namespaces: HashMap<&'input str, &'input str>, +} +impl<'input> Default for ParentContext<'input> { + fn default() -> ParentContext<'input> { + let mut namespaces = HashMap::new(); + namespaces.insert("xmlns", "xmlns"); + namespaces.insert("xml", "xml"); + ParentContext { namespaces } + } +} +pub trait ParseContext<'input> { + fn on_xmlns(&mut self, _name: Option<&'input str>, _uri: &'input str) { + } +} +#[derive(Default)] +pub struct DefaultParseContext<'input> { + _phantom: PhantomData<&'input str>, +} + +impl<'input> ParseContext<'input> for DefaultParseContext<'input> { +} + +pub trait ParseXml<'input>: Sized { + const NODE_NAME: &'static str; + + fn parse_self_xml>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>) -> Option; + + + fn parse_empty>(_parse_context: &mut TParseContext, _parent_context: &ParentContext<'input>) -> Option { + None + } + + fn parse_xml>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>) -> Option { + //println!("// Entering: {:?}", Self::NODE_NAME); + let ret = Self::parse_self_xml(stream, parse_context, parent_context); + /* + match ret { + Some(_) => println!("// Leaving: {:?} (succeeded)", Self::NODE_NAME), + None => println!("// Leaving: {:?} (aborted)", Self::NODE_NAME), + }*/ + ret + } +} + +pub trait ParseXmlStr<'input>: Sized { + const NODE_NAME: &'static str; + + fn parse_self_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Self)>; + + fn parse_xml_str<'a, TParseContext: ParseContext<'input>>(input: &'input str, parse_context: &mut TParseContext, parent_context: &ParentContext<'input>, facets: &Facets<'a>) -> Option<(&'input str, Self)> { + //println!("// Entering: {:?}", Self::NODE_NAME); + let ret = Self::parse_self_xml_str(input, parse_context, parent_context, facets); + /* + match ret { + Some(_) => println!("// Leaving: {:?} (succeeded)", Self::NODE_NAME), + None => println!("// Leaving: {:?} (aborted)", Self::NODE_NAME), + }*/ + ret + } +} + +impl<'input, T> ParseXml<'input> for T where T: ParseXmlStr<'input> { + const NODE_NAME: &'static str = Self::NODE_NAME; + fn parse_self_xml<'b, TParseContext: ParseContext<'input>>(stream: &mut Stream<'input>, parse_context: &mut TParseContext, parent_context: &'b ParentContext<'input>) -> Option { + match stream.next() { + Some(XmlToken::Text(strspan)) => { + match Self::parse_self_xml_str(strspan.to_str(), parse_context, parent_context, &Facets::default()) { + Some(("", out)) => Some(out), + Some((unparsed, _)) => None, + None => None, + } + } + _ => None, + } + } +} diff --git a/src/test_generated2.rs b/xml-schema/src/test_parser.rs similarity index 71% rename from src/test_generated2.rs rename to xml-schema/src/test_parser.rs index 0750bd5..b7e8d08 100644 --- a/src/test_generated2.rs +++ b/xml-schema/src/test_parser.rs @@ -1,8 +1,7 @@ use xmlparser; use parse_xsd; -use round0_parser::*; -use generated2::*; +use parser::*; use support::*; const PERSON_XSD: &'static str = r#" @@ -20,8 +19,6 @@ const PERSON_XSD: &'static str = r#" #[test] fn generated_parses_person_xsd() { - let tokenizer = xmlparser::Tokenizer::from(PERSON_XSD); - let mut stream = Box::new(InnerStream::new(tokenizer)); - let doc = xs::Schema::parse_xml(&mut stream, &mut (), &()); + let (doc, _) = parse_xsd(PERSON_XSD); assert_ne!(doc, None); } diff --git a/xml-schema/src/test_parser_schema.rs b/xml-schema/src/test_parser_schema.rs new file mode 100644 index 0000000..179f066 --- /dev/null +++ b/xml-schema/src/test_parser_schema.rs @@ -0,0 +1,31 @@ +use std::fs::File; +use std::io::Read; +use std::collections::HashMap; + +use xmlparser; + +use parse_xsd; +use parser::xs; +use parser_generator::ParserGenerator; +use support::*; + +#[test] +fn generated_parses_person_xsd() { + let mut f = File::open("XMLSchema.xsd").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + let (doc, _) = parse_xsd(&s); + assert_ne!(doc, None); +} + +#[test] +fn round1_parser_person_xsd() { + let mut f = File::open("XMLSchema.xsd").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + let (doc, _) = parse_xsd(&s); + assert_ne!(doc, None); + //let mut parser_generator = ParserGenerator::new(doc.as_ref().unwrap(), HashMap::new()); + //parser_generator.gen(doc.as_ref().unwrap()).to_string(); +} + diff --git a/xml-schema/src/xml_utils.rs b/xml-schema/src/xml_utils.rs new file mode 100644 index 0000000..e4ee254 --- /dev/null +++ b/xml-schema/src/xml_utils.rs @@ -0,0 +1,31 @@ +/// https://www.w3.org/TR/xml11/#NT-Char +#[inline(always)] +pub fn is_xml_char(c: char) -> bool { + match c as u32 { + 0x0..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF => true, + 0xFFFE | 0xFFFF => false, + _ => unreachable!(), + } +} + +/// https://www.w3.org/TR/xml-names11/#NT-NCNameStartChar +#[inline(always)] +pub fn is_name_start_char(c: char) -> bool { + match c { + ':' | 'A'..='Z' | '_' | 'a'..='z' | '\u{C0}'..='\u{D6}' | '\u{F8}'..='\u{2FF}' | + '\u{370}'..='\u{1FFF}' | '\u{200C}'..='\u{200D}' | '\u{2070}'..='\u{218F}' | + '\u{2C00}'..='\u{2FEF}' | '\u{3001}'..='\u{D7FF}' | '\u{F900}'..='\u{FDCF}' | + '\u{FDF0}'..='\u{FFFD}' | '\u{10000}'..='\u{EFFFF}' => true, + _ => false, + } +} + +/// https://www.w3.org/TR/xml-names11/#NT-NCNameChar +#[inline(always)] +pub fn is_name_char(c: char) -> bool { + match c { + '-' | '.' | '0'..='9' | '\u{B7}' | '\u{0300}'..='\u{036F}' | + '\u{203F}'..='\u{2040}' => true, + _ => is_name_start_char(c), + } +} diff --git a/tests/po.rs b/xml-schema/tests/po.rs similarity index 98% rename from tests/po.rs rename to xml-schema/tests/po.rs index 8a02bfc..540da71 100644 --- a/tests/po.rs +++ b/xml-schema/tests/po.rs @@ -1,6 +1,6 @@ extern crate xml_schema; use xml_schema::parse_xsd; -use xml_schema::round0_parser::*; +use xml_schema::parser::*; const PO_XSD: &'static str = r#"