From 707cc94fe52463870a9c6c8e2e66eaaa389e601d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 24 Feb 2009 15:16:26 +0200 Subject: Start tracking XSD/e with git after version 3.0.0 --- xsde/cxx/elements.cxx | 1089 ++++++++ xsde/cxx/elements.hxx | 599 +++++ xsde/cxx/hybrid/cli.hxx | 188 ++ xsde/cxx/hybrid/elements.cxx | 493 ++++ xsde/cxx/hybrid/elements.hxx | 1880 ++++++++++++++ xsde/cxx/hybrid/generator.cxx | 2476 ++++++++++++++++++ xsde/cxx/hybrid/generator.hxx | 90 + xsde/cxx/hybrid/parser-aggregate-header.cxx | 837 ++++++ xsde/cxx/hybrid/parser-aggregate-header.hxx | 22 + xsde/cxx/hybrid/parser-aggregate-source.cxx | 330 +++ xsde/cxx/hybrid/parser-aggregate-source.hxx | 22 + xsde/cxx/hybrid/parser-header.cxx | 574 +++++ xsde/cxx/hybrid/parser-header.hxx | 22 + xsde/cxx/hybrid/parser-name-processor.cxx | 709 +++++ xsde/cxx/hybrid/parser-name-processor.hxx | 32 + xsde/cxx/hybrid/parser-source.cxx | 1185 +++++++++ xsde/cxx/hybrid/parser-source.hxx | 22 + xsde/cxx/hybrid/serializer-aggregate-header.cxx | 847 ++++++ xsde/cxx/hybrid/serializer-aggregate-header.hxx | 22 + xsde/cxx/hybrid/serializer-aggregate-source.cxx | 330 +++ xsde/cxx/hybrid/serializer-aggregate-source.hxx | 22 + xsde/cxx/hybrid/serializer-header.cxx | 534 ++++ xsde/cxx/hybrid/serializer-header.hxx | 22 + xsde/cxx/hybrid/serializer-name-processor.cxx | 723 ++++++ xsde/cxx/hybrid/serializer-name-processor.hxx | 32 + xsde/cxx/hybrid/serializer-source.cxx | 1001 ++++++++ xsde/cxx/hybrid/serializer-source.hxx | 22 + xsde/cxx/hybrid/tree-forward.cxx | 626 +++++ xsde/cxx/hybrid/tree-forward.hxx | 22 + xsde/cxx/hybrid/tree-header.cxx | 2459 ++++++++++++++++++ xsde/cxx/hybrid/tree-header.hxx | 22 + xsde/cxx/hybrid/tree-inline.cxx | 1817 +++++++++++++ xsde/cxx/hybrid/tree-inline.hxx | 22 + xsde/cxx/hybrid/tree-name-processor.cxx | 1993 +++++++++++++++ xsde/cxx/hybrid/tree-name-processor.hxx | 32 + xsde/cxx/hybrid/tree-size-processor.cxx | 850 ++++++ xsde/cxx/hybrid/tree-size-processor.hxx | 32 + xsde/cxx/hybrid/tree-source.cxx | 1672 ++++++++++++ xsde/cxx/hybrid/tree-source.hxx | 22 + xsde/cxx/hybrid/tree-type-map.cxx | 248 ++ xsde/cxx/hybrid/tree-type-map.hxx | 32 + xsde/cxx/hybrid/validator.cxx | 584 +++++ xsde/cxx/hybrid/validator.hxx | 35 + xsde/cxx/parser/attribute-validation-source.cxx | 468 ++++ xsde/cxx/parser/attribute-validation-source.hxx | 22 + xsde/cxx/parser/characters-validation-source.cxx | 76 + xsde/cxx/parser/characters-validation-source.hxx | 22 + xsde/cxx/parser/cli.hxx | 156 ++ xsde/cxx/parser/driver-source.cxx | 1139 +++++++++ xsde/cxx/parser/driver-source.hxx | 22 + xsde/cxx/parser/element-validation-source.cxx | 2120 +++++++++++++++ xsde/cxx/parser/element-validation-source.hxx | 22 + xsde/cxx/parser/elements.cxx | 258 ++ xsde/cxx/parser/elements.hxx | 431 ++++ xsde/cxx/parser/generator.cxx | 1615 ++++++++++++ xsde/cxx/parser/generator.hxx | 56 + xsde/cxx/parser/impl-header.cxx | 309 +++ xsde/cxx/parser/impl-header.hxx | 22 + xsde/cxx/parser/impl-source.cxx | 543 ++++ xsde/cxx/parser/impl-source.hxx | 22 + xsde/cxx/parser/name-processor.cxx | 1326 ++++++++++ xsde/cxx/parser/name-processor.hxx | 32 + xsde/cxx/parser/parser-forward.cxx | 112 + xsde/cxx/parser/parser-forward.hxx | 22 + xsde/cxx/parser/parser-header.cxx | 1818 +++++++++++++ xsde/cxx/parser/parser-header.hxx | 22 + xsde/cxx/parser/parser-inline.cxx | 721 ++++++ xsde/cxx/parser/parser-inline.hxx | 22 + xsde/cxx/parser/parser-source.cxx | 1626 ++++++++++++ xsde/cxx/parser/parser-source.hxx | 22 + xsde/cxx/parser/print-impl-common.hxx | 1063 ++++++++ xsde/cxx/parser/state-processor.cxx | 319 +++ xsde/cxx/parser/state-processor.hxx | 28 + xsde/cxx/parser/type-processor.cxx | 352 +++ xsde/cxx/parser/type-processor.hxx | 34 + xsde/cxx/parser/validator.cxx | 704 +++++ xsde/cxx/parser/validator.hxx | 36 + .../cxx/serializer/attribute-validation-source.cxx | 463 ++++ .../cxx/serializer/attribute-validation-source.hxx | 22 + xsde/cxx/serializer/cli.hxx | 154 ++ xsde/cxx/serializer/driver-source.cxx | 1047 ++++++++ xsde/cxx/serializer/driver-source.hxx | 22 + xsde/cxx/serializer/element-validation-source.cxx | 903 +++++++ xsde/cxx/serializer/element-validation-source.hxx | 22 + xsde/cxx/serializer/elements.cxx | 278 ++ xsde/cxx/serializer/elements.hxx | 443 ++++ xsde/cxx/serializer/generator.cxx | 1600 ++++++++++++ xsde/cxx/serializer/generator.hxx | 56 + xsde/cxx/serializer/impl-header.cxx | 488 ++++ xsde/cxx/serializer/impl-header.hxx | 22 + xsde/cxx/serializer/impl-source.cxx | 664 +++++ xsde/cxx/serializer/impl-source.hxx | 22 + xsde/cxx/serializer/name-processor.cxx | 1409 ++++++++++ xsde/cxx/serializer/name-processor.hxx | 32 + xsde/cxx/serializer/serializer-forward.cxx | 112 + xsde/cxx/serializer/serializer-forward.hxx | 22 + xsde/cxx/serializer/serializer-header.cxx | 2006 +++++++++++++++ xsde/cxx/serializer/serializer-header.hxx | 22 + xsde/cxx/serializer/serializer-inline.cxx | 631 +++++ xsde/cxx/serializer/serializer-inline.hxx | 22 + xsde/cxx/serializer/serializer-source.cxx | 2703 ++++++++++++++++++++ xsde/cxx/serializer/serializer-source.hxx | 22 + xsde/cxx/serializer/type-processor.cxx | 356 +++ xsde/cxx/serializer/type-processor.hxx | 34 + xsde/cxx/serializer/validator.cxx | 501 ++++ xsde/cxx/serializer/validator.hxx | 36 + 106 files changed, 54269 insertions(+) create mode 100644 xsde/cxx/elements.cxx create mode 100644 xsde/cxx/elements.hxx create mode 100644 xsde/cxx/hybrid/cli.hxx create mode 100644 xsde/cxx/hybrid/elements.cxx create mode 100644 xsde/cxx/hybrid/elements.hxx create mode 100644 xsde/cxx/hybrid/generator.cxx create mode 100644 xsde/cxx/hybrid/generator.hxx create mode 100644 xsde/cxx/hybrid/parser-aggregate-header.cxx create mode 100644 xsde/cxx/hybrid/parser-aggregate-header.hxx create mode 100644 xsde/cxx/hybrid/parser-aggregate-source.cxx create mode 100644 xsde/cxx/hybrid/parser-aggregate-source.hxx create mode 100644 xsde/cxx/hybrid/parser-header.cxx create mode 100644 xsde/cxx/hybrid/parser-header.hxx create mode 100644 xsde/cxx/hybrid/parser-name-processor.cxx create mode 100644 xsde/cxx/hybrid/parser-name-processor.hxx create mode 100644 xsde/cxx/hybrid/parser-source.cxx create mode 100644 xsde/cxx/hybrid/parser-source.hxx create mode 100644 xsde/cxx/hybrid/serializer-aggregate-header.cxx create mode 100644 xsde/cxx/hybrid/serializer-aggregate-header.hxx create mode 100644 xsde/cxx/hybrid/serializer-aggregate-source.cxx create mode 100644 xsde/cxx/hybrid/serializer-aggregate-source.hxx create mode 100644 xsde/cxx/hybrid/serializer-header.cxx create mode 100644 xsde/cxx/hybrid/serializer-header.hxx create mode 100644 xsde/cxx/hybrid/serializer-name-processor.cxx create mode 100644 xsde/cxx/hybrid/serializer-name-processor.hxx create mode 100644 xsde/cxx/hybrid/serializer-source.cxx create mode 100644 xsde/cxx/hybrid/serializer-source.hxx create mode 100644 xsde/cxx/hybrid/tree-forward.cxx create mode 100644 xsde/cxx/hybrid/tree-forward.hxx create mode 100644 xsde/cxx/hybrid/tree-header.cxx create mode 100644 xsde/cxx/hybrid/tree-header.hxx create mode 100644 xsde/cxx/hybrid/tree-inline.cxx create mode 100644 xsde/cxx/hybrid/tree-inline.hxx create mode 100644 xsde/cxx/hybrid/tree-name-processor.cxx create mode 100644 xsde/cxx/hybrid/tree-name-processor.hxx create mode 100644 xsde/cxx/hybrid/tree-size-processor.cxx create mode 100644 xsde/cxx/hybrid/tree-size-processor.hxx create mode 100644 xsde/cxx/hybrid/tree-source.cxx create mode 100644 xsde/cxx/hybrid/tree-source.hxx create mode 100644 xsde/cxx/hybrid/tree-type-map.cxx create mode 100644 xsde/cxx/hybrid/tree-type-map.hxx create mode 100644 xsde/cxx/hybrid/validator.cxx create mode 100644 xsde/cxx/hybrid/validator.hxx create mode 100644 xsde/cxx/parser/attribute-validation-source.cxx create mode 100644 xsde/cxx/parser/attribute-validation-source.hxx create mode 100644 xsde/cxx/parser/characters-validation-source.cxx create mode 100644 xsde/cxx/parser/characters-validation-source.hxx create mode 100644 xsde/cxx/parser/cli.hxx create mode 100644 xsde/cxx/parser/driver-source.cxx create mode 100644 xsde/cxx/parser/driver-source.hxx create mode 100644 xsde/cxx/parser/element-validation-source.cxx create mode 100644 xsde/cxx/parser/element-validation-source.hxx create mode 100644 xsde/cxx/parser/elements.cxx create mode 100644 xsde/cxx/parser/elements.hxx create mode 100644 xsde/cxx/parser/generator.cxx create mode 100644 xsde/cxx/parser/generator.hxx create mode 100644 xsde/cxx/parser/impl-header.cxx create mode 100644 xsde/cxx/parser/impl-header.hxx create mode 100644 xsde/cxx/parser/impl-source.cxx create mode 100644 xsde/cxx/parser/impl-source.hxx create mode 100644 xsde/cxx/parser/name-processor.cxx create mode 100644 xsde/cxx/parser/name-processor.hxx create mode 100644 xsde/cxx/parser/parser-forward.cxx create mode 100644 xsde/cxx/parser/parser-forward.hxx create mode 100644 xsde/cxx/parser/parser-header.cxx create mode 100644 xsde/cxx/parser/parser-header.hxx create mode 100644 xsde/cxx/parser/parser-inline.cxx create mode 100644 xsde/cxx/parser/parser-inline.hxx create mode 100644 xsde/cxx/parser/parser-source.cxx create mode 100644 xsde/cxx/parser/parser-source.hxx create mode 100644 xsde/cxx/parser/print-impl-common.hxx create mode 100644 xsde/cxx/parser/state-processor.cxx create mode 100644 xsde/cxx/parser/state-processor.hxx create mode 100644 xsde/cxx/parser/type-processor.cxx create mode 100644 xsde/cxx/parser/type-processor.hxx create mode 100644 xsde/cxx/parser/validator.cxx create mode 100644 xsde/cxx/parser/validator.hxx create mode 100644 xsde/cxx/serializer/attribute-validation-source.cxx create mode 100644 xsde/cxx/serializer/attribute-validation-source.hxx create mode 100644 xsde/cxx/serializer/cli.hxx create mode 100644 xsde/cxx/serializer/driver-source.cxx create mode 100644 xsde/cxx/serializer/driver-source.hxx create mode 100644 xsde/cxx/serializer/element-validation-source.cxx create mode 100644 xsde/cxx/serializer/element-validation-source.hxx create mode 100644 xsde/cxx/serializer/elements.cxx create mode 100644 xsde/cxx/serializer/elements.hxx create mode 100644 xsde/cxx/serializer/generator.cxx create mode 100644 xsde/cxx/serializer/generator.hxx create mode 100644 xsde/cxx/serializer/impl-header.cxx create mode 100644 xsde/cxx/serializer/impl-header.hxx create mode 100644 xsde/cxx/serializer/impl-source.cxx create mode 100644 xsde/cxx/serializer/impl-source.hxx create mode 100644 xsde/cxx/serializer/name-processor.cxx create mode 100644 xsde/cxx/serializer/name-processor.hxx create mode 100644 xsde/cxx/serializer/serializer-forward.cxx create mode 100644 xsde/cxx/serializer/serializer-forward.hxx create mode 100644 xsde/cxx/serializer/serializer-header.cxx create mode 100644 xsde/cxx/serializer/serializer-header.hxx create mode 100644 xsde/cxx/serializer/serializer-inline.cxx create mode 100644 xsde/cxx/serializer/serializer-inline.hxx create mode 100644 xsde/cxx/serializer/serializer-source.cxx create mode 100644 xsde/cxx/serializer/serializer-source.hxx create mode 100644 xsde/cxx/serializer/type-processor.cxx create mode 100644 xsde/cxx/serializer/type-processor.hxx create mode 100644 xsde/cxx/serializer/validator.cxx create mode 100644 xsde/cxx/serializer/validator.hxx (limited to 'xsde/cxx') diff --git a/xsde/cxx/elements.cxx b/xsde/cxx/elements.cxx new file mode 100644 index 0000000..6116856 --- /dev/null +++ b/xsde/cxx/elements.cxx @@ -0,0 +1,1089 @@ +// file : xsde/cxx/elements.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include + +#include +#include +#include + +using std::wcerr; +using std::endl; + +namespace CXX +{ + // + // + wchar_t + upcase (wchar_t c) + { + return std::toupper (c); + } + + // Context + // + + Context:: + Context (std::wostream& o, + SemanticGraph::Schema& root, + Char const* name_key, + NarrowString const& char_type__, + Boolean include_with_brackets__, + NarrowString const& include_prefix__, + NarrowString const& esymbol, + Containers::Vector const& nsm, + Containers::Vector const& nsr, + Boolean trace_namespace_regex_, + Containers::Vector const& ir, + Boolean trace_include_regex_, + Boolean inline_, + Containers::Vector const& reserved_name) + : os (o), + schema_root (root), + ename_key (ename_key_), + char_type (char_type_), + L (L_), + string_type (string_type_), + include_with_brackets (include_with_brackets_), + include_prefix (include_prefix_), + type_exp (type_exp_), + inst_exp (inst_exp_), + inl (inl_), + ns_mapping_cache (ns_mapping_cache_), + xs_ns_ (0), + ename_key_ (name_key), + char_type_ (char_type__), + L_ (char_type == L"wchar_t" ? L"L" : L""), + include_with_brackets_ (include_with_brackets__), + include_prefix_ (include_prefix__), + type_exp_ (esymbol ? esymbol + " " : esymbol), + inst_exp_ (esymbol ? esymbol + "\n" : esymbol), + inl_ (inline_ ? L"inline\n" : L""), + cxx_id_expr_ (L"^(::)?([a-zA-Z_]\\w*)(::[a-zA-Z_]\\w*)*$"), + cxx_id_expr (cxx_id_expr_), + trace_namespace_regex (trace_namespace_regex_), + nsr_mapping (nsr_mapping_), + nsm_mapping (nsm_mapping_), + include_mapping (include_mapping_), + trace_include_regex (trace_include_regex_), + reserved_name_map (reserved_name_map_) + { + // Resolve and cache XML Schema namespace. + // + { + SemanticGraph::Nameable* n; + + if (schema_root.names_begin ()->name () == + L"http://www.w3.org/2001/XMLSchema") + { + // schema_root is the XML Schema itself. + // + n = &schema_root.names_begin ()->named (); + } + else + { + // Otherwise, the first used schema is implied XML Schema. + // + SemanticGraph::Uses& u = *schema_root.uses_begin (); + assert (u.is_a ()); + n = &u.schema ().names_begin ()->named (); + } + + xs_ns_ = dynamic_cast (n); + } + + // + // + if (char_type == L"char") + string_type_ = L"::std::string"; + else if (char_type == L"wchar_t") + string_type_ = L"::std::wstring"; + else + string_type_ = L"::std::basic_string< " + char_type + L" >"; + + // Default mapping. + // + nsr_mapping_.push_back ( + Regex (L"#^.* (.*?/)??"L"(([a-zA-Z_]\\w*)(/[a-zA-Z_]\\w*)*)/?$#$2#")); + nsr_mapping_.push_back ( + Regex (L"#^.* http://www\\.w3\\.org/2001/XMLSchema$#xml_schema#")); + + // Custom regex mapping. + // + for (Containers::Vector::ConstIterator + i (nsr.begin ()), e (nsr.end ()); i != e; ++i) + { + nsr_mapping_.push_back (Regex (*i)); + } + + // Custom direct mapping. + // + for (Containers::Vector::ConstIterator + i (nsm.begin ()), e (nsm.end ()); i != e; ++i) + { + String s (*i); + + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); + + if (pos == String::npos) + throw InvalidNamespaceMapping (s, "delimiter ('=') not found"); + + // Empty xml_ns designates the no-namespace case. + // + String xml_ns (s, 0, pos); + String cxx_ns (s, pos + 1); + + if (!cxx_ns.empty () && !cxx_id_expr.match (cxx_ns)) + throw InvalidNamespaceMapping (s, "invalid C++ identifier"); + + nsm_mapping_[xml_ns] = cxx_ns; + } + + // Include path regex + // + for (Containers::Vector::ConstIterator + i (ir.begin ()), e (ir.end ()); i != e; ++i) + { + include_mapping_.push_back (Regex (*i)); + } + + // Reserved names. + // + for (Containers::Vector::ConstIterator + i (reserved_name.begin ()), e (reserved_name.end ()); i != e; ++i) + { + String s (*i); + + // Split the string in two parts at '='. + // + Size pos (s.find ('=')); + + if (pos == String::npos) + reserved_name_map_[s] = L""; + else + reserved_name_map_[String (s, 0, pos)] = String (s, pos + 1); + } + } + + String Context:: + ns_name (SemanticGraph::Namespace& ns) const + { + using SemanticGraph::Schema; + using SemanticGraph::Includes; + using SemanticGraph::Imports; + using SemanticGraph::Implies; + using SemanticGraph::Sources; + + String tmp; + MapMapping::ConstIterator i (nsm_mapping.find (ns.name ())); + + if (i != nsm_mapping.end ()) + { + tmp = i->second; + } + else + { + SemanticGraph::Path path; + Schema& schema (dynamic_cast (ns.scope ())); + + if (schema.used ()) + { + SemanticGraph::Uses& u (*schema.used_begin ()); + path = u.path (); + } + + String pair; + + if (!path.empty ()) + { + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + try + { + pair = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + pair = path.native_file_string (); + } + } + + pair += L' ' + ns.name (); + + // Check cache first + // + MappingCache::ConstIterator i (ns_mapping_cache.find (pair)); + + if (i != ns_mapping_cache.end ()) + { + tmp = i->second; + } + else + { + if (trace_namespace_regex) + wcerr << "namespace: '" << pair << "'" << endl; + + Boolean found (false); + Regex colon (L"#/#::#"); + + for (RegexMapping::ConstReverseIterator e (nsr_mapping.rbegin ()); + e != nsr_mapping.rend (); ++e) + { + if (trace_namespace_regex) + wcerr << "try: '" << e->pattern () << "' : "; + + if (e->match (pair)) + { + tmp = e->merge (pair); + tmp = colon.merge (tmp); // replace `/' with `::' + + // Check the result. + // + found = cxx_id_expr.match (tmp); + + if (trace_namespace_regex) + wcerr << "'" << tmp << "' : "; + } + + if (trace_namespace_regex) + wcerr << (found ? '+' : '-') << endl; + + if (found) + break; + } + + if (!found) + { + // Check if the name is valid by itself. + // + if (ns.name ().empty ()) + { + // Empty name denotes a no-namespace case. + // + tmp = ns.name (); + } + else + { + tmp = colon.merge (ns.name ()); // replace `/' with `::' + + if (!cxx_id_expr.match (tmp)) + { + throw NoNamespaceMapping ( + ns.file (), ns.line (), ns.column (), ns.name ()); + } + } + } + + // Add the mapping to the cache. + // + ns_mapping_cache[pair] = tmp; + } + } + + + // Parse resulting namespace string and id() each name. + // + String r; + String::size_type b (0), e; + + do + { + e = tmp.find (L"::", b); + + String name (tmp, b, e == tmp.npos ? e : e - b); + + if (!name.empty ()) + r += L"::" + escape (name); + + b = e; + + if (b == tmp.npos) + break; + + b += 2; + + } while (true); + + return r; + } + + SemanticGraph::Namespace& Context:: + xs_ns () + { + return *xs_ns_; + } + + String Context:: + xs_ns_name () + { + return ns_name (*xs_ns_); + } + + SemanticGraph::Namespace& Context:: + namespace_ (SemanticGraph::Nameable& n) + { + // The basic idea goes like this: go up Names edges until you + // reach Namespace. There are, however, anonymous types which + // need special handling. In the case of an anonymous type we + // will go up the first Belongs edge (because the first edge + // is where the type was defined. + // + + if (n.named ()) + { + SemanticGraph::Scope& s (n.scope ()); + + SemanticGraph::Namespace* ns ( + dynamic_cast (&n)); + + return ns ? *ns : namespace_ (s); + } + else + { + SemanticGraph::Type& t (dynamic_cast (n)); + + SemanticGraph::Belongs& b (*t.classifies_begin ()); + + return namespace_ (b.instance ()); + } + } + + String Context:: + xml_ns_name (SemanticGraph::Nameable& n) + { + return namespace_ (n).name (); + } + + String Context:: + fq_name (SemanticGraph::Nameable& n, Char const* name_key) const + { + using namespace SemanticGraph; + + String r; + + if (dynamic_cast (&n)) + { + return L""; // Map to global namespace. + } + else if (SemanticGraph::Namespace* ns = + dynamic_cast (&n)) + { + r = ns_name (*ns); + } + else + { + r = fq_name (n.scope ()); + r += L"::"; + r += n.context ().get ( + name_key ? name_key : ename_key.c_str ()); + } + + return r; + } + + SemanticGraph::Type& Context:: + ultimate_base (SemanticGraph::Complex& c) + { + using namespace SemanticGraph; + + Type* b (&c.inherits ().base ()); + + while (true) + { + Complex* cb (dynamic_cast (b)); + + if (cb != 0 && cb->inherits_p ()) + { + b = &cb->inherits ().base (); + continue; + } + + break; + } + + return *b; + } + + // Restriction correspondance. + // + SemanticGraph::Element* Context:: + correspondent (SemanticGraph::Element& r) + { + SemanticGraph::Context& c (r.context ()); + + if (c.count ("xsd-frontend-restriction-correspondence")) + { + return c.get ( + "xsd-frontend-restriction-correspondence"); + } + + return 0; + } + + SemanticGraph::Any* Context:: + correspondent (SemanticGraph::Any& r) + { + SemanticGraph::Context& c (r.context ()); + + if (c.count ("xsd-frontend-restriction-correspondence")) + { + return c.get ( + "xsd-frontend-restriction-correspondence"); + } + + return 0; + } + + SemanticGraph::Compositor* Context:: + correspondent (SemanticGraph::Compositor& r) + { + SemanticGraph::Context& c (r.context ()); + + if (c.count ("xsd-frontend-restriction-correspondence")) + { + return c.get ( + "xsd-frontend-restriction-correspondence"); + } + + return 0; + } + + + // + // + namespace + { + WideChar const* keywords[] = { + L"NULL", + L"and", + L"asm", + L"auto", + L"bitand", + L"bitor", + L"bool", + L"break", + L"case", + L"catch", + L"char", + L"class", + L"compl", + L"const", + L"const_cast", + L"continue", + L"default", + L"delete", + L"do", + L"double", + L"dynamic_cast", + L"else", + L"end_eq", + L"enum", + L"explicit", + L"export", + L"extern", + L"false", + L"float", + L"for", + L"friend", + L"goto", + L"if", + L"inline", + L"int", + L"long", + L"mutable", + L"namespace", + L"new", + L"not", + L"not_eq", + L"operator", + L"or", + L"or_eq", + L"private", + L"protected", + L"public", + L"register", + L"reinterpret_cast", + L"return", + L"short", + L"signed", + L"sizeof", + L"static", + L"static_cast", + L"struct", + L"switch", + L"template", + L"this", + L"throw", + L"true", + L"try", + L"typedef", + L"typeid", + L"typename", + L"union", + L"unsigned", + L"using", + L"virtual", + L"void", + L"volatile", + L"wchar_t", + L"while", + L"xor", + L"xor_eq" + }; + } + + String Context:: + escape (String const& name) const + { + String r; + Size n (name.size ()); + + // In most common cases we will have that many chars. + // + r.reserve (n); + + for (Size i (0); i < n; ++i) + { + Boolean first (i == 0); + + UnsignedLong u (unicode_char (name, i)); // May advance i. + + if (first) + { + if (!((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + u == '_')) + r = (u >= '0' && u <= '9') ? L"cxx_" : L"cxx"; + } + + if (!((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9') || + u == '_')) + r.push_back ('_'); + else + r.push_back (static_cast (u)); + } + + if (r.empty ()) + r = L"cxx"; + + // Custom reserved words. + // + ReservedNameMap::ConstIterator i (reserved_name_map.find (r)); + + if (i != reserved_name_map.end ()) + { + if (i->second) + return i->second; + else + r += L'_'; + } + + // Keywords + // + Size const size (sizeof (keywords) / sizeof (WideChar*)); + + if (std::binary_search (keywords, keywords + size, r)) + { + r += L'_'; + + // Re-run custom words. + // + i = reserved_name_map.find (r); + + if (i != reserved_name_map.end ()) + { + if (i->second) + return i->second; + else + r += L'_'; + } + } + + return r; + } + + // String escaping. + // + + String + charlit (UnsignedLong u) + { + String r ("\\x"); + Boolean lead (true); + + for (Long i (7); i >= 0; --i) + { + UnsignedLong x ((u >> (i * 4)) & 0x0F); + + if (lead) + { + if (x == 0) + continue; + + lead = false; + } + + r += x < 10 ? ('0' + x) : ('A' + x - 10); + } + + return r; + } + + const UnsignedLong utf8_first_char_mask[5] = + { + 0x00, 0x00, 0xC0, 0xE0, 0xF0 + }; + + String + strlit_utf8 (String const& str) + { + String r; + Size n (str.size ()); + + // In most common cases we will have that many chars. + // + r.reserve (n + 2); + + r += '"'; + + Boolean escape (false); + + for (Size i (0); i < n; ++i) + { + UnsignedLong u (Context::unicode_char (str, i)); // May advance i. + + // [128 - ] - UTF-8 + // 127 - \x7F + // [32 - 126] - as is + // [0 - 31] - \X or \xXX + // + + if (u < 32 || u == 127) + { + switch (u) + { + case L'\n': + { + r += L"\\n"; + break; + } + case L'\t': + { + r += L"\\t"; + break; + } + case L'\v': + { + r += L"\\v"; + break; + } + case L'\b': + { + r += L"\\b"; + break; + } + case L'\r': + { + r += L"\\r"; + break; + } + case L'\f': + { + r += L"\\f"; + break; + } + case L'\a': + { + r += L"\\a"; + break; + } + default: + { + r += charlit (u); + escape = true; + break; + } + } + } + else if (u < 127) + { + if (escape) + { + // Close and open the string so there are no clashes. + // + r += '"'; + r += '"'; + + escape = false; + } + + switch (u) + { + case L'"': + { + r += L"\\\""; + break; + } + case L'\\': + { + r += L"\\\\"; + break; + } + default: + { + r += static_cast (u); + break; + } + } + } + else + { + UnsignedLong count; + UnsignedLong tmp[4]; + + if (u < 0x800) + count = 2; + else if (u < 0x10000) + count = 3; + else if (u < 0x110000) + count = 4; + + switch (count) + { + case 4: + { + tmp[3] = (u | 0x80UL) & 0xBFUL; + u >>= 6; + } + case 3: + { + tmp[2] = (u | 0x80UL) & 0xBFUL; + u >>= 6; + } + case 2: + { + tmp[1] = (u | 0x80UL) & 0xBFUL; + u >>= 6; + } + case 1: + { + tmp[0] = u | utf8_first_char_mask[count]; + } + } + + for (UnsignedLong j (0); j < count; ++j) + r += charlit (tmp[j]); + + escape = true; + } + } + + r += '"'; + + return r; + } + + String + strlit_utf32 (String const& str) + { + String r; + Size n (str.size ()); + + // In most common cases we will have that many chars. + // + r.reserve (n + 2); + + r += '"'; + + Boolean escape (false); + + for (Size i (0); i < n; ++i) + { + UnsignedLong u (Context::unicode_char (str, i)); // May advance i. + + // [128 - ] - \xUUUUUUUU + // 127 - \x7F + // [32 - 126] - as is + // [0 - 31] - \X or \xXX + // + + if (u < 32 || u == 127) + { + switch (u) + { + case L'\n': + { + r += L"\\n"; + break; + } + case L'\t': + { + r += L"\\t"; + break; + } + case L'\v': + { + r += L"\\v"; + break; + } + case L'\b': + { + r += L"\\b"; + break; + } + case L'\r': + { + r += L"\\r"; + break; + } + case L'\f': + { + r += L"\\f"; + break; + } + case L'\a': + { + r += L"\\a"; + break; + } + default: + { + r += charlit (u); + escape = true; + break; + } + } + } + else if (u < 127) + { + if (escape) + { + // Close and open the string so there are no clashes. + // + r += '"'; + r += '"'; + + escape = false; + } + + switch (u) + { + case L'"': + { + r += L"\\\""; + break; + } + case L'\\': + { + r += L"\\\\"; + break; + } + default: + { + r += static_cast (u); + break; + } + } + } + else + { + r += charlit (u); + escape = true; + } + } + + r += '"'; + + return r; + } + + String Context:: + strlit (String const& str) + { + if (char_type == L"char") + return strlit_utf8 (str); + else + return strlit_utf32 (str); + } + + String Context:: + comment (String const& str) + { + String r; + + WideChar const* s (str.c_str ()); + Size size (str.size ()); + + // In most common cases we will have that many chars. + // + r.reserve (size); + + for (WideChar const* p (s); p < s + size; ++p) + { + UnsignedLong u (unicode_char (p)); // May advance p. + + // We are going to treat \v, \f and \n as unrepresentable + // here even though they can be present in C++ source code. + // + if (u > 127 || (u < 32 && u != '\t')) + r += L'?'; + else + r += static_cast (u); + } + + return r; + } + + String Context:: + process_include_path (String const& name) const + { + String path (include_prefix + name); + + if (trace_include_regex) + wcerr << "include: '" << path << "'" << endl; + + String r; + Boolean found (false); + + for (RegexMapping::ConstReverseIterator e (include_mapping.rbegin ()); + e != include_mapping.rend (); ++e) + { + if (trace_include_regex) + wcerr << "try: '" << e->pattern () << "' : "; + + if (e->match (path)) + { + r = e->merge (path); + found = true; + + if (trace_include_regex) + wcerr << "'" << r << "' : "; + } + + if (trace_include_regex) + wcerr << (found ? '+' : '-') << endl; + + if (found) + break; + } + + if (!found) + r = path; + + if (!r.empty () && r[0] != L'"' && r[0] != L'<') + { + WideChar op (include_with_brackets ? L'<' : L'"'); + WideChar cl (include_with_brackets ? L'>' : L'"'); + r = op + r + cl; + } + + return r; + } + + // Namespace + // + + Void Namespace:: + pre (Type& n) + { + String ns (ctx_.ns_name (n)); + + String::size_type b (0), e; + + if (st_) + st_->enter (L""); + + do + { + e = ns.find (L"::", b); + + String name (ns, b, e == ns.npos ? e : e - b); + + if (!name.empty ()) + { + ctx_.os << "namespace " << name << "{"; + + if (st_) + st_->enter (name); + } + + + b = e; + + if (b == ns.npos) + break; + + b += 2; + + } while (true); + } + + Void Namespace:: + post (Type& n) + { + String ns (ctx_.ns_name (n)); + + String::size_type b (0), e; + + do + { + e = ns.find (L"::", b); + + String name (ns, b, e == ns.npos ? e : e - b); + + if (!name.empty ()) + { + ctx_.os << "}"; + + if (st_) + st_->leave (); + } + + + b = e; + + if (b == ns.npos) + break; + + b += 2; + + } + while (true); + + if (st_) + st_->leave (); + } + + // Include + // + Void Includes:: + traverse (SemanticGraph::Path const& path) + { + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + NarrowString path_str; + try + { + path_str = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + path_str = path.native_file_string (); + } + + String hxx_path (expr_.merge (path_str)); + + ctx_.os << "#include " << ctx_.process_include_path (hxx_path) << endl + << endl; + } +} diff --git a/xsde/cxx/elements.hxx b/xsde/cxx/elements.hxx new file mode 100644 index 0000000..3125cd6 --- /dev/null +++ b/xsde/cxx/elements.hxx @@ -0,0 +1,599 @@ +// file : xsde/cxx/elements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_ELEMENTS_HXX +#define CXX_ELEMENTS_HXX + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +namespace CXX +{ + using std::endl; + typedef WideString String; + + + // On some platforms std::toupper can be something other than a + // function with C++ linkage. + // + wchar_t + upcase (wchar_t c); + + + // Exceptions. + // + + struct NoNamespaceMapping + { + NoNamespaceMapping (SemanticGraph::Path const& file, + UnsignedLong line, + UnsignedLong column, + String const& ns) + : file_ (file), + line_ (line), + column_ (column), + ns_ (ns) + { + } + + SemanticGraph::Path const& + file () const + { + return file_; + } + + UnsignedLong + line () const + { + return line_; + } + + UnsignedLong + column () const + { + return column_; + } + + String const& + ns () const + { + return ns_; + } + + private: + SemanticGraph::Path file_; + UnsignedLong line_; + UnsignedLong column_; + String ns_; + }; + + struct InvalidNamespaceMapping + { + InvalidNamespaceMapping (String const& mapping, + String const& reason) + : mapping_ (mapping), reason_ (reason) + { + } + + String const& + mapping () const + { + return mapping_; + } + + String const& + reason () const + { + return reason_; + } + + private: + String mapping_; + String reason_; + }; + + + // + // + class Context + { + public: + typedef BackendElements::Regex::Pattern RegexPat; + typedef BackendElements::Regex::Expression Regex; + typedef Cult::Containers::Vector RegexMapping; + typedef Cult::Containers::Map MapMapping; + typedef Cult::Containers::Map MappingCache; + + typedef Cult::Containers::Map ReservedNameMap; + + public: + Context (std::wostream& o, + SemanticGraph::Schema& root, + Char const* name_key, + NarrowString const& char_type__, + Boolean include_with_brackets__, + NarrowString const& include_prefix__, + NarrowString const& esymbol, + Containers::Vector const& nsm, + Containers::Vector const& nsr, + Boolean trace_namespace_regex_, + Containers::Vector const& include_regex, + Boolean trace_include_regex_, + Boolean inline_, + Containers::Vector const& reserved_name); + + protected: + Context (Context& c) + : os (c.os), + schema_root (c.schema_root), + ename_key (c.ename_key), + char_type (c.char_type), + L (c.L), + string_type (c.string_type), + include_with_brackets (c.include_with_brackets), + include_prefix (c.include_prefix), + type_exp (c.type_exp), + inst_exp (c.inst_exp), + inl (c.inl), + ns_mapping_cache (c.ns_mapping_cache), + xs_ns_ (c.xs_ns_), + cxx_id_expr (c.cxx_id_expr), + trace_namespace_regex (c.trace_namespace_regex), + nsr_mapping (c.nsr_mapping), + nsm_mapping (c.nsm_mapping), + include_mapping (c.include_mapping), + trace_include_regex (c.trace_include_regex), + reserved_name_map (c.reserved_name_map) + { + } + + Context (Context& c, std::wostream& o) + : os (o), + schema_root (c.schema_root), + ename_key (c.ename_key), + char_type (c.char_type), + L (c.L), + string_type (c.string_type), + include_with_brackets (c.include_with_brackets), + include_prefix (c.include_prefix), + type_exp (c.type_exp), + inst_exp (c.inst_exp), + inl (c.inl), + ns_mapping_cache (c.ns_mapping_cache), + xs_ns_ (c.xs_ns_), + cxx_id_expr (c.cxx_id_expr), + trace_namespace_regex (c.trace_namespace_regex), + nsr_mapping (c.nsr_mapping), + nsm_mapping (c.nsm_mapping), + include_mapping (c.include_mapping), + trace_include_regex (c.trace_include_regex), + reserved_name_map (c.reserved_name_map) + { + } + + public: + static String + unclash (String const& name, String const& new_name) + { + return name == new_name ? (new_name + L'_') : new_name; + } + + public: + // Return UTF-32 character starting at this position. Position is + // advanced by 1 if this Unicode character takes more than one + // underlying character. + // + static UnsignedLong + unicode_char (String const& str, Size& pos); + + static UnsignedLong + unicode_char (WideChar const*& p); + + // Escape C++ keywords and illegal characters. + // + String + escape (String const&) const; + + // Create a string literal so that it can be used in C++ source + // code. It includes "". + // + String + strlit (String const&); + + // Escape the string so that it can be used in C++ comment. + // + String + comment (String const&); + + // Translate XML namespace name to a C++ identifier. + // + String + ns_name (SemanticGraph::Namespace&) const; + + // XML Schema namespace. + // + SemanticGraph::Namespace& + xs_ns (); + + // C++ namespace for XML Schema. + // + String + xs_ns_name (); + + // + // + SemanticGraph::Namespace& + namespace_ (SemanticGraph::Nameable& n); + + // Original XML namespace name. + // + String + xml_ns_name (SemanticGraph::Nameable& ns); + + + // Fully-qualified C++ name. + // + String + fq_name (SemanticGraph::Nameable& n, Char const* name_key = 0) const; + + public: + static SemanticGraph::Type& + ultimate_base (SemanticGraph::Complex&); + + public: + String + process_include_path (String const&) const; + + public: + static Boolean + anonymous (SemanticGraph::Type& t) + { + return t.context ().count ("anonymous"); + } + + // Restriction correspondance. + // + public: + static SemanticGraph::Element* + correspondent (SemanticGraph::Element& r); + + static SemanticGraph::Any* + correspondent (SemanticGraph::Any& r); + + static SemanticGraph::Compositor* + correspondent (SemanticGraph::Compositor& r); + + public: + // Get escaped name. + // + String const& + ename (SemanticGraph::Nameable const& n) const + { + return n.context ().get (ename_key.c_str ()); + } + + public: + std::wostream& os; + SemanticGraph::Schema& schema_root; + + NarrowString const& ename_key; + + String& char_type; + String& L; // string literal prefix + String& string_type; + + Boolean& include_with_brackets; + String& include_prefix; + + String& type_exp; + String& inst_exp; + String& inl; + + public: + MappingCache& ns_mapping_cache; + + private: + SemanticGraph::Namespace* xs_ns_; + + NarrowString const ename_key_; + + String char_type_; + String L_; + String string_type_; + + Boolean include_with_brackets_; + String include_prefix_; + + String type_exp_; + String inst_exp_; + String inl_; + + private: + RegexPat const cxx_id_expr_; + RegexPat const& cxx_id_expr; + Boolean trace_namespace_regex; + RegexMapping nsr_mapping_; + MapMapping nsm_mapping_; + RegexMapping const& nsr_mapping; + MapMapping const& nsm_mapping; + MappingCache ns_mapping_cache_; + + RegexMapping include_mapping_; + RegexMapping const& include_mapping; + Boolean trace_include_regex; + + ReservedNameMap const& reserved_name_map; + ReservedNameMap reserved_name_map_; + }; + + inline UnsignedLong Context:: + unicode_char (String const& str, Size& pos) + { + if (sizeof (WideChar) == 4) + { + return str[pos]; + } + else if (sizeof (WideChar) == 2) + { + WideChar x (str[pos]); + + if (x < 0xD800 || x > 0xDBFF) + return x; + else + return ((x - 0xD800) << 10) + (str[++pos] - 0xDC00) + 0x10000; + } + else + return 0; + } + + inline UnsignedLong Context:: + unicode_char (WideChar const*& p) + { + if (sizeof (WideChar) == 4) + { + return *p; + } + else if (sizeof (WideChar) == 2) + { + WideChar x (*p); + + if (x < 0xD800 || x > 0xDBFF) + return x; + else + return ((x - 0xD800) << 10) + (*(++p) - 0xDC00) + 0x10000; + } + else + return 0; + } + + // Usual namespace mapping. + // + struct Namespace : Traversal::Namespace + { + struct ScopeTracker + { + virtual + ~ScopeTracker () {} + + virtual Void + enter (String const&) = 0; + + virtual Void + leave () = 0; + }; + + + Namespace (Context& c, ScopeTracker* st = 0) + : ctx_ (c), st_ (st) + { + } + + Namespace (Context& c, ScopeTracker& st) + : ctx_ (c), st_ (&st) + { + } + + virtual Void + pre (Type&); + + virtual Void + post (Type&); + + private: + Context& ctx_; + ScopeTracker* st_; + }; + + + // + // + template + struct Has : X + { + Has (Boolean& result) + : result_ (result) + { + } + + virtual Void + traverse (typename X::Type&) + { + result_ = true; + } + + private: + Boolean& result_; + }; + + // Checks if scope 'Y' names any of 'X' + // + template + Boolean + has (Y& y) + { + using SemanticGraph::Scope; + + Boolean result (false); + Has t (result); + + for (Scope::NamesIterator i (y.names_begin ()), e (y.names_end ()); + !result && i != e; ++i) + t.dispatch (i->named ()); + + return result; + } + + // Checks if the compositor has any particle of 'X' + // + template + Boolean + has_particle (SemanticGraph::Compositor& y) + { + using SemanticGraph::Compositor; + + Boolean result (false); + Has t (result); + + for (Compositor::ContainsIterator i (y.contains_begin ()), + e (y.contains_end ()); !result && i != e; ++i) + { + SemanticGraph::Particle& p (i->particle ()); + + t.dispatch (p); + + if (!result && p.is_a ()) + result = has_particle (dynamic_cast (p)); + } + + return result; + } + + // Specialization for Complex + // + template + Boolean + has_particle (SemanticGraph::Complex& c) + { + return c.contains_compositor_p () && + has_particle (c.contains_compositor ().compositor ()); + } + + // Fundamental type mapping helper. + // + struct Fundamental : Traversal::Fundamental::Type, + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef + { + virtual Void + fundamental_type (SemanticGraph::Fundamental::Type& t) = 0; + + virtual Void + fundamental_template (SemanticGraph::Fundamental::Type& t) = 0; + + virtual Void + traverse (SemanticGraph::Fundamental::Type& t) + { + fundamental_type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + fundamental_template (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + fundamental_template (t); + } + }; + + // + // + struct Includes : Traversal::Imports, + Traversal::Includes + { + typedef BackendElements::Regex::Expression Regex; + + Includes (Context& c, Regex const& expr) + : ctx_ (c), expr_ (expr) + { + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + traverse (i.path ()); + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + traverse (i.path ()); + } + + Void + traverse (SemanticGraph::Path const&); + + private: + Context& ctx_; + Regex expr_; + }; +} + +#endif // CXX_TREE_ELEMENTS_HXX diff --git a/xsde/cxx/hybrid/cli.hxx b/xsde/cxx/hybrid/cli.hxx new file mode 100644 index 0000000..57aa3d4 --- /dev/null +++ b/xsde/cxx/hybrid/cli.hxx @@ -0,0 +1,188 @@ +// file : xsde/cxx/hybrid/cli.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_CLI_HXX +#define CXX_HYBRID_CLI_HXX + +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace CLI + { + using namespace Cult::Types; + + typedef Char const Key[]; + + extern Key no_stl; + extern Key no_iostream; + extern Key no_exceptions; + extern Key no_long_long; + extern Key generate_parser; + extern Key generate_serializer; + extern Key generate_aggregate; + extern Key suppress_validation; + extern Key suppress_parser_val; + extern Key suppress_serializer_val; + extern Key generate_inline; + extern Key generate_forward; + extern Key generate_xml_schema; + extern Key extern_xml_schema; + extern Key suppress_reset; + extern Key reuse_style_mixin; + extern Key custom_data; + extern Key custom_parser; + extern Key custom_serializer; + extern Key root_element_first; + extern Key root_element_last; + extern Key root_element_all; + extern Key root_element_none; + extern Key root_element; + extern Key root_type; + extern Key output_dir; + extern Key pskel_type_suffix; + extern Key sskel_type_suffix; + extern Key pskel_file_suffix; + extern Key sskel_file_suffix; + extern Key pimpl_type_suffix; + extern Key simpl_type_suffix; + extern Key pimpl_file_suffix; + extern Key simpl_file_suffix; + extern Key paggr_type_suffix; + extern Key saggr_type_suffix; + extern Key namespace_map; + extern Key namespace_regex; + extern Key namespace_regex_trace; + extern Key reserved_name; + extern Key include_with_brackets; + extern Key include_prefix; + extern Key include_regex; + extern Key include_regex_trace; + extern Key guard_prefix; + extern Key hxx_suffix; + extern Key ixx_suffix; + extern Key cxx_suffix; + extern Key fwd_suffix; + extern Key hxx_regex; + extern Key ixx_regex; + extern Key cxx_regex; + extern Key fwd_regex; + extern Key hxx_prologue; + extern Key ixx_prologue; + extern Key cxx_prologue; + extern Key fwd_prologue; + extern Key prologue; + extern Key hxx_epilogue; + extern Key ixx_epilogue; + extern Key cxx_epilogue; + extern Key fwd_epilogue; + extern Key epilogue; + extern Key hxx_prologue_file; + extern Key ixx_prologue_file; + extern Key cxx_prologue_file; + extern Key fwd_prologue_file; + extern Key prologue_file; + extern Key hxx_epilogue_file; + extern Key ixx_epilogue_file; + extern Key cxx_epilogue_file; + extern Key fwd_epilogue_file; + extern Key epilogue_file; + extern Key show_anonymous; + extern Key show_sloc; + extern Key proprietary_license; + + typedef Cult::CLI::Options< + no_stl, Boolean, + no_iostream, Boolean, + no_exceptions, Boolean, + no_long_long, Boolean, + generate_parser, Boolean, + generate_serializer, Boolean, + generate_aggregate, Boolean, + suppress_validation, Boolean, + suppress_parser_val, Boolean, + suppress_serializer_val, Boolean, + generate_inline, Boolean, + generate_forward, Boolean, + generate_xml_schema, Boolean, + extern_xml_schema, NarrowString, + suppress_reset, Boolean, + reuse_style_mixin, Boolean, + custom_data, Cult::Containers::Vector, + custom_parser, Cult::Containers::Vector, + custom_serializer, Cult::Containers::Vector, + root_element_first, Boolean, + root_element_last, Boolean, + root_element_all, Boolean, + root_element_none, Boolean, + root_element, Cult::Containers::Vector, + root_type, Cult::Containers::Vector, + output_dir, NarrowString, + pskel_type_suffix, NarrowString, + sskel_type_suffix, NarrowString, + pskel_file_suffix, NarrowString, + sskel_file_suffix, NarrowString, + pimpl_type_suffix, NarrowString, + simpl_type_suffix, NarrowString, + pimpl_file_suffix, NarrowString, + simpl_file_suffix, NarrowString, + paggr_type_suffix, NarrowString, + saggr_type_suffix, NarrowString, + namespace_map, Cult::Containers::Vector, + namespace_regex, Cult::Containers::Vector, + namespace_regex_trace, Boolean, + reserved_name, Cult::Containers::Vector, + include_with_brackets, Boolean, + include_prefix, NarrowString, + include_regex, Cult::Containers::Vector, + include_regex_trace, Boolean, + guard_prefix, NarrowString, + hxx_suffix, NarrowString, + ixx_suffix, NarrowString, + cxx_suffix, NarrowString, + fwd_suffix, NarrowString, + hxx_regex, Cult::Containers::Vector, + ixx_regex, Cult::Containers::Vector, + cxx_regex, Cult::Containers::Vector, + fwd_regex, NarrowString, + hxx_prologue, Cult::Containers::Vector, + ixx_prologue, Cult::Containers::Vector, + cxx_prologue, Cult::Containers::Vector, + fwd_prologue, Cult::Containers::Vector, + prologue, Cult::Containers::Vector, + hxx_epilogue, Cult::Containers::Vector, + ixx_epilogue, Cult::Containers::Vector, + cxx_epilogue, Cult::Containers::Vector, + fwd_epilogue, Cult::Containers::Vector, + epilogue, Cult::Containers::Vector, + hxx_prologue_file, Cult::Containers::Vector, + ixx_prologue_file, Cult::Containers::Vector, + cxx_prologue_file, Cult::Containers::Vector, + fwd_prologue_file, NarrowString, + prologue_file, Cult::Containers::Vector, + hxx_epilogue_file, Cult::Containers::Vector, + ixx_epilogue_file, Cult::Containers::Vector, + cxx_epilogue_file, Cult::Containers::Vector, + fwd_epilogue_file, NarrowString, + epilogue_file, Cult::Containers::Vector, + show_anonymous, Boolean, + show_sloc, Boolean, + proprietary_license, Boolean + + > Options; + + struct OptionsSpec: Cult::CLI::OptionsSpec {}; + } + } +} + +#endif // CXX_HYBRID_CLI_HXX diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx new file mode 100644 index 0000000..454d0c3 --- /dev/null +++ b/xsde/cxx/hybrid/elements.cxx @@ -0,0 +1,493 @@ +// file : xsde/cxx/hybrid/elements.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace CXX +{ + namespace Hybrid + { + Context:: + Context (std::wostream& o, + SemanticGraph::Schema& root, + CLI::Options const& ops, + Regex const* fe, + Regex const* he, + Regex const* ie) + : CXX::Context (o, + root, + "name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + options (ops), + exceptions (!ops.value ()), + stl (!ops.value ()), + poly_code (false), + poly_runtime (false), + reset (!ops.value ()), + mixin (ops.value ()), + tiein (!mixin), + fwd_expr (fe), + hxx_expr (he), + ixx_expr (ie), + ns_stack (ns_stack_) + { + String xs_ns (xs_ns_name ()); + + string_type = L"::xsde::cxx::ro_string"; + } + + // Parser + // + String const& Context:: + pret_type (SemanticGraph::Type& t) + { + return t.context ().get ("p:ret-type"); + } + + String const& Context:: + parg_type (SemanticGraph::Type& t) + { + return t.context ().get ("p:arg-type"); + } + + String const& Context:: + post_name (SemanticGraph::Type& t) + { + return t.context ().get ("p:post"); + } + + static String pre_impl ("pre_impl"); + + String const& Context:: + pre_impl_name (SemanticGraph::Type&) + { + // @@ Currently not assigned because we don't assign names to + // types in included/imported schemas which makes assigning + // this name correctly impossible. + // + return pre_impl; + // return t.context ().get ("ppre-impl"); + } + + String const& Context:: + epname (SemanticGraph::Particle& p) + { + return p.context ().get ("p:name"); + } + + String const& Context:: + epname (SemanticGraph::Attribute& a) + { + return a.context ().get ("p:name"); + } + + String const& Context:: + epimpl (SemanticGraph::Type& t) + { + // Use p:impl instead of pimpl because C++/Parser assigns impl + // names to the built-in types. + // + return t.context ().get ("p:impl"); + } + + String const& Context:: + epimpl_custom (SemanticGraph::Type& t) + { + SemanticGraph::Context& c (t.context ()); + + if (!c.count ("p:impl-base")) + return c.get ("p:impl"); + else + return c.get ("p:impl-base"); + } + + String const& Context:: + epstate (SemanticGraph::Type& t) + { + return t.context ().get ("pstate"); + } + + String const& Context:: + epstate_type (SemanticGraph::Type& t) + { + return t.context ().get ("pstate-type"); + } + + String const& Context:: + epstate_member (SemanticGraph::Type& t) + { + return t.context ().get ("pstate-member"); + } + + String const& Context:: + epstate_base (SemanticGraph::Type& t) + { + return t.context ().get ("pstate-base"); + } + + String const& Context:: + epstate_member (SemanticGraph::Compositor& c) + { + return c.context ().get ("pstate-member"); + } + + String const& Context:: + epskel (SemanticGraph::Type& t) + { + return t.context ().get ("p:name"); + } + + String const& Context:: + eppresent (SemanticGraph::Compositor& c) + { + return c.context ().get ("p:present"); + } + + String const& Context:: + epnext (SemanticGraph::Compositor& c) + { + return c.context ().get ("p:next"); + } + + String const& Context:: + eptag (SemanticGraph::Particle& p) + { + return p.context ().get ("p:tag"); + } + + String const& Context:: + eparm (SemanticGraph::Choice& c) + { + return c.context ().get ("p:arm"); + } + + String const& Context:: + eparm_tag (SemanticGraph::Choice& c) + { + return c.context ().get ("p:arm-tag"); + } + + // Serializer + // + String const& Context:: + sret_type (SemanticGraph::Type& t) + { + return t.context ().get ("s:ret-type"); + } + + String const& Context:: + sarg_type (SemanticGraph::Type& t) + { + return t.context ().get ("s:arg-type"); + } + + String const& Context:: + esname (SemanticGraph::Particle& p) + { + return p.context ().get ("s:name"); + } + + String const& Context:: + esname (SemanticGraph::Attribute& a) + { + return a.context ().get ("s:name"); + } + + String const& Context:: + esimpl (SemanticGraph::Type& t) + { + // Use s:impl instead of simpl because C++/Serializer assigns impl + // names to the built-in types. + // + return t.context ().get ("s:impl"); + } + + String const& Context:: + esimpl_custom (SemanticGraph::Type& t) + { + SemanticGraph::Context& c (t.context ()); + + if (!c.count ("s:impl-base")) + return c.get ("s:impl"); + else + return c.get ("s:impl-base"); + } + + String const& Context:: + esstate (SemanticGraph::Type& t) + { + return t.context ().get ("sstate"); + } + + String const& Context:: + esstate_type (SemanticGraph::Type& t) + { + return t.context ().get ("sstate-type"); + } + + String const& Context:: + esstate_member (SemanticGraph::Type& t) + { + return t.context ().get ("sstate-member"); + } + + String const& Context:: + esstate_member (SemanticGraph::Particle& p) + { + return p.context ().get ("sstate-member"); + } + + String const& Context:: + esstate_member_end (SemanticGraph::Particle& p) + { + return p.context ().get ("sstate-member-end"); + } + + String const& Context:: + esskel (SemanticGraph::Type& t) + { + return t.context ().get ("s:name"); + } + + String const& Context:: + espresent (SemanticGraph::Particle& p) + { + return p.context ().get ("s:present"); + } + + String const& Context:: + espresent (SemanticGraph::Attribute& a) + { + return a.context ().get ("s:present"); + } + + String const& Context:: + esnext (SemanticGraph::Particle& p) + { + return p.context ().get ("s:next"); + } + + String const& Context:: + estag (SemanticGraph::Particle& p) + { + return p.context ().get ("s:tag"); + } + + String const& Context:: + esarm (SemanticGraph::Choice& c) + { + return c.context ().get ("s:arm"); + } + + String const& Context:: + esarm_tag (SemanticGraph::Choice& c) + { + return c.context ().get ("s:arm-tag"); + } + + // + // + String Context:: + scope (SemanticGraph::Compositor& c, Boolean fq) const + { + using namespace SemanticGraph; + + String r; + + Compositor* p (&c); + + while (!p->contained_compositor_p ()) + { + p = &p->contained_particle ().compositor (); + + if (!p->context ().count ("type")) + continue; // See-through compositor. + + if (!r) + r = etype (*p); + else + { + String tmp; + tmp.swap (r); + r = etype (*p); + r += L"::"; + r += tmp; + } + } + + Complex& t ( + dynamic_cast ( + p->contained_compositor ().container ())); + + if (!r) + r = fq ? fq_name (t) : ename (t); + else + { + String tmp; + tmp.swap (r); + r = fq ? fq_name (t) : ename (t); + r += L"::"; + r += tmp; + } + + return r; + } + + String Context:: + scope (SemanticGraph::Element& e, Boolean fq) const + { + SemanticGraph::Compositor& c (e.contained_particle ().compositor ()); + + if (!c.context ().count ("type")) + return scope (c, fq); + else + return scope (c, fq) + L"::" + etype (c); + } + + String Context:: + scope (SemanticGraph::Attribute& a, Boolean fq) const + { + using SemanticGraph::Complex; + + Complex& t (dynamic_cast (a.scope ())); + return fq ? fq_name (t) : ename (t); + } + + Void Context:: + close_ns () + { + for (Size i (0), n (ns_stack.size () - 1); i < n; ++i) + os << "}"; + } + + Void Context:: + open_ns () + { + for (NamespaceStack::Iterator i (ns_stack.begin () + 1); + i != ns_stack.end (); + ++i) + { + os << "namespace " << *i + << "{"; + } + } + + // Namespace + // + Namespace:: + Namespace (Context& c, Boolean track_scope) + : CXX::Namespace (c, track_scope ? this : 0), ctx_ (c) + { + } + + Void Namespace:: + enter (String const& name) + { + ctx_.ns_stack.push_back (name); + } + + Void Namespace:: + leave () + { + ctx_.ns_stack.pop_back (); + } + + // Includes + // + Void TypeForward:: + traverse (SemanticGraph::Type& t) + { + os << "class " << ename (t) << ";"; + } + + Void Includes:: + traverse_ (SemanticGraph::Uses& u) + { + // Support for weak (forward) inclusion used in the file-per-type + // compilation model. + // + Type t (type_); + Boolean weak (u.context ().count ("weak")); + + if (weak && (t == header || t == impl_header)) + { + // Generate forward declarations. We don't really need them + // in the impl files. + // + if (t == impl_header) + return; + + if (forward_) + t = forward; + else + { + schema_.dispatch (u.schema ()); + return; + } + } + + if (t == source && !weak) + return; + + SemanticGraph::Path path (u.path ()); + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + NarrowString path_str; + try + { + path_str = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + path_str = path.native_file_string (); + } + + String inc_path; + + switch (t) + { + case forward: + { + inc_path = ctx_.fwd_expr->merge (path_str); + break; + } + case header: + case impl_header: + case source: + { + inc_path = ctx_.hxx_expr->merge (path_str); + break; + } + case inline_: + { + if (weak) + { + inc_path = ctx_.hxx_expr->merge (path_str); + ctx_.os << "#include " << ctx_.process_include_path (inc_path) + << endl; + } + + inc_path = ctx_.ixx_expr->merge (path_str); + break; + } + } + + ctx_.os << "#include " << ctx_.process_include_path (inc_path) << endl + << endl; + } + } +} diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx new file mode 100644 index 0000000..816c80f --- /dev/null +++ b/xsde/cxx/hybrid/elements.hxx @@ -0,0 +1,1880 @@ +// file : xsde/cxx/hybrid/elements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_ELEMENTS_HXX +#define CXX_HYBRID_ELEMENTS_HXX + +#include + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + // + // + class Context: public CXX::Context + { + public: + typedef BackendElements::Regex::Expression Regex; + + public: + Context (std::wostream&, + SemanticGraph::Schema&, + CLI::Options const&, + Regex const* fwd_expr, + Regex const* hxx_expr, + Regex const* ixx_expr); + + protected: + Context (Context& c) + : CXX::Context (c), + options (c.options), + exceptions (c.exceptions), + stl (c.stl), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + fwd_expr (c.fwd_expr), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + ns_stack (c.ns_stack) + { + } + + Context (Context& c, std::wostream& o) + : CXX::Context (c, o), + options (c.options), + exceptions (c.exceptions), + stl (c.stl), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + fwd_expr (c.fwd_expr), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + ns_stack (c.ns_stack) + { + } + + public: + using CXX::Context::ename; + + static String const& + ename (SemanticGraph::Compositor& c) + { + return c.context ().get ("name"); + } + + static String const& + etype (SemanticGraph::Compositor& c) + { + return c.context ().get ("type"); + } + + static String const& + emember (SemanticGraph::Particle& p) + { + return p.context ().get ("member"); + } + + static String const& + emember (SemanticGraph::Attribute& a) + { + return a.context ().get ("member"); + } + + // Optional. + // + static String const& + epresent (SemanticGraph::Particle& p) + { + return p.context ().get ("present"); + } + + static String const& + epresent (SemanticGraph::Attribute& a) + { + return a.context ().get ("present"); + } + + static String const& + epresent_member (SemanticGraph::Particle& p) + { + return p.context ().get ("present-member"); + } + + static String const& + epresent_member (SemanticGraph::Attribute& a) + { + return a.context ().get ("present-member"); + } + + // Sequence. + // + static String const& + esequence (SemanticGraph::Element& e) + { + return e.context ().get ("sequence"); + } + + static String const& + esequence (SemanticGraph::Compositor& c) + { + return c.context ().get ("sequence"); + } + + static String const& + eiterator (SemanticGraph::Element& e) + { + return e.context ().get ("iterator"); + } + + static String const& + eiterator (SemanticGraph::Compositor& c) + { + return c.context ().get ("iterator"); + } + + static String const& + econst_iterator (SemanticGraph::Element& e) + { + return e.context ().get ("const-iterator"); + } + + static String const& + econst_iterator (SemanticGraph::Compositor& c) + { + return c.context ().get ("const-iterator"); + } + + // Choice. + // + static String const& + etag (SemanticGraph::Particle& p) + { + return p.context ().get ("tag"); + } + + static String const& + earm (SemanticGraph::Choice& c) + { + return c.context ().get ("arm"); + } + + static String const& + earm_tag (SemanticGraph::Choice& c) + { + return c.context ().get ("arm-tag"); + } + + static UnsignedLong const& + arm_tag_count (SemanticGraph::Choice& c) + { + return c.context ().get ("arm-tag-count"); + } + + static String const& + earm_member (SemanticGraph::Choice& c) + { + return c.context ().get ("arm-member"); + } + + // Custom data. + // + static String const& + ecd_name (SemanticGraph::Type& t) + { + return t.context ().get ("cd-name"); + } + + static String const& + ecd_name (SemanticGraph::Compositor& c) + { + return c.context ().get ("cd-name"); + } + + static String const& + ecd_member (SemanticGraph::Type& t) + { + return t.context ().get ("cd-member"); + } + + static String const& + ecd_member (SemanticGraph::Compositor& c) + { + return c.context ().get ("cd-member"); + } + + static String const& + ecd_sequence (SemanticGraph::Type& t) + { + return t.context ().get ("cd-sequence"); + } + + static String const& + ecd_sequence (SemanticGraph::Compositor& c) + { + return c.context ().get ("cd-sequence"); + } + + static String const& + ecd_iterator (SemanticGraph::Type& t) + { + return t.context ().get ("cd-iterator"); + } + + static String const& + ecd_iterator (SemanticGraph::Compositor& c) + { + return c.context ().get ("cd-iterator"); + } + + static String const& + ecd_const_iterator (SemanticGraph::Type& t) + { + return t.context ().get ("cd-const-iterator"); + } + + static String const& + ecd_const_iterator (SemanticGraph::Compositor& c) + { + return c.context ().get ("cd-const-iterator"); + } + + // Parser + // + public: + static String const& + pret_type (SemanticGraph::Type&); + + static String const& + parg_type (SemanticGraph::Type&); + + static String const& + post_name (SemanticGraph::Type&); + + static String const& + pre_impl_name (SemanticGraph::Type&); + + // Names + // + static String const& + epname (SemanticGraph::Particle&); + + static String const& + epname (SemanticGraph::Attribute&); + + static String const& + epimpl (SemanticGraph::Type&); + + static String const& + epimpl_custom (SemanticGraph::Type&); + + static String const& + epskel (SemanticGraph::Type&); + + // Optional. + // + static String const& + eppresent (SemanticGraph::Compositor&); + + // Sequence. + // + static String const& + epnext (SemanticGraph::Compositor&); + + // Choice. + // + static String const& + eptag (SemanticGraph::Particle&); + + static String const& + eparm (SemanticGraph::Choice&); + + static String const& + eparm_tag (SemanticGraph::Choice&); + + // State + // + static String const& + epstate (SemanticGraph::Type&); + + static String const& + epstate_type (SemanticGraph::Type&); + + static String const& + epstate_base (SemanticGraph::Type&); + + static String const& + epstate_member (SemanticGraph::Type&); + + static String const& + epstate_member (SemanticGraph::Compositor&); + + // Serializer + // + public: + static String const& + sret_type (SemanticGraph::Type&); + + static String const& + sarg_type (SemanticGraph::Type&); + + // Names + // + static String const& + esname (SemanticGraph::Particle&); + + static String const& + esname (SemanticGraph::Attribute&); + + static String const& + esimpl (SemanticGraph::Type&); + + static String const& + esimpl_custom (SemanticGraph::Type&); + + static String const& + esskel (SemanticGraph::Type&); + + // Optional. + // + static String const& + espresent (SemanticGraph::Particle&); + + static String const& + espresent (SemanticGraph::Attribute&); + + // Sequence. + // + static String const& + esnext (SemanticGraph::Particle&); + + // Choice. + // + static String const& + estag (SemanticGraph::Particle&); + + static String const& + esarm (SemanticGraph::Choice&); + + static String const& + esarm_tag (SemanticGraph::Choice&); + + // State + // + static String const& + esstate (SemanticGraph::Type&); + + static String const& + esstate_type (SemanticGraph::Type&); + + static String const& + esstate_member (SemanticGraph::Type&); + + static String const& + esstate_member (SemanticGraph::Particle&); + + static String const& + esstate_member_end (SemanticGraph::Particle&); + + public: + String + scope (SemanticGraph::Compositor& c) const + { + return scope (c, false); + } + + String + scope (SemanticGraph::Element& e) const + { + return scope (e, false); + } + + String + scope (SemanticGraph::Attribute& a) const + { + return scope (a, false); + } + + String + fq_scope (SemanticGraph::Compositor& c) const + { + return scope (c, true); + } + + String + fq_scope (SemanticGraph::Element& e) const + { + return scope (e, true); + } + + String + fq_scope (SemanticGraph::Attribute& a) const + { + return scope (a, true); + } + + private: + String + scope (SemanticGraph::Compositor&, Boolean fq) const; + + String + scope (SemanticGraph::Element&, Boolean fq) const; + + String + scope (SemanticGraph::Attribute&, Boolean fq) const; + + public: + Boolean + restriction_p (SemanticGraph::Complex& c) const + { + if (c.inherits_p () && + c.inherits ().is_a ()) + { + // Restriction of anyType is a special case. + // + return !c.inherits ().base ().is_a (); + } + + return false; + } + + public: + static Boolean + fixed_length (SemanticGraph::Type& t) + { + return t.context ().get ("fixed"); + } + + static Boolean + fixed_length (SemanticGraph::Compositor& c) + { + return c.context ().get ("fixed"); + } + + public: + Void + close_ns (); + + Void + open_ns (); + + public: + typedef + Cult::Containers::Deque + NamespaceStack; + + public: + CLI::Options const& options; + + Boolean exceptions; + Boolean stl; + Boolean poly_code; + Boolean poly_runtime; + Boolean reset; + Boolean mixin; + Boolean tiein; + + Regex const* fwd_expr; + Regex const* hxx_expr; + Regex const* ixx_expr; + + NamespaceStack& ns_stack; + + private: + NamespaceStack ns_stack_; + }; + + // + // + struct Namespace: CXX::Namespace, CXX::Namespace::ScopeTracker + { + Namespace (Context&, Boolean track_scope = false); + + protected: + virtual Void + enter (String const& name); + + virtual Void + leave (); + + protected: + Context& ctx_; + }; + + // + // + struct FundamentalType: Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal + + { + FundamentalType (Boolean& result) + : r_ (result) + { + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger&) + { + r_ = true; + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean&) + { + r_ = true; + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal&) + { + r_ = true; + } + + private: + Boolean& r_; + }; + + // + // + struct StringType: Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::AnyURI, + Traversal::Fundamental::Entity + { + StringType (Boolean& result) + : r_ (result) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Id&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + r_ = true; + } + + private: + Boolean& r_; + }; + + + // + // + struct TypeName : Traversal::Type, + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + enum Use + { + base, + ro_ret, + ret, + arg, + var, + seq + }; + + TypeName (Context& c, Use use) + : Context (c), use_ (use) + { + if (use == base) + xs_ns_ = xs_ns_name (); + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + type (t); + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + type (t); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean&) + { + if (use_ != base) + fund_type ("bool"); + else + os << xs_ns_ << "::boolean_base"; + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte&) + { + if (use_ != base) + fund_type ("signed char"); + else + os << xs_ns_ << "::byte_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte&) + { + if (use_ != base) + fund_type ("unsigned char"); + else + os << xs_ns_ << "::unsigned_byte_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short&) + { + if (use_ != base) + fund_type ("short"); + else + os << xs_ns_ << "::short_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort&) + { + if (use_ != base) + fund_type ("unsigned short"); + else + os << xs_ns_ << "::unsigned_short_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int&) + { + if (use_ != base) + fund_type ("int"); + else + os << xs_ns_ << "::int_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt&) + { + if (use_ != base) + fund_type ("unsigned int"); + else + os << xs_ns_ << "::unsigned_int_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long&) + { + if (use_ != base) + { + if (options.value ()) + fund_type ("long"); + else + fund_type ("long long"); + } + else + os << xs_ns_ << "::long_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong&) + { + if (use_ != base) + { + if (options.value ()) + fund_type ("unsigned long"); + else + fund_type ("unsigned long long"); + } + else + os << xs_ns_ << "::unsigned_long_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer&) + { + if (use_ != base) + fund_type ("long"); + else + os << xs_ns_ << "::integer_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger&) + { + if (use_ != base) + fund_type ("long"); + else + os << xs_ns_ << "::non_positive_integer_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger&) + { + if (use_ != base) + fund_type ("unsigned long"); + else + os << xs_ns_ << "::non_negative_integer_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger&) + { + if (use_ != base) + fund_type ("unsigned long"); + else + os << xs_ns_ << "::positive_integer_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger&) + { + if (use_ != base) + fund_type ("long"); + else + os << xs_ns_ << "::negative_integer_base"; + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float&) + { + if (use_ != base) + fund_type ("float"); + else + os << xs_ns_ << "::float_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double&) + { + if (use_ != base) + fund_type ("double"); + else + os << xs_ns_ << "::double_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal&) + { + if (use_ != base) + fund_type ("double"); + else + os << xs_ns_ << "::decimal_base"; + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::string_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::normalized_string_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::token_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::nmtoken_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::name_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::ncname_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::language_base"; + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + type (t); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::id_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::idref_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + type (t); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::uri_base"; + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + type (t); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + type (t); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + if (stl || use_ != base) + string_type (); + else + os << xs_ns_ << "::entity_base"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + type (t); + } + + private: + Void + type (SemanticGraph::Type& t) + { + String fq (fq_name (t)); + + switch (use_) + { + case base: + { + os << fq; + break; + } + case ro_ret: + { + os << "const " << fq << "&"; + break; + } + case ret: + { + os << fq << "&"; + break; + } + case arg: + { + if (fixed_length (t)) + os << "const " << fq << "&"; + else + os << fq << "*"; + + break; + } + case var: + { + if (fixed_length (t)) + os << fq; + else + os << fq << "*"; + + break; + } + case seq: + { + if (fixed_length (t)) + os << "::xsde::cxx::hybrid::fix_seq"; + else + os << "::xsde::cxx::hybrid::var_seq"; + + os << "< " << fq << " >"; + break; + } + } + } + + Void + fund_type (Char const* name) + { + switch (use_) + { + case ret: + { + os << name << "&"; + break; + } + case seq: + { + os << "::xsde::cxx::hybrid::pod_seq< " << name << " >"; + break; + } + default: + { + os << name; + break; + } + } + } + + Void + string_type () + { + switch (use_) + { + case base: + { + // Non-STL case is handled by the caller. + // + os << "::std::string"; + break; + } + case ro_ret: + { + if (stl) + os << "const ::std::string&"; + else + os << "const char*"; + break; + } + case ret: + { + if (stl) + os << "::std::string&"; + else + os << "char*"; + break; + } + case arg: + { + if (stl) + os << "const ::std::string&"; + else + os << "char*"; + break; + } + case var: + { + if (stl) + os << "::std::string"; + else + os << "char*"; + break; + } + case seq: + { + os << "::xsde::cxx::hybrid::str_seq"; + break; + } + } + } + + private: + Use use_; + String xs_ns_; + }; + + struct TypeOps: Traversal::Type, + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + enum Use + { + deref, + delete_ + }; + + TypeOps (Context& c, Use use) + : Context (c), use_ (use) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + type (t); + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + type (t); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean&) + { + fund_type (); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger&) + { + fund_type (); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double&) + { + fund_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal&) + { + fund_type (); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + string_type (); + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + type (t); + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + type (t); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI&) + { + string_type (); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + type (t); + } + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + type (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + type (t); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + string_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + type (t); + } + + private: + Void + type (SemanticGraph::Type& t) + { + switch (use_) + { + case deref: + { + if (!fixed_length (t)) + os << "*"; + + break; + } + case delete_: + { + os << "delete"; + break; + } + } + } + + Void + fund_type () + { + switch (use_) + { + case deref: + { + break; + } + case delete_: + { + os << "delete"; + break; + } + } + } + + Void + string_type () + { + switch (use_) + { + case deref: + { + break; + } + case delete_: + { + if (stl) + os << "delete"; + else + os << "delete[]"; + break; + } + } + } + + private: + Use use_; + }; + + // + // + struct TypeForward: Traversal::Type, Context + { + TypeForward (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t); + }; + + struct Includes : Traversal::Imports, + Traversal::Includes + { + enum Type + { + forward, + header, + impl_header, + inline_, + source + }; + + Includes (Context& c, Type type) + : ctx_ (c), + type_ (type), + forward_ (c.options.value ()), + namespace_ (c), + type_forward_ (c) + { + schema_ >> schema_names_ >> namespace_ >> names_ >> type_forward_; + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + traverse_ (i); + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + traverse_ (i); + } + + private: + Void + traverse_ (SemanticGraph::Uses&); + + private: + Context& ctx_; + Type type_; + Boolean forward_; + + Traversal::Schema schema_; + Traversal::Names schema_names_; + Namespace namespace_; + Traversal::Names names_; + TypeForward type_forward_; + }; + + // Test whether there are any aggregates to be generated. + // + struct AggregateTest: Traversal::Type, Traversal::Element + { + AggregateTest (Boolean& generate, Char const* key) + : gen_ (generate), key_ (key) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (!gen_ && t.context ().count (key_)) + gen_ = true; + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!gen_ && e.context ().count (key_)) + gen_ = true; + } + + private: + Boolean& gen_; + Char const* key_; + }; + } +} + +#endif // CXX_HYBRID_ELEMENTS_HXX diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx new file mode 100644 index 0000000..b6215f9 --- /dev/null +++ b/xsde/cxx/hybrid/generator.cxx @@ -0,0 +1,2476 @@ +// file : xsde/cxx/hybrid/generator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include + +#include +#include + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "../../../libxsde/xsde/cxx/version.hxx" + +using std::endl; +using std::wcerr; + +using namespace XSDFrontend::SemanticGraph; + +// +// +typedef +boost::filesystem::wifstream +WideInputFileStream; + +typedef +boost::filesystem::wofstream +WideOutputFileStream; + +typedef +boost::filesystem::ifstream +NarrowInputFileStream; + +namespace CXX +{ + namespace + { + Char const copyright_gpl[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema\n" + "// to C++ data binding compiler for embedded systems.\n" + "//\n" + "// This program is free software; you can redistribute it and/or modify\n" + "// it under the terms of the GNU General Public License version 2 as\n" + "// published by the Free Software Foundation.\n" + "//\n" + "// This program is distributed in the hope that it will be useful,\n" + "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "// GNU General Public License for more details.\n" + "//\n" + "// You should have received a copy of the GNU General Public License\n" + "// along with this program; if not, write to the Free Software\n" + "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" + "//\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema to\n" + "// C++ data binding compiler for embedded systems, in the Proprietary\n" + "// License mode. You should have received a proprietary license from\n" + "// Code Synthesis Tools CC prior to generating this code. See the\n" + "// license text for conditions.\n" + "//\n\n"; + } + + namespace Hybrid + { + namespace CLI + { + extern Key no_stl = "no-stl"; + extern Key no_iostream = "no-iostream"; + extern Key no_exceptions = "no-exceptions"; + extern Key no_long_long = "no-long-long"; + extern Key generate_parser = "generate-parser"; + extern Key generate_serializer = "generate-serializer"; + extern Key generate_aggregate = "generate-aggregate"; + extern Key suppress_validation = "suppress-validation"; + extern Key suppress_parser_val = "suppress-parser-val"; + extern Key suppress_serializer_val = "suppress-serializer-val"; + extern Key generate_inline = "generate-inline"; + extern Key generate_forward = "generate-forward"; + extern Key generate_xml_schema = "generate-xml-schema"; + extern Key extern_xml_schema = "extern-xml-schema"; + extern Key suppress_reset = "suppress-reset"; + extern Key reuse_style_mixin = "reuse-style-mixin"; + extern Key custom_data = "custom-data"; + extern Key custom_parser = "custom-parser"; + extern Key custom_serializer = "custom-serializer"; + extern Key root_element_first = "root-element-first"; + extern Key root_element_last = "root-element-last"; + extern Key root_element_all = "root-element-all"; + extern Key root_element_none = "root-element-none"; + extern Key root_element = "root-element"; + extern Key root_type = "root-type"; + extern Key output_dir = "output-dir"; + extern Key pskel_type_suffix = "pskel-type-suffix"; + extern Key sskel_type_suffix = "sskel-type-suffix"; + extern Key pskel_file_suffix = "pskel-file-suffix"; + extern Key sskel_file_suffix = "sskel-file-suffix"; + extern Key pimpl_type_suffix = "pimpl-type-suffix"; + extern Key simpl_type_suffix = "simpl-type-suffix"; + extern Key pimpl_file_suffix = "pimpl-file-suffix"; + extern Key simpl_file_suffix = "simpl-file-suffix"; + extern Key paggr_type_suffix = "paggr-type-suffix"; + extern Key saggr_type_suffix = "saggr-type-suffix"; + extern Key namespace_map = "namespace-map"; + extern Key namespace_regex = "namespace-regex"; + extern Key namespace_regex_trace = "namespace-regex-trace"; + extern Key reserved_name = "reserved-name"; + extern Key include_with_brackets = "include-with-brackets"; + extern Key include_prefix = "include-prefix"; + extern Key include_regex = "include-regex"; + extern Key include_regex_trace = "include-regex-trace"; + extern Key guard_prefix = "guard-prefix"; + extern Key hxx_suffix = "hxx-suffix"; + extern Key ixx_suffix = "ixx-suffix"; + extern Key cxx_suffix = "cxx-suffix"; + extern Key fwd_suffix = "fwd-suffix"; + extern Key hxx_regex = "hxx-regex"; + extern Key ixx_regex = "ixx-regex"; + extern Key cxx_regex = "cxx-regex"; + extern Key fwd_regex = "fwd-regex"; + extern Key hxx_prologue = "hxx-prologue"; + extern Key ixx_prologue = "ixx-prologue"; + extern Key cxx_prologue = "cxx-prologue"; + extern Key fwd_prologue = "fwd-prologue"; + extern Key prologue = "prologue"; + extern Key hxx_epilogue = "hxx-epilogue"; + extern Key ixx_epilogue = "ixx-epilogue"; + extern Key cxx_epilogue = "cxx-epilogue"; + extern Key fwd_epilogue = "fwd-epilogue"; + extern Key epilogue = "epilogue"; + extern Key hxx_prologue_file = "hxx-prologue-file"; + extern Key ixx_prologue_file = "ixx-prologue-file"; + extern Key cxx_prologue_file = "cxx-prologue-file"; + extern Key fwd_prologue_file = "fwd-prologue-file"; + extern Key prologue_file = "prologue-file"; + extern Key hxx_epilogue_file = "hxx-epilogue-file"; + extern Key ixx_epilogue_file = "ixx-epilogue-file"; + extern Key cxx_epilogue_file = "cxx-epilogue-file"; + extern Key fwd_epilogue_file = "fwd-epilogue-file"; + extern Key epilogue_file = "epilogue-file"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + } + } + + Void Hybrid::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--no-stl" << endl + << " Generate code that does not use STL." + << endl; + + e << "--no-iostream" << endl + << " Generate code that does not use the iostream\n" + << " library." + << endl; + + e << "--no-exceptions" << endl + << " Generate code that does not use C++ exceptions." + << endl; + + e << "--no-long-long" << endl + << " Generate code that does not use the long long\n" + << " and unsigned long long types." + << endl; + + e << "--generate-parser" << endl + << " Generate XML parsing code." + << endl; + + e << "--generate-serializer" << endl + << " Generate XML serialization code." + << endl; + + e << "--generate-aggregate" << endl + << " Generate parser/serializer aggregates for root\n" + << " elements and/or types." + << endl; + + e << "--suppress-validation" << endl + << " Suppress the generation of validation code in\n" + << " parser and serializer." + << endl; + + e << "--suppress-parser-val" << endl + << " Suppress the generation of validation code in\n" + << " parser." + << endl; + + e << "--suppress-serializer-val" << endl + << " Suppress the generation of validation code in\n" + << " serializer." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--generate-forward" << endl + << " Generate forward declaration file." + << endl; + + e << "--generate-xml-schema" << endl + << " Generate C++ header files as if the schema being\n" + << " compiled defines the XML Schema namespace." + << endl; + + e << "--extern-xml-schema " << endl + << " Generate code as if the XML Schema namespace was\n" + << " defined in and xsd:included in the schema\n" + << " being compiled." + << endl; + + e << "--suppress-reset" << endl + << " Suppress the generation of parser and serializer\n" + << " reset code." + << endl; + + e << "--reuse-style-mixin" << endl + << " Generate code that supports the mixin base\n" + << " parser/serializer implementation reuse style." + << endl; + + e << "--custom-data " << endl + << " Add custom data to the C++ class generated for\n" + << " XML Schema type ." + << endl; + + e << "--custom-parser " << endl + << " Use a custom parser implementation instead of the\n" + << " generated version. The argument is in the\n" + << " form type[=base[/include]], where is an XML\n" + << " Schema type name, optional is a C++ name\n" + << " that should be given to the generated version,\n" + << " and optional is the header file that\n" + << " defines the custom implementation." + << endl; + + e << "--custom-serializer " << endl + << " Use a custom serializer implementation instead of\n" + << " the generated version. The argument is in\n" + << " the form type[=base[/include]], where is\n" + << " an XML Schema type name, optional is a C++\n" + << " name that should be given to the generated\n" + << " version, and optional is the header\n" + << " file that defines the custom implementation." + << endl; + + e << "--root-element-first" << endl + << " Treat only the first global element as a document\n" + << " root." + << endl; + + e << "--root-element-last" << endl + << " Treat only the last global element as a document\n" + << " root." + << endl; + + e << "--root-element-all" << endl + << " Treat all global elements as document roots." + << endl; + + e << "--root-element-none" << endl + << " Don't treat any global elements as document roots." + << endl; + + e << "--root-element " << endl + << " Treat only as a document root. Repeat\n" + << " this option to specify more than one root element." + << endl; + + e << "--root-type " << endl + << " Generate parser/serializer aggregate for .\n" + << " Repeat this option to specify more than one type." + << endl; + + e << "--output-dir " << endl + << " Write generated files to instead of the\n" + << " current directory." + << endl; + + e << "--pskel-type-suffix " << endl + << " Use instead of the default '_pskel' suffix\n" + << " to construct the names of generated parser\n" + << " skeletons." + << endl; + + e << "--sskel-type-suffix " << endl + << " Use instead of the default '_sskel' suffix\n" + << " to construct the names of generated serializer\n" + << " skeletons." + << endl; + + e << "--pskel-file-suffix " << endl + << " Use instead of the default '-pskel' suffix\n" + << " to construct the names of generated parser\n" + << " skeleton files." + << endl; + + e << "--sskel-file-suffix " << endl + << " Use instead of the default '-sskel' suffix\n" + << " to construct the names of generated serializer\n" + << " skeleton files." + << endl; + + e << "--pimpl-type-suffix " << endl + << " Use instead of the default '_pimpl' suffix\n" + << " to construct the names of generated parser\n" + << " implementations." + << endl; + + e << "--simpl-type-suffix " << endl + << " Use instead of the default '_simpl' suffix\n" + << " to construct the names of generated serializer\n" + << " implementations." + << endl; + + e << "--pimpl-file-suffix " << endl + << " Use instead of the default '-pimpl' suffix\n" + << " to construct the names of generated parser\n" + << " implementation files." + << endl; + + e << "--simpl-file-suffix " << endl + << " Use instead of the default '-simpl' suffix\n" + << " to construct the names of generated serializer\n" + << " implementation files." + << endl; + + e << "--paggr-type-suffix " << endl + << " Use instead of the default '_paggs' suffix\n" + << " to construct the names of generated parser\n" + << " aggregates." + << endl; + + e << "--saggr-type-suffix " << endl + << " Use instead of the default '_saggr' suffix\n" + << " to construct the names of generated serializer\n" + << " aggregates." + << endl; + + e << "--namespace-map =" << endl + << " Map XML Schema namespace to C++ namespace\n" + << " . Repeat this option to specify mapping for\n" + << " more than one XML Schema namespace." + << endl; + + e << "--namespace-regex " << endl + << " Add to the list of regular expressions\n" + << " used to translate XML Schema namespace names to\n" + << " C++ namespace names." + << endl; + + e << "--namespace-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --namespace-regex option." + << endl; + + e << "--reserved-name " << endl + << " Add to the list of names that should not\n" + << " be used as identifiers. The name can optionally\n" + << " be followed by '=' and the replacement name that\n" + << " should be used instead." + << endl; + + e << "--include-with-brackets" << endl + << " Use angle brackets (<>) instead of quotes (\"\") in\n" + << " generated #include directives." + << endl; + + e << "--include-prefix " << endl + << " Add to generated #include directive\n" + << " paths." + << endl; + + e << "--include-regex " << endl + << " Add to the list of regular expressions\n" + << " used to transform #include directive paths." + << endl; + + e << "--include-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --include-regex option." + << endl; + + e << "--guard-prefix " << endl + << " Add to generated header inclusion guards." + << endl; + + // File suffix. + // + e << "--hxx-suffix " << endl + << " Use instead of the default '.hxx' to\n" + << " construct the name of the header files." + << endl; + + e << "--ixx-suffix " << endl + << " Use instead of the default '.ixx' to\n" + << " construct the name of the inline files." + << endl; + + e << "--cxx-suffix " << endl + << " Use instead of the default '.cxx' to\n" + << " construct the name of the source files." + << endl; + + e << "--fwd-suffix " << endl + << " Use instead of the default '-fwd.hxx'\n" + << " to construct the name of the forward declaration\n" + << " file." + << endl; + + // File regex. + // + e << "--hxx-regex " << endl + << " Use to construct the names of the header\n" + << " files." + << endl; + + e << "--ixx-regex " << endl + << " Use to construct the names of the inline\n" + << " files." + << endl; + + e << "--cxx-regex " << endl + << " Use to construct the names of the source\n" + << " files." + << endl; + + e << "--fwd-regex " << endl + << " Use to construct the name of the forward\n" + << " declaration file." + << endl; + + + // Prologues. + // + e << "--hxx-prologue " << endl + << " Insert at the beginning of the header\n" + << " files." + << endl; + + e << "--ixx-prologue " << endl + << " Insert at the beginning of the inline\n" + << " files." + << endl; + + e << "--cxx-prologue " << endl + << " Insert at the beginning of the source\n" + << " files." + << endl; + + e << "--fwd-prologue " << endl + << " Insert at the beginning of the forward\n" + << " declaration file." + << endl; + + e << "--prologue " << endl + << " Insert at the beginning of each generated\n" + << " file for which there is no file-specific prologue." + << endl; + + + // Epilogues. + // + e << "--hxx-epilogue " << endl + << " Insert at the end of the header files." + << endl; + + e << "--ixx-epilogue " << endl + << " Insert at the end of the inline files." + << endl; + + e << "--cxx-epilogue " << endl + << " Insert at the end of the source files." + << endl; + + e << "--fwd-epilogue " << endl + << " Insert at the end of the forward\n" + << " declaration file." + << endl; + + e << "--epilogue " << endl + << " Insert at the end of each generated file\n" + << " for which there is no file-specific epilogue." + << endl; + + + // Prologue files. + // + e << "--hxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the header files." + << endl; + + e << "--ixx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the inline files." + << endl; + + e << "--cxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the source files." + << endl; + + e << "--fwd-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the forward declaration file." + << endl; + + e << "--prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of each generated file for which there is no file-\n" + << " specific prologue file." + << endl; + + + // Epilogue files. + // + e << "--hxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the header files." + << endl; + + e << "--ixx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the inline files." + << endl; + + e << "--cxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the source files." + << endl; + + e << "--fwd-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the forward declaration file." + << endl; + + e << "--epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " each generated file for which there is no file-\n" + << " specific epilogue file." + << endl; + + + // Misc. + // + e << "--show-anonymous" << endl + << " Show elements and attributes that are of anonymous\n" + << " types." + << endl; + + e << "--show-sloc" << endl + << " Show the number of generated physical source lines\n" + << " of code (SLOC)." + << endl; + + e << "--sloc-limit " << endl + << " Check that the number of generated physical source\n" + << " lines of code (SLOC) does not exceed ." + << endl; + + e << "--options-file " << endl + << " Read additional options from . Each option\n" + << " should appear on a separate line optionally\n" + << " followed by space and an argument." + << endl; + + e << "--proprietary-license" << endl + << " Indicate that the generated code is licensed under\n" + << " a proprietary license instead of the GPL." + << endl; + } + + Hybrid::CLI::OptionsSpec Hybrid::Generator:: + options_spec () + { + CLI::OptionsSpec spec; + + spec.option ().default_value ("-pskel"); + spec.option ().default_value ("-sskel"); + spec.option ().default_value ("_pskel"); + spec.option ().default_value ("_sskel"); + + spec.option ().default_value ("-pimpl"); + spec.option ().default_value ("-simpl"); + spec.option ().default_value ("_pimpl"); + spec.option ().default_value ("_simpl"); + + spec.option ().default_value ("_paggr"); + spec.option ().default_value ("_saggr"); + + spec.option ().default_value (".hxx"); + spec.option ().default_value (".ixx"); + spec.option ().default_value (".cxx"); + spec.option ().default_value ("-fwd.hxx"); + + return spec; + } + + namespace + { + NarrowString + find_value (Cult::Containers::Vector const& v, + Char const* key) + { + typedef Cult::Containers::Vector Values; + + for (Values::ConstIterator i (v.begin ()), e (v.end ()); i != e; ++i) + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + return NarrowString ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos); + } + + return NarrowString (); + } + + Void + copy_values (Cult::Containers::Vector& dst, + Cult::Containers::Vector const& src, + Char const* key) + { + typedef Cult::Containers::Vector Values; + + for (Values::ConstIterator i (src.begin ()), e (src.end ()); i != e; ++i) + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + dst.push_back ( + NarrowString ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos)); + } + } + } + + Parser::CLI::Options* Hybrid::Generator:: + parser_options (CLI::Options const& h) + { + namespace H = CLI; + namespace P = Parser::CLI; + + Evptr r (new P::Options); + + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = false; + r->value () = h.value (); + r->value () = h.value () + || h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + + Char const* k = "pskel"; + + r->value () = + find_value (h.value (), k); + r->value () = + find_value (h.value (), k); + r->value () = + find_value (h.value (), k); + + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + + r->value () = h.value (); + r->value () = h.value (); + + return r.release (); + } + + Serializer::CLI::Options* Hybrid::Generator:: + serializer_options (CLI::Options const& h) + { + namespace H = CLI; + namespace S = Serializer::CLI; + + Evptr r (new S::Options); + + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = false; + r->value () = h.value (); + r->value () = h.value () + || h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + + r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); + + Char const* k = "sskel"; + + r->value () = + find_value (h.value (), k); + r->value () = + find_value (h.value (), k); + r->value () = + find_value (h.value (), k); + + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + r->value () = find_value ( + h.value (), k); + + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + copy_values (r->value (), h.value (), k); + + r->value () = h.value (); + r->value () = h.value (); + + return r.release (); + } + + Void Hybrid::Generator:: + calculate_size (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + // Determine which types are fixed/variable-sized. + // + TreeSizeProcessor proc; + proc.process (ops, schema, file); + } + + namespace + { + template + Void + open (S& ifs, NarrowString const& path) + { + try + { + Path fs_path (path, boost::filesystem::native); + ifs.open (fs_path, std::ios_base::in | std::ios_base::binary); + + if (!ifs.is_open ()) + { + wcerr << path.c_str () << ": error: unable to open in read mode" + << endl; + + throw Hybrid::Generator::Failed (); + } + } + catch (InvalidPath const&) + { + wcerr << "error: '" << path.c_str () << "' is not a valid " + << "filesystem path" << endl; + + throw Hybrid::Generator::Failed (); + } + } + + Void + append (WideOutputFileStream& os, + NarrowString const& path, + WideInputFileStream& default_is) + { + using std::ios_base; + + if (path) + { + WideInputFileStream is; + open (is, path); + os << is.rdbuf (); + } + else if (default_is.is_open ()) + { + os << default_is.rdbuf (); + default_is.seekg (0, ios_base::beg); + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector const& primary, + Cult::Containers::Vector const& def, + Char const* primary_key, + Char const* def_key) + { + typedef Cult::Containers::Vector Values; + + for (Values const* v = &primary; v != 0; v = (v == &def ? 0 : &def)) + { + Boolean found (false); + Char const* key (v == &primary ? primary_key : def_key); + + for (Values::ConstIterator i (v->begin ()), e (v->end ()); i != e; ++i) + { + if (key == 0) + os << i->c_str () << endl; + else + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + NarrowString s ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos); + os << s.c_str () << endl; + } + + found = true; + } + + if (found) + break; + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector const& primary, + Cult::Containers::Vector const& def, + Char const* key) + { + append (os, primary, def, key, key); + } + } + + + UnsignedLong Hybrid::Generator:: + generate_tree (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet& disabled_warnings, + TypeMap::Namespaces& parser_type_map, + TypeMap::Namespaces& serializer_type_map, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef Context::Regex Regex; + + try + { + Boolean generate_xml_schema (ops.value ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (generate_xml_schema) + { + if (NarrowString name = ops.value ()) + { + if (file_path.native_file_string () != name) + generate_xml_schema = false; + } + } + + // Evaluate the graph for possibility of generating something useful. + // + { + Validator validator; + if (!validator.validate (ops, schema, file_path, disabled_warnings)) + throw Failed (); + } + + // Process names. + // + { + TreeNameProcessor proc; + proc.process (ops, schema, file_path); + } + + // Generate code. + // + Boolean inline_ (ops.value () && + !generate_xml_schema); + + Boolean forward (ops.value () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + NarrowString name (file_path.leaf ()); + + NarrowString hxx_suffix (ops.value ()); + NarrowString ixx_suffix (ops.value ()); + NarrowString cxx_suffix (ops.value ()); + NarrowString fwd_suffix (ops.value ()); + + NarrowString hxx_regex (find_value (ops.value (), "")); + NarrowString ixx_regex (find_value (ops.value (), "")); + NarrowString cxx_regex (find_value (ops.value (), "")); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + hxx_suffix + "#" + : hxx_regex); + + Regex ixx_expr ( + ixx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + ixx_suffix + "#" + : ixx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + cxx_suffix + "#" + : cxx_regex); + + Regex fwd_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + fwd_suffix + "#" + : ops.value ()); + + if (!hxx_expr.match (name)) + { + wcerr << "error: header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (inline_ && !ixx_expr.match (name)) + { + wcerr << "error: inline expression '" << + ixx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (source && !cxx_expr.match (name)) + { + wcerr << "error: source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (forward && !fwd_expr.match (name)) + { + wcerr << "error: forward expression '" << + fwd_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString ixx_name (inline_ ? ixx_expr.merge (name) : NarrowString ()); + NarrowString cxx_name (source ? cxx_expr.merge (name) : NarrowString ()); + NarrowString fwd_name (forward ? fwd_expr.merge (name) : NarrowString ()); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path ixx_path (ixx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + Path fwd_path (fwd_name, boost::filesystem::native); + + if (NarrowString dir = ops.value ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + ixx_path = path / ixx_path; + cxx_path = path / cxx_path; + fwd_path = path / fwd_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + // Open the tree files. + // + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream ixx; + WideOutputFileStream cxx; + WideOutputFileStream fwd; + + // FWD + // + if (forward) + { + fwd.open (fwd_path, ios_base::out); + + if (!fwd.is_open ()) + { + wcerr << fwd_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (fwd_path); + file_list.push_back (fwd_path.native_file_string ()); + } + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (inline_) + { + ixx.open (ixx_path, ios_base::out); + + if (!ixx.is_open ()) + { + wcerr << ixx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (ixx_path); + file_list.push_back (ixx_path.native_file_string ()); + } + + if (source) + { + cxx.open (cxx_path, ios_base::out); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + } + + // Print copyright and license. + // + Char const* copyright ( + ops.value () + ? copyright_proprietary + : copyright_gpl); + + if (forward) + fwd << copyright; + + hxx << copyright; + + if (inline_) + ixx << copyright; + + if (source) + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value (), "")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (ops.value (), "")); + + if (name) + open (epilogue, name); + } + + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value ()); + + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value ()); + + if (!guard_prefix) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // FWD + // + if (forward) + { + Context ctx (fwd, schema, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip fwd_sloc (fwd); + + String guard (guard_expr.merge (guard_prefix + fwd_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + fwd << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + fwd << "// Begin prologue." << endl + << "//" << endl; + + append (fwd, + ops.value (), + ops.value (), + 0, + ""); + append (fwd, ops.value (), prologue); + + fwd << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + fwd << "#include " << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + fwd << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip fwd_clip (fwd); + + // Generate. + // + generate_tree_forward (ctx, false); + + fwd << "#include " << endl + << endl; + } + + // Copy epilogue. + // + fwd << "// Begin epilogue." << endl + << "//" << endl; + + append (fwd, ops.value (), epilogue); + append (fwd, + ops.value (), + ops.value (), + 0, + ""); + + fwd << "//" << endl + << "// End epilogue." << endl + << endl; + + fwd << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << fwd_path << ": " + << fwd_sloc.buffer ().count () << endl; + + sloc += fwd_sloc.buffer ().count (); + } + } + + + // HXX + // + { + Context ctx (hxx, schema, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append (hxx, + ops.value (), + ops.value (), + ""); + append (hxx, + find_value (ops.value (), ""), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + hxx << "#include " << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + // Runtime/generated code compatibility checks. + // + + hxx << "#include " << endl + << endl; + + if (ops.value ()) + { + hxx << "#ifdef XSDE_STL" << endl + << "#error the XSD/e runtime uses STL while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-stl)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_STL" << endl + << "#error the generated code uses STL while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-stl)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_EXCEPTIONS" << endl + << "#error the XSD/e runtime uses exceptions while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_EXCEPTIONS" << endl + << "#error the generated code uses exceptions while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_LONGLONG" << endl + << "#error the XSD/e runtime uses long long while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-long-long)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_LONGLONG" << endl + << "#error the generated code uses long long while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-long-long)" << endl + << "#endif" << endl + << endl; + } + + // + // + + hxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip hxx_clip (hxx); + + // Generate. + // + if (!generate_xml_schema) + { + if (forward) + hxx << "#include " << ctx.process_include_path (fwd_name) + << endl << endl; + else + generate_tree_forward (ctx, false); + + generate_tree_header (ctx); + } + else + generate_tree_forward (ctx, true); + + if (inline_) + { + hxx << "#ifndef XSDE_DONT_INCLUDE_INLINE" << endl + << "#include " << ctx.process_include_path (ixx_name) << endl + << "#endif // XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + } + + hxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (ops.value (), ""), + epilogue); + append (hxx, + ops.value (), + ops.value (), + ""); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + + // IXX + // + if (inline_) + { + Context ctx (ixx, schema, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip ixx_sloc (ixx); + // Guard + // + String guard (guard_expr.merge (guard_prefix + ixx_name)); + guard = ctx.escape (guard); // make a c++ id + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + ixx << "#ifndef " << guard.c_str () << endl + << "#define " << guard.c_str () << endl + << endl; + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + + append (ixx, + ops.value (), + ops.value (), + ""); + append (ixx, + find_value (ops.value (), ""), + prologue); + + ixx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip ixx_clip (ixx); + + // Generate. + // + generate_tree_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + + append (ixx, + find_value (ops.value (), ""), + epilogue); + append (ixx, + ops.value (), + ops.value (), + ""); + + ixx << "//" << endl + << "// End epilogue." << endl + << endl; + + ixx << "#endif // " << guard.c_str () << endl; + + if (show_sloc) + { + wcerr << ixx_path << ": " + << ixx_sloc.buffer ().count () << endl; + + sloc += ixx_sloc.buffer ().count (); + } + } + + + // CXX + // + if (source) + { + Context ctx (cxx, schema, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append (cxx, + ops.value (), + ops.value (), + ""); + append (cxx, + find_value (ops.value (), ""), + prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + cxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + if (!inline_) + generate_tree_inline (ctx); + + generate_tree_source (ctx); + + cxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (ops.value (), ""), + epilogue); + append (cxx, + ops.value (), + ops.value (), + ""); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + // Populate the type maps if we are generating parsing or + // serialization code. + // + if (ops.value () || + ops.value ()) + { + generate_tree_type_map ( + ops, schema, hxx_name, parser_type_map, serializer_type_map); + } + + return sloc; + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } + + UnsignedLong Hybrid::Generator:: + generate_parser (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet&, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression Regex; + + try + { + { + Boolean gen_xml_schema (ops.value ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (gen_xml_schema) + { + if (NarrowString name = ops.value ()) + { + if (file_path.native_file_string () != name) + gen_xml_schema = false; + } + } + + if (gen_xml_schema) + return 0; + } + + // Process names. + // + { + ParserNameProcessor proc; + proc.process (ops, schema, file_path); + } + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value ()); + NarrowString impl_suffix (ops.value ()); + + NarrowString hxx_suffix (ops.value ()); + NarrowString cxx_suffix (ops.value ()); + + NarrowString hxx_obj_regex ( + find_value (ops.value (), "")); + + NarrowString hxx_skel_regex ( + find_value (ops.value (), "pskel")); + + NarrowString hxx_regex ( + find_value (ops.value (), "pimpl")); + NarrowString cxx_regex ( + find_value (ops.value (), "pimpl")); + + // Here we need to make sure that hxx_obj_expr is the same + // as in generate(). + // + Regex hxx_obj_expr ( + hxx_obj_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + hxx_suffix + "#" + : hxx_obj_regex); + + // Here we need to make sure that hxx_skel_expr is the same + // as in the C++/Parser generator. + // + Regex hxx_skel_expr ( + hxx_skel_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : hxx_skel_regex); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#" + : hxx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#" + : cxx_regex); + + if (!hxx_expr.match (name)) + { + wcerr << "error: parser implementation header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_expr.match (name)) + { + wcerr << "error: parser implementation source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + NarrowString hxx_skel_name (hxx_skel_expr.merge (name)); + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString cxx_name (cxx_expr.merge (name)); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + if (NarrowString dir = ops.value ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + cxx_path = path / cxx_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream cxx (cxx_path, ios_base::out); + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + + // Print copyright and license. + // + Char const* copyright ( + ops.value () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value (), "pimpl")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (ops.value (), "pimpl")); + + if (name) + open (epilogue, name); + } + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value ()); + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value ()); + + if (!guard_prefix) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, 0, &hxx_expr, 0); + + Indentation::Clip hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append (hxx, + ops.value (), + ops.value (), + "pimpl"); + append (hxx, + find_value (ops.value (), "pimpl"), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + hxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip hxx_clip (hxx); + + hxx << "#include " << ctx.process_include_path (hxx_skel_name) + << endl << endl; + + generate_parser_header (ctx); + + if (ops.value ()) + generate_parser_aggregate_header (ctx); + + hxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (ops.value (), "pimpl"), + epilogue); + append (hxx, + ops.value (), + ops.value (), + "pimpl"); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + // CXX + // + { + Context ctx (cxx, schema, ops, 0, &hxx_obj_expr, 0); + + Indentation::Clip cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append (cxx, + ops.value (), + ops.value (), + "pimpl"); + append (cxx, + find_value (ops.value (), "pimpl"), + prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + generate_parser_source (ctx); + + if (ops.value ()) + generate_parser_aggregate_source (ctx); + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (ops.value (), "pimpl"), + epilogue); + append (cxx, + ops.value (), + ops.value (), + "pimpl"); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + return sloc; + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } + + UnsignedLong Hybrid::Generator:: + generate_serializer (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet&, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression Regex; + + try + { + { + Boolean gen_xml_schema (ops.value ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (gen_xml_schema) + { + if (NarrowString name = ops.value ()) + { + if (file_path.native_file_string () != name) + gen_xml_schema = false; + } + } + + if (gen_xml_schema) + return 0; + } + + // Process names. + // + { + SerializerNameProcessor proc; + proc.process (ops, schema, file_path); + } + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value ()); + NarrowString impl_suffix (ops.value ()); + + NarrowString hxx_suffix (ops.value ()); + NarrowString cxx_suffix (ops.value ()); + + NarrowString hxx_skel_regex ( + find_value (ops.value (), "sskel")); + NarrowString hxx_regex ( + find_value (ops.value (), "simpl")); + NarrowString cxx_regex ( + find_value (ops.value (), "simpl")); + + // Here we need to make sure that hxx_skel_expr is the same + // as in the C++/Serializer generator. + // + Regex hxx_skel_expr ( + hxx_skel_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : hxx_skel_regex); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#" + : hxx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#" + : cxx_regex); + + if (!hxx_expr.match (name)) + { + wcerr << "error: serializer implementation header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_expr.match (name)) + { + wcerr << "error: serializer implementation source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + NarrowString hxx_skel_name (hxx_skel_expr.merge (name)); + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString cxx_name (cxx_expr.merge (name)); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + if (NarrowString dir = ops.value ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + cxx_path = path / cxx_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream cxx (cxx_path, ios_base::out); + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + + // Print copyright and license. + // + Char const* copyright ( + ops.value () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value (), "simpl")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (ops.value (), "simpl")); + + if (name) + open (epilogue, name); + } + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value ()); + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value ()); + + if (!guard_prefix) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, 0, &hxx_expr, 0); + + Indentation::Clip hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append (hxx, + ops.value (), + ops.value (), + "simpl"); + append (hxx, + find_value (ops.value (), "simpl"), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + hxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip hxx_clip (hxx); + + hxx << "#include " << ctx.process_include_path (hxx_skel_name) + << endl << endl; + + generate_serializer_header (ctx); + + if (ops.value ()) + generate_serializer_aggregate_header (ctx); + + hxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (ops.value (), "simpl"), + epilogue); + append (hxx, + ops.value (), + ops.value (), + "simpl"); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + // CXX + // + { + Context ctx (cxx, schema, ops, 0, &hxx_expr, 0); + + Indentation::Clip cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append (cxx, + ops.value (), + ops.value (), + "simpl"); + append (cxx, + find_value (ops.value (), "simpl"), + prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + generate_serializer_source (ctx); + + if (ops.value ()) + generate_serializer_aggregate_source (ctx); + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (ops.value (), "simpl"), + epilogue); + append (cxx, + ops.value (), + ops.value (), + "simpl"); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + return sloc; + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } +} diff --git a/xsde/cxx/hybrid/generator.hxx b/xsde/cxx/hybrid/generator.hxx new file mode 100644 index 0000000..ff29750 --- /dev/null +++ b/xsde/cxx/hybrid/generator.hxx @@ -0,0 +1,90 @@ +// file : xsde/cxx/hybrid/generator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_GENERATOR_HXX +#define CXX_HYBRID_GENERATOR_HXX + +#include + +#include + +#include +#include + +#include // Path +#include + +#include +#include +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class Generator + { + public: + static Void + usage (); + + static CLI::OptionsSpec + options_spec (); + + static Parser::CLI::Options* + parser_options (CLI::Options const&); + + static Serializer::CLI::Options* + serializer_options (CLI::Options const&); + + struct Failed {}; + + static Void + calculate_size ( + CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + + static UnsignedLong + generate_tree ( + CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file, + const WarningSet& disabled_warnings, + TypeMap::Namespaces& parser_type_map, + TypeMap::Namespaces& serializer_type_map, + FileList& file_list, + AutoUnlinks& unlinks); + + static UnsignedLong + generate_parser ( + CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks); + + static UnsignedLong + generate_serializer ( + CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks); + + private: + Generator (); + }; + } +} + +#endif // CXX_HYBRID_GENERATOR_HXX diff --git a/xsde/cxx/hybrid/parser-aggregate-header.cxx b/xsde/cxx/hybrid/parser-aggregate-header.cxx new file mode 100644 index 0000000..a717c68 --- /dev/null +++ b/xsde/cxx/hybrid/parser-aggregate-header.cxx @@ -0,0 +1,837 @@ +// file : xsde/cxx/hybrid/parser-aggregate-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + typedef Cult::Containers::Set InstanceSet; + + // For base types we only want member's types, but not the + // base itself. + // + struct BaseType: Traversal::Complex, Context + { + BaseType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + }; + + struct ParserDef: Traversal::Type, + Traversal::List, + Traversal::Complex, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + ParserDef (Context& c, TypeInstanceMap& map, InstanceSet& set) + : Context (c), map_ (map), set_ (set), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (t)); + map_[&t] = inst; + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (map_.find (&l) == map_.end ()) + { + String inst (find_instance_name (l)); + map_[&l] = inst; + + dispatch (l.argumented ().type ()); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (map_.find (&c) == map_.end ()) + { + String inst (find_instance_name (c)); + map_[&c] = inst; + + // Use base type's parsers in case of a restriction + // since we are not capable of using a derived type + // in place of a base (no virtual d-tor, for one). + // + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + fund_type (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + fund_type (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + fund_type (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + fund_type (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + fund_type (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + fund_type (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + fund_type (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + fund_type (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + fund_type (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + fund_type (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + fund_type (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + fund_type (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + fund_type (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + fund_type (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + fund_type (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + fund_type (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + fund_type (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + fund_type (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + fund_type (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + fund_type (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + fund_type (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + fund_type (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + fund_type (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + fund_type (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + fund_type (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + fund_type (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + fund_type (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + fund_type (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + fund_type (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + fund_type (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + fund_type (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + fund_type (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + fund_type (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + fund_type (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + fund_type (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + fund_type (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + fund_type (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + fund_type (t, "day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + fund_type (t, "month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + fund_type (t, "month_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + fund_type (t, "year"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + fund_type (t, "year_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + fund_type (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + fund_type (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + fund_type (t, "entities"); + } + + private: + virtual Void + fund_type (SemanticGraph::Type& t, String const& name) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (name)); + map_[&t] = inst; + } + } + + String + find_instance_name (String const& raw_name) + { + String name (escape (raw_name + L"_p_")); + + for (UnsignedLong i (1); set_.find (name) != set_.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (raw_name + L"_p" + os.str () + L"_"); + } + + set_.insert (name); + return name; + } + + String + find_instance_name (SemanticGraph::Type& t) + { + return find_instance_name (t.name ()); + } + + TypeInstanceMap& map_; + InstanceSet& set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + + if (!tc.count ("paggr")) + return; + + String const& name (tc.get ("paggr")); + + String pre (unclash (name, "pre")); + String post (unclash (name, "post")); + String root_parser (unclash (name, "root_parser")); + String error, reset; + + InstanceSet set; + set.insert (pre); + set.insert (post); + set.insert (name); + set.insert (root_parser); + + if (!exceptions) + { + error = unclash (name, "_error"); + set.insert (error); + } + + if (Context::reset) + { + reset = unclash (name, "reset"); + set.insert (reset); + } + + tc.set ("paggr-map", TypeInstanceMap ()); + TypeInstanceMap& map (tc.get ("paggr-map")); + + ParserDef def (*this, map, set); + def.dispatch (t); + + String const& root_member (map.find (&t)->second); + + os << "// Parser aggregate for the " << comment (t.name ()) << + " type." << endl + << "//" << endl; + + os << "class " << name + << "{" + << "public:" << endl; + + // c-tor () + // + os << name << " ();" + << endl; + + // pre () + // + os << "void" << endl + << pre << " ()" + << "{" + << "this->" << root_member << ".pre ();" + << "}"; + + // post () + // + String const& ret (pret_type (t)); + + os << ret << endl + << post << " ()" + << "{" + << (ret == L"void" ? "" : "return ") << "this->" << + root_member << "." << post_name (t) << " ();" + << "}"; + + // root_parser () + // + os << fq_name (t, "p:impl") << "&" << endl + << root_parser << " ()" + << "{" + << "return this->" << root_member << ";" + << "}"; + + // _error () + // + if (error) + { + os << xs_ns_name () << "::parser_error" << endl + << error << " ()" + << "{" + << "return this->" << root_member << "._error ();" + << "}"; + } + + // reset () + // + if (reset) + { + os << "void" << endl + << reset << " ()" + << "{" + << "this->" << root_member << "._reset ();" + << "}"; + } + + os << "public:" << endl; + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + os << fq_name (*i->first, "p:impl") << " " << i->second << ";"; + + os << "};"; + } + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("paggr")) + return; + + SemanticGraph::Type& t (e.type ()); + String const& name (ec.get ("paggr")); + + String pre (unclash (name, "pre")); + String post (unclash (name, "post")); + String root_parser (unclash (name, "root_parser")); + String root_name (unclash (name, "root_name")); + String root_namespace (unclash (name, "root_namespace")); + String error, reset; + + InstanceSet set; + set.insert (pre); + set.insert (post); + set.insert (name); + set.insert (root_parser); + set.insert (root_name); + set.insert (root_namespace); + + if (!exceptions) + { + error = unclash (name, "_error"); + set.insert (error); + } + + if (Context::reset) + { + reset = unclash (name, "reset"); + set.insert (reset); + } + + ec.set ("paggr-map", TypeInstanceMap ()); + TypeInstanceMap& map (ec.get ("paggr-map")); + + ParserDef def (*this, map, set); + def.dispatch (t); + + String const& root_member (map.find (&t)->second); + + os << "// Parser aggregate for the " << comment (e.name ()) << + " element." << endl + << "//" << endl; + + os << "class " << name + << "{" + << "public:" << endl; + + // c-tor () + // + os << name << " ();" + << endl; + + // pre () + // + os << "void" << endl + << pre << " ()" + << "{" + << "this->" << root_member << ".pre ();" + << "}"; + + // post () + // + String const& ret (pret_type (t)); + + os << ret << endl + << post << " ()" + << "{" + << (ret == L"void" ? "" : "return ") << "this->" << + root_member << "." << post_name (t) << " ();" + << "}"; + + // root_parser () + // + os << fq_name (t, "p:impl") << "&" << endl + << root_parser << " ()" + << "{" + << "return this->" << root_member << ";" + << "}"; + + // root_name () + // + os << "static const char*" << endl + << root_name << " ();" + << endl; + + // root_namespace () + // + os << "static const char*" << endl + << root_namespace << " ();" + << endl; + + // _error () + // + if (error) + { + os << xs_ns_name () << "::parser_error" << endl + << error << " ()" + << "{" + << "return this->" << root_member << "._error ();" + << "}"; + } + + // reset () + // + if (reset) + { + os << "void" << endl + << reset << " ()" + << "{" + << "this->" << root_member << "._reset ();" + << "}"; + } + + os << "public:" << endl; + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + os << fq_name (*i->first, "p:impl") << " " << i->second << ";"; + + os << "};"; + } + }; + } + + Void + generate_parser_aggregate_header (Context& ctx) + { + Boolean gen (false); + + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateTest test (gen, "paggr"); + + schema >> schema_names >> ns >> names >> test; + + schema.dispatch (ctx.schema_root); + } + + if (gen) + { + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + GlobalType type (ctx); + GlobalElement element (ctx); + + names >> type; + names >> element; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/hybrid/parser-aggregate-header.hxx b/xsde/cxx/hybrid/parser-aggregate-header.hxx new file mode 100644 index 0000000..ea10495 --- /dev/null +++ b/xsde/cxx/hybrid/parser-aggregate-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/parser-aggregate-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_PARSER_AGGREGATE_HEADER_HXX +#define CXX_HYBRID_PARSER_AGGREGATE_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_parser_aggregate_header (Context&); + } +} + +#endif // CXX_HYBRID_PARSER_AGGREGATE_HEADER_HXX diff --git a/xsde/cxx/hybrid/parser-aggregate-source.cxx b/xsde/cxx/hybrid/parser-aggregate-source.cxx new file mode 100644 index 0000000..6e80318 --- /dev/null +++ b/xsde/cxx/hybrid/parser-aggregate-source.cxx @@ -0,0 +1,330 @@ +// file : xsde/cxx/hybrid/parser-aggregate-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + // + // + struct ParticleArg: Traversal::Element, Context + { + ParticleArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&e.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct AttributeArg: Traversal::Attribute, Context + { + AttributeArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&a.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct ArgList : Traversal::Complex, + Traversal::List, + Context + { + ArgList (Context& c, TypeInstanceMap& map) + : Context (c), + map_ (map), + particle_ (c, map, first_), + attribute_ (c, map, first_), + first_ (true) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&l.argumented ().type ()]; + } + + private: + TypeInstanceMap& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleArg particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + AttributeArg attribute_; + + Boolean first_; + }; + + struct ParserConnect: Traversal::List, + Traversal::Complex, + Context + { + ParserConnect (Context& c, TypeInstanceMap& map) + : Context (c), map_ (map) + { + } + + virtual Void + traverse (SemanticGraph::List& l) + { + os << "this->" << map_[&l] << ".parsers (this->" << + map_[&l.argumented ().type ()] << ");" + << endl; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (has_members (c)) + { + os << "this->" << map_[&c] << ".parsers ("; + + ArgList args (*this, map_); + args.dispatch (c); + + os << ");" + << endl; + } + } + + private: + Boolean + has_members (SemanticGraph::Complex& c) + { + using SemanticGraph::Complex; + + if (has (c)) + return true; + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&b)) + return has_members (*cb); + + return b.is_a (); + } + + return false; + } + + private: + TypeInstanceMap& map_; + }; + + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + + if (!tc.count ("paggr")) + return; + + String const& name (tc.get ("paggr")); + TypeInstanceMap& map (tc.get ("paggr-map")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor () + // + os << name << "::" << endl + << name << " ()" + << "{"; + + ParserConnect connect (*this, map); + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + connect.dispatch (*i->first); + + os << "}"; + } + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("paggr")) + return; + + String const& name (ec.get ("paggr")); + TypeInstanceMap& map (ec.get ("paggr-map")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor () + // + os << name << "::" << endl + << name << " ()" + << "{"; + + ParserConnect connect (*this, map); + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + connect.dispatch (*i->first); + + os << "}"; + + // root_name () + // + String root_name (unclash (name, "root_name")); + + os << "const char* " << name << "::" << endl + << root_name << " ()" + << "{" + << "return " << strlit (e.name ()) << ";" + << "}"; + + // root_namespace () + // + String root_namespace (unclash (name, "root_namespace")); + + os << "const char* " << name << "::" << endl + << root_namespace << " ()" + << "{" + << "return " << strlit (e.namespace_ ().name ()) << ";" + << "}"; + } + }; + } + + Void + generate_parser_aggregate_source (Context& ctx) + { + Boolean gen (false); + + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateTest test (gen, "paggr"); + + schema >> schema_names >> ns >> names >> test; + + schema.dispatch (ctx.schema_root); + } + + if (gen) + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + GlobalType type (ctx); + GlobalElement element (ctx); + + names >> type; + names >> element; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/hybrid/parser-aggregate-source.hxx b/xsde/cxx/hybrid/parser-aggregate-source.hxx new file mode 100644 index 0000000..bb5b947 --- /dev/null +++ b/xsde/cxx/hybrid/parser-aggregate-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/parser-aggregate-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_PARSER_AGGREGATE_SOURCE_HXX +#define CXX_HYBRID_PARSER_AGGREGATE_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_parser_aggregate_source (Context&); + } +} + +#endif // CXX_HYBRID_PARSER_AGGREGATE_SOURCE_HXX diff --git a/xsde/cxx/hybrid/parser-header.cxx b/xsde/cxx/hybrid/parser-header.cxx new file mode 100644 index 0000000..450a27e --- /dev/null +++ b/xsde/cxx/hybrid/parser-header.cxx @@ -0,0 +1,574 @@ +// file : xsde/cxx/hybrid/parser-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (epimpl_custom (l)); + + // We may not need to generate the class if this parser is + // being customized. + // + if (name) + { + String item (unclash (epskel (l), "item")); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << epskel (l) + << "{" + << "public:" << endl; + + // d-tor & c-tor + // + os << "~" << name << " ();" + << name << " (bool = false);" + << endl; + + // reset + // + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + + // pre + // + os << "virtual void" << endl + << "pre ();" + << endl; + + // item + // + String const& arg (parg_type (l.argumented ().type ())); + + os << "virtual void" << endl + << item << " (" << arg << ");" + << endl; + + // post + // + String const& ret (pret_type (l)); + + os << "virtual " << ret << endl + << post_name (l) << " ();" + << endl; + + // pre_impl + // + String const& type (fq_name (l)); + + os << "void" << endl + << pre_impl_name (l) << " (" << type << "*);" + << endl; + + os << (tiein ? "public:" : "protected:") << endl; + + // State. + // + os << type << "* " << epstate_member (l) << ";" + << "bool " << epstate_base (l) << ";" + << "};"; + } + + // Generate include for custom parser. + // + if (l.context ().count ("p:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + l.context ().get ("p:impl-include")) << endl + << endl; + + open_ns (); + } + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (epimpl_custom (u)); + + // We may not need to generate the class if this parser is + // being customized. + // + if (name) + { + Boolean fl (fixed_length (u)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << epskel (u) + << "{" + << "public:" << endl; + + if (!fl) + { + // d-tor & c-tor + // + os << "~" << name << " ();" + << name << " (bool = false);" + << endl; + + // reset + // + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + } + + // pre + // + os << "virtual void" << endl + << "pre ();" + << endl; + + // _characters + // + os << "virtual void" << endl + << "_characters (const " << string_type << "&);" + << endl; + + // post + // + String const& ret (pret_type (u)); + + os << "virtual " << ret << endl + << post_name (u) << " ();" + << endl; + + String const& type (fq_name (u)); + + // pre_impl + // + if (!fl) + os << "void" << endl + << pre_impl_name (u) << " (" << type << "*);" + << endl; + + os << (tiein ? "public:" : "protected:") << endl; + + // State. + // + String const& state_type (epstate_type (u)); + + os << "struct " << state_type + << "{"; + + if (!fl) + os << type << "* " << "x_;"; + + if (stl) + os << "::std::string str_;"; + else + os << "::xsde::cxx::string str_;"; + + os << "};" + << state_type << " " << epstate (u) << ";"; + + if (!fl) + os << "bool " << epstate_base (u) << ";"; + + os << "};"; + } + + // Generate include for custom parser. + // + if (u.context ().count ("p:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + u.context ().get ("p:impl-include")) << endl + << endl; + + open_ns (); + } + } + }; + + // + // State. + // + + struct CompositorState: Traversal::Compositor, Context + { + CompositorState (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + if (c.max () != 1) + { + String scope (fq_scope (c)); + + os << scope << "::" << etype (c) << "* " << + epstate_member (c) << ";"; + } + + Compositor::traverse (c); + } + }; + + + // + // Callbacks. + // + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + os << "virtual void" << endl + << eppresent (a) << " ();" + << endl; + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + os << "virtual void" << endl + << eparm (c) << " (" << eparm_tag (c) << ");" + << endl; + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + { + os << "virtual void" << endl + << epnext (s) << " ();" + << endl; + } + else if (s.min () == 0) + { + os << "virtual void" << endl + << eppresent (s) << " ();" + << endl; + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& arg (parg_type (e.type ())); + + os << "virtual void" << endl + << epname (e) << " ("; + + if (arg != L"void") + os << arg; + + os << ");" + << endl; + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& arg (parg_type (a.type ())); + + os << "virtual void" << endl + << epname (a) << " ("; + + if (arg != L"void") + os << arg; + + os << ");" + << endl; + } + }; + + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + // State. + // + compositor_state_ (c), + + // Callbacks. + // + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + // State. + // + contains_compositor_state_ >> compositor_state_; + compositor_state_ >> contains_particle_state_; + contains_particle_state_ >> compositor_state_; + + // Callbacks. + // + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (epimpl_custom (c)); + + // We may not need to generate the class if this parser is + // being customized. + // + if (name) + { + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + Boolean hae (has_particle (c)); + + Boolean restriction (restriction_p (c)); + Boolean fixed (fixed_length (c)); + + String const& ret (pret_type (c)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << epskel (c); + + if (mixin && hb) + os << "," << endl + << " public " << fq_name (c.inherits ().base (), "p:impl"); + + os << "{" + << "public:" << endl; + + // c-tor + // + if (!fixed || (hb && tiein)) + os << name << " (" << (fixed ? "" : "bool = false") << ");" + << endl; + + if (!fixed) + { + // d-tor + // + os << "~" << name << " ();" + << endl; + + // reset + // + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + } + + // pre + // + os << "virtual void" << endl + << "pre ();" + << endl; + + // In case of an inheritance-by-restriction, we don't need to + // generate parser callbacks, etc. since they are the same as + // in the base. + // + if (!restriction) + { + if (ha) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + + if (he || hae) + { + os << "// Elements." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_callback_); + } + } + + // post + // + os << "virtual " << ret << endl + << post_name (c) << " ();" + << endl; + + // pre_impl + // + String const& type (fq_name (c)); + + if (!fixed) + os << (tiein ? "public:" : "protected:") << endl + << "void" << endl + << pre_impl_name (c) << " (" << type << "*);" + << endl; + + // State. + // + String const& state_type (epstate_type (c)); + String const& member (epstate_member (c)); + + os << (tiein ? "public:" : "protected:") << endl + << "struct " << state_type + << "{"; + + if (fixed) + os << type << " " << member << ";"; + else + os << type << "* " << member << ";"; + + if (!restriction && c.contains_compositor_p ()) + contains_compositor (c, contains_compositor_state_); + + os << "};" + << state_type << " " << epstate (c) << ";"; + + if (!fixed) + os << "bool " << epstate_base (c) << ";"; + + os << endl; + + // Base implementation. + // + if (tiein && hb) + os << (tiein ? "public:" : "protected:") << endl + << fq_name (c.inherits ().base (), "p:impl") << " base_impl_;" + << endl; + + os << "};"; + } + + // Generate include for custom parser. + // + if (c.context ().count ("p:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + c.context ().get ("p:impl-include")) << endl + << endl; + + open_ns (); + } + } + + private: + // State. + // + CompositorState compositor_state_; + Traversal::ContainsCompositor contains_compositor_state_; + Traversal::ContainsParticle contains_particle_state_; + + // Callbacks. + // + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_parser_header (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::impl_header); + Traversal::Names schema_names; + + Namespace ns (ctx, true); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/parser-header.hxx b/xsde/cxx/hybrid/parser-header.hxx new file mode 100644 index 0000000..1663b3b --- /dev/null +++ b/xsde/cxx/hybrid/parser-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/parser-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_PARSER_HEADER_HXX +#define CXX_HYBRID_PARSER_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_parser_header (Context&); + } +} + +#endif // CXX_HYBRID_PARSER_HEADER_HXX diff --git a/xsde/cxx/hybrid/parser-name-processor.cxx b/xsde/cxx/hybrid/parser-name-processor.cxx new file mode 100644 index 0000000..482c195 --- /dev/null +++ b/xsde/cxx/hybrid/parser-name-processor.cxx @@ -0,0 +1,709 @@ +// file : xsde/cxx/hybrid/parser-name-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + // + // + typedef Cult::Containers::Set NameSet; + + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, + SemanticGraph::Schema& root, + SemanticGraph::Path const& file) + : CXX::Context (std::wcerr, + root, + "name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + schema_path_ (file), + impl_suffix_ (ops.value ()), + aggr_suffix_ (ops.value ()), + options (ops), + schema (root), + schema_path (schema_path_), + aggregate (ops.value ()), + impl_suffix (impl_suffix_), + aggr_suffix (aggr_suffix_), + custom_parser_map (custom_parser_map_), + global_type_names (global_type_names_) + { + // Custom parser mapping. + // + typedef Containers::Vector Vector; + Vector const& v (ops.value ()); + + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); + i != e; ++i) + { + String s (*i); + + if (s.empty ()) + continue; + + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); + + // If no delimiter found then both base and include are empty. + // + if (pos == String::npos) + { + custom_parser_map_[s].base.clear (); + custom_parser_map_[s].include.clear (); + continue; + } + + String name (s, 0, pos); + String rest (s, pos + 1); + + // See if we've got the include part after '/'. + // + pos = rest.find ('/'); + + String base, include; + + if (pos != String::npos) + { + base.assign (rest, 0, pos); + include.assign (rest, pos + 1, String::npos); + } + else + base = rest; + + custom_parser_map_[name].base = base; + custom_parser_map_[name].include = include; + } + } + + protected: + Context (Context& c) + : CXX::Context (c), + options (c.options), + schema (c.schema), + schema_path (c.schema_path), + aggregate (c.aggregate), + impl_suffix (c.impl_suffix), + aggr_suffix (c.aggr_suffix), + custom_parser_map (c.custom_parser_map), + global_type_names (c.global_type_names) + { + } + + public: + Boolean + fixed_length (SemanticGraph::Type& t) + { + return t.context ().get ("fixed"); + } + + public: + String + find_name (String const& n, String const& suffix, NameSet& set) + { + String name (escape (n + suffix)); + + for (UnsignedLong i (1); set.find (name) != set.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + String + find_name (String const& n, NameSet& set) + { + return find_name (n, L"", set); + } + + public: + using CXX::Context::ename; + + static String const& + ename (SemanticGraph::Compositor& c) + { + return c.context ().get ("name"); + } + + String + state_name (SemanticGraph::Compositor& c) + { + using namespace SemanticGraph; + + String r; + + for (Compositor* p (&c);; + p = &p->contained_particle ().compositor ()) + { + if (p->context ().count ("type")) + { + // Not a see-through compositor. + // + if (!r) + r = ename (*p); + else + { + String tmp; + tmp.swap (r); + r = ename (*p); + r += L"_"; + r += tmp; + } + } + + if (p->contained_compositor_p ()) + break; + } + + return r; + } + + String + state_name (SemanticGraph::Element& e) + { + String r (state_name (e.contained_particle ().compositor ())); + + if (!r) + r = ename (e); + else + { + r += L"_"; + r += ename (e); + } + + return r; + } + + public: + struct CustomParser + { + CustomParser (String const& b = L"", String const& i = L"") + : base (b), include (i) + { + } + + String base; + String include; + }; + + typedef + Cult::Containers::Map + CustomParserMap; + + private: + SemanticGraph::Path const schema_path_; + String const impl_suffix_; + String const aggr_suffix_; + CustomParserMap custom_parser_map_; + + Cult::Containers::Map global_type_names_; + + public: + CLI::Options const& options; + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + Boolean aggregate; + String const& impl_suffix; + String const& aggr_suffix; + CustomParserMap const& custom_parser_map; + + Cult::Containers::Map& global_type_names; + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + SemanticGraph::Context& lc (l.context ()); + + // In case of customization use p:impl-base instead of p:impl. + // If the name is empty then we are not generating anything. + // + String const& name (lc.count ("p:impl-base") + ? lc.get ("p:impl-base") + : lc.get ("p:impl")); + if (!name) + return; + + NameSet set; + set.insert (name); + set.insert (unclash (lc.get ("p:name"), "item")); + + lc.set ("pstate-member", + find_name (lc.get ("name"), "_", set)); + + lc.set ("pstate-base", find_name (name + L"_base", "_", set)); + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + SemanticGraph::Context& uc (u.context ()); + + // In case of customization use p:impl-base instead of p:impl. + // If the name is empty then we are not generating anything. + // + String const& name (uc.count ("p:impl-base") + ? uc.get ("p:impl-base") + : uc.get ("p:impl")); + if (!name) + return; + + NameSet set; + set.insert (name); + + String state_type (find_name (name + L"_state", set)); + + uc.set ("pstate-type", state_type); + uc.set ("pstate", find_name (state_type, "_", set)); + + if (!fixed_length (u)) + uc.set ("pstate-base", find_name (name + L"_base", "_", set)); + } + }; + + // State names. + // + + struct CompositorState: Traversal::Compositor, Context + { + CompositorState (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + if (c.max () != 1) + { + SemanticGraph::Context& cc (c.context ()); + cc.set ("pstate-member", find_name (state_name (c), L"_", set_)); + } + + Compositor::traverse (c); + } + + private: + NameSet& set_; + }; + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + Boolean restriction (false); + + if (c.inherits_p ()) + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + + SemanticGraph::Context& cc (c.context ()); + + // In case of customization use p:impl-base instead of p:impl. + // If the name is empty then we are not generating anything. + // + String const& base (cc.count ("p:impl-base") + ? cc.get ("p:impl-base") + : cc.get ("p:impl")); + + if (!base) + return; + + // Use skeleton's name set to make sure we don't clash + // with callbacks which we are overriding. + // + NameSet& set ( + cc.get ("cxx-parser-name-processor-member-set")); + + String state_type (find_name (base + L"_state", set)); + + cc.set ("pstate-type", state_type); + cc.set ("pstate", find_name (state_type, "_", set)); + cc.set ("pstate-base", find_name (base + L"_base", "_", set)); + + // State members are in a nested struct so use a new and + // empty name set. + // + NameSet state_set; + + String member ( + find_name (cc.get ("name"), "_", state_set)); + + cc.set ("pstate-member", member); + state_set.insert (member); + + // Assign state names. + // + if (!restriction && c.contains_compositor_p ()) + { + CompositorState compositor (*this, state_set); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor; + contains_particle >> compositor >> contains_particle; + + Complex::contains_compositor (c, contains_compositor); + } + } + }; + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + String const& name (t.name ()); + + tc.set ("p:impl", find_name (name + impl_suffix, set_)); + + // See if this parser is being customized. + // + CustomParserMap::ConstIterator i (custom_parser_map.find (name)); + + if (i != custom_parser_map.end ()) + { + tc.set ("p:impl-base", i->second.base + ? find_name (i->second.base, set_) + : i->second.base); + + if (i->second.include) + tc.set ("p:impl-include", i->second.include); + } + + if (aggregate) + { + typedef Cult::Containers::Vector Names; + Names const& names (options.value ()); + + // Hopefully nobody will specify more than a handful of names. + // + for (Names::ConstIterator i (names.begin ()); + i != names.end (); ++i) + { + if (name == String (*i)) + { + tc.set ("paggr", find_name (name + aggr_suffix, set_)); + break; + } + } + } + } + + private: + NameSet& set_; + }; + + // + // + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c, NameSet& set) + : Context (c), set_ (set), last_ (0) + { + } + + ~GlobalElement () + { + if (last_ != 0 && options.value ()) + process (*last_); + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + Boolean p (false); + + if (last_ == 0 && options.value ()) + p = true; + + last_ = &e; + + if (!p && + !options.value () && + !options.value () && + !options.value () && + !options.value () && + options.value ().empty ()) + { + // By default process them all. + // + p = true; + } + + if (!p && options.value ()) + p = true; + + if (!p) + { + typedef Cult::Containers::Vector Names; + Names const& names (options.value ()); + + // Hopefully nobody will specify more than a handful of names. + // + for (Names::ConstIterator i (names.begin ()); + !p && i != names.end (); + ++i) + { + if (e.name () == String (*i)) + p = true; + } + } + + if (p) + process (e); + } + + private: + Void + process (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("paggr")) + { + ec.set ("paggr", find_name (e.name () + aggr_suffix, set_)); + } + } + + private: + NameSet& set_; + SemanticGraph::Element* last_; + }; + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& ns) + { + SemanticGraph::Context& nsc (ns.context ()); + String const& name (ns.name ()); + + // Use a name set associated with this namespace if present. + // This will make sure that we don't get any conflicts in the + // multi-mapping translation case. Note that here we assume + // that all mappings traverse schemas in the same order which + // is currently the case. + // + if (global_type_names.find (name) == global_type_names.end ()) + { + if (!nsc.count ("name-set")) + nsc.set ("name-set", NameSet ()); + + NameSet& s (nsc.get ("name-set")); + global_type_names[name] = &s; + } + + NameSet& type_set (*global_type_names[name]); + + // Parser implementations. + // + { + GlobalType type (*this, type_set); + Traversal::Names names (type); + + Traversal::Namespace::names (ns, names); + } + + // Parser aggregates. + // + if (aggregate) + { + GlobalElement element (*this, type_set); + Traversal::Names names (element); + + Traversal::Namespace::names (ns, names); + } + } + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Imports::traverse (i); + } + } + + static Char const* seen_key; + }; + + Char const* Uses::seen_key = "cxx-hybrid-parser-name-processor-seen"; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + Context ctx (ops, tu, file); + + // Pass one - assign names to global types. This pass cannot + // be combined with pass two because of possible recursive + // schema inclusions. Also note that we check first if this + // schema has already been processed which may happen in the + // file-per-type compilation mode. + // + if (!tu.context ().count (Uses::seen_key)) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + + schema >> schema_names >> ns; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set (Uses::seen_key, true); + + schema.dispatch (tu); + } + + // Pass two - assign names inside complex types. Here we don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + ns_names >> list; + ns_names >> union_; + ns_names >> complex; + + schema.dispatch (tu); + } + } + } + + Void ParserNameProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/hybrid/parser-name-processor.hxx b/xsde/cxx/hybrid/parser-name-processor.hxx new file mode 100644 index 0000000..ea3e985 --- /dev/null +++ b/xsde/cxx/hybrid/parser-name-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/hybrid/parser-name-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_PARSER_NAME_PROCESSOR_HXX +#define CXX_HYBRID_PARSER_NAME_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class ParserNameProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_HYBRID_PARSER_NAME_PROCESSOR_HXX diff --git a/xsde/cxx/hybrid/parser-source.cxx b/xsde/cxx/hybrid/parser-source.cxx new file mode 100644 index 0000000..4f5fc38 --- /dev/null +++ b/xsde/cxx/hybrid/parser-source.cxx @@ -0,0 +1,1185 @@ +// file : xsde/cxx/hybrid/parser-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (epimpl_custom (l)); + + if (!name) + return; + + String const& type (fq_name (l)); + String const& base (epstate_base (l)); + String const& member (epstate_member (l)); + String item (unclash (epskel (l), "item")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + os << name << "::" << endl + << name << " (bool b)" + << "{" + << "this->" << base << " = b;" + << "this->" << member << " = 0;" + << "}"; + + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "if (!this->" << base << ")" << endl + << "delete this->" << member << ";" + << "}"; + + // reset + // + if (reset) + os << "void " << name << "::" << endl + << "_reset ()" + << "{" + << epskel (l) << "::_reset ();" + << endl + << "if (!this->" << base << ")" + << "{" + << "delete this->" << member << ";" + << "this->" << member << " = 0;" + << "}" + << "}"; + + // pre_impl + // + os << "void " << name << "::" << endl + << pre_impl_name (l) << " (" << type << "* x)" + << "{" + << "this->" << member << " = x;" + << "}"; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (exceptions) + os << "this->" << pre_impl_name (l) << " (new " << type << ");"; + else + os << type << "* x = new " << type << ";" + << "if (x)" << endl + << "this->" << pre_impl_name (l) << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + + os << "}"; + + // item + // + String const& arg (parg_type (l.argumented ().type ())); + + os << "void " << name << "::" << endl + << item << " (" << arg << " i)" + << "{"; + + if (exceptions) + os << "this->" << member << "->push_back (i);"; + else + os << "if (this->" << member << "->push_back (i))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + + os << "}"; + + // post + // + String const& ret (pret_type (l)); + + os << ret << " " << name << "::" << endl + << post_name (l) << " ()" + << "{" + << type << "* r = this->" << member << ";" + << "this->" << member << " = 0;" + << "return r;" + << "}"; + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (epimpl_custom (u)); + + if (!name) + return; + + String const& type (fq_name (u)); + String const& state (epstate (u)); + String const& ret (pret_type (u)); + String const& value (u.context ().get ("value")); + + os << "// " << name << endl + << "//" << endl + << endl; + + if (stl) + { + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "this->" << state << ".str_.clear ();" + << "}"; + + // _characters + // + os << "void " << name << "::" << endl + << "_characters (const " << string_type << "& s)" + << "{" + << "this->" << state << ".str_.append (s.data (), s.size ());" + << "}"; + + // post + // + os << ret << " " << name << "::" << endl + << post_name (u) << " ()" + << "{" + << "::std::string s;" + << "s.swap (this->" << state << ".str_);" + << type << " r;" + << "r." << value << " (s);" + << "return r;" + << "}"; + } + else + { + String const& base (epstate_base (u)); + + // c-tor + // + os << name << "::" << endl + << name << " (bool b)" + << "{" + << "this->" << base << " = b;" + << "this->" << state << ".x_ = 0;" + << "}"; + + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "if (!this->" << base << ")" << endl + << "delete this->" << state << ".x_;" + << "}"; + + // reset + // + if (reset) + os << "void " << name << "::" << endl + << "_reset ()" + << "{" + << epskel (u) << "::_reset ();" + << endl + << "if (!this->" << base << ")" + << "{" + << "delete this->" << state << ".x_;" + << "this->" << state << ".x_ = 0;" + << "}" + << "}"; + + // pre_impl + // + os << "void " << name << "::" << endl + << pre_impl_name (u) << " (" << type << "* x)" + << "{" + << "this->" << state << ".x_ = x;"; + + if (exceptions) + os << "this->" << state << ".str_.assign (\"\", 0);"; + else + { + os << endl + << "if (this->" << state << ".str_.assign (\"\", 0))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (exceptions) + os << "this->" << pre_impl_name (u) << " (new " << type << ");"; + else + os << type << "* x = new " << type << ";" + << "if (x)" << endl + << "this->" << pre_impl_name (u) << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + + os << "}"; + + // _characters + // + os << "void " << name << "::" << endl + << "_characters (const " << string_type << "& s)" + << "{"; + + if (exceptions) + os << "this->" << state << ".str_.append (s.data (), s.size ());"; + else + { + os << "if (this->" << state << ".str_.append (" << + "s.data (), s.size ()))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + + // post + // + os << ret << " " << name << "::" << endl + << post_name (u) << " ()" + << "{" + << type << "* r = this->" << state << ".x_;" + << "this->" << state << ".x_ = 0;" + << "r->" << value << " (this->" << state << ".str_.detach ());" + << "return r;" + << "}"; + } + } + }; + + struct ParserContext: Context + { + ParserContext (Context& c) + : Context (c) + { + } + + // Return the access sequence up until this particle. If + // element is false then the access sequence for the + // container is returned. Otherwise the access sequence + // for the current element in the container is returned. + // + String + access_seq (SemanticGraph::Particle& p, Boolean element = true) + { + using namespace SemanticGraph; + + String r; + + Boolean seq (false); + + Compositor* c; + + if (p.contained_particle_p ()) + { + c = &p.contained_particle ().compositor (); + + // Check if this particle is a sequence. In this case + // we just need the top-level struct member. + // + if (element && p.max () != 1 && p.is_a ()) + { + seq = true; + } + else + { + for (;; c = &c->contained_particle ().compositor ()) + { + if (c->context ().count ("type")) + { + // Not a see-through compositor. + // + if (c->max () != 1) + { + String const& ptr (epstate_member (*c)); + + if (!r) + { + r = ptr; + r += L"->"; + } + else + { + String tmp; + tmp.swap (r); + r = ptr; + r += L"->"; + r += tmp; + } + + seq = true; + break; + } + else + { + String const& func (ename (*c)); + + if (!r) + { + r = func; + r += L" ()."; + } + else + { + String tmp; + tmp.swap (r); + r = func; + r += L" ()."; + r += tmp; + } + } + } + + if (c->contained_compositor_p ()) + break; + } + } + + // Get to the top in case we bailed out on a sequence. + // + while (!c->contained_compositor_p ()) + c = &c->contained_particle ().compositor (); + } + else + { + // This particle is a top-level compositor. + // + c = &dynamic_cast (p); + seq = element && c->max () != 1; + } + + Complex& t ( + dynamic_cast ( + c->contained_compositor ().container ())); + + if (!seq) + { + Boolean fixed (fixed_length (t)); + String const& s (epstate_member (t)); + + if (!r) + { + r = s; + r += fixed ? L"." : L"->"; + } + else + { + String tmp; + tmp.swap (r); + r = s; + r += fixed ? L"." : L"->"; + r += tmp; + } + } + + String tmp; + tmp.swap (r); + r = epstate (t); + r += L"."; + r += tmp; + + return r; + } + + String + access_seq (SemanticGraph::Attribute& a) + { + using namespace SemanticGraph; + + Complex& t (dynamic_cast (a.scope ())); + + String r (epstate (t)); + r += L"."; + r += epstate_member (t); + r += fixed_length (t) ? L"." : L"->"; + + return r; + } + }; + + // + // Test for presence of var-length compositor in choice + // that need initialization. + // + + struct CompositorTest: Traversal::Compositor + { + CompositorTest (Boolean& p) + : p_ (p) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + // We are only interested in var-length required compositors. + // + if (c.max () == 1 && + c.min () == 1 && + !c.context ().get ("fixed")) + p_ = true; + } + + private: + Boolean& p_; + }; + + // + // Callbacks. + // + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + ParserContext + { + CompositorCallback (Context& c) + : ParserContext (c), compositor_test_ (init_) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + String const& s (epimpl_custom (scope (a))); + + os << "void " << s << "::" << endl + << eppresent (a) << " ()" + << "{"; + + String access (access_seq (a)); + + if (fixed_length (a)) + os << "this->" << access << epresent (a) << " (true);"; + else + { + String const& name (ename (a)); + String const& type (etype (a)); + String const& scope (fq_scope (a)); + + if (exceptions) + os << "this->" << access << name << " (new " << + scope << "::" << type << ");"; + else + os << scope << "::" << type << "* x = new " << + scope << "::" << type << ";" + << "if (x)" << endl + << "this->" << access << name << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + String const& s (epimpl_custom (scope (c))); + String const& access (access_seq (c)); + String const& type_scope (fq_scope (c)); + + os << "void " << s << "::" << endl + << eparm (c) << " (" << eparm_tag (c) << " t)" + << "{"; + + if (c.max () != 1) + { + String const& name (ename (c)); + String const& type (etype (c)); + String const& access_s (access_seq (c, false)); + String const& ptr (epstate_member (c)); + + if (fixed_length (c)) + { + if (exceptions) + os << "this->" << access_s << name << " ().push_back (" << + type_scope << "::" << type << " ());"; + else + os << "if (this->" << access_s << name << " ().push_back (" << + type_scope << "::" << type << " ()))" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + + os << "this->" << access << ptr << " = &this->" << + access_s << name << " ().back ();"; + } + else + { + os << "this->" << access << ptr << " = new " << + type_scope << "::" << type << ";"; + + if (exceptions) + os << "this->" << access_s << name << " ().push_back (" << + "this->" << access << ptr << ");"; + else + os << "if (!this->" << access << ptr << " ||" << endl + << "this->" << access_s << name << " ().push_back (" << + "this->" << access << ptr << "))" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + } + + os << "this->" << access << ptr << "->"; + } + else if (c.min () == 0) + { + String const& name (ename (c)); + + if (fixed_length (c)) + os << "this->" << access << epresent (c) << " (true);"; + else + { + String const& type (etype (c)); + + if (exceptions) + os << "this->" << access << name << " (new " << + type_scope << "::" << type << ");"; + else + os << type_scope << "::" << type << "* x = new " << + type_scope << "::" << type << ";" + << "if (x)" << endl + << "this->" << access << name << " (x);" + << "else" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + } + + os << "this->" << access << name << " ()."; + } + else + { + // We may be in a choice in which case we get a nested + // type (and accessor function) even for min == max == 1. + // + if (c.context ().count ("type")) + os << "this->" << access << ename (c) << " ()."; + else + os << "this->" << access; + } + + os << earm (c) << " (static_cast< " << type_scope; + + if (c.context ().count ("type")) + os << "::" << etype (c); + + os << "::" << earm_tag (c) << " > (t));" + << endl; + + // Test whether we have any arms that need initialization. + // Those are var-length required compositors. + // + init_ = false; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()), e (c.contains_end ()); + !init_ && i != e; ++i) + { + compositor_test_.dispatch (i->particle ()); + } + + if (init_) + { + os << "switch (t)" + << "{"; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()), e (c.contains_end ()); + i != e; ++i) + { + // Test if this arm needs initialization. + // + init_ = false; + compositor_test_.dispatch (i->particle ()); + + if (init_) + { + SemanticGraph::Compositor& p ( + dynamic_cast ( + i->particle ())); + + os << "case " << eptag (p) << ":" + << "{"; + + String const& type (etype (p)); + String const& scope (fq_scope (p)); + + if (exceptions) + os << "this->" << access_seq (p) << ename (p) << + " (new " << scope << "::" << type << ");"; + else + os << scope << "::" << type << "* x = new " << + scope << "::" << type << ";" + << "if (x)" << endl + << "this->" << access_seq (p) << ename (p) << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + + os << "break;" + << "}"; + } + } + + os << "default:" + << "{" + << "break;" + << "}" + << "}"; + } + + os << "}"; + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + { + String const& sc (epimpl_custom (scope (s))); + + String const& access (access_seq (s)); + String const& access_s (access_seq (s, false)); + String const& name (ename (s)); + String const& type (etype (s)); + String const& scope (fq_scope (s)); + String const& ptr (epstate_member (s)); + + os << "void " << sc << "::" << endl + << epnext (s) << " ()" + << "{"; + + if (fixed_length (s)) + { + if (exceptions) + os << "this->" << access_s << name << " ().push_back (" << + scope << "::" << type << " ());"; + else + os << "if (this->" << access_s << name << " ().push_back (" << + scope << "::" << type << " ()))" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + + os << "this->" << access << ptr << " = &this->" << + access_s << name << " ().back ();"; + } + else + { + os << "this->" << access << ptr << " = new " << + scope << "::" << type << ";"; + + if (exceptions) + os << "this->" << access_s << name << " ().push_back (" << + "this->" << access << ptr << ");"; + else + os << "if (!this->" << access << ptr << " ||" << endl + << "this->" << access_s << name << " ().push_back (" << + "this->" << access << ptr << "))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + } + else if (s.min () == 0) + { + String const& sc (epimpl_custom (scope (s))); + + os << "void " << sc << "::" << endl + << eppresent (s) << " ()" + << "{"; + + String access (access_seq (s)); + + if (fixed_length (s)) + os << "this->" << access << epresent (s) << " (true);"; + else + { + String const& name (ename (s)); + String const& type (etype (s)); + String const& scope (fq_scope (s)); + + if (exceptions) + os << "this->" << access << name << " (new " << + scope << "::" << type << ");"; + else + os << scope << "::" << type << "* x = new " << + scope << "::" << type << ";" + << "if (x)" << endl + << "this->" << access << name << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + } + + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Complex& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + + private: + Boolean init_; + CompositorTest compositor_test_; + }; + + struct ParticleCallback: Traversal::Element, ParserContext + { + ParticleCallback (Context& c) + : ParserContext (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Complex; + + String const& name (epname (e)); + String const& arg (parg_type (e.type ())); + Complex& c (dynamic_cast (e.scope ())); + + os << "void " << epimpl_custom (c) << "::" << endl + << name << " ("; + + if (arg != L"void") + { + os << arg << " x)" + << "{"; + + if (e.max () != 1) + { + if (exceptions) + os << "this->" << access_seq (e) << ename (e) << + " ().push_back (x);"; + else + os << "if (this->" << access_seq (e) << ename (e) << + " ().push_back (x))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + else + { + os << "this->" << access_seq (e) << ename (e) << " (x);"; + } + + os << "}"; + } + else + { + os << ")" + << "{" + << "}"; + } + } + }; + + struct AttributeCallback: Traversal::Attribute, ParserContext + { + AttributeCallback (Context& c) + : ParserContext (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Complex; + + String const& name (epname (a)); + String const& arg (parg_type (a.type ())); + Complex& c (dynamic_cast (a.scope ())); + + os << "void " << epimpl_custom (c) << "::" << endl + << name << " ("; + + if (arg != L"void") + { + os << arg << " x)" + << "{" + << "this->" << access_seq (a) << ename (a) << " (x);" + << "}"; + } + else + { + os << ")" + << "{" + << "}"; + } + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + base_name_ (c, TypeName::base), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (epimpl_custom (c)); + + if (!name) + return; + + Boolean hb (c.inherits_p ()); + Boolean restriction (restriction_p (c)); + Boolean fixed (fixed_length (c)); + Boolean c_string_base (false); + + if (!stl && hb) + { + StringType test (c_string_base); + test.dispatch (c.inherits ().base ()); + } + + String const& ret (pret_type (c)); + + String const& state (epstate (c)); + String const& member (epstate_member (c)); + String const& type (fq_name (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (!fixed || (hb && tiein)) + { + os << name << "::" << endl + << name << " (" << (fixed ? "" : "bool b") << ")"; + + if (hb) + { + if (tiein) + os << endl + << ": " << epskel (c) << " (&base_impl_)"; + + SemanticGraph::Type& b (c.inherits ().base ()); + + // C-string-based built-in parser implementations don't + // have c-tor (bool base). + // + if (!c_string_base && !fixed_length (b)) + { + if (tiein) + os << "," << endl + << " " << "base_impl_" << " (true)"; + else + os << endl + << ": " << fq_name (b, "p:impl") << " (true)"; + } + } + + os << "{"; + + if (!fixed) + os << "this->" << epstate_base (c) << " = b;" + << "this->" << state << "." << member << " = 0;"; + + os << "}"; + } + + if (!fixed) + { + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "if (!this->" << epstate_base (c) << ")" << endl + << "delete this->" << state << "." << member << ";" + << "}"; + + // reset + // + if (reset) + os << "void " << name << "::" << endl + << "_reset ()" + << "{"; + + if (mixin && hb) + os << epimpl (c); //@@ fq-name + else + os << epskel (c); //@@ fq-name + + os << "::_reset ();" + << endl; + + os << "if (!this->" << epstate_base (c) << ")" + << "{" + << "delete this->" << state << "." << member << ";" + << "this->" << state << "." << member << " = 0;" + << "}" + << "}"; + } + + // pre_impl + // + if (!fixed) + { + os << "void " << name << "::" << endl + << pre_impl_name (c) << " (" << type << "* x)" + << "{" + << "this->" << state << "." << member << " = x;"; + + // Call base pre_impl (var-length) or pre (fix-length). C-string- + // based built-in parser implementations don't have pre_impl(). + // + if (hb && !c_string_base) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + if (fixed_length (b)) + os << "pre ();"; + else + os << pre_impl_name (b) << " (x);"; + } + + os << "}"; + } + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (fixed) + { + if (hb) + { + // Our base is also fixed-length so call its pre() + // + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (c.inherits ().base ()) << "::"; //@@ fq-name. + + os << "pre ();"; + } + + os << "this->" << state << "." << member << " = " << + type << " ();"; + } + else + { + if (exceptions) + os << "this->" << pre_impl_name (c) << " (new " << type << ");"; + else + os << type << "* x = new " << type << ";" + << "if (x)" << endl + << "this->" << pre_impl_name (c) << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + + // Parser callbacks. + // + if (!restriction) + { + names (c, names_attribute_callback_); + contains_compositor (c, contains_compositor_callback_); + } + + // post + // + os << ret << " " << name << "::" << endl + << post_name (c) << " ()" + << "{"; + + if (hb) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + // Default parser implementations for anyType and + // anySimpleType return void. + // + if (!b.is_a () && + !b.is_a ()) + { + // If our base is a fixed-length type or C-string-base, then + // copy the data over. + // + if (fixed_length (b)) + { + os << "static_cast< "; + + base_name_.dispatch (b); + + os << "& > (" << (fixed ? "" : "*") << "this->" << + state << "." << member << ") = "; + } + + if (c_string_base) + { + os << "static_cast< "; + + base_name_.dispatch (b); + + os << "* > (this->" << + state << "." << member << ")->base_value ("; + } + + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + os << post_name (b) << " ()"; + + if (c_string_base) + os << ")"; + + os << ";"; + } + } + + if (fixed) + os << "return this->" << state << "." << member << ";"; + else + os << type << "* r = this->" << state << "." << member << ";" + << "this->" << state << "." << member << " = 0;" + << "return r;"; + + os << "}"; + } + + private: + TypeName base_name_; + + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_parser_source (Context& ctx) + { + { + // Emit "weak" header includes for the object model types. + // Otherwise we cannot delete the objects of forward-declared + // classes in the parser implementations. + // + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/parser-source.hxx b/xsde/cxx/hybrid/parser-source.hxx new file mode 100644 index 0000000..23f1399 --- /dev/null +++ b/xsde/cxx/hybrid/parser-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/parser-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_PARSER_SOURCE_HXX +#define CXX_HYBRID_PARSER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_parser_source (Context&); + } +} + +#endif // CXX_HYBRID_PARSER_SOURCE_HXX diff --git a/xsde/cxx/hybrid/serializer-aggregate-header.cxx b/xsde/cxx/hybrid/serializer-aggregate-header.cxx new file mode 100644 index 0000000..b697715 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-aggregate-header.cxx @@ -0,0 +1,847 @@ +// file : xsde/cxx/hybrid/serializer-aggregate-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + typedef Cult::Containers::Set InstanceSet; + + // For base types we only want member's types, but not the + // base itself. + // + struct BaseType: Traversal::Complex, Context + { + BaseType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + }; + + struct SerializerDef: Traversal::Type, + Traversal::List, + Traversal::Complex, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + SerializerDef (Context& c, TypeInstanceMap& map, InstanceSet& set) + : Context (c), map_ (map), set_ (set), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (t)); + map_[&t] = inst; + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (map_.find (&l) == map_.end ()) + { + String inst (find_instance_name (l)); + map_[&l] = inst; + + dispatch (l.argumented ().type ()); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (map_.find (&c) == map_.end ()) + { + String inst (find_instance_name (c)); + map_[&c] = inst; + + // Use base type's serializers in case of a restriction + // since we are not capable of using a derived type + // in place of a base (need upcasting, ect). + // + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + fund_type (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + fund_type (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + fund_type (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + fund_type (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + fund_type (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + fund_type (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + fund_type (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + fund_type (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + fund_type (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + fund_type (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + fund_type (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + fund_type (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + fund_type (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + fund_type (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + fund_type (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + fund_type (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + fund_type (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + fund_type (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + fund_type (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + fund_type (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + fund_type (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + fund_type (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + fund_type (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + fund_type (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + fund_type (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + fund_type (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + fund_type (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + fund_type (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + fund_type (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + fund_type (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + fund_type (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + fund_type (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + fund_type (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + fund_type (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + fund_type (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + fund_type (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + fund_type (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + fund_type (t, "day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + fund_type (t, "month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + fund_type (t, "month_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + fund_type (t, "year"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + fund_type (t, "year_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + fund_type (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + fund_type (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + fund_type (t, "entities"); + } + + private: + virtual Void + fund_type (SemanticGraph::Type& t, String const& name) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (name)); + map_[&t] = inst; + } + } + + String + find_instance_name (String const& raw_name) + { + String name (escape (raw_name + L"_s_")); + + for (UnsignedLong i (1); set_.find (name) != set_.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (raw_name + L"_s" + os.str () + L"_"); + } + + set_.insert (name); + return name; + } + + String + find_instance_name (SemanticGraph::Type& t) + { + return find_instance_name (t.name ()); + } + + TypeInstanceMap& map_; + InstanceSet& set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + + if (!tc.count ("saggr")) + return; + + String const& name (tc.get ("saggr")); + + String pre (unclash (name, "pre")); + String post (unclash (name, "post")); + String root_serializer (unclash (name, "root_serializer")); + String error, reset; + + InstanceSet set; + set.insert (pre); + set.insert (post); + set.insert (name); + set.insert (root_serializer); + + if (!exceptions) + { + error = unclash (name, "_error"); + set.insert (error); + } + + if (Context::reset) + { + reset = unclash (name, "reset"); + set.insert (reset); + } + + tc.set ("saggr-map", TypeInstanceMap ()); + TypeInstanceMap& map (tc.get ("saggr-map")); + + SerializerDef def (*this, map, set); + def.dispatch (t); + + String const& root_member (map.find (&t)->second); + + os << "// Serializer aggregate for the " << comment (t.name ()) << + " type." << endl + << "//" << endl; + + os << "class " << name + << "{" + << "public:" << endl; + + // c-tor () + // + os << name << " ();" + << endl; + + // pre () + // + String const& arg (sarg_type (t)); + + os << "void" << endl + << pre << " ("; + + if (arg != L"void") + os << arg << " x"; + + os <<")" + << "{" + << "this->" << root_member << ".pre (" << + (arg != L"void" ? "x" : "") << ");" + << "}"; + + // post () + // + os << "void" << endl + << post << " ()" + << "{" + << "this->" << root_member << ".post ();" + << "}"; + + // root_serializer () + // + os << fq_name (t, "s:impl") << "&" << endl + << root_serializer << " ()" + << "{" + << "return this->" << root_member << ";" + << "}"; + + // _error () + // + if (error) + { + os << xs_ns_name () << "::serializer_error" << endl + << error << " ()" + << "{" + << "return this->" << root_member << "._error ();" + << "}"; + } + + // reset () + // + if (reset) + { + os << "void" << endl + << reset << " ()" + << "{" + << "this->" << root_member << "._reset ();" + << "}"; + } + + os << "public:" << endl; + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + os << fq_name (*i->first, "s:impl") << " " << i->second << ";"; + + os << "};"; + } + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("saggr")) + return; + + SemanticGraph::Type& t (e.type ()); + String const& name (ec.get ("saggr")); + + String pre (unclash (name, "pre")); + String post (unclash (name, "post")); + String root_serializer (unclash (name, "root_serializer")); + String root_name (unclash (name, "root_name")); + String root_namespace (unclash (name, "root_namespace")); + String error, reset; + + InstanceSet set; + set.insert (pre); + set.insert (post); + set.insert (name); + set.insert (root_serializer); + set.insert (root_name); + set.insert (root_namespace); + + if (!exceptions) + { + error = unclash (name, "_error"); + set.insert (error); + } + + if (Context::reset) + { + reset = unclash (name, "reset"); + set.insert (reset); + } + + ec.set ("saggr-map", TypeInstanceMap ()); + TypeInstanceMap& map (ec.get ("saggr-map")); + + SerializerDef def (*this, map, set); + def.dispatch (t); + + String const& root_member (map.find (&t)->second); + + os << "// Serializer aggregate for the " << comment (e.name ()) << + " element." << endl + << "//" << endl; + + os << "class " << name + << "{" + << "public:" << endl; + + // c-tor () + // + os << name << " ();" + << endl; + + // pre () + // + String const& arg (sarg_type (t)); + + os << "void" << endl + << pre << " ("; + + if (arg != L"void") + os << arg << " x"; + + os <<")" + << "{" + << "this->" << root_member << ".pre (" << + (arg != L"void" ? "x" : "") << ");" + << "}"; + + // post () + // + os << "void" << endl + << post << " ()" + << "{" + << "this->" << root_member << ".post ();" + << "}"; + + // root_serializer () + // + os << fq_name (t, "s:impl") << "&" << endl + << root_serializer << " ()" + << "{" + << "return this->" << root_member << ";" + << "}"; + + // root_name () + // + os << "static const char*" << endl + << root_name << " ();" + << endl; + + // root_namespace () + // + os << "static const char*" << endl + << root_namespace << " ();" + << endl; + + // _error () + // + if (error) + { + os << xs_ns_name () << "::serializer_error" << endl + << error << " ()" + << "{" + << "return this->" << root_member << "._error ();" + << "}"; + } + + // reset () + // + if (reset) + { + os << "void" << endl + << reset << " ()" + << "{" + << "this->" << root_member << "._reset ();" + << "}"; + } + + os << "public:" << endl; + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + os << fq_name (*i->first, "s:impl") << " " << i->second << ";"; + + os << "};"; + } + }; + } + + Void + generate_serializer_aggregate_header (Context& ctx) + { + Boolean gen (false); + + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateTest test (gen, "saggr"); + + schema >> schema_names >> ns >> names >> test; + + schema.dispatch (ctx.schema_root); + } + + if (gen) + { + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + GlobalType type (ctx); + GlobalElement element (ctx); + + names >> type; + names >> element; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/hybrid/serializer-aggregate-header.hxx b/xsde/cxx/hybrid/serializer-aggregate-header.hxx new file mode 100644 index 0000000..3fde7b4 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-aggregate-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/serializer-aggregate-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_SERIALIZER_AGGREGATE_HEADER_HXX +#define CXX_HYBRID_SERIALIZER_AGGREGATE_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_serializer_aggregate_header (Context&); + } +} + +#endif // CXX_HYBRID_SERIALIZER_AGGREGATE_HEADER_HXX diff --git a/xsde/cxx/hybrid/serializer-aggregate-source.cxx b/xsde/cxx/hybrid/serializer-aggregate-source.cxx new file mode 100644 index 0000000..7e305b6 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-aggregate-source.cxx @@ -0,0 +1,330 @@ +// file : xsde/cxx/hybrid/serializer-aggregate-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + // + // + struct ParticleArg: Traversal::Element, Context + { + ParticleArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&e.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct AttributeArg: Traversal::Attribute, Context + { + AttributeArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&a.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct ArgList : Traversal::Complex, + Traversal::List, + Context + { + ArgList (Context& c, TypeInstanceMap& map) + : Context (c), + map_ (map), + particle_ (c, map, first_), + attribute_ (c, map, first_), + first_ (true) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << "this->" << map_[&l.argumented ().type ()]; + } + + private: + TypeInstanceMap& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleArg particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + AttributeArg attribute_; + + Boolean first_; + }; + + struct SerializerConnect: Traversal::List, + Traversal::Complex, + Context + { + SerializerConnect (Context& c, TypeInstanceMap& map) + : Context (c), map_ (map) + { + } + + virtual Void + traverse (SemanticGraph::List& l) + { + os << "this->" << map_[&l] << ".serializers (this->" << + map_[&l.argumented ().type ()] << ");" + << endl; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (has_members (c)) + { + os << "this->" << map_[&c] << ".serializers ("; + + ArgList args (*this, map_); + args.dispatch (c); + + os << ");" + << endl; + } + } + + private: + Boolean + has_members (SemanticGraph::Complex& c) + { + using SemanticGraph::Complex; + + if (has (c)) + return true; + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&b)) + return has_members (*cb); + + return b.is_a (); + } + + return false; + } + + private: + TypeInstanceMap& map_; + }; + + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + + if (!tc.count ("saggr")) + return; + + String const& name (tc.get ("saggr")); + TypeInstanceMap& map (tc.get ("saggr-map")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor () + // + os << name << "::" << endl + << name << " ()" + << "{"; + + SerializerConnect connect (*this, map); + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + connect.dispatch (*i->first); + + os << "}"; + } + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("saggr")) + return; + + String const& name (ec.get ("saggr")); + TypeInstanceMap& map (ec.get ("saggr-map")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor () + // + os << name << "::" << endl + << name << " ()" + << "{"; + + SerializerConnect connect (*this, map); + + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + connect.dispatch (*i->first); + + os << "}"; + + // root_name () + // + String root_name (unclash (name, "root_name")); + + os << "const char* " << name << "::" << endl + << root_name << " ()" + << "{" + << "return " << strlit (e.name ()) << ";" + << "}"; + + // root_namespace () + // + String root_namespace (unclash (name, "root_namespace")); + + os << "const char* " << name << "::" << endl + << root_namespace << " ()" + << "{" + << "return " << strlit (e.namespace_ ().name ()) << ";" + << "}"; + } + }; + } + + Void + generate_serializer_aggregate_source (Context& ctx) + { + Boolean gen (false); + + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateTest test (gen, "saggr"); + + schema >> schema_names >> ns >> names >> test; + + schema.dispatch (ctx.schema_root); + } + + if (gen) + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + GlobalType type (ctx); + GlobalElement element (ctx); + + names >> type; + names >> element; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/hybrid/serializer-aggregate-source.hxx b/xsde/cxx/hybrid/serializer-aggregate-source.hxx new file mode 100644 index 0000000..c011366 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-aggregate-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/serializer-aggregate-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_SERIALIZER_AGGREGATE_SOURCE_HXX +#define CXX_HYBRID_SERIALIZER_AGGREGATE_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_serializer_aggregate_source (Context&); + } +} + +#endif // CXX_HYBRID_SERIALIZER_AGGREGATE_SOURCE_HXX diff --git a/xsde/cxx/hybrid/serializer-header.cxx b/xsde/cxx/hybrid/serializer-header.cxx new file mode 100644 index 0000000..c6fbc6c --- /dev/null +++ b/xsde/cxx/hybrid/serializer-header.cxx @@ -0,0 +1,534 @@ +// file : xsde/cxx/hybrid/serializer-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (esimpl_custom (l)); + + // We may not need to generate the class if this serializer is + // being customized. + // + if (name) + { + String const& skel (esskel (l)); + String const& arg (sarg_type (l)); + String const& ret (sret_type (l.argumented ().type ())); + + String item (unclash (skel, "item")); + String item_next (unclash (skel, "item_next")); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << skel + << "{" + << "public:" << endl; + + // pre + // + os << "virtual void" << endl + << "pre (" << arg << ");" + << endl; + + // item_next + // + os << "virtual bool" << endl + << item_next << " ();" + << endl; + + // item + // + os << "virtual " << ret << endl + << item << " ();" + << endl; + + // State. + // + os << (tiein ? "public:" : "protected:") << endl; + + String const& type (fq_name (l)); + String const& state_type (esstate_type (l)); + + os << "struct " << state_type + << "{" + << type << "::const_iterator i_;" + << type << "::const_iterator end_;" + << "};" + << state_type << " " << esstate (l) << ";" + << "};"; + } + + // Generate include for custom serializer. + // + if (l.context ().count ("s:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + l.context ().get ("s:impl-include")) << endl + << endl; + + open_ns (); + } + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (esimpl_custom (u)); + + // We may not need to generate the class if this serializer is + // being customized. + // + if (name) + { + String const& arg (sarg_type (u)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << esskel (u) + << "{" + << "public:" << endl; + + // pre + // + os << "virtual void" << endl + << "pre (" << arg << ");" + << endl; + + // _serialize_content + // + os << "virtual void" << endl + << "_serialize_content ();" + << endl; + + // State. + // + os << (tiein ? "public:" : "protected:") << endl + << "const " << fq_name (u) << "* " << esstate (u) << ";" + << "};"; + } + + // Generate include for custom serializer. + // + if (u.context ().count ("s:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + u.context ().get ("s:impl-include")) << endl + << endl; + + open_ns (); + } + } + }; + + // + // State. + // + + struct CompositorState: Traversal::Compositor, Context + { + CompositorState (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + if (c.max () != 1) + { + String scope (fq_scope (c)); + String const& const_iterator (econst_iterator (c)); + + os << scope << "::" << const_iterator << " " << + esstate_member (c) << ";" + << scope << "::" << const_iterator << " " << + esstate_member_end (c) << ";"; + } + + Compositor::traverse (c); + } + }; + + struct ParticleState: Traversal::Element, Context + { + ParticleState (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + { + String scope (fq_scope (e)); + String const& const_iterator (econst_iterator (e)); + + os << scope << "::" << const_iterator << " " << + esstate_member (e) << ";" + << scope << "::" << const_iterator << " " << + esstate_member_end (e) << ";"; + } + } + }; + + // + // Callbacks. + // + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + os << "virtual bool" << endl + << espresent (a) << " ();" + << endl; + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << espresent (c) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << esnext (c) << " ();" + << endl; + } + + os << "virtual " << esarm_tag (c) << endl + << esarm (c) << " ();" + << endl; + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << espresent (s) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << esnext (s) << " ();" + << endl; + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << espresent (e) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << esnext (e) << " ();" + << endl; + } + + String const& ret (sret_type (e.type ())); + + os << "virtual " << ret << endl + << esname (e) << " ();" + << endl; + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + if (a.optional ()) + { + os << "virtual bool" << endl + << espresent (a) << " ();" + << endl; + } + + String const& ret (sret_type (a.type ())); + + os << "virtual " << ret << endl + << esname (a) << " ();" + << endl; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + + // State. + // + compositor_state_ (c), + particle_state_ (c), + + // Callbacks. + // + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + // State. + // + contains_compositor_state_ >> compositor_state_; + compositor_state_ >> contains_particle_state_; + contains_particle_state_ >> compositor_state_; + contains_particle_state_ >> particle_state_; + + + // Callbacks. + // + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (esimpl_custom (c)); + + // We may not need to generate the class if this serializer is + // being customized. + // + if (name) + { + // In case of an inheritance-by-restriction, we don't need to + // generate serializer callbacks, etc. since they are the same + // as in the base. We only need the serialization/validation code. + // + Boolean restriction (restriction_p (c)); + + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + Boolean haa (has (c)); + + String const& arg (sarg_type (c)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << esskel (c); + + if (mixin && hb) + os << "," << endl + << " public " << fq_name (c.inherits ().base (), "s:impl"); + + os << "{" + << "public:" << endl; + + // c-tor + // + if (tiein && hb) + os << name << " ();" + << endl; + + // pre + // + os << "virtual void" << endl + << "pre (" << arg << ");" + << endl; + + // Member callbacks. + // + if (!restriction && (ha || he || hae || haa)) + { + if (ha || haa) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + + if (he || hae) + { + os << "// Elements." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_callback_); + } + } + + if (!restriction) + { + String const& state_type (esstate_type (c)); + String const& member (esstate_member (c)); + + os << "protected:" << endl + << "struct " << state_type + << "{" + << "const " << fq_name (c) << "* " << member << ";"; + + if (c.contains_compositor_p ()) + contains_compositor (c, contains_compositor_state_); + + os << "};" + << state_type << " " << esstate (c) << ";"; + } + + if (tiein && hb) + os << endl + << "protected:" << endl + << fq_name (c.inherits ().base (), "s:impl") << " base_impl_;"; + + os << "};"; + } + + // Generate include for custom serializer. + // + if (c.context ().count ("s:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + c.context ().get ("s:impl-include")) << endl + << endl; + + open_ns (); + } + } + + private: + // State. + // + CompositorState compositor_state_; + ParticleState particle_state_; + Traversal::ContainsCompositor contains_compositor_state_; + Traversal::ContainsParticle contains_particle_state_; + + // Callbacks. + // + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_serializer_header (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::impl_header); + Traversal::Names schema_names; + + Namespace ns (ctx, true); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/serializer-header.hxx b/xsde/cxx/hybrid/serializer-header.hxx new file mode 100644 index 0000000..d24bc6a --- /dev/null +++ b/xsde/cxx/hybrid/serializer-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/serializer-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_SERIALIZER_HEADER_HXX +#define CXX_HYBRID_SERIALIZER_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_serializer_header (Context&); + } +} + +#endif // CXX_HYBRID_SERIALIZER_HEADER_HXX diff --git a/xsde/cxx/hybrid/serializer-name-processor.cxx b/xsde/cxx/hybrid/serializer-name-processor.cxx new file mode 100644 index 0000000..8d3c15d --- /dev/null +++ b/xsde/cxx/hybrid/serializer-name-processor.cxx @@ -0,0 +1,723 @@ +// file : xsde/cxx/hybrid/serializer-name-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + // + // + typedef Cult::Containers::Set NameSet; + + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, + SemanticGraph::Schema& root, + SemanticGraph::Path const& file) + : CXX::Context (std::wcerr, + root, + "name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + schema_path_ (file), + impl_suffix_ (ops.value ()), + aggr_suffix_ (ops.value ()), + options (ops), + schema (root), + schema_path (schema_path_), + aggregate (ops.value ()), + impl_suffix (impl_suffix_), + aggr_suffix (aggr_suffix_), + custom_serializer_map (custom_serializer_map_), + global_type_names (global_type_names_) + { + // Custom serializer mapping. + // + typedef Containers::Vector Vector; + Vector const& v (ops.value ()); + + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); + i != e; ++i) + { + String s (*i); + + if (s.empty ()) + continue; + + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); + + // If no delimiter found then both base and include are empty. + // + if (pos == String::npos) + { + custom_serializer_map_[s].base.clear (); + custom_serializer_map_[s].include.clear (); + continue; + } + + String name (s, 0, pos); + String rest (s, pos + 1); + + // See if we've got the include part after '/'. + // + pos = rest.find ('/'); + + String base, include; + + if (pos != String::npos) + { + base.assign (rest, 0, pos); + include.assign (rest, pos + 1, String::npos); + } + else + base = rest; + + custom_serializer_map_[name].base = base; + custom_serializer_map_[name].include = include; + } + } + + protected: + Context (Context& c) + : CXX::Context (c), + options (c.options), + schema (c.schema), + schema_path (c.schema_path), + aggregate (c.aggregate), + impl_suffix (c.impl_suffix), + aggr_suffix (c.aggr_suffix), + custom_serializer_map (c.custom_serializer_map), + global_type_names (c.global_type_names) + { + } + + public: + String + find_name (String const& n, String const& suffix, NameSet& set) + { + String name (escape (n + suffix)); + + for (UnsignedLong i (1); set.find (name) != set.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + String + find_name (String const& n, NameSet& set) + { + return find_name (n, L"", set); + } + + public: + using CXX::Context::ename; + + static String const& + ename (SemanticGraph::Compositor& c) + { + return c.context ().get ("name"); + } + + String + state_name (SemanticGraph::Compositor& c) + { + using namespace SemanticGraph; + + String r; + + for (Compositor* p (&c);; + p = &p->contained_particle ().compositor ()) + { + if (p->context ().count ("type")) + { + // Not a see-through compositor. + // + if (!r) + r = ename (*p); + else + { + String tmp; + tmp.swap (r); + r = ename (*p); + r += L"_"; + r += tmp; + } + } + + if (p->contained_compositor_p ()) + break; + } + + return r; + } + + String + state_name (SemanticGraph::Element& e) + { + String r (state_name (e.contained_particle ().compositor ())); + + if (!r) + r = ename (e); + else + { + r += L"_"; + r += ename (e); + } + + return r; + } + + public: + struct CustomSerializer + { + CustomSerializer (String const& b = L"", String const& i = L"") + : base (b), include (i) + { + } + + String base; + String include; + }; + + typedef + Cult::Containers::Map + CustomSerializerMap; + + private: + SemanticGraph::Path const schema_path_; + String const impl_suffix_; + String const aggr_suffix_; + CustomSerializerMap custom_serializer_map_; + + Cult::Containers::Map global_type_names_; + + public: + CLI::Options const& options; + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + Boolean aggregate; + String const& impl_suffix; + String const& aggr_suffix; + CustomSerializerMap const& custom_serializer_map; + + Cult::Containers::Map& global_type_names; + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + SemanticGraph::Context& lc (l.context ()); + + // In case of customization use s:impl-base instead of s:impl. + // If the name is empty then we are not generating anything. + // + String const& name (lc.count ("s:impl-base") + ? lc.get ("s:impl-base") + : lc.get ("s:impl")); + if (!name) + return; + + String const& skel (lc.get ("p:name")); + + NameSet set; + set.insert (name); + set.insert (unclash (skel, "item")); + set.insert (unclash (skel, "item_next")); + + String state_type (find_name (name + L"_state", set)); + lc.set ("sstate-type", state_type); + lc.set ("sstate", find_name (state_type, "_", set)); + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + SemanticGraph::Context& uc (l.context ()); + + // In case of customization use s:impl-base instead of s:impl. + // If the name is empty then we are not generating anything. + // + String const& name (uc.count ("s:impl-base") + ? uc.get ("s:impl-base") + : uc.get ("s:impl")); + if (!name) + return; + + NameSet set; + set.insert (name); + + uc.set ("sstate", find_name (name + L"_state", "_", set)); + } + }; + + // State names. + // + + struct CompositorState: Traversal::Compositor, Context + { + CompositorState (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + if (c.max () != 1) + { + SemanticGraph::Context& cc (c.context ()); + String b (state_name (c)); + cc.set ("sstate-member", find_name (b, L"_", set_)); + cc.set ("sstate-member-end", find_name (b + L"_end", L"_", set_)); + } + + Compositor::traverse (c); + } + + private: + NameSet& set_; + }; + + struct ParticleState: Traversal::Element, Context + { + ParticleState (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + { + SemanticGraph::Context& ec (e.context ()); + String b (state_name (e)); + ec.set ("sstate-member", find_name (b, L"_", set_)); + ec.set ("sstate-member-end", find_name (b + L"_end", L"_", set_)); + } + } + + private: + NameSet& set_; + }; + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + Boolean restriction (false); + + if (c.inherits_p ()) + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + + SemanticGraph::Context& cc (c.context ()); + + // In case of customization use s:impl-base instead of s:impl. + // If the name is empty then we are not generating anything. + // + String const& base (cc.count ("s:impl-base") + ? cc.get ("s:impl-base") + : cc.get ("s:impl")); + if (!base) + return; + + // Use skeleton's name set to make sure we don't clash + // with callbacks which we are overriding. + // + NameSet& set ( + cc.get ("cxx-serializer-name-processor-member-set")); + + String state_type (find_name (base + L"_state", set)); + cc.set ("sstate-type", state_type); + cc.set ("sstate", find_name (state_type, "_", set)); + + // State members are in a nested struct so use a new and + // empty name set. + // + NameSet state_set; + + String member ( + find_name (cc.get ("name"), "_", state_set)); + + cc.set ("sstate-member", member); + state_set.insert (member); + + // Assign state names. + // + if (!restriction && c.contains_compositor_p ()) + { + ParticleState particle (*this, state_set); + CompositorState compositor (*this, state_set); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + } + }; + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& tc (t.context ()); + String const& name (t.name ()); + + tc.set ("s:impl", find_name (name + impl_suffix, set_)); + + // See if this serializer is being customized. + // + CustomSerializerMap::ConstIterator i ( + custom_serializer_map.find (name)); + + if (i != custom_serializer_map.end ()) + { + tc.set ("s:impl-base", i->second.base + ? find_name (i->second.base, set_) + : i->second.base); + + if (i->second.include) + tc.set ("s:impl-include", i->second.include); + } + + if (aggregate) + { + typedef Cult::Containers::Vector Names; + Names const& names (options.value ()); + + // Hopefully nobody will specify more than a handful of names. + // + for (Names::ConstIterator i (names.begin ()); + i != names.end (); ++i) + { + if (name == String (*i)) + { + tc.set ("saggr", find_name (name + aggr_suffix, set_)); + break; + } + } + } + } + + private: + NameSet& set_; + }; + + // + // + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c, NameSet& set) + : Context (c), set_ (set), last_ (0) + { + } + + ~GlobalElement () + { + if (last_ != 0 && options.value ()) + process (*last_); + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + Boolean p (false); + + if (last_ == 0 && options.value ()) + p = true; + + last_ = &e; + + if (!p && + !options.value () && + !options.value () && + !options.value () && + !options.value () && + options.value ().empty ()) + { + // By default process them all. + // + p = true; + } + + if (!p && options.value ()) + p = true; + + if (!p) + { + typedef Cult::Containers::Vector Names; + Names const& names (options.value ()); + + // Hopefully nobody will specify more than a handful of names. + // + for (Names::ConstIterator i (names.begin ()); + !p && i != names.end (); + ++i) + { + if (e.name () == String (*i)) + p = true; + } + } + + if (p) + process (e); + } + + private: + Void + process (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!ec.count ("saggr")) + { + ec.set ("saggr", find_name (e.name () + aggr_suffix, set_)); + } + } + + private: + NameSet& set_; + SemanticGraph::Element* last_; + }; + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& ns) + { + SemanticGraph::Context& nsc (ns.context ()); + String const& name (ns.name ()); + + // Use a name set associated with this namespace if present. + // This will make sure that we don't get any conflicts in the + // multi-mapping translation case. Note that here we assume + // that all mappings traverse schemas in the same order which + // is currently the case. + // + if (global_type_names.find (name) == global_type_names.end ()) + { + if (!nsc.count ("name-set")) + nsc.set ("name-set", NameSet ()); + + NameSet& s (nsc.get ("name-set")); + global_type_names[name] = &s; + } + + NameSet& type_set (*global_type_names[name]); + + // Serializer implementations. + // + { + GlobalType type (*this, type_set); + Traversal::Names names (type); + + Traversal::Namespace::names (ns, names); + } + + // Serializer aggregates. + // + if (aggregate) + { + GlobalElement element (*this, type_set); + Traversal::Names names (element); + + Traversal::Namespace::names (ns, names); + } + } + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count (seen_key)) + { + s.context ().set (seen_key, true); + Traversal::Imports::traverse (i); + } + } + + static Char const* seen_key; + }; + + Char const* Uses::seen_key = "cxx-hybrid-serializer-name-processor-seen"; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + Context ctx (ops, tu, file); + + // Pass one - assign names to global types. This pass cannot + // be combined with pass two because of possible recursive + // schema inclusions. Also note that we check first if this + // schema has already been processed which may happen in the + // file-per-type compilation mode. + // + if (!tu.context ().count (Uses::seen_key)) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + + schema >> schema_names >> ns; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set (Uses::seen_key, true); + + schema.dispatch (tu); + } + + // Pass two - assign names inside complex types. Here we don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + ns_names >> list; + ns_names >> union_; + ns_names >> complex; + + schema.dispatch (tu); + } + } + } + + Void SerializerNameProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/hybrid/serializer-name-processor.hxx b/xsde/cxx/hybrid/serializer-name-processor.hxx new file mode 100644 index 0000000..f69dfe4 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-name-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/hybrid/serializer-name-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_SERIALIZER_NAME_PROCESSOR_HXX +#define CXX_HYBRID_SERIALIZER_NAME_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class SerializerNameProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_HYBRID_SERIALIZER_NAME_PROCESSOR_HXX diff --git a/xsde/cxx/hybrid/serializer-source.cxx b/xsde/cxx/hybrid/serializer-source.cxx new file mode 100644 index 0000000..37fff42 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-source.cxx @@ -0,0 +1,1001 @@ +// file : xsde/cxx/hybrid/serializer-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + // Some built-in types are passed by pointer to built-in serializer + // implementations. + // + struct TypePass: Traversal::Fundamental::NameTokens, + Traversal::Fundamental::QName, + Traversal::Fundamental::IdRefs, + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + Traversal::Fundamental::Entities, + Context + { + TypePass (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens&) + { + os << "&"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::QName&) + { + if (!stl) + os << "&"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs&) + { + os << "&"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary&) + { + os << "&"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary&) + { + os << "&"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities&) + { + os << "&"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c), type_pass_ (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (esimpl_custom (l)); + + if (!name) + return; + + SemanticGraph::Type& t (l.argumented ().type ()); + + String const& skel (esskel (l)); + String const& arg (sarg_type (l)); + String const& ret (sret_type (t)); + + String item (unclash (skel, "item")); + String item_next (unclash (skel, "item_next")); + + os << "// " << name << endl + << "//" << endl + << endl; + + String const& state (esstate (l)); + + // pre + // + os << "void " << name << "::" << endl + << "pre (" << arg << " x)" + << "{" + << "this->" << state << ".i_ = x.begin ();" + << "this->" << state << ".end_ = x.end ();" + << "}"; + + // item_next + // + os << "bool " << name << "::" << endl + << item_next << " ()" + << "{" + << "return this->" << state << ".i_ != this->" << + state << ".end_;" + << "}"; + + // item + // + os << ret << " " << name << "::" << endl + << item << " ()" + << "{" + << "return "; + + type_pass_.dispatch (t); + + os << "*this->" << state << ".i_++;" + << "}"; + } + + private: + TypePass type_pass_; + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (esimpl_custom (u)); + + if (!name) + return; + + String const& state (esstate (u)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + String const& arg (sarg_type (u)); + + os << "void " << name << "::" << endl + << "pre (" << arg << " x)" + << "{" + << "this->" << state << " = &x;" + << "}"; + + // _serialize_content + // + String const& value (u.context ().get ("value")); + + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{"; + + if (stl) + { + os << "const ::std::string& s = this->" << state << "->" << + value << " ();" + << "this->_characters (s.c_str (), s.size ());"; + } + else + os << "this->_characters (" << + "this->" << state << "->" << value << " ());"; + + os << "}"; + } + }; + + // + // + struct SerializerContext: Context + { + SerializerContext (Context& c) + : Context (c) + { + } + + // Return the access sequence up until this particle. If + // element is false then the access sequence for the + // container is returned. Otherwise the access sequence + // for the current element in the container is returned. + // + String + access_seq (SemanticGraph::Particle& p, Boolean element = true) + { + using namespace SemanticGraph; + + String r; + + Boolean seq (false); + + Compositor* c; + + if (p.contained_particle_p ()) + { + c = &p.contained_particle ().compositor (); + + // Check if this particle is a sequence. In this case + // we just need the top-level struct member. + // + if (element && p.max () != 1) + { + seq = true; + } + else + { + for (;; c = &c->contained_particle ().compositor ()) + { + if (c->context ().count ("type")) + { + // Not a see-through compositor. + // + if (c->max () != 1) + { + String const& iter (esstate_member (*c)); + + if (!r) + { + r = iter; + r += L"->"; + } + else + { + String tmp; + tmp.swap (r); + r = iter; + r += L"->"; + r += tmp; + } + + seq = true; + break; + } + else + { + String const& func (ename (*c)); + + if (!r) + { + r = func; + r += L" ()."; + } + else + { + String tmp; + tmp.swap (r); + r = func; + r += L" ()."; + r += tmp; + } + } + } + + if (c->contained_compositor_p ()) + break; + } + } + + // Get to the top in case we bailed out on a sequence. + // + while (!c->contained_compositor_p ()) + c = &c->contained_particle ().compositor (); + } + else + { + // This particle is a top-level compositor. + // + c = &dynamic_cast (p); + seq = element && c->max () != 1; + } + + Complex& t ( + dynamic_cast ( + c->contained_compositor ().container ())); + + if (!seq) + { + String const& s (esstate_member (t)); + + if (!r) + { + r = s; + r += L"->"; + } + else + { + String tmp; + tmp.swap (r); + r = s; + r += L"->"; + r += tmp; + } + } + + String tmp; + tmp.swap (r); + r = esstate (t); + r += L"."; + r += tmp; + + return r; + } + + String + access_seq (SemanticGraph::Attribute& a) + { + using namespace SemanticGraph; + + Complex& t (dynamic_cast (a.scope ())); + + String r (esstate (t)); + r += L"."; + r += esstate_member (t); + r += L"->"; + + return r; + } + }; + + // + // Test for presence of sequences. + // + + struct CompositorTest: Traversal::Choice, + Traversal::Sequence + { + CompositorTest (Boolean& seq) + : seq_ (seq) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () != 1) + seq_ = true; + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + seq_ = true; + else if (s.min () == 1) + { + // Test nested particles of the see-through sequence. + // + Sequence::traverse (s); + } + } + + private: + Boolean& seq_; + }; + + struct ParticleTest: Traversal::Element + { + ParticleTest (Boolean& seq) + : seq_ (seq) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + seq_ = true; + } + + private: + Boolean& seq_; + }; + + // + // State initializers. + // + + struct CompositorInit: Traversal::Choice, + Traversal::Sequence, + SerializerContext + { + CompositorInit (Context& c) + : SerializerContext (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () != 1) + { + String access (access_seq (c)); + String access_s (access_seq (c, false)); + String const& iter (esstate_member (c)); + String const& end (esstate_member_end (c)); + + // Initialize the iterator. + // + os << "this->" << access << end << " = this->" << + access_s << ename (c) << " ().end ();" + << "this->" << access << iter << " = this->" << + access << end << ";"; + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + { + String access (access_seq (s)); + String access_s (access_seq (s, false)); + String const& iter (esstate_member (s)); + String const& end (esstate_member_end (s)); + + // Initialize the iterator. + // + os << "this->" << access << end << " = this->" << + access_s << ename (s) << " ().end ();" + << "this->" << access << iter << " = this->" << + access << end << ";"; + } + else if (s.min () == 1) + { + // Initialize nested particles of the see-through sequence. + // + Sequence::traverse (s); + } + } + }; + + struct ParticleInit: Traversal::Element, SerializerContext + { + ParticleInit (Context& c) + : SerializerContext (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + { + String access (access_seq (e)); + String access_s (access_seq (e, false)); + String const& iter (esstate_member (e)); + String const& end (esstate_member_end (e)); + String const& name (ename (e)); + + // Initialize the iterator. + // + os << "this->" << access << iter << " = this->" << + access_s << name << " ().begin ();" + << "this->" << access << end << " = this->" << + access_s << name << " ().end ();"; + } + } + }; + + // + // Callbacks. + // + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + SerializerContext + { + CompositorCallback (Context& c, Traversal::ContainsParticle& init) + : SerializerContext (c), + init_ (init), + compositor_test_ (seq_), + particle_test_ (seq_) + { + compositor_test_ >> contains_particle_test_; + contains_particle_test_ >> compositor_test_; + contains_particle_test_ >> particle_test_; + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + String const& s (esimpl_custom (scope (a))); + + os << "bool " << s << "::" << endl + << espresent (a) << " ()" + << "{" + << "return this->" << access_seq (a) << epresent (a) << " ();" + << "}"; + } + + All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + SemanticGraph::Complex& t (scope (c)); + + String access (access_seq (c)); + String const& s (esimpl_custom (t)); + String const& arm_tag (esarm_tag (c)); + + if (c.max () != 1) + { + String access_s (access_seq (c, false)); + String const& iter (esstate_member (c)); + String const& end (esstate_member_end (c)); + + // When iterating over a compositor sequence, there is no + // simple place to increment the iterator. So we will need + // to increment it in *_next() and make sure we handle the + // first call in a special way. + // + os << "bool " << s << "::" << endl + << esnext (c) << " ()" + << "{" + << "if (this->" << access << iter << " != this->" << + access << end << ")" << endl + << "this->" << access << iter << "++;" + << "else" << endl + << "this->" << access << iter << " = this->" << + access_s << ename (c) << " ().begin ();" + << endl + << "return this->" << access << iter << " != this->" << + access << end << ";" + << "}"; + + os << esskel (t) << "::" << arm_tag << " " << s << "::" << endl + << esarm (c) << " ()" + << "{" + << arm_tag << " t (static_cast< " << arm_tag << " > (" << endl + << "this->" << access << iter << "->" << earm (c) << " ()));"; + } + else if (c.min () == 0) + { + os << "bool " << s << "::" << endl + << espresent (c) << " ()" + << "{" + << "return this->" << access << epresent (c) << " ();" + << "}"; + + os << esskel (t) << "::" << arm_tag << " " << s << "::" << endl + << esarm (c) << " ()" + << "{" + << arm_tag << " t (static_cast< " << arm_tag << " > (" << endl + << "this->" << access << ename (c) << " ()." << + earm (c) << " ()));"; + } + else + { + os << esskel (t) << "::" << arm_tag << " " << s << "::" << endl + << esarm (c) << " ()" + << "{" + << arm_tag << " t (static_cast< " << arm_tag << " > (" << endl; + + + // We may be in a choice in which case we get a nested + // type (and accessor function) even for min == max == 1. + // + if (c.context ().count ("type")) + os << "this->" << access << ename (c) << " ()." << + earm (c) << " ()));"; + else + os << "this->" << access << earm (c) << " ()));"; + } + + // Test whether we have any arms that need initialization. + // + seq_ = false; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()), e (c.contains_end ()); + !seq_ && i != e; ++i) + { + contains_particle_test_.dispatch (*i); + } + + if (seq_) + { + os << "switch (t)" + << "{"; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()), e (c.contains_end ()); + i != e; ++i) + { + // Test if this arm needs initialization. + // + seq_ = false; + contains_particle_test_.dispatch (*i); + + if (seq_) + { + SemanticGraph::Particle& p (i->particle ()); + + os << "case " << estag (p) << ":" + << "{"; + init_.dispatch (*i); + os << "break;" + << "}"; + } + } + + os << "default:" + << "{" + << "break;" + << "}" + << "}"; + } + + os << "return t;" + << "}"; + + Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + String const& sc (esimpl_custom (scope (s))); + + if (s.max () != 1) + { + String access (access_seq (s)); + String access_s (access_seq (s, false)); + String const& iter (esstate_member (s)); + String const& end (esstate_member_end (s)); + + // When iterating over a compositor sequence, there is no + // simple place to increment the iterator. So we will need + // to increment it in *_next() and make sure we handle the + // first call in a special way. + // + os << "bool " << sc << "::" << endl + << esnext (s) << " ()" + << "{" + << "if (this->" << access << iter << " != this->" << + access << end << ")" << endl + << "this->" << access << iter << "++;" + << "else" << endl + << "this->" << access << iter << " = this->" << + access_s << ename (s) << " ().begin ();" + << endl + << "if (this->" << access << iter << " != this->" << + access << end << ")" + << "{"; + + Sequence::contains (s, init_); + + os << "return true;" + << "}" + << "else" << endl + << "return false;" + << "}"; + } + else if (s.min () == 0) + { + os << "bool " << sc << "::" << endl + << espresent (s) << " ()" + << "{" + << "if (this->" << access_seq (s) << epresent (s) << " ())" + << "{"; + + Sequence::contains (s, init_); + + os << "return true;" + << "}" + << "else" << endl + << "return false;" + << "}"; + } + + Sequence::traverse (s); + } + + private: + SemanticGraph::Complex& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + + private: + Traversal::ContainsParticle& init_; + + Boolean seq_; + CompositorTest compositor_test_; + ParticleTest particle_test_; + Traversal::ContainsParticle contains_particle_test_; + }; + + struct ParticleCallback: Traversal::Element, SerializerContext + { + ParticleCallback (Context& c) + : SerializerContext (c), type_pass_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& s ( + esimpl_custom ( + dynamic_cast (e.scope ()))); + + SemanticGraph::Type& t (e.type ()); + String const& ret (sret_type (t)); + String access (access_seq (e)); + + if (e.max () != 1) + { + String const& iter (esstate_member (e)); + + os << "bool " << s << "::" << endl + << esnext (e) << " ()" + << "{" + << "return this->" << access << iter << " != this->" << + access << esstate_member_end (e) << ";" + << "}"; + + os << ret << " " << s << "::" << endl + << esname (e) << " ()" + << "{"; + + if (ret != L"void") + { + os << "return "; + type_pass_.dispatch (t); + os << "*this->" << access << iter << "++;"; + } + + os << "}"; + } + else + { + if (e.min () == 0) + { + os << "bool " << s << "::" << endl + << espresent (e) << " ()" + << "{" + << "return this->" << access << epresent (e) << " ();" + << "}"; + } + + os << ret << " " << s << "::" << endl + << esname (e) << " ()" + << "{"; + + if (ret != L"void") + { + os << "return "; + type_pass_.dispatch (t); + os << "this->" << access << ename (e) << " ();"; + } + + os << "}"; + } + } + + private: + TypePass type_pass_; + }; + + struct AttributeCallback: Traversal::Attribute, SerializerContext + { + AttributeCallback (Context& c) + : SerializerContext (c), type_pass_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& s ( + esimpl_custom ( + dynamic_cast (a.scope ()))); + + String access (access_seq (a)); + + if (a.optional ()) + { + os << "bool " << s << "::" << endl + << espresent (a) << " ()" + << "{" + << "return this->" << access << epresent (a) << " ();" + << "}"; + } + + SemanticGraph::Type& t (a.type ()); + String const& ret (sret_type (t)); + + os << ret << " " << s << "::" << endl + << esname (a) << " ()" + << "{"; + + if (ret != L"void") + { + os << "return "; + type_pass_.dispatch (t); + os << "this->" << access << ename (a) << " ();"; + } + + os << "}"; + } + + private: + TypePass type_pass_; + }; + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + type_pass_ (c), + + // Initializers. + // + compositor_init_ (c), + particle_init_ (c), + + // Callbacks. + // + compositor_callback_ (c, contains_particle_init_), + particle_callback_ (c), + attribute_callback_ (c) + { + // Initializers. + // + contains_compositor_init_ >> compositor_init_; + compositor_init_ >> contains_particle_init_; + contains_particle_init_ >> compositor_init_; + contains_particle_init_ >> particle_init_; + + // Callbacks. + // + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (esimpl_custom (c)); + + if (!name) + return; + + Boolean hb (c.inherits_p ()); + Boolean restriction (restriction_p (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein && hb) + os << name << "::" << endl + << name << " ()" << endl + << ": " << esskel (c) << " (&base_impl_)" + << "{" + << "}"; + + // pre + // + String const& arg (sarg_type (c)); + + os << "void " << name << "::" << endl + << "pre (" << arg << " x)" + << "{"; + + if (hb) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + // Default serializer implementations for anyType and + // anySimpleType return void. + // + if (!b.is_a () && + !b.is_a ()) + { + + if (tiein) + os << "this->base_impl_.pre ("; + else + os << esimpl (b) << "::pre ("; + + type_pass_.dispatch (b); + + os << "x);"; + } + } + + if (!restriction) + { + os << "this->" << esstate (c) << "." << esstate_member (c) << + " = &x;"; + + contains_compositor (c, contains_compositor_init_); + } + + os << "}"; + + // Member callbacks. + // + if (!restriction) + { + names (c, names_attribute_callback_); + contains_compositor (c, contains_compositor_callback_); + } + } + + private: + TypePass type_pass_; + + // Initializers. + // + CompositorInit compositor_init_; + ParticleInit particle_init_; + Traversal::ContainsCompositor contains_compositor_init_; + Traversal::ContainsParticle contains_particle_init_; + + // Callbacks. + // + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_serializer_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/serializer-source.hxx b/xsde/cxx/hybrid/serializer-source.hxx new file mode 100644 index 0000000..dee3629 --- /dev/null +++ b/xsde/cxx/hybrid/serializer-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/serializer-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_SERIALIZER_SOURCE_HXX +#define CXX_HYBRID_SERIALIZER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_serializer_source (Context&); + } +} + +#endif // CXX_HYBRID_SERIALIZER_SOURCE_HXX diff --git a/xsde/cxx/hybrid/tree-forward.cxx b/xsde/cxx/hybrid/tree-forward.cxx new file mode 100644 index 0000000..f1c0dfa --- /dev/null +++ b/xsde/cxx/hybrid/tree-forward.cxx @@ -0,0 +1,626 @@ +// file : xsd/cxx/hybrid/tree-forward.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List : Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + os << "class " << ename (l) << ";"; + } + }; + + struct Union : Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + os << "class " << ename (u) << ";"; + } + }; + + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + os << "class " << ename (c) << ";"; + } + }; + + struct FundType : Context, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities + { + FundType (Context& c) + : Context (c) + { + if (stl) + string_type_ = L"::std::string"; + else + string_type_ = L"char*"; + + if (options.value ()) + { + long_type_ = L"long"; + unsigned_long_type_ = L"unsigned long"; + } + else + { + long_type_ = L"long long"; + unsigned_long_type_ = L"unsigned long long"; + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType&) + { + gen_using ("::xsde::cxx::hybrid::any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType&) + { + gen_using ("::xsde::cxx::hybrid::any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean&) + { + gen_typedef ("boolean", "bool"); + gen_using ("::xsde::cxx::hybrid::boolean_base"); + os << endl; + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte&) + { + gen_typedef ("byte", "signed char"); + gen_using ("::xsde::cxx::hybrid::byte_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte&) + { + gen_typedef ("unsigned_byte", "unsigned char"); + gen_using ("::xsde::cxx::hybrid::unsigned_byte_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short&) + { + gen_typedef ("short", "short"); + gen_using ("::xsde::cxx::hybrid::short_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort&) + { + gen_typedef ("unsigned_short", "unsigned short"); + gen_using ("::xsde::cxx::hybrid::unsigned_short_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int&) + { + gen_typedef ("int", "int"); + gen_using ("::xsde::cxx::hybrid::int_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt&) + { + gen_typedef ("unsigned_int", "unsigned int"); + gen_using ("::xsde::cxx::hybrid::unsigned_int_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long&) + { + gen_typedef ("long", long_type_); + gen_using ("::xsde::cxx::hybrid::long_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong&) + { + gen_typedef ("unsigned_long", unsigned_long_type_); + gen_using ("::xsde::cxx::hybrid::unsigned_long_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer&) + { + gen_typedef ("integer", "long"); + gen_using ("::xsde::cxx::hybrid::integer_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger&) + { + gen_typedef ("negative_integer", "long"); + gen_using ("::xsde::cxx::hybrid::negative_integer_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger&) + { + gen_typedef ("non_positive_integer", "long"); + gen_using ("::xsde::cxx::hybrid::non_positive_integer_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger&) + { + gen_typedef ("positive_integer", "unsigned long"); + gen_using ("::xsde::cxx::hybrid::positive_integer_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger&) + { + gen_typedef ("non_negative_integer", "unsigned long"); + gen_using ("::xsde::cxx::hybrid::non_negative_integer_base"); + os << endl; + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float&) + { + gen_typedef ("float", "float"); + gen_using ("::xsde::cxx::hybrid::float_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double&) + { + gen_typedef ("double", "double"); + gen_using ("::xsde::cxx::hybrid::double_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal&) + { + gen_typedef ("decimal", "double"); + gen_using ("::xsde::cxx::hybrid::decimal_base"); + os << endl; + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + gen_typedef ("string", string_type_); + gen_using ("::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + gen_typedef ("normalized_string", string_type_); + + if (!stl) + gen_typedef ("normalized_string_base", + "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + gen_typedef ("token", string_type_); + if (!stl) + gen_typedef ("token_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + gen_typedef ("nmtoken", string_type_); + if (!stl) + gen_typedef ("nmtoken_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens&) + { + gen_typedef ("nmtokens", "::xsde::cxx::string_sequence"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + gen_typedef ("name", string_type_); + if (!stl) + gen_typedef ("name_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + gen_typedef ("ncname", string_type_); + if (!stl) + gen_typedef ("ncname_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + gen_typedef ("language", string_type_); + if (!stl) + gen_typedef ("language_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName&) + { + gen_using ("::xsde::cxx::qname"); + os << endl; + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id&) + { + gen_typedef ("id", string_type_); + if (!stl) + gen_typedef ("id_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef&) + { + gen_typedef ("idref", string_type_); + if (!stl) + gen_typedef ("idref_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs&) + { + gen_typedef ("idrefs", "::xsde::cxx::string_sequence"); + os << endl; + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI&) + { + gen_typedef ("uri", string_type_); + if (!stl) + gen_typedef ("uri_base", "::xsde::cxx::hybrid::string_base"); + os << endl; + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary&) + { + gen_typedef ("base64_binary", "::xsde::cxx::buffer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary&) + { + gen_typedef ("hex_binary", "::xsde::cxx::buffer"); + os << endl; + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date&) + { + gen_using ("::xsde::cxx::date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime&) + { + gen_using ("::xsde::cxx::date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration&) + { + gen_using ("::xsde::cxx::duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day&) + { + gen_using ("::xsde::cxx::gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month&) + { + gen_using ("::xsde::cxx::gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay&) + { + gen_using ("::xsde::cxx::gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year&) + { + gen_using ("::xsde::cxx::gyear"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth&) + { + gen_using ("::xsde::cxx::gyear_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time&) + { + gen_using ("::xsde::cxx::time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities&) + { + } + + private: + Void + gen_typedef (String const& name, String const& type) + { + os << "typedef " << type << " " << escape (name) << ";"; + } + + Void + gen_using (String const& name) + { + os << "using " << name << ";"; + } + + String string_type_; + String long_type_; + String unsigned_long_type_; + }; + + struct FundNamespace : Namespace, Context + { + FundNamespace (Context& c) + : Namespace (c), Context (c) + { + } + + void + traverse (Type& ns) + { + pre (ns); + names (ns); + + // strdupx + // + if (!stl) + { + os << endl + << "using ::xsde::cxx::strdupx;" + << "using ::xsde::cxx::strndupx;"; + } + + post (ns); + } + }; + } + + Void + generate_tree_forward (Context& ctx, Boolean generate_xml_schema) + { + NarrowString xml_schema (ctx.options.value ()); + + // Inlcude or Emit fundamental types. + // + if (!generate_xml_schema && xml_schema) + { + String name (ctx.hxx_expr->merge (xml_schema)); + + ctx.os << "#include " << ctx.process_include_path (name) << endl + << endl; + } + else + { + if (ctx.stl) + ctx.os << "#include " << endl; + else + ctx.os << "#include " << endl; + + ctx.os << "#include " << endl + << endl; + + if (generate_xml_schema) + { + Traversal::Schema schema; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + + return; + } + else + { + Traversal::Schema schema, xsd; + Traversal::Implies implies; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> implies >> xsd >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + } + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names names_ns, names; + + Namespace ns (ctx); + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + //Enumeration enumeration (ctx); + + schema >> sources >> schema; + schema >> names_ns >> ns >> names; + + names >> list; + names >> union_; + names >> complex; + //names >> enumeration; + + schema.dispatch (ctx.schema_root); + + ctx.os << endl; + } + } +} diff --git a/xsde/cxx/hybrid/tree-forward.hxx b/xsde/cxx/hybrid/tree-forward.hxx new file mode 100644 index 0000000..19dbf5d --- /dev/null +++ b/xsde/cxx/hybrid/tree-forward.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/tree-forward.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_FORWARD_HXX +#define CXX_HYBRID_TREE_FORWARD_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_tree_forward (Context&, Boolean generate_xml_schema); + } +} + +#endif // CXX_HYBRID_TREE_FORWARD_HXX diff --git a/xsde/cxx/hybrid/tree-header.cxx b/xsde/cxx/hybrid/tree-header.cxx new file mode 100644 index 0000000..c7231c9 --- /dev/null +++ b/xsde/cxx/hybrid/tree-header.cxx @@ -0,0 +1,2459 @@ +// file : xsd/cxx/hybrid/tree-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List : Traversal::List, Context + { + List (Context& c) + : Context (c), base_name_ (c, TypeName::seq) + { + } + + virtual Void + traverse (Type& l) + { + String name (ename (l)); + + os << "// " << comment (l.name ()) << " (variable-length)" << endl + << "//" << endl; + + os << "class " << name << ": public "; + + base_name_.dispatch (l.argumented ().type ()); + + os << "{" + << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; + + // c-tor + // + os << "public:" << endl + << name << " ();"; + + // Custom data. + // + if (l.context ().count ("cd-name")) + { + String const& name (ecd_name (l)); + String const& sequence (ecd_sequence (l)); + String const& iterator (ecd_iterator (l)); + String const& const_iterator (ecd_const_iterator (l)); + + os << endl + << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + + os << "private:" << endl + << sequence << " " << ecd_member (l) << ";"; + } + + os << "};"; + } + + private: + TypeName base_name_; + }; + + struct Union : Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + SemanticGraph::Context& uc (u.context ()); + + String name (ename (u)); + Boolean cd (uc.count ("cd-name")); + + os << "// " << comment (u.name ()) << " (variable-length)" << endl + << "//" << endl; + + os << "class " << name + << "{"; + + if (!fixed_length (u)) + os << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; + + os << "public:" << endl; + + // c-tor + // + os << name << " ();"; + + String const& value (uc.get ("value")); + String const& member (uc.get ("value-member")); + + if (stl) + { + os << endl; + + // const std::string& + // name () const + // + os << "const ::std::string&" << endl + << value << " () const;" + << endl; + + // std::string& + // name () + // + os << "::std::string&" << endl + << value << " ();" + << endl; + + // void + // name (const std::string&) + // + os << "void" << endl + << value << " (const ::std::string&);" + << endl; + } + else + { + // d-tor + // + os << "~" << name << " ();" + << endl; + + // const char* + // name () const + // + os << "const char*" << endl + << value << " () const;" + << endl; + + // char* + // name () + // + os << "char*" << endl + << value << " ();" + << endl; + + // void + // name (char*) + // + os << "void" << endl + << value << " (char*);" + << endl; + } + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (u)); + String const& sequence (ecd_sequence (u)); + String const& iterator (ecd_iterator (u)); + String const& const_iterator (ecd_const_iterator (u)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + if (stl) + { + os << "private:" << endl + << "::std::string " << member << ";"; + } + else + { + os << "private:" << endl + << "char* " << member << ";"; + } + + // Custom data. + // + if (cd) + os << ecd_sequence (u) << " " << ecd_member (u) << ";"; + + os << "};"; + } + }; + + // + // Data. + // + + struct AlignType: Traversal::Compositor, + + Traversal::List, + Traversal::Union, + Traversal::Complex, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + + Context + { + AlignType (Context& c) + : Context (c), nested_ (false) + { + *this >> inherits_ >> *this; + + *this >> attribute_names_ >> attribute_; + + *this >> contains_particle_; + contains_particle_ >> particle_; + contains_particle_ >> *this; + contains_compositor_ >> *this; + + attribute_ >> belongs_; + particle_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + dispatch (SemanticGraph::Node& n) + { + found_ = false; + NodeBase::dispatch (n); + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + Boolean top (false); + + if (!nested_) + { + nested_ = true; + top = true; + } + + Traversal::Compositor::traverse (c); + + if (top) + { + nested_ = false; + + if (!found_) + os << "char"; // Empty compositor. + } + } + + virtual Void + traverse (SemanticGraph::List&) + { + align_type ("size_t"); + } + + virtual Void + traverse (SemanticGraph::Union&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + // Keep track of the nested calls for base types. + // + Boolean top (false); + + if (!nested_) + { + nested_ = true; + top = true; + } + + Complex::inherits (c, inherits_); + + if (!found_) + { + Complex::names (c, attribute_names_); + + if (!found_ && c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); + } + + if (top) + { + nested_ = false; + + if (!found_) + os << "char"; // Empty class. + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType&) + { + align_type ("char"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType&) + { + align_type ("char"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean&) + { + align_type ("bool"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte&) + { + align_type ("signed char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte&) + { + align_type ("unsigned char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short&) + { + align_type ("short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort&) + { + align_type ("unsigned short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int&) + { + align_type ("int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt&) + { + align_type ("unsigned int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long&) + { + align_type (options.value () + ? "long" + : "long long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong&) + { + align_type (options.value () + ? "unsigned long" + : "unsigned long long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer&) + { + align_type ("long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger&) + { + align_type ("long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger&) + { + align_type ("unsigned long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger&) + { + align_type ("unsigned long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger&) + { + align_type ("long"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float&) + { + align_type ("float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double&) + { + align_type ("double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal&) + { + align_type ("double"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + align_type ("size_t"); // std::string + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName&) + { + align_type ("size_t"); // std::string + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id&) + { + align_type ("size_t"); // std::string + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef&) + { + align_type ("size_t"); // std::string + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI&) + { + align_type ("size_t"); // std::string + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth&) + { + align_type ("bool"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time&) + { + align_type ("bool"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + align_type ("size_t"); // std::string + } + + private: + Void + align_type (Char const* t) + { + if (!found_) + { + os << t; + found_ = true; + } + } + + private: + Boolean found_; + Boolean nested_; + + private: + Traversal::Inherits inherits_; + + Traversal::Attribute attribute_; + Traversal::Names attribute_names_; + + Traversal::Element particle_; + Traversal::ContainsParticle contains_particle_; + Traversal::ContainsCompositor contains_compositor_; + + Traversal::Belongs belongs_; + }; + + struct AttributeData: Traversal::Attribute, Context + { + AttributeData (Context& c) + : Context (c), var_ (c, TypeName::var) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + SemanticGraph::Type& t (a.type ()); + + var_.dispatch (t); + os << " " << emember (a) << ";"; + + if (a.optional () && fixed_length (t)) + os << "bool " << epresent_member (a) << ";"; + } + + private: + TypeName var_; + }; + + + struct ElementData: Traversal::Element, Context + { + ElementData (Context& c) + : Context (c), var_ (c, TypeName::var) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + { + os << esequence (e) << " " << emember (e) << ";"; + } + else + { + SemanticGraph::Type& t (e.type ()); + + var_.dispatch (t); + os << " " << emember (e) << ";"; + + if (e.min () == 0 && fixed_length (t)) + os << "bool " << epresent_member (e) << ";"; + } + } + + private: + TypeName var_; + }; + + struct ElementInChoiceData: Traversal::Element, Context + { + ElementInChoiceData (Context& c) + : Context (c), var_ (c, TypeName::var), align_type_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () != 1) + { + os << "union" + << "{" + << "size_t align_;" + << "char data_[sizeof (" << esequence (e) << ")];" + << "} " << emember (e) << ";"; + } + else + { + SemanticGraph::Type& t (e.type ()); + + if (fixed_length (t)) + { + os << "union" + << "{"; + + align_type_.dispatch (t); + + os << " align_;" + << "char data_[sizeof ("; + + var_.dispatch (t); + + os << ")"; + + // Reserve an extra byte for the present flag. + // + if (e.min () == 0) + os << " + 1"; + + os << "];" + << "} " << emember (e) << ";"; + } + else + { + var_.dispatch (t); + os << " " << emember (e) << ";"; + } + } + } + + private: + TypeName var_; + AlignType align_type_; + }; + + struct AllData: Traversal::All, Context + { + AllData (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + String const& type (etype (a)); + String const& member (emember(a)); + + if (fixed_length (a)) + { + os << type << " " << member << ";" + << "bool " << epresent_member (a) << ";"; + } + else + os << type << "* " << member << ";"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceData: Traversal::Choice, Context + { + ChoiceInSequenceData (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () != 1) + { + os << esequence (c) << " " << emember (c) << ";"; + } + else if (c.min () == 0) + { + String const& type (etype (c)); + String const& member (emember (c)); + + if (fixed_length (c)) + os << type << " " << member << ";" + << "bool " << epresent_member (c) << ";"; + else + os << type << "* " << member << ";"; + } + else + { + os << "union" + << "{"; + + Choice::contains (c); + + os << "} " << emember (c) << ";" + << earm_tag (c) << " " << earm_member (c) << ";"; + } + } + }; + + struct ChoiceInChoiceData: Traversal::Choice, Context + { + ChoiceInChoiceData (Context& c) + : Context (c), align_type_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // For choice in choice we always have a nested class. + // + if (c.max () != 1) + { + os << "union" + << "{" + << "size_t align_;" + << "char data_[sizeof (" << esequence (c) << ")];" + << "} " << emember (c) << ";"; + } + else + { + if (fixed_length (c)) + { + os << "union" + << "{"; + + align_type_.dispatch (c); + + os << " align_;" + << "char data_[sizeof (" << etype (c) << ")"; + + // Reserve an extra byte for the present flag. + // + if (c.min () == 0) + os << " + 1"; + + os << "];" + << "} " << emember (c) << ";"; + } + else + os << etype (c) << "* " << emember (c) << ";"; + } + } + + private: + AlignType align_type_; + }; + + struct SequenceInSequenceData: Traversal::Sequence, Context + { + SequenceInSequenceData (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + { + os << esequence (s) << " " << emember (s) << ";"; + } + else if (s.min () == 0) + { + String const& type (etype (s)); + String const& member (emember (s)); + + if (fixed_length (s)) + os << type << " " << member << ";" + << "bool " << epresent_member (s) << ";"; + else + os << type << "* " << member << ";"; + } + else + Sequence::contains (s); + } + }; + + struct SequenceInChoiceData: Traversal::Sequence, Context + { + SequenceInChoiceData (Context& c) + : Context (c), align_type_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // For sequence in choice we always have a nested class. + // + if (s.max () != 1) + { + os << "union" + << "{" + << "size_t align_;" + << "char data_[sizeof (" << esequence (s) << ")];" + << "} " << emember (s) << ";"; + } + else + { + if (fixed_length (s)) + { + os << "union" + << "{"; + + align_type_.dispatch (s); + + os << " align_;" + << "char data_[sizeof (" << etype (s) << ")"; + + // Reserve an extra byte for the present flag. + // + if (s.min () == 0) + os << " + 1"; + + os << "];" + << "} " << emember (s) << ";"; + } + else + os << etype (s) << "* " << emember (s) << ";"; + } + } + + private: + AlignType align_type_; + }; + + // + // Accessors/modifiers. + // + + struct Attribute: Traversal::Attribute, Context + { + Attribute (Context& c) + : Context (c), + ro_ret_ (c, TypeName::ro_ret), + ret_ (c, TypeName::ret), + arg_ (c, TypeName::arg) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + os << "// " << comment (a.name ()) << endl + << "// " << endl; + + String const& name (ename (a)); + SemanticGraph::Type& t (a.type ()); + + if (a.optional ()) + { + String const& present (epresent (a)); + + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + } + + // const type& + // name () const + // + ro_ret_.dispatch (t); + os << endl + << name << " () const;" + << endl; + + // type& + // name () + // + ret_.dispatch (t); + os << endl + << name << " ();" + << endl; + + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + arg_.dispatch (t); + os << ");" + << endl; + } + + private: + TypeName ro_ret_; + TypeName ret_; + TypeName arg_; + }; + + struct Element: Traversal::Element, virtual Context + { + Element (Context& c) + : Context (c), + seq_ (c, TypeName::seq), + ro_ret_ (c, TypeName::ro_ret), + ret_ (c, TypeName::ret), + arg_ (c, TypeName::arg) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + os << "// " << comment (e.name ()) << endl + << "// " << endl; + + String const& name (ename (e)); + SemanticGraph::Type& t (e.type ()); + + if (e.max () != 1) + { + String const& sequence (esequence (e)); + String const& iterator (eiterator (e)); + String const& const_iterator (econst_iterator (e)); + + // sequence & iterators + // + os << "typedef "; + seq_.dispatch (t); + os << " " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + else + { + if (e.min () == 0) + { + // optional + // + String const& present (epresent (e)); + + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + } + + // const type& + // name () const + // + ro_ret_.dispatch (t); + os << endl + << name << " () const;" + << endl; + + // type& + // name () + // + ret_.dispatch (t); + os << endl + << name << " ();" + << endl; + + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + arg_.dispatch (t); + os << ");" + << endl; + } + } + + private: + TypeName seq_; + TypeName ro_ret_; + TypeName ret_; + TypeName arg_; + }; + + struct All: Traversal::All, Context + { + All (Context& c, Traversal::ContainsParticle& contains_data) + : Context (c), contains_data_ (contains_data) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + Boolean fl (fixed_length (a)); + Boolean cd (a.context ().count ("cd-name")); + + String const& name (ename (a)); + String const& type (etype (a)); + String const& present (epresent (a)); + + os << "// " << comment (name) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "// " << endl; + + os << "class " << type + << "{"; + + // c-tor & d-tor + // + os << "public:" << endl + << type << " ();" + << "~" << type << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + os << type << " (const " << type << "&);" + << type << "& operator= (const " << type << "&);" + << endl; + + if (!fl) + os << "public:" << endl; + + All::contains (a); + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (a)); + String const& sequence (ecd_sequence (a)); + String const& iterator (ecd_iterator (a)); + String const& const_iterator (ecd_const_iterator (a)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + os << "private:" << endl; + + All::contains (a, contains_data_); + + // Custom data. + // + if (cd) + os << ecd_sequence (a) << " " << ecd_member (a) << ";"; + + os << "};"; + + // name_present + // + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + + // const type& + // name () const + // + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + // type& + // name () + // + os << type << "&" << endl + << name << " ();" + << endl; + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << ");" + << endl; + } + else + All::contains (a); + } + + private: + Traversal::ContainsParticle& contains_data_; + }; + + struct ParticleTag: Traversal::Element, + Traversal::Any, + Traversal::Choice, + Traversal::Sequence, + Context + { + ParticleTag (Context& c) + : Context (c), first_ (true) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + emit_tag (etag (e)); + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + emit_tag (etag (a)); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + emit_tag (etag (c)); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + emit_tag (etag (s)); + } + + virtual Void + emit_tag (String const& tag) + { + if (first_) + first_ = false; + else + os << "," << endl; + + os << tag; + } + + private: + Boolean first_; + }; + + struct ChoiceInSequence: Traversal::Choice, Context + { + ChoiceInSequence (Context& c, + Traversal::ContainsParticle& contains_data) + : Context (c), contains_data_ (contains_data) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + UnsignedLong min (c.min ()), max (c.max ()); + + String const& name (ename (c)); + + Boolean fl; + String type; + + if (max != 1 || min == 0) + { + type = etype (c); + + fl = fixed_length (c); + + os << "// " << comment (name) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "// " << endl; + + os << "class " << type + << "{"; + + // c-tor & d-tor + // + os << "public:" << endl + << type << " ();" + << "~" << type << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + os << type << " (const " << type << "&);" + << type << "& operator= (const " << type << "&);" + << endl; + + if (!fl) + os << "public:" << endl; + } + else + { + os << "// " << comment (name) << endl + << "// " << endl; + } + + String const& arm_tag (earm_tag (c)); + String const& arm (earm (c)); + + os << "enum " << arm_tag + << "{"; + + { + ParticleTag particle (*this); + Traversal::ContainsParticle contains_particle (particle); + Traversal::Choice::contains (c, contains_particle); + } + + os << "};"; + + // arm_tag + // arm () const; + // + os << arm_tag << endl + << arm << " () const;" + << endl; + + // void + // arm (arm_tag); + // + os << "void" << endl + << arm << " (" << arm_tag << ");" + << endl; + + Choice::contains (c); + + if (max != 1 || min == 0) + { + Boolean cd (c.context ().count ("cd-name")); + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (c)); + String const& sequence (ecd_sequence (c)); + String const& iterator (ecd_iterator (c)); + String const& const_iterator (ecd_const_iterator (c)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + os << "private:" << endl + << "union" + << "{"; + + Choice::contains (c, contains_data_); + + os << "} " << emember (c) << ";" + << arm_tag << " " << earm_member (c) << ";"; + + // Custom data. + // + if (cd) + os << ecd_sequence (c) << " " << ecd_member (c) << ";"; + + os << "};"; + } + + if (max != 1) + { + String const& sequence (esequence (c)); + String const& iterator (eiterator (c)); + String const& const_iterator (econst_iterator (c)); + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::"; + + if (fl) + os << "fix_seq"; + else + os << "var_seq"; + + os << "< " << type << " > " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + + } + else if (min == 0) + { + String const& present (epresent (c)); + + // name_present + // + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + + // const type& + // name () const + // + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + // type& + // name () + // + os << type << "&" << endl + << name << " ();" + << endl; + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << ");" + << endl; + } + } + + private: + Traversal::ContainsParticle& contains_data_; + }; + + struct ChoiceInChoice: Traversal::Choice, Context + { + ChoiceInChoice (Context& c, + Traversal::ContainsParticle& contains_data) + : Context (c), contains_data_ (contains_data) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // When shoice is in choice we generate nested class even + // for min == max == 1. + // + UnsignedLong min (c.min ()), max (c.max ()); + + Boolean fl (fixed_length (c)); + Boolean cd (c.context ().count ("cd-name")); + + String const& name (ename (c)); + String const& type (etype (c)); + + os << "// " << comment (name) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "// " << endl; + + os << "class " << type + << "{"; + + // c-tor & d-tor + // + os << "public:" << endl + << type << " ();" + << "~" << type << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + os << type << " (const " << type << "&);" + << type << "& operator= (const " << type << "&);" + << endl; + + if (!fl) + os << "public:" << endl; + + String const& arm_tag (earm_tag (c)); + String const& arm (earm (c)); + + os << "enum " << arm_tag + << "{"; + + { + ParticleTag particle (*this); + Traversal::ContainsParticle contains_particle (particle); + Traversal::Choice::contains (c, contains_particle); + } + + os << "};"; + + // arm_tag + // arm () const; + // + os << arm_tag << endl + << arm << " () const;" + << endl; + + // void + // arm (arm_tag); + // + os << "void" << endl + << arm << " (" << arm_tag << ");" + << endl; + + Choice::contains (c); + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (c)); + String const& sequence (ecd_sequence (c)); + String const& iterator (ecd_iterator (c)); + String const& const_iterator (ecd_const_iterator (c)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + os << "private:" << endl + << "union" + << "{"; + + Choice::contains (c, contains_data_); + + os << "} " << emember (c) << ";" + << arm_tag << " " << earm_member (c) << ";"; + + // Custom data. + // + if (cd) + os << ecd_sequence (c) << " " << ecd_member (c) << ";"; + + os << "};"; + + if (max != 1) + { + String const& sequence (esequence (c)); + String const& iterator (eiterator (c)); + String const& const_iterator (econst_iterator (c)); + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::"; + + if (fl) + os << "fix_seq"; + else + os << "var_seq"; + + os << "< " << type << " > " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + else + { + if (min == 0) + { + String const& present (epresent (c)); + + // name_present + // + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + } + + // const type& + // name () const + // + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + // type& + // name () + // + os << type << "&" << endl + << name << " ();" + << endl; + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << ");" + << endl; + } + } + + private: + Traversal::ContainsParticle& contains_data_; + }; + + + struct SequenceInSequence: Traversal::Sequence, Context + { + SequenceInSequence (Context& c, + Traversal::ContainsParticle& contains_data) + : Context (c), contains_data_ (contains_data) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (max == 1 && min == 1) + { + Sequence::contains (s); + return; + } + + Boolean fl (fixed_length (s)); + Boolean cd (s.context ().count ("cd-name")); + + String const& name (ename (s)); + String const& type (etype (s)); + + os << "// " << comment (name) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "// " << endl; + + os << "class " << type + << "{"; + + // c-tor & d-tor + // + os << "public:" << endl + << type << " ();" + << "~" << type << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + os << type << " (const " << type << "&);" + << type << "& operator= (const " << type << "&);" + << endl; + + if (!fl) + os << "public:" << endl; + + Sequence::contains (s); + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (s)); + String const& sequence (ecd_sequence (s)); + String const& iterator (ecd_iterator (s)); + String const& const_iterator (ecd_const_iterator (s)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + os << "private:" << endl; + + Sequence::contains (s, contains_data_); + + // Custom data. + // + if (cd) + os << ecd_sequence (s) << " " << ecd_member (s) << ";"; + + os << "};"; + + if (max != 1) + { + String const& sequence (esequence (s)); + String const& iterator (eiterator (s)); + String const& const_iterator (econst_iterator (s)); + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::"; + + if (fl) + os << "fix_seq"; + else + os << "var_seq"; + + os << "< " << type << " > " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + + } + else if (min == 0) + { + String const& present (epresent (s)); + + // name_present + // + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + + // const type& + // name () const + // + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + // type& + // name () + // + os << type << "&" << endl + << name << " ();" + << endl; + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << ");" + << endl; + } + } + + private: + Traversal::ContainsParticle& contains_data_; + }; + + struct SequenceInChoice: Traversal::Sequence, Context + { + SequenceInChoice (Context& c, + Traversal::ContainsParticle& contains_data) + : Context (c), contains_data_ (contains_data) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we generate nested class even + // for min == max == 1. + // + Boolean fl (fixed_length (s)); + Boolean cd (s.context ().count ("cd-name")); + + String const& name (ename (s)); + String const& type (etype (s)); + + os << "// " << comment (name) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "// " << endl; + + os << "class " << type + << "{"; + + // c-tor & d-tor + // + os << "public:" << endl + << type << " ();" + << "~" << type << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + os << type << " (const " << type << "&);" + << type << "& operator= (const " << type << "&);" + << endl; + + if (!fl) + os << "public:" << endl; + + Sequence::contains (s); + + if (cd) + { + String const& name (ecd_name (s)); + String const& sequence (ecd_sequence (s)); + String const& iterator (ecd_iterator (s)); + String const& const_iterator (ecd_const_iterator (s)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + os << "private:" << endl; + + Sequence::contains (s, contains_data_); + + // Custom data. + // + if (cd) + os << ecd_sequence (s) << " " << ecd_member (s) << ";"; + + os << "};"; + + if (s.max () != 1) + { + String const& sequence (esequence (s)); + String const& iterator (eiterator (s)); + String const& const_iterator (econst_iterator (s)); + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::"; + + if (fl) + os << "fix_seq"; + else + os << "var_seq"; + + os << "< " << type << " > " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + + } + else + { + if (s.min () == 0) + { + String const& present (epresent (s)); + + // name_present + // + os << "bool" << endl + << present << " () const;" + << endl; + + os << "void" << endl + << present << " (bool);" + << endl; + } + + // const type& + // name () const + // + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + // type& + // name () + // + os << type << "&" << endl + << name << " ();" + << endl; + + // void + // name (const type& | type*) + // + os << "void" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << ");" + << endl; + } + } + + private: + Traversal::ContainsParticle& contains_data_; + }; + + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + base_name_ (c, TypeName::base), + + // Data. + // + attribute_data_ (c), + element_data_ (c), + element_in_choice_data_ (c), + all_data_ (c), + choice_in_choice_data_ (c), + choice_in_sequence_data_ (c), + sequence_in_choice_data_ (c), + sequence_in_sequence_data_ (c), + + // Functions and nested classes. + // + attribute_ (c), + element_ (c), + all_ (c, all_contains_data_), + choice_in_choice_ (c, choice_contains_data_), + choice_in_sequence_ (c, choice_contains_data_), + sequence_in_choice_ (c, sequence_contains_data_), + sequence_in_sequence_ (c, sequence_contains_data_) + { + // Data + // + attribute_names_data_ >> attribute_data_; + + all_data_ >> all_contains_data_ >> element_data_; + + sequence_in_choice_data_ >> sequence_contains_data_; + sequence_in_sequence_data_ >> sequence_contains_data_; + sequence_contains_data_ >> element_data_; + sequence_contains_data_ >> choice_in_sequence_data_; + sequence_contains_data_ >> sequence_in_sequence_data_; + + choice_in_choice_data_ >> choice_contains_data_; + choice_in_sequence_data_ >> choice_contains_data_; + choice_contains_data_ >> element_in_choice_data_; + choice_contains_data_ >> choice_in_choice_data_; + choice_contains_data_ >> sequence_in_choice_data_; + + contains_compositor_data_ >> all_data_; + contains_compositor_data_ >> choice_in_sequence_data_; + contains_compositor_data_ >> sequence_in_sequence_data_; + + // Functions and nested classes. + // + attribute_names_ >> attribute_; + + all_ >> all_contains_ >> element_; + + choice_in_choice_ >> choice_contains_; + choice_in_sequence_ >> choice_contains_; + choice_contains_ >> element_; + choice_contains_ >> choice_in_choice_; + choice_contains_ >> sequence_in_choice_; + + sequence_in_choice_ >> sequence_contains_; + sequence_in_sequence_ >> sequence_contains_; + sequence_contains_ >> element_; + sequence_contains_ >> choice_in_sequence_; + sequence_contains_ >> sequence_in_sequence_; + + contains_compositor_ >> all_; + contains_compositor_ >> choice_in_sequence_; + contains_compositor_ >> sequence_in_sequence_; + } + + virtual Void + traverse (Type& c) + { + String name (ename (c)); + Boolean fl (fixed_length (c)); + Boolean restriction (restriction_p (c)); + Boolean cd (c.context ().count ("cd-name")); + + os << "// " << comment (c.name ()) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "//" << endl; + + os << "class " << name; + + if (c.inherits_p ()) + { + os << ": public "; + base_name_.dispatch (c.inherits ().base ()); + } + + os << "{"; + + // c-tor + // + os << "public:" << endl + << name << " ();"; + + // d-tor + // + if (!restriction) + os << "~" << name << " ();"; + + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; + + if (!fl || !restriction) + os << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; + + if ((!restriction && !fl) || cd) + os << "public:" << endl; + + if (!restriction) + { + Complex::names (c, attribute_names_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); + } + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (c)); + String const& sequence (ecd_sequence (c)); + String const& iterator (ecd_iterator (c)); + String const& const_iterator (ecd_const_iterator (c)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + if (!restriction || cd) + os << "private:" << endl; + + if (!restriction) + { + Complex::names (c, attribute_names_data_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_data_); + } + + // Custom data. + // + if (cd) + os << ecd_sequence (c) << " " << ecd_member (c) << ";"; + + os << "};"; + } + + private: + TypeName base_name_; + + // Data. + // + AttributeData attribute_data_; + Traversal::Names attribute_names_data_; + + ElementData element_data_; + ElementInChoiceData element_in_choice_data_; + AllData all_data_; + ChoiceInChoiceData choice_in_choice_data_; + ChoiceInSequenceData choice_in_sequence_data_; + SequenceInChoiceData sequence_in_choice_data_; + SequenceInSequenceData sequence_in_sequence_data_; + Traversal::ContainsParticle all_contains_data_; + Traversal::ContainsParticle choice_contains_data_; + Traversal::ContainsParticle sequence_contains_data_; + + Traversal::ContainsCompositor contains_compositor_data_; + + // Functions and nested classes. + // + Attribute attribute_; + Traversal::Names attribute_names_; + + Element element_; + All all_; + ChoiceInChoice choice_in_choice_; + ChoiceInSequence choice_in_sequence_; + SequenceInChoice sequence_in_choice_; + SequenceInSequence sequence_in_sequence_; + Traversal::ContainsParticle all_contains_; + Traversal::ContainsParticle choice_contains_; + Traversal::ContainsParticle sequence_contains_; + + Traversal::ContainsCompositor contains_compositor_; + }; + } + + Void + generate_tree_header (Context& ctx) + { + ctx.os << "#include " << endl + << endl; + + Boolean inline_ (ctx.options.value ()); + + // Emit header includes. + // + { + if (inline_) + { + ctx.os << "#ifndef XSDE_DONT_INCLUDE_INLINE" << endl + << "#define XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + } + + Traversal::Schema schema; + Includes includes (ctx, Includes::header); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + + if (inline_) + { + ctx.os << "#undef XSDE_DONT_INCLUDE_INLINE" << endl + << "#else" << endl + << endl; + + schema.dispatch (ctx.schema_root); + + ctx.os << "#endif // XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + } + } + + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names names_ns, names; + + Namespace ns (ctx); + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + //Enumeration enumeration (ctx); + + schema >> sources >> schema; + schema >> names_ns >> ns >> names; + + names >> list; + names >> union_; + names >> complex; + //names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + + // Emit inline includes. + // + if (inline_) + { + ctx.os << "#ifndef XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + + Traversal::Schema schema; + Includes ixx_includes (ctx, Includes::inline_); + schema >> ixx_includes; + + schema.dispatch (ctx.schema_root); + + ctx.os << "#endif // XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + } + } + } +} diff --git a/xsde/cxx/hybrid/tree-header.hxx b/xsde/cxx/hybrid/tree-header.hxx new file mode 100644 index 0000000..2ef9573 --- /dev/null +++ b/xsde/cxx/hybrid/tree-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/tree-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_HEADER_HXX +#define CXX_HYBRID_TREE_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_tree_header (Context&); + } +} + +#endif // CXX_HYBRID_TREE_HEADER_HXX diff --git a/xsde/cxx/hybrid/tree-inline.cxx b/xsde/cxx/hybrid/tree-inline.cxx new file mode 100644 index 0000000..72d2d8f --- /dev/null +++ b/xsde/cxx/hybrid/tree-inline.cxx @@ -0,0 +1,1817 @@ +// file : xsd/cxx/hybrid/tree-inline.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct List : Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String name (ename (l)); + + os << "// " << comment (l.name ()) << endl + << "//" << endl + << endl; + + // c-tor + // + os << inl + << name << "::" << endl + << name << " ()" + << "{" + << "}"; + + // Custom data. + // + if (l.context ().count ("cd-name")) + { + String const& cd_name (ecd_name (l)); + String const& member (ecd_member (l)); + String const& sequence (ecd_sequence (l)); + + // const seq& + // name () const + // + os << inl + << "const " << name << "::" << sequence << "& " << + name << "::" << endl + << cd_name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << name << "::" << sequence << "& " << name << "::" << endl + << cd_name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + }; + + // + // + struct Union : Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String name (ename (u)); + + os << "// " << comment (u.name ()) << endl + << "//" << endl + << endl; + + SemanticGraph::Context& uc (u.context ()); + String const& value (uc.get ("value")); + String const& member (uc.get ("value-member")); + + // c-tor + // + os << inl + << name << "::" << endl + << name << " ()" + << "{"; + + if (!stl) + os << "this->" << member << " = 0;"; + + os << "}"; + + if (stl) + { + // const std::string& + // name () const + // + os << inl + << "const ::std::string& " << name << "::" << endl + << value << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // std::string& + // name () + // + os << inl + << "::std::string& " << name << "::" << endl + << value << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + + // void + // name (const std::string&) + // + os << inl + << "void " << name << "::" << endl + << value << " (const ::std::string& x)" + << "{" + << "this->" << member << " = x;" + << "}"; + } + else + { + // d-tor + // + os << inl + << name << "::" << endl + << "~" << name << " ()" + << "{" + << "delete[] this->" << member << ";" + << "}"; + + // const char* + // name () const + // + os << inl + << "const char* " << name << "::" << endl + << value << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // char* + // name () + // + os << inl + << "char* " << name << "::" << endl + << value << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + + // void + // name (char*) + // + os << inl + << "void " << name << "::" << endl + << value << " (char* x)" + << "{" + << "delete[] this->" << member << ";" + << "this->" << member << " = x;" + << "}"; + } + + // Custom data. + // + if (uc.count ("cd-name")) + { + String const& cd_name (ecd_name (u)); + String const& member (ecd_member (u)); + String const& sequence (ecd_sequence (u)); + + // const seq& + // name () const + // + os << inl + << "const " << name << "::" << sequence << "& " << + name << "::" << endl + << cd_name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << name << "::" << sequence << "& " << name << "::" << endl + << cd_name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + }; + + // + // + struct AttributeFunc: Traversal::Attribute, Context + { + AttributeFunc (Context& c) + : Context (c), + ro_ret_ (c, TypeName::ro_ret), + ret_ (c, TypeName::ret), + arg_ (c, TypeName::arg), + deref_ (c, TypeOps::deref), + delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& name (ename (a)); + String const& member (emember (a)); + + SemanticGraph::Type& t (a.type ()); + Boolean fl (fixed_length (t)); + String scope (Context::scope (a)); + + if (a.optional ()) + { + String const& present (epresent (a)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + os << "return this->" << epresent_member (a) << ";"; + else + os << "return this->" << member << " != 0;"; + + os << "}"; + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{"; + + if (fl) + os << "this->" << epresent_member (a) << " = x;"; + else + { + os << "if (!x)" + << "{"; + delete_.dispatch (t); + os << " this->" << member << ";" + << "this->" << member << " = 0;" + << "}"; + } + + os << "}"; + } + + // const type& + // name () const + // + os << inl; + ro_ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " () const" + << "{" + << "return "; + deref_.dispatch (t); + os << "this->" << member << ";" + << "}"; + + // type& + // name () + // + os << inl; + ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " ()" + << "{" + << "return "; + deref_.dispatch (t); + os << "this->" << member << ";" + << "}"; + + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + arg_.dispatch (t); + os << " x)" + << "{"; + + if (!fl) + { + delete_.dispatch (t); + os << " this->" << member << ";"; + } + + os << "this->" << member << " = x;"; + + if (fl && a.optional ()) + os << "this->" << epresent_member (a) << " = true;"; + + os << "}"; + } + + private: + TypeName ro_ret_; + TypeName ret_; + TypeName arg_; + TypeOps deref_; + TypeOps delete_; + }; + + struct ElementFunc: Traversal::Element, Context + { + ElementFunc (Context& c) + : Context (c), + ro_ret_ (c, TypeName::ro_ret), + ret_ (c, TypeName::ret), + arg_ (c, TypeName::arg), + deref_ (c, TypeOps::deref), + delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& name (ename (e)); + String const& member (emember (e)); + + SemanticGraph::Type& t (e.type ()); + Boolean fl (fixed_length (t)); + String scope (Context::scope (e)); + + if (e.max () != 1) + { + String const& sequence (esequence (e)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + else + { + if (e.min () == 0) + { + String const& present (epresent (e)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + os << "return this->" << epresent_member (e) << ";"; + else + os << "return this->" << member << " != 0;"; + + os << "}"; + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{"; + + if (fl) + os << "this->" << epresent_member (e) << " = x;"; + else + { + os << "if (!x)" + << "{"; + delete_.dispatch (t); + os << " this->" << member << ";" + << "this->" << member << " = 0;" + << "}"; + } + + os << "}"; + } + + // const type& + // name () const + // + os << inl; + ro_ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " () const" + << "{" + << "return "; + deref_.dispatch (t); + os << "this->" << member << ";" + << "}"; + + // type& + // name () + // + os << inl; + ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " ()" + << "{" + << "return "; + deref_.dispatch (t); + os << "this->" << member << ";" + << "}"; + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + arg_.dispatch (t); + os << " x)" + << "{"; + + if (!fl) + { + delete_.dispatch (t); + os << " this->" << member << ";"; + } + + os << "this->" << member << " = x;"; + + if (fl && e.min () == 0) + os << "this->" << epresent_member (e) << " = true;"; + + os << "}"; + } + } + + private: + TypeName ro_ret_; + TypeName ret_; + TypeName arg_; + TypeOps deref_; + TypeOps delete_; + }; + + struct ElementInChoiceFunc: Traversal::Element, Context + { + ElementInChoiceFunc (Context& c) + : Context (c), + ro_ret_ (c, TypeName::ro_ret), + ret_ (c, TypeName::ret), + arg_ (c, TypeName::arg), + var_ (c, TypeName::var), + deref_ (c, TypeOps::deref), + delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& name (ename (e)); + String const& member (emember (e)); + + SemanticGraph::Choice& c ( + dynamic_cast ( + e.contained_particle ().compositor ())); + + String const& arm (earm (c)); + String const& umember (emember (c)); + + String scope (Context::scope (e)); + + if (e.max () != 1) + { + String const& sequence (esequence (e)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return reinterpret_cast< const " << sequence << "& > (" << + "this->" << umember << "." << member << ");" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return reinterpret_cast< " << sequence << "& > (" << + "this->" << umember << "." << member << ");" + << "}"; + } + else + { + UnsignedLong min (e.min ()); + + SemanticGraph::Type& t (e.type ()); + Boolean fl (fixed_length (t)); + + String const& tag (etag (e)); + String const& arm_member (earm_member (c)); + + if (min == 0) + { + String const& present (epresent (e)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + { + os << "return this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")];"; + } + else + os << "return this->" << umember << "." << member << " != 0;"; + + os << "}"; + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{" + << "if (this->" << arm_member << " != " << tag << ")" << endl + << "this->" << arm << " (" << tag << ");"; + + if (fl) + { + os << endl + << "this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")] = x;"; + } + else + { + os << "else if (!x)" + << "{"; + delete_.dispatch (t); + os << " this->" << umember << "." << member << ";" + << "this->" << umember << "." << member << " = 0;" + << "}"; + } + + os << "}"; + } + + // const type& + // name () const + // + os << inl; + ro_ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " () const" + << "{" + << "return "; + + if (fl) + { + os << "reinterpret_cast< const "; + var_.dispatch (t); + os << "& > (this->" << umember << "." << member << ");"; + } + else + { + deref_.dispatch (t); + os << "this->" << umember << "." << member << ";"; + } + + os << "}"; + + // type& + // name () + // + os << inl; + ret_.dispatch (t); + os << " " << scope << "::" << endl + << name << " ()" + << "{" + << "return "; + + if (fl) + { + os << "reinterpret_cast< "; + var_.dispatch (t); + os << "& > (this->" << umember << "." << member << ");"; + } + else + { + deref_.dispatch (t); + os << "this->" << umember << "." << member << ";"; + } + + os << "}"; + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + arg_.dispatch (t); + os << " x)" + << "{" + << "if (this->" << arm_member << " != " << tag << ")" << endl + << "this->" << arm << " (" << tag << ");"; + + if (fl) + { + os << endl + << "reinterpret_cast< "; + var_.dispatch (t); + os << "& > (this->" << umember << "." << member << ") = x;"; + + if (min == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")] = true;"; + } + } + else + { + os << "else" << endl; + delete_.dispatch (t); + os << " this->" << umember << "." << member << ";" + << endl + << "this->" << umember << "." << member << " = x;"; + } + + os << "}"; + } + } + + private: + TypeName ro_ret_; + TypeName ret_; + TypeName arg_; + TypeName var_; + TypeOps deref_; + TypeOps delete_; + }; + + struct AllFunc: Traversal::All, Context + { + AllFunc (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + String const& name (ename (a)); + String const& type (etype (a)); + String const& present (epresent (a)); + String const& member (emember (a)); + + Boolean fl (fixed_length (a)); + String scope (Context::scope (a)); + + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + os << "return this->" << epresent_member (a) << ";"; + else + os << "return this->" << member << " != 0;"; + + os << "}"; + + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{"; + + if (fl) + os << "this->" << epresent_member (a) << " = x;"; + else + { + os << "if (!x)" + << "{" + << "delete this->" << member << ";" + << "this->" << member << " = 0;" + << "}"; + } + + os << "}"; + + + // const type& + // name () const + // + os << inl + << "const " << scope << "::" << type << "& " << + scope << "::" << endl + << name << " () const" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // type& + // name () + // + os << inl + << scope << "::" << type << "& " << scope << "::" << endl + << name << " ()" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << " x)" + << "{"; + + if (!fl) + os << "delete this->" << member << ";"; + + os << "this->" << member << " = x;"; + + if (fl) + os << "this->" << epresent_member (a) << " = true;"; + + os << "}"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceFunc: Traversal::Choice, Context + { + ChoiceInSequenceFunc (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (max == 1 && min == 1) + { + String scope (Context::scope (c)); + + // void + // arm (arm_tag) + // + os << inl + << scope << "::" << earm_tag (c) << " " << scope << "::" << endl + << earm (c) << " () const" + << "{" + << "return this->" << earm_member (c) << ";" + << "}"; + + Choice::contains (c); + return; + } + + String const& name (ename (c)); + String const& member (emember (c)); + String scope (Context::scope (c)); + + if (max != 1) + { + String const& sequence (esequence (c)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + else if (min == 0) + { + Boolean fl (fixed_length (c)); + + String const& type (etype (c)); + String const& present (epresent (c)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + os << "return this->" << epresent_member (c) << ";"; + else + os << "return this->" << member << " != 0;"; + + os << "}"; + + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{"; + + if (fl) + os << "this->" << epresent_member (c) << " = x;"; + else + { + os << "if (!x)" + << "{" + << "delete this->" << member << ";" + << "this->" << member << " = 0;" + << "}"; + } + + os << "}"; + + + // const type& + // name () const + // + os << inl + << "const " << scope << "::" << type << "& " << + scope << "::" << endl + << name << " () const" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // type& + // name () + // + os << inl + << scope << "::" << type << "& " << scope << "::" << endl + << name << " ()" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << " x)" + << "{"; + + if (!fl) + os << "delete this->" << member << ";"; + + os << "this->" << member << " = x;"; + + if (fl) + os << "this->" << epresent_member (c) << " = true;"; + + os << "}"; + } + } + }; + + struct SequenceInSequenceFunc: Traversal::Sequence, Context + { + SequenceInSequenceFunc (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (max == 1 && min == 1) + { + Sequence::contains (s); + return; + } + + String const& name (ename (s)); + String const& member (emember (s)); + String scope (Context::scope (s)); + + if (max != 1) + { + String const& sequence (esequence (s)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + else if (min == 0) + { + Boolean fl (fixed_length (s)); + + String const& type (etype (s)); + String const& present (epresent (s)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + os << "return this->" << epresent_member (s) << ";"; + else + os << "return this->" << member << " != 0;"; + + os << "}"; + + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{"; + + if (fl) + os << "this->" << epresent_member (s) << " = x;"; + else + { + os << "if (!x)" + << "{" + << "delete this->" << member << ";" + << "this->" << member << " = 0;" + << "}"; + } + + os << "}"; + + + // const type& + // name () const + // + os << inl + << "const " << scope << "::" << type << "& " << + scope << "::" << endl + << name << " () const" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // type& + // name () + // + os << inl + << scope << "::" << type << "& " << scope << "::" << endl + << name << " ()" + << "{"; + + if (fl) + os << "return this->" << member << ";"; + else + os << "return *this->" << member << ";"; + + os << "}"; + + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << " x)" + << "{"; + + if (!fl) + os << "delete this->" << member << ";"; + + os << "this->" << member << " = x;"; + + if (fl) + os << "this->" << epresent_member (s) << " = true;"; + + os << "}"; + } + } + }; + + struct CompositorInChoiceFunc: Context + { + CompositorInChoiceFunc (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + // When compositor is in choice we generate nested class even + // for min == max == 1. + // + String const& name (ename (c)); + String const& member (emember (c)); + + SemanticGraph::Choice& cont ( + dynamic_cast ( + c.contained_particle ().compositor ())); + + String const& arm (earm (cont)); + String const& umember (emember (cont)); + + String scope (Context::scope (c)); + + if (c.max () != 1) + { + String const& sequence (esequence (c)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return reinterpret_cast< const " << sequence << "& > (" << + "this->" << umember << "." << member << ");" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return reinterpret_cast< " << sequence << "& > (" << + "this->" << umember << "." << member << ");" + << "}"; + } + else + { + UnsignedLong min (c.min ()); + + Boolean fl (fixed_length (c)); + + String const& type (etype (c)); + String const& tag (etag (c)); + String const& arm_member (earm_member (cont)); + + if (min == 0) + { + String const& present (epresent (c)); + + // bool + // preset () const; + // + os << inl + << "bool " << scope << "::" << endl + << present << " () const" + << "{"; + + if (fl) + { + os << "return this->" << umember << "." << member << + ".data_[sizeof (" << type << ")];"; + } + else + os << "return this->" << umember << "." << member << " != 0;"; + + os << "}"; + + // void + // preset (bool); + // + os << inl + << "void " << scope << "::" << endl + << present << " (bool x)" + << "{" + << "if (this->" << arm_member << " != " << tag << ")" << endl + << "this->" << arm << " (" << tag << ");"; + + if (fl) + { + os << endl + << "this->" << umember << "." << member << + ".data_[sizeof (" << type << ")] = x;"; + } + else + { + os << "else if (!x)" + << "{" + << "delete this->" << umember << "." << member << ";" + << "this->" << umember << "." << member << " = 0;" + << "}"; + } + + os << "}"; + } + + // const type& + // name () const + // + os << inl + << "const " << scope << "::" << type << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return "; + + if (fl) + os << "reinterpret_cast< const " << type << "& > (this->" << + umember << "." << member << ");"; + else + os << "*this->" << umember << "." << member << ";"; + + os << "}"; + + // type& + // name () + // + os << inl + << scope << "::" << type << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return "; + + if (fl) + os << "reinterpret_cast< " << type << "& > (this->" << + umember << "." << member << ");"; + else + os << "*this->" << umember << "." << member << ";"; + + os << "}"; + + // void + // name (const type& | type*) + // + os << inl + << "void " << scope << "::" << endl + << name << " ("; + + if (fl) + os << "const " << type << "&"; + else + os << type << "*"; + + os << " x)" + << "{" + << "if (this->" << arm_member << " != " << tag << ")" << endl + << "this->" << arm << " (" << tag << ");"; + + if (fl) + { + os << endl + << "reinterpret_cast< " << type << "& > (this->" << + umember << "." << member << ") = x;"; + + if (min == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof (" << type << ")] = true;"; + } + } + else + { + os << "else" << endl + << "delete this->" << umember << "." << member << ";" + << endl + << "this->" << umember << "." << member << " = x;"; + } + + os << "}"; + } + } + }; + + struct ChoiceInChoiceFunc: Traversal::Choice, CompositorInChoiceFunc + { + ChoiceInChoiceFunc (Context& c) + : CompositorInChoiceFunc (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + CompositorInChoiceFunc::traverse (c); + } + }; + + struct SequenceInChoiceFunc: Traversal::Sequence, CompositorInChoiceFunc + { + SequenceInChoiceFunc (Context& c) + : CompositorInChoiceFunc (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + CompositorInChoiceFunc::traverse (s); + } + }; + + // + // + // + + struct All: Traversal::All, Context + { + All (Context& c, Traversal::ContainsParticle& contains_func) + : Context (c), contains_func_ (contains_func) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + All::contains (a, contains_func_); + + // Custom data. + // + if (a.context ().count ("cd-name")) + { + String const& scope (Context::scope (a)); + String const& type (etype (a)); + + String const& name (ecd_name (a)); + String const& member (ecd_member (a)); + String const& sequence (ecd_sequence (a)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << type << "::" << + sequence << "& " << scope << "::" << type << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << type << "::" << sequence << "& " << + scope << "::" << type << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + } + + private: + Traversal::ContainsParticle& contains_func_; + }; + + struct Choice: Traversal::Choice, Context + { + Choice (Context& c, + Boolean in_choice, + Traversal::ContainsParticle& contains_func) + : Context (c), + in_choice_ (in_choice), + contains_func_ (contains_func) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // When choice is in choice we generate nested class even + // for min == max == 1. + // + if (in_choice_ || c.max () != 1 || c.min () == 0) + { + String scope (Context::scope (c)); + String const& type (etype (c)); + + // void + // arm (arm_tag) + // + os << inl + << scope << "::" << type << "::" << earm_tag (c) << " " << + scope << "::" << type << "::" << endl + << earm (c) << " () const" + << "{" + << "return this->" << earm_member (c) << ";" + << "}"; + + Choice::contains (c, contains_func_); + + // Custom data. + // + if (c.context ().count ("cd-name")) + { + String const& name (ecd_name (c)); + String const& member (ecd_member (c)); + String const& sequence (ecd_sequence (c)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << type << "::" << + sequence << "& " << scope << "::" << type << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << type << "::" << sequence << "& " << + scope << "::" << type << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + + Choice::contains (c); + } + + private: + Boolean in_choice_; + Traversal::ContainsParticle& contains_func_; + }; + + + struct SequenceInSequence: Traversal::Sequence, Context + { + SequenceInSequence (Context& c, + Traversal::ContainsParticle& contains_func) + : Context (c), contains_func_ (contains_func) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1 || s.min () == 0) + { + Sequence::contains (s, contains_func_); + + // Custom data. + // + if (s.context ().count ("cd-name")) + { + String const& scope (Context::scope (s)); + String const& type (etype (s)); + + String const& name (ecd_name (s)); + String const& member (ecd_member (s)); + String const& sequence (ecd_sequence (s)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << type << "::" << + sequence << "& " << scope << "::" << type << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << type << "::" << sequence << "& " << + scope << "::" << type << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + + Sequence::contains (s); + } + + private: + Traversal::ContainsParticle& contains_func_; + }; + + struct SequenceInChoice: Traversal::Sequence, Context + { + SequenceInChoice (Context& c, + Traversal::ContainsParticle& contains_func) + : Context (c), contains_func_ (contains_func) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we generate nested class even + // for min == max == 1. + // + Sequence::contains (s, contains_func_); + + // Custom data. + // + if (s.context ().count ("cd-name")) + { + String const& scope (Context::scope (s)); + String const& type (etype (s)); + + String const& name (ecd_name (s)); + String const& member (ecd_member (s)); + String const& sequence (ecd_sequence (s)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << type << "::" << + sequence << "& " << scope << "::" << type << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << type << "::" << sequence << "& " << + scope << "::" << type << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + + Sequence::contains (s); + } + + private: + Traversal::ContainsParticle& contains_func_; + }; + + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + + // Functions. + // + attribute_func_ (c), + element_func_ (c), + element_in_choice_func_ (c), + all_func_ (c), + choice_in_choice_func_ (c), + choice_in_sequence_func_ (c), + sequence_in_choice_func_ (c), + sequence_in_sequence_func_ (c), + + // Nested classes. + // + all_ (c, all_contains_func_), + choice_in_choice_ (c, true, choice_contains_func_), + choice_in_sequence_ (c, false, choice_contains_func_), + sequence_in_choice_ (c, sequence_contains_func_), + sequence_in_sequence_ (c, sequence_contains_func_) + { + // Functions. + // + attribute_names_func_ >> attribute_func_; + + all_func_ >> all_contains_func_ >> element_func_; + + sequence_in_choice_func_ >> sequence_contains_func_; + sequence_in_sequence_func_ >> sequence_contains_func_; + sequence_contains_func_ >> element_func_; + sequence_contains_func_ >> choice_in_sequence_func_; + sequence_contains_func_ >> sequence_in_sequence_func_; + + choice_in_choice_func_ >> choice_contains_func_; + choice_in_sequence_func_ >> choice_contains_func_; + choice_contains_func_ >> element_in_choice_func_; + choice_contains_func_ >> sequence_in_choice_func_; + choice_contains_func_ >> choice_in_choice_func_; + + contains_compositor_func_ >> all_func_; + contains_compositor_func_ >> choice_in_sequence_func_; + contains_compositor_func_ >> sequence_in_sequence_func_; + + // Nested classes. + // + all_ >> all_contains_; + + choice_in_choice_ >> choice_contains_; + choice_in_sequence_ >> choice_contains_; + choice_contains_ >> choice_in_choice_; + choice_contains_ >> sequence_in_choice_; + + sequence_in_choice_ >> sequence_contains_; + sequence_in_sequence_ >> sequence_contains_; + sequence_contains_ >> choice_in_sequence_; + sequence_contains_ >> sequence_in_sequence_; + + contains_compositor_ >> all_; + contains_compositor_ >> choice_in_sequence_; + contains_compositor_ >> sequence_in_sequence_; + } + + virtual Void + traverse (Type& c) + { + if (!restriction_p (c)) + { + os << "// " << comment (c.name ()) << endl + << "//" << endl + << endl; + + Complex::names (c, attribute_names_func_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_func_); + + // Nested classes. + // + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); + } + + // Custom data. + // + if (c.context ().count ("cd-name")) + { + String const& scope (ename (c)); + String const& name (ecd_name (c)); + String const& member (ecd_member (c)); + String const& sequence (ecd_sequence (c)); + + // const seq& + // name () const + // + os << inl + << "const " << scope << "::" << sequence << "& " << + scope << "::" << endl + << name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << scope << "::" << sequence << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + + private: + // Functions. + // + AttributeFunc attribute_func_; + Traversal::Names attribute_names_func_; + + ElementFunc element_func_; + ElementInChoiceFunc element_in_choice_func_; + AllFunc all_func_; + ChoiceInChoiceFunc choice_in_choice_func_; + ChoiceInSequenceFunc choice_in_sequence_func_; + SequenceInChoiceFunc sequence_in_choice_func_; + SequenceInSequenceFunc sequence_in_sequence_func_; + Traversal::ContainsParticle all_contains_func_; + Traversal::ContainsParticle choice_contains_func_; + Traversal::ContainsParticle sequence_contains_func_; + + Traversal::ContainsCompositor contains_compositor_func_; + + // Nested classes. + // + All all_; + Choice choice_in_choice_; + Choice choice_in_sequence_; + SequenceInChoice sequence_in_choice_; + SequenceInSequence sequence_in_sequence_; + Traversal::ContainsParticle all_contains_; + Traversal::ContainsParticle choice_contains_; + Traversal::ContainsParticle sequence_contains_; + + Traversal::ContainsCompositor contains_compositor_; + }; + } + + Void + generate_tree_inline (Context& ctx) + { + // Generate includes. + // + if (ctx.options.value ()) + { + Traversal::Schema schema; + Includes includes (ctx, Includes::inline_); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + } + else + { + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + Traversal::Sources sources; + Traversal::Names names_ns, names; + + Namespace ns (ctx); + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + //Enumeration enumeration (ctx); + + schema >> sources >> schema; + schema >> names_ns >> ns >> names; + + names >> list; + names >> union_; + names >> complex; + //names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/tree-inline.hxx b/xsde/cxx/hybrid/tree-inline.hxx new file mode 100644 index 0000000..9c8866d --- /dev/null +++ b/xsde/cxx/hybrid/tree-inline.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/tree-inline.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_INLINE_HXX +#define CXX_HYBRID_TREE_INLINE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_tree_inline (Context&); + } +} + +#endif // CXX_HYBRID_TREE_INLINE_HXX diff --git a/xsde/cxx/hybrid/tree-name-processor.cxx b/xsde/cxx/hybrid/tree-name-processor.cxx new file mode 100644 index 0000000..c828250 --- /dev/null +++ b/xsde/cxx/hybrid/tree-name-processor.cxx @@ -0,0 +1,1993 @@ +// file : xsde/cxx/hybrid/tree-name-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + // + // + typedef Cult::Containers::Set NameSet; + Char const* member_set_key = "cxx-hybrid-name-processor-member-set"; + + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, + SemanticGraph::Schema& root, + SemanticGraph::Path const& file) + : CXX::Context (std::wcerr, + root, + "name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + schema_path_ (file), + schema (root), + schema_path (schema_path_), + custom_data_map (custom_data_map_), + global_type_names (global_type_names_) + { + // Translate the type names with custom data. + // + { + typedef Cult::Containers::Vector CustomData; + CustomData const& cd (ops.value ()); + + for (CustomData::ConstIterator i (cd.begin ()); + i != cd.end (); ++i) + { + String name (*i); + CustomDataMap* map (&custom_data_map); + String::size_type b (0), e; + + do + { + e = name.find (L"::", b); + String entry (name, b, e == String::npos ? e : e - b); + + Shptr& p ((*map)[entry]); + + if (p == 0) + p = Shptr (new CustomDataMap); + + b = e; + + if (b == String::npos) + { + // Last name. Add an empty string to indicate this. + // + (*p)[L""] = Shptr (0); + break; + } + + map = p.get (); + b += 2; + + } while (true); + } + } + } + + protected: + Context (Context& c) + : CXX::Context (c), + schema (c.schema), + schema_path (c.schema_path), + custom_data_map (c.custom_data_map), + global_type_names (c.global_type_names) + { + } + + public: + Boolean + fixed_length (SemanticGraph::Type& t) + { + return t.context ().get ("fixed"); + } + + Boolean + fixed_length (SemanticGraph::Compositor& c) + { + return c.context ().get ("fixed"); + } + + Void + mark_variable (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* p (&c); + + while (true) + { + p->context ().set ("fixed", false); + + if (p->contained_compositor_p ()) + break; + + p = &p->contained_particle ().compositor (); + + if (!p->context ().get ("fixed")) + break; + } + } + + public: + String + find_name (String const& n, String const& suffix, NameSet& set) + { + String name (escape (n + suffix)); + + for (UnsignedLong i (1); set.find (name) != set.end (); ++i) + { + std::wostringstream os; + os << i; + name = Hybrid::Context::escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + String + find_name (String const& n, NameSet& set) + { + return find_name (n, L"", set); + } + + public: + struct CustomDataMap: + Cult::Containers::Map > + { + }; + + private: + SemanticGraph::Path const schema_path_; + + CustomDataMap custom_data_map_; + Cult::Containers::Map global_type_names_; + + public: + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + + CustomDataMap& custom_data_map; + Cult::Containers::Map& global_type_names; + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c, Boolean data_members) + : Context (c), data_members_ (data_members) + { + } + + virtual Void + traverse (Type& l) + { + if (!data_members_) + { + // Check if this type has custom data. + // + CustomDataMap::Iterator i (custom_data_map.find (l.name ())); + + if (i != custom_data_map.end () && + i->second->find (L"") != i->second->end ()) + { + SemanticGraph::Context& lc (l.context ()); + + // Use processed name. + // + String const& name (lc.get ("name")); + + lc.set (member_set_key, NameSet ()); + NameSet& set (lc.get (member_set_key)); + set.insert (name); + + { + String name (find_name ("custom_data", set)); + + lc.set ("cd-name", name); + lc.set ("cd-sequence", find_name (name + L"_sequence", set)); + lc.set ("cd-iterator", find_name (name + L"_iterator", set)); + lc.set ("cd-const-iterator", + find_name (name + L"_const_iterator", set)); + } + } + } + else + { + SemanticGraph::Context& lc (l.context ()); + + // Custom data. + // + if (lc.count ("cd-name")) + { + NameSet& set (lc.get (member_set_key)); + String const& base (lc.get ("cd-name")); + lc.set ("cd-member", find_name (base + L"_", set)); + } + } + } + + private: + Boolean data_members_; + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c, Boolean data_members) + : Context (c), data_members_ (data_members) + { + } + + virtual Void + traverse (Type& u) + { + SemanticGraph::Context& uc (u.context ()); + + if (!data_members_) + { + // Use processed name. + // + String const& name (uc.get ("name")); + + uc.set (member_set_key, NameSet ()); + NameSet& set (uc.get (member_set_key)); + set.insert (name); + + uc.set ("value", find_name ("value", set)); + + // Check if this type has custom data. + // + CustomDataMap::Iterator i (custom_data_map.find (u.name ())); + + if (i != custom_data_map.end () && + i->second->find (L"") != i->second->end ()) + { + String name (find_name ("custom_data", set)); + + uc.set ("cd-name", name); + uc.set ("cd-sequence", find_name (name + L"_sequence", set)); + uc.set ("cd-iterator", find_name (name + L"_iterator", set)); + uc.set ("cd-const-iterator", + find_name (name + L"_const_iterator", set)); + } + } + else + { + NameSet& set (uc.get (member_set_key)); + uc.set ("value-member", find_name ("value_", set)); + + // Custom data. + // + if (uc.count ("cd-name")) + { + String const& base (uc.get ("cd-name")); + uc.set ("cd-member", find_name (base + L"_", set)); + } + } + } + + private: + Boolean data_members_; + }; + + // + // Primary names. + // + + struct PrimaryAttribute: Traversal::Attribute, Context + { + PrimaryAttribute (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + a.context ().set ("name", find_name (a.name (), set_)); + } + + private: + NameSet& set_; + }; + + struct PrimaryElement: Traversal::Element, Context + { + PrimaryElement (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + e.context ().set ("name", find_name (e.name (), set_)); + } + + private: + NameSet& set_; + }; + + struct PrimaryAll: Traversal::All, Context + { + PrimaryAll (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + a.context ().set ("name", find_name ("all", set_)); + else + All::contains (a); + } + + private: + NameSet& set_; + }; + + struct PrimaryChoice: Traversal::Choice, Context + { + PrimaryChoice (Context& c, NameSet& set, Boolean in_choice) + : Context (c), set_ (set), in_choice_ (in_choice) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // In case of choice assign primary name even if there is + // no nested class. It is used to derive names for arm + // functions. + // + c.context ().set ("name", find_name ("choice", set_)); + + if (!in_choice_ && c.max () == 1 && c.min () == 1) + Choice::contains (c); + } + + private: + NameSet& set_; + Boolean in_choice_; + }; + + struct PrimarySequence: Traversal::Sequence, Context + { + PrimarySequence (Context& c, NameSet& set, Boolean in_choice) + : Context (c), set_ (set), in_choice_ (in_choice) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we have nested class even + // for min == max == 1. + // + if (in_choice_ || s.max () != 1 || s.min () == 0) + s.context ().set ("name", find_name ("sequence", set_)); + else + Sequence::contains (s); + } + + private: + NameSet& set_; + Boolean in_choice_; + }; + + // + // Secondary names. + // + + struct SecondaryAttribute: Traversal::Attribute, Context + { + SecondaryAttribute (Context& c, NameSet& set, Boolean data_members) + : Context (c), set_ (set), data_members_ (data_members) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + SemanticGraph::Context& ac (a.context ()); + + if (!data_members_) + { + if (a.optional ()) + ac.set ( + "present", + find_name (ac.get ("name") + L"_present", set_)); + } + else + { + String const& base (ac.get ("name")); + + if (a.optional ()) + { + if (fixed_length (a.type ())) + ac.set ("present-member", + find_name (ac.get ("present") + L"_", set_)); + } + + ac.set ("member", find_name (base + L"_", set_)); + } + } + + private: + NameSet& set_; + Boolean data_members_; + }; + + struct SecondaryElement: Traversal::Element, Context + { + SecondaryElement (Context& c, NameSet& set, Boolean data_members) + : Context (c), set_ (set), data_members_ (data_members) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Context& ec (e.context ()); + + if (!data_members_) + { + if (e.max () != 1) + { + String const& base (ec.get ("name")); + + ec.set ("sequence", find_name (base + L"_sequence", set_)); + ec.set ("iterator", find_name (base + L"_iterator", set_)); + ec.set ("const-iterator", + find_name (base + L"_const_iterator", set_)); + } + else if (e.min () == 0) + { + ec.set ( + "present", + find_name (ec.get ("name") + L"_present", set_)); + } + } + else + { + String const& base (ec.get ("name")); + + if (e.max () == 1 && e.min () == 0) + { + if (fixed_length (e.type ())) + ec.set ("present-member", + find_name (ec.get ("present") + L"_", set_)); + } + + ec.set ("member", find_name (base + L"_", set_)); + } + } + + + private: + NameSet& set_; + Boolean data_members_; + }; + + struct SecondaryAll: Traversal::All, Context + { + SecondaryAll (Context& c, + NameSet& set, + CustomDataMap* map, + Boolean data_members) + : Context (c), + set_ (set), + map_ (map), + data_members_ (data_members) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + SemanticGraph::Context& ac (a.context ()); + String const& base (ac.get ("name")); + + if (!data_members_) + { + // Check if this type has custom data. + // + CustomDataMap* map (0); + + if (map_) + { + CustomDataMap::Iterator i (map_->find (base)); + if (i != map_->end ()) + map = i->second.get (); + } + + String type (find_name (base + L"_type", set_)); + ac.set ("type", type); + + // Handle the nested class. + // + { + ac.set (member_set_key, NameSet ()); + NameSet& name_set (ac.get (member_set_key)); + + name_set.insert (type); + + { + PrimaryElement element (*this, name_set); + Traversal::ContainsParticle contains_particle (element); + All::contains (a, contains_particle); + } + + { + SecondaryElement element (*this, name_set, false); + Traversal::ContainsParticle contains_particle (element); + All::contains (a, contains_particle); + } + + // Custom data. + // + if (map && map->find (L"") != map->end ()) + { + // Make the type var-length if we have custom data. + // + if (fixed_length (a)) + mark_variable (a); + + String name (find_name ("custom_data", name_set)); + + ac.set ("cd-name", name); + + ac.set ("cd-sequence", + find_name (name + L"_sequence", name_set)); + + ac.set ("cd-iterator", + find_name (name + L"_iterator", name_set)); + + ac.set ("cd-const-iterator", + find_name (name + L"_const_iterator", name_set)); + } + } + + ac.set ("present", find_name (base + L"_present", set_)); + } + else + { + // Handle the nested class. + // + { + NameSet& name_set (ac.get (member_set_key)); + + SecondaryElement element (*this, name_set, true); + Traversal::ContainsParticle contains_particle (element); + All::contains (a, contains_particle); + + // Custom data. + // + if (ac.count ("cd-name")) + { + String const& base (ac.get ("cd-name")); + ac.set ("cd-member", find_name (base + L"_", name_set)); + } + } + + if (fixed_length (a)) + ac.set ("present-member", + find_name (ac.get ("present") + L"_", set_)); + + ac.set ("member", find_name (base + L"_", set_)); + } + } + else + All::contains (a); + } + + private: + NameSet& set_; + CustomDataMap* map_; + Boolean data_members_; + }; + + struct ParticleTag: Traversal::Element, + Traversal::Any, + Traversal::Choice, + Traversal::Sequence, + Context + { + ParticleTag (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& base (e.context ().get ("name")); + e.context ().set ("tag", find_name (base, L"_tag", set_)); + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + a.context ().set ("tag", find_name (L"any", L"_tag", set_)); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + String const& base (c.context ().get ("name")); + c.context ().set ("tag", find_name (base, L"_tag", set_)); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + String const& base (s.context ().get ("name")); + s.context ().set ("tag", find_name (base, L"_tag", set_)); + } + + private: + NameSet& set_; + }; + + struct SecondaryChoice: Traversal::Choice, Context + { + SecondaryChoice (Context& c, + NameSet& set, + CustomDataMap* map, + Boolean in_choice, + Boolean data_members) + : Context (c), + set_ (set), + map_ (map), + in_choice_ (in_choice), + data_members_ (data_members) + { + } + + virtual Void + traverse (SemanticGraph::Choice&); + + Void + traverse_nested (SemanticGraph::Choice&, NameSet&, CustomDataMap*); + + private: + NameSet& set_; + CustomDataMap* map_; + Boolean in_choice_; + Boolean data_members_; + }; + + struct SecondarySequence: Traversal::Sequence, Context + { + SecondarySequence (Context& c, + NameSet& set, + CustomDataMap* map, + Boolean in_choice, + Boolean data_members) + : Context (c), + set_ (set), + map_ (map), + in_choice_ (in_choice), + data_members_ (data_members) + { + } + + virtual Void + traverse (SemanticGraph::Sequence&); + + Void + traverse_nested (SemanticGraph::Sequence&, NameSet&, CustomDataMap*); + + private: + NameSet& set_; + CustomDataMap* map_; + Boolean in_choice_; + Boolean data_members_; + }; + + + Void SecondaryChoice:: + traverse (SemanticGraph::Choice& c) + { + SemanticGraph::Context& cc (c.context ()); + String const& base (cc.get ("name")); + + // When choice is in choice we have nested class even + // for min == max == 1. + // + if (in_choice_ || c.max () != 1 || c.min () == 0) + { + if (!data_members_) + { + // Check if this type or any of its nested types have + // custom data. + // + CustomDataMap* map (0); + + if (map_) + { + CustomDataMap::Iterator i (map_->find (base)); + if (i != map_->end ()) + map = i->second.get (); + } + + // + // + String type (find_name (base + L"_type", set_)); + cc.set ("type", type); + + // Handle the nested class. + // + { + cc.set (member_set_key, NameSet ()); + NameSet& name_set (cc.get (member_set_key)); + + // Add both base and type names so that we get consistent + // naming for nested choices if any. + // + name_set.insert (base); + name_set.insert (type); + + traverse_nested (c, name_set, map); + + // Tags. + // + String arm (find_name (base + L"_arm", name_set)); + cc.set ("arm", arm); + cc.set ("arm-tag", find_name (arm + L"_tag", name_set)); + + { + UnsignedLong count (name_set.size ()); + + ParticleTag particle (*this, name_set); + Traversal::ContainsParticle contains (particle); + + Choice::contains (c, contains); + + count = name_set.size () - count; + cc.set ("arm-tag-count", count); + } + + // Custom data. + // + if (map && map->find (L"") != map->end ()) + { + // Make the type var-length if we have custom data. + // + if (fixed_length (c)) + mark_variable (c); + + String name (find_name ("custom_data", name_set)); + + cc.set ("cd-name", name); + + cc.set ("cd-sequence", + find_name (name + L"_sequence", name_set)); + + cc.set ("cd-iterator", + find_name (name + L"_iterator", name_set)); + + cc.set ("cd-const-iterator", + find_name (name + L"_const_iterator", name_set)); + } + } + + if (c.max () != 1) + { + cc.set ("sequence", find_name (base + L"_sequence", set_)); + cc.set ("iterator", find_name (base + L"_iterator", set_)); + cc.set ("const-iterator", + find_name (base + L"_const_iterator", set_)); + } + else if (c.min () == 0) + cc.set ("present", find_name (base + L"_present", set_)); + } + else + { + // Handle the nested class. + // + { + NameSet& name_set (cc.get (member_set_key)); + traverse_nested (c, name_set, 0); + + // Tags. + // + cc.set ("arm-member", + find_name (cc.get ("arm") + L"_", name_set)); + cc.set ("member", find_name (base + L"_", name_set)); + + // Custom data. + // + if (cc.count ("cd-name")) + { + String const& base (cc.get ("cd-name")); + cc.set ("cd-member", find_name (base + L"_", name_set)); + } + } + + if (c.max () == 1 && c.min () == 0) + { + if (fixed_length (c)) + cc.set ("present-member", + find_name (cc.get ("present") + L"_", set_)); + } + + cc.set ("member", find_name (base + L"_", set_)); + } + } + else + { + Choice::contains (c); + + if (!data_members_) + { + String arm (find_name (base + L"_arm", set_)); + cc.set ("arm", arm); + cc.set ("arm-tag", find_name (arm + L"_tag", set_)); + + { + UnsignedLong count (set_.size ()); + + ParticleTag particle (*this, set_); + Traversal::ContainsParticle contains (particle); + + Choice::contains (c, contains); + + count = set_.size () - count; + cc.set ("arm-tag-count", count); + } + } + else + { + cc.set ("arm-member", + find_name (cc.get ("arm") + L"_", set_)); + cc.set ("member", find_name (base + L"_", set_)); + } + } + } + + Void SecondaryChoice:: + traverse_nested (SemanticGraph::Choice& c, + NameSet& name_set, + CustomDataMap* map) + { + if (!data_members_) + { + PrimaryElement element (*this, name_set); + PrimaryChoice choice_in_sequence (*this, name_set, false); + PrimarySequence sequence_in_sequence (*this, name_set, false); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + PrimaryChoice choice_in_choice (*this, name_set, true); + PrimarySequence sequence_in_choice (*this, name_set, true); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Choice::contains (c, choice_contains_particle); + } + + SecondaryElement element (*this, name_set, data_members_); + SecondaryChoice choice_in_sequence ( + *this, name_set, map, false, data_members_); + SecondarySequence sequence_in_sequence ( + *this, name_set, map, false, data_members_); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + SecondaryChoice choice_in_choice ( + *this, name_set, map, true, data_members_); + SecondarySequence sequence_in_choice ( + *this, name_set, map, true, data_members_); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Choice::contains (c, choice_contains_particle); + } + + Void SecondarySequence:: + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we have nested class even + // for min == max == 1. + // + if (in_choice_ || s.max () != 1 || s.min () == 0) + { + SemanticGraph::Context& sc (s.context ()); + String const& base (sc.get ("name")); + + if (!data_members_) + { + // Check if this type or any of its nested types have + // custom data. + // + CustomDataMap* map (0); + + if (map_) + { + CustomDataMap::Iterator i (map_->find (base)); + if (i != map_->end ()) + map = i->second.get (); + } + + String type (find_name (base + L"_type", set_)); + sc.set ("type", type); + + // Handle the nested class. + // + { + sc.set (member_set_key, NameSet ()); + NameSet& name_set (sc.get (member_set_key)); + + // Add both base and type names so that we get consistent + // naming for nested sequences if any. + // + name_set.insert (base); + name_set.insert (type); + + traverse_nested (s, name_set, map); + + // Custom data. + // + if (map && map->find (L"") != map->end ()) + { + // Make the type var-length if we have custom data. + // + if (fixed_length (s)) + mark_variable (s); + + String name (find_name ("custom_data", name_set)); + + sc.set ("cd-name", name); + + sc.set ("cd-sequence", + find_name (name + L"_sequence", name_set)); + + sc.set ("cd-iterator", + find_name (name + L"_iterator", name_set)); + + sc.set ("cd-const-iterator", + find_name (name + L"_const_iterator", name_set)); + } + } + + if (s.max () != 1) + { + sc.set ("sequence", find_name (base + L"_sequence", set_)); + sc.set ("iterator", find_name (base + L"_iterator", set_)); + sc.set ("const-iterator", + find_name (base + L"_const_iterator", set_)); + } + else if (s.min () == 0) + sc.set ("present", find_name (base + L"_present", set_)); + } + else + { + // Handle the nested class. + // + { + NameSet& name_set (sc.get (member_set_key)); + traverse_nested (s, name_set, 0); + + // Custom data. + // + if (sc.count ("cd-name")) + { + String const& base (sc.get ("cd-name")); + sc.set ("cd-member", find_name (base + L"_", name_set)); + } + } + + if (s.max () == 1 && s.min () == 0) + { + if (fixed_length (s)) + sc.set ("present-member", + find_name (sc.get ("present") + L"_", set_)); + } + + sc.set ("member", find_name (base + L"_", set_)); + } + } + else + Sequence::contains (s); + } + + Void SecondarySequence:: + traverse_nested (SemanticGraph::Sequence& s, + NameSet& name_set, + CustomDataMap* map) + { + if (!data_members_) + { + PrimaryElement element (*this, name_set); + PrimaryChoice choice_in_sequence (*this, name_set, false); + PrimarySequence sequence_in_sequence (*this, name_set, false); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + PrimaryChoice choice_in_choice (*this, name_set, true); + PrimarySequence sequence_in_choice (*this, name_set, true); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Sequence::contains (s, sequence_contains_particle); + } + + SecondaryElement element (*this, name_set, data_members_); + SecondaryChoice choice_in_sequence ( + *this, name_set, map, false, data_members_); + SecondarySequence sequence_in_sequence ( + *this, name_set, map, false, data_members_); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + SecondaryChoice choice_in_choice ( + *this, name_set, map, true, data_members_); + SecondarySequence sequence_in_choice ( + *this, name_set, map, true, data_members_); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Sequence::contains (s, sequence_contains_particle); + } + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c, Boolean data_members) + : Context (c), data_members_ (data_members) + { + } + + virtual Void + traverse (Type& c) + { + if (data_members_) + assign_data (c); + else + assign_names (c); + } + + virtual Void + assign_names (Type& c) + { + SemanticGraph::Context& cc (c.context ()); + + // Check if this type or any of its nested types have + // custom data. + // + CustomDataMap* map (0); + { + CustomDataMap::Iterator i (custom_data_map.find (c.name ())); + if (i != custom_data_map.end ()) + map = i->second.get (); + } + + // Use processed name. + // + String const& name (cc.get ("name")); + + cc.set (member_set_key, NameSet ()); + NameSet& member_set (cc.get (member_set_key)); + + member_set.insert (name); + + // Add our base's members to the initial list. + // + Boolean restriction (false); + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (b.is_a ()) + { + SemanticGraph::Context& bc (b.context ()); + + if (!bc.count (member_set_key)) + dispatch (b); + + NameSet const& bset (bc.get (member_set_key)); + member_set.insert (bset.begin (), bset.end ()); + } + + // Inheritance by restriction from anyType is a special case. + // + restriction = c.inherits ().is_a () && + !b.is_a (); + } + + if (!restriction) + { + // First assign the "primary" names. + // + PrimaryAttribute pri_attribute (*this, member_set); + Traversal::Names pri_names (pri_attribute); + + Complex::names (c, pri_names); + + if (c.contains_compositor_p ()) + { + PrimaryElement element (*this, member_set); + PrimaryAll all (*this, member_set); + Traversal::ContainsParticle all_contains_particle; + + all >> all_contains_particle >> element; + + PrimaryChoice choice_in_sequence (*this, member_set, false); + PrimarySequence sequence_in_sequence (*this, member_set, false); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + PrimaryChoice choice_in_choice (*this, member_set, true); + PrimarySequence sequence_in_choice (*this, member_set, true); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Traversal::ContainsCompositor contains_compositor; + + contains_compositor >> all; + contains_compositor >> choice_in_sequence; + contains_compositor >> sequence_in_sequence; + + Complex::contains_compositor (c, contains_compositor); + } + + // Assign "secondary" names. + // + SecondaryAttribute sec_attribute (*this, member_set, false); + Traversal::Names sec_names (sec_attribute); + + Complex::names (c, sec_names); + + if (c.contains_compositor_p ()) + { + SecondaryElement element (*this, member_set, false); + SecondaryAll all (*this, member_set, map, false); + Traversal::ContainsParticle all_contains_particle; + + all >> all_contains_particle >> element; + + SecondaryChoice choice_in_sequence ( + *this, member_set, map, false, false); + SecondarySequence sequence_in_sequence ( + *this, member_set, map, false, false); + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + SecondaryChoice choice_in_choice ( + *this, member_set, map, true, false); + SecondarySequence sequence_in_choice ( + *this, member_set, map, true, false); + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Traversal::ContainsCompositor contains_compositor; + + contains_compositor >> all; + contains_compositor >> choice_in_sequence; + contains_compositor >> sequence_in_sequence; + + Complex::contains_compositor (c, contains_compositor); + } + } + + // Custom data. + // + if (map && map->find (L"") != map->end ()) + { + String name (find_name ("custom_data", member_set)); + + cc.set ("cd-name", name); + + cc.set ("cd-sequence", + find_name (name + L"_sequence", member_set)); + + cc.set ("cd-iterator", + find_name (name + L"_iterator", member_set)); + + cc.set ("cd-const-iterator", + find_name (name + L"_const_iterator", member_set)); + } + } + + virtual Void + assign_data (Type& c) + { + SemanticGraph::Context& cc (c.context ()); + Boolean restriction (false); + + if (c.inherits_p ()) + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + + NameSet& member_set (cc.get (member_set_key)); + + if (!restriction) + { + SecondaryAttribute sec_attribute (*this, member_set, true); + Traversal::Names sec_names (sec_attribute); + + Complex::names (c, sec_names); + + if (c.contains_compositor_p ()) + { + SecondaryElement element (*this, member_set, true); + SecondaryAll all (*this, member_set, 0, true); + Traversal::ContainsParticle all_contains_particle; + + all >> all_contains_particle >> element; + + SecondaryChoice choice_in_sequence ( + *this, member_set, 0, false, true); + + SecondarySequence sequence_in_sequence ( + *this, member_set, 0, false, true); + + Traversal::ContainsParticle sequence_contains_particle; + + sequence_contains_particle >> element; + sequence_contains_particle >> choice_in_sequence; + sequence_contains_particle >> sequence_in_sequence; + sequence_in_sequence >> sequence_contains_particle; + + SecondaryChoice choice_in_choice ( + *this, member_set, 0, true, true); + + SecondarySequence sequence_in_choice ( + *this, member_set, 0, true, true); + + Traversal::ContainsParticle choice_contains_particle; + + sequence_in_choice >> sequence_contains_particle; + choice_contains_particle >> element; + choice_contains_particle >> choice_in_choice; + choice_contains_particle >> sequence_in_choice; + choice_in_choice >> choice_contains_particle; + choice_in_sequence >> choice_contains_particle; + + Traversal::ContainsCompositor contains_compositor; + + contains_compositor >> all; + contains_compositor >> choice_in_sequence; + contains_compositor >> sequence_in_sequence; + + Complex::contains_compositor (c, contains_compositor); + } + } + + // Custom data. + // + if (cc.count ("cd-name")) + { + String const& base (cc.get ("cd-name")); + cc.set ("cd-member", find_name (base + L"_", member_set)); + } + } + + private: + Boolean data_members_; + }; + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + String name (find_name (t.name (), set_)); + t.context ().set ("name", name); + } + + private: + NameSet& set_; + }; + + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& ns) + { + SemanticGraph::Context& nsc (ns.context ()); + String const& name (ns.name ()); + + // Use a name set associated with this namespace if present. + // This will make sure that we don't get any conflicts in the + // multi-mapping translation case. Note that here we assume + // that all mappings traverse schemas in the same order which + // is currently the case. + // + if (global_type_names.find (name) == global_type_names.end ()) + { + if (!nsc.count ("name-set")) + nsc.set ("name-set", NameSet ()); + + NameSet& s (nsc.get ("name-set")); + global_type_names[name] = &s; + } + + NameSet& type_set (*global_type_names[name]); + + GlobalType type (*this, type_set); + Traversal::Names names (type); + + Traversal::Namespace::names (ns, names); + } + }; + + struct FundType : Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + + { + FundType (Context& c) + : Context (c) + { + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + set_name (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + set_name (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + set_name (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + set_name (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + set_name (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + set_name (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + set_name (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + set_name (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + set_name (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + set_name (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + set_name (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + set_name (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + set_name (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + set_name (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + set_name (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + set_name (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + set_name (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + set_name (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + set_name (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + set_name (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + set_name (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + set_name (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + set_name (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + set_name (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + set_name (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + set_name (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + set_name (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + set_name (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + set_name (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + set_name (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + set_name (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + set_name (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + set_name (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + set_name (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + set_name (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + set_name (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + set_name (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + set_name (t, "gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + set_name (t, "gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + set_name (t, "gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + set_name (t, "gyear"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + set_name (t, "gyear_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + set_name (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + set_name (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + set_name (t, "entities"); + } + + private: + Void + set_name (SemanticGraph::Type& t, String const& name) + { + SemanticGraph::Context& c (t.context ()); + c.set ("name", escape (name)); + } + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count ("cxx-hybrid-name-processor-seen")) + { + s.context ().set ("cxx-hybrid-name-processor-seen", true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-hybrid-name-processor-seen")) + { + s.context ().set ("cxx-hybrid-name-processor-seen", true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-hybrid-name-processor-seen")) + { + s.context ().set ("cxx-hybrid-name-processor-seen", true); + Traversal::Imports::traverse (i); + } + } + }; + + // Go into implied schemas while making sure we don't process + // the same stuff more than once. + // + struct Implies: Traversal::Implies + { + virtual Void + traverse (SemanticGraph::Implies& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-hybrid-name-processor-seen")) + { + s.context ().set ("cxx-hybrid-name-processor-seen", true); + Traversal::Implies::traverse (i); + } + } + }; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + Context ctx (ops, tu, file); + + if (tu.names_begin ()->named ().name () == + L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + schema >> schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + else + { + // Pass one - assign names to fundamental types. + // + { + Traversal::Schema schema; + Implies implies; + Traversal::Schema xs_schema; + + schema >> implies >> xs_schema; + + Traversal::Names xs_schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + xs_schema >> xs_schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + + // Pass two - assign names to global types. This pass cannot + // be combined with pass three because of possible recursive + // schema inclusions. Also note that we check first if this + // schema has already been processed which may happen in the + // file-per-type compilation mode. + // + if (!tu.context ().count ("cxx-hybrid-name-processor-seen")) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + + schema >> schema_names >> ns; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("cxx-hybrid-name-processor-seen", true); + + schema.dispatch (tu); + } + + // Pass three - assign names inside complex types. Here we don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + List list (ctx, false); + Union union_ (ctx, false); + Complex complex (ctx, false); + + ns_names >> list; + ns_names >> union_; + ns_names >> complex; + + schema.dispatch (tu); + } + + // Pass four - assign names to data memeber. Here we aslo don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + List list (ctx, true); + Union union_ (ctx, true); + Complex complex (ctx, true); + + ns_names >> list; + ns_names >> union_; + ns_names >> complex; + + schema.dispatch (tu); + } + } + } + } + + Void TreeNameProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/hybrid/tree-name-processor.hxx b/xsde/cxx/hybrid/tree-name-processor.hxx new file mode 100644 index 0000000..4d884bc --- /dev/null +++ b/xsde/cxx/hybrid/tree-name-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/hybrid/tree-name-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_NAME_PROCESSOR_HXX +#define CXX_HYBRID_TREE_NAME_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class TreeNameProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_HYBRID_TREE_NAME_PROCESSOR_HXX diff --git a/xsde/cxx/hybrid/tree-size-processor.cxx b/xsde/cxx/hybrid/tree-size-processor.cxx new file mode 100644 index 0000000..43fa2fc --- /dev/null +++ b/xsde/cxx/hybrid/tree-size-processor.cxx @@ -0,0 +1,850 @@ +// file : xsde/cxx/hybrid/tree-size-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + typedef Cult::Containers::Set TypeSet; + + Boolean + test (SemanticGraph::Type& t) + { + return t.context ().count ("fixed") != 0; + } + + Void + set (SemanticGraph::Type& t, Boolean v) + { + t.context ().set ("fixed", v); + } + + Void + set (SemanticGraph::Compositor& c, Boolean v) + { + c.context ().set ("fixed", v); + } + + Boolean + get (SemanticGraph::Type& t) + { + return t.context ().get ("fixed"); + } + + // + // + struct Particle: Traversal::Element + { + Particle (Boolean& fixed, Traversal::NodeBase& type_traverser) + : fixed_ (fixed), type_traverser_ (type_traverser) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (fixed_) + { + // Check cardinality. + // + if (e.max () != 1) + { + fixed_ = false; + return; + } + + // Check the type. + // + SemanticGraph::Type& t (e.type ()); + + if (!test (t)) + type_traverser_.dispatch (t); + + fixed_ = get (t); + } + } + + /* + virtual Void + traverse (SemanticGraph::Any&) + { + // Types with wildcards are always variable length. + // + if (fixed_) + fixed_ = false; + } + */ + + private: + Boolean& fixed_; + Traversal::NodeBase& type_traverser_; + }; + + struct Compositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence + { + Compositor (Boolean& fixed, Traversal::NodeBase& type_traverser) + : fixed_ (fixed), type_traverser_ (type_traverser) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. In case of an optional + // compositor we need to assign the size for the nested class. + // + if (a.min () == 0) + { + Boolean fixed = true; + + { + Particle particle (fixed, type_traverser_); + Traversal::ContainsParticle contains_particle; + + contains_particle >> particle; + + All::contains (a, contains_particle); + } + + set (a, fixed); + + if (!fixed) + fixed_ = false; + } + else + All::contains (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // Here we need to assign the size for the nested class in + // all three cases because this choice might be in choice. + // + Boolean fixed = true; + + { + Particle particle (fixed, type_traverser_); + Compositor compositor (fixed, type_traverser_); + Traversal::ContainsParticle contains_particle; + + contains_particle >> compositor >> contains_particle; + contains_particle >> particle; + + Choice::contains (c, contains_particle); + } + + set (c, fixed); + + if (c.max () != 1 || !fixed) + fixed_ = false; + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // Here we need to assign the size for the nested class in + // all three cases because this sequence might be in choice. + // + Boolean fixed = true; + + { + Particle particle (fixed, type_traverser_); + Compositor compositor (fixed, type_traverser_); + Traversal::ContainsParticle contains_particle; + + contains_particle >> compositor >> contains_particle; + contains_particle >> particle; + + Sequence::contains (s, contains_particle); + } + + set (s, fixed); + + if (s.max () != 1 || !fixed) + fixed_ = false; + } + + private: + Boolean& fixed_; + Traversal::NodeBase& type_traverser_; + }; + + struct Attribute: Traversal::Attribute + { + Attribute (Boolean& fixed, Traversal::NodeBase& type_traverser) + : fixed_ (fixed), type_traverser_ (type_traverser) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + if (fixed_) + { + SemanticGraph::Type& t (a.type ()); + + if (!test (t)) + type_traverser_.dispatch (t); + + fixed_ = get (t); + } + } + + /* + virtual Void + traverse (SemanticGraph::AnyAttribute&) + { + // Types with wildcards are always variable length. + // + if (fixed_) + fixed_ = false; + } + */ + + private: + Boolean& fixed_; + Traversal::NodeBase& type_traverser_; + }; + + // + // + struct Type: Traversal::List, + Traversal::Union, + Traversal::Complex + { + Type (TypeSet& custom_data, Boolean stl_) + : custom_data_ (custom_data), stl (stl_) + { + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!test (l)) + set (l, false); + } + + virtual Void + traverse (SemanticGraph::Union& u) + { + if (!test (u)) + { + Boolean fixed (stl); + + // Check for custom data. + // + if (fixed) + { + if (custom_data_.find (u.name ()) != custom_data_.end ()) + fixed = false; + } + + set (u, fixed); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + SemanticGraph::Context& ctx (c.context ()); + + if (test (c)) + return; + + if (ctx.count ("recurse")) + set (c, false); + else + { + ctx.set ("recurse", true); + + Boolean fixed = true; + + // First check our base. + // + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (!test (b)) + dispatch (b); + + fixed = get (b); + } + + // Check particles. Do this even if fixed is already false + // because we need to calculate sizes for nested classes. + // + if (c.contains_compositor_p ()) + { + Particle particle (fixed, *this); + Compositor compositor (fixed, *this); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor; + + contains_particle >> compositor >> contains_particle; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + + // Check attributes. + // + if (fixed) + { + Attribute attr (fixed, *this); + Traversal::Names names (attr); + + Complex::names (c, names); + } + + // Check for custom data. + // + if (fixed) + { + if (custom_data_.find (c.name ()) != custom_data_.end ()) + fixed = false; + } + + // If we recursed then we should have the value already set. + // + if (!test (c)) + set (c, fixed); + + ctx.remove ("recurse"); + } + } + + private: + TypeSet& custom_data_; + Boolean stl; + }; + + struct FundType : Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities + + { + FundType (Boolean stl_) + : stl (stl_) + { + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + set (t, true); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + set (t, true); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + set (t, true); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + set (t, true); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + set (t, false); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + set (t, stl); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + set (t, stl); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + set (t, false); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + set (t, stl); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + set (t, false); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + set (t, false); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + set (t, true); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + set (t, true); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + set (t, stl); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + set (t, false); + } + + private: + Boolean stl; + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + { + s.context ().set ("cxx-hybrid-size-processor-seen", true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + { + s.context ().set ("cxx-hybrid-size-processor-seen", true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + { + s.context ().set ("cxx-hybrid-size-processor-seen", true); + Traversal::Imports::traverse (i); + } + } + }; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const&) + { + Boolean stl (!ops.value ()); + + // Root schema in the file-per-type mode is just a bunch + // of includes without a namespace. + // + SemanticGraph::Schema::NamesIterator i (tu.names_begin ()); + + if (i != tu.names_end () && + i->named ().name () == L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (stl); + + schema >> schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + else + { + // Pass one - assign sizes to fundamental types. + // + { + Traversal::Schema schema; + Traversal::Implies implies; + Traversal::Schema xs_schema; + + schema >> implies >> xs_schema; + + Traversal::Names xs_schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (stl); + + xs_schema >> xs_schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + + // Note that we check first if this schema has already been + // processed which may happen in the file-per-type compilation + // mode. + // + if (!tu.context ().count ("cxx-hybrid-size-processor-seen")) + { + // Prepare a set of types with custom data. Here we are + // only interested in detecting global types. If a type + // has a nested compositor type which has custom data + // then the type itself will automatically be variable + // size. + // + TypeSet custom_data_types; + + { + typedef Cult::Containers::Vector CustomData; + CustomData const& cd (ops.value ()); + + for (CustomData::ConstIterator i (cd.begin ()); + i != cd.end (); ++i) + { + String n (*i); + custom_data_types.insert (String (n, 0, n.find (L"::"))); + } + } + + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + Type type (custom_data_types, stl); + + schema >> schema_names >> ns >> ns_names >> type; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("cxx-hybrid-size-processor-seen", true); + + schema.dispatch (tu); + } + } + } + } + + Void TreeSizeProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/hybrid/tree-size-processor.hxx b/xsde/cxx/hybrid/tree-size-processor.hxx new file mode 100644 index 0000000..130451f --- /dev/null +++ b/xsde/cxx/hybrid/tree-size-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/hybrid/tree-size-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_SIZE_PROCESSOR_HXX +#define CXX_HYBRID_TREE_SIZE_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class TreeSizeProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_HYBRID_TREE_SIZE_PROCESSOR_HXX diff --git a/xsde/cxx/hybrid/tree-source.cxx b/xsde/cxx/hybrid/tree-source.cxx new file mode 100644 index 0000000..d6c3672 --- /dev/null +++ b/xsde/cxx/hybrid/tree-source.cxx @@ -0,0 +1,1672 @@ +// file : xsd/cxx/hybrid/tree-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + struct ChoiceParticle: Traversal::Element, + Traversal::Compositor, + Context + { + enum Action + { + alloc, + free, + copy, + assign + }; + + ChoiceParticle (Context& c, Action action) + : Context (c), + action_ (action), + var_ (c, TypeName::var), + delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + Boolean fund (false); + { + FundamentalType test (fund); + test.dispatch (t); + } + + // Detect cases where we don't need to generate anything. + // + if (fund) + { + switch (action_) + { + case alloc: + { + if (e.max () == 1 && e.min () == 1) + return; + + break; + } + case free: + { + if (e.max () == 1) + return; + + break; + } + default: + break; + } + } + + String const& member (emember (e)); + String const& umember ( + emember (e.contained_particle ().compositor ())); + + os << "case " << etag (e) << ":" + << "{"; + + switch (action_) + { + case alloc: + { + if (e.max () != 1) + { + os << "new (&this->" << umember << "." << member << ") " << + esequence (e) << ";"; + } + else + { + if (fixed_length (t)) + { + if (!fund) + { + os << "new (&this->" << umember << "." << member << ") "; + var_.dispatch (t); + os << ";"; + } + + if (e.min () == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")] = false;"; + } + } + else + os << "this->" << umember << "." << member << " = 0;"; + } + + break; + } + case free: + { + if (e.max () != 1) + { + String const& sequence (esequence (e)); + + os << "typedef " << sequence << " _dtor;" + << "reinterpret_cast< " << sequence << "& > (this->" << + umember << "." << member << ").~_dtor ();"; + } + else + { + if (fixed_length (t)) + { + os << "typedef "; + var_.dispatch (t); + os << " _dtor;"; + + os << "reinterpret_cast< "; + var_.dispatch (t); + os << "& > (this->" << umember << "." << member << ")." + << "~_dtor ();"; + } + else + { + delete_.dispatch (t); + os << " this->" << umember << "." << member << ";"; + } + } + + break; + } + case copy: + { + // Here we only need to handle the fixed-length situation. + // + if (fund) + { + // Use POD copying. + // + os << "this->" << umember << "." << member << " = x." << + umember << "." << member << ";"; + } + else + { + if (e.min () == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")] = x." << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")];" + << "if (this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")])" << endl; + } + + os << "new (&this->" << umember << "." << member << ") "; + var_.dispatch (t); + os << " (reinterpret_cast< const "; + var_.dispatch (t); + os << "& > (x." << umember << "." << member << "));"; + } + + break; + } + case assign: + { + // Here we only need to handle the fixed-length situation. + // + if (fund) + { + // Use POD assignment. + // + os << "this->" << umember << "." << member << " = x." << + umember << "." << member << ";"; + } + else + { + if (e.min () == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")] = x." << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")];" + << "if (this->" << umember << "." << member << + ".data_[sizeof ("; + var_.dispatch (t); + os << ")])" << endl; + } + + os << "reinterpret_cast< "; + var_.dispatch (t); + os << "& > (this->" << umember << "." << member << ") = " << + "reinterpret_cast< const "; + var_.dispatch (t); + os << "& > (x." << umember << "." << member << ");"; + } + + break; + } + } + + os << "break;" + << "}"; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + String const& member (emember (c)); + String const& umember ( + emember (c.contained_particle ().compositor ())); + + os << "case " << etag (c) << ":" + << "{"; + + switch (action_) + { + case alloc: + { + if (c.max () != 1) + { + os << "new (&this->" << umember << "." << member << ") " << + esequence (c) << ";"; + } + else + { + if (fixed_length (c)) + { + String const& type (etype (c)); + + os << "new (&this->" << umember << "." << member << ") " << + type << ";"; + + if (c.min () == 0) + os << "this->" << umember << "." << member << + ".data_[sizeof (" << type << ")] = false;"; + } + else + os << "this->" << umember << "." << member << " = 0;"; + } + + break; + } + case free: + { + if (c.max () != 1) + { + String const& sequence (esequence (c)); + + os << "typedef " << sequence << " _dtor;" + << "reinterpret_cast< " << sequence << "& > (this->" << + umember << "." << member << ").~_dtor ();"; + } + else + { + if (fixed_length (c)) + { + String const& type (etype (c)); + + os << "reinterpret_cast< " << type << "& > (this->" << + umember << "." << member << ").~" << type << " ();"; + } + else + os << "delete this->" << umember << "." << member << ";"; + } + + break; + } + case copy: + { + // Here we only need to handle the fixed-length situation. + // + String const& type (etype (c)); + + if (c.min () == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof (" << type << ")] = x." << umember << + "." << member << ".data_[sizeof (" << type << ")];" + << "if (this->" << umember << "." << member << + ".data_[sizeof (" << type << ")])" << endl; + } + + os << "new (&this->" << umember << "." << member << ") " << + type << " (reinterpret_cast< const " << type << "& > (x." << + umember << "." << member << "));"; + + break; + } + case assign: + { + // Here we only need to handle the fixed-length situation. + // + String const& type (etype (c)); + + if (c.min () == 0) + { + os << "this->" << umember << "." << member << + ".data_[sizeof (" << type << ")] = x." << umember << + "." << member << ".data_[sizeof (" << type << ")];" + << "if (this->" << umember << "." << member << + ".data_[sizeof (" << type << ")])" << endl; + } + + os << "reinterpret_cast< " << type << "& > (this->" << + umember << "." << member << ") = " << + "reinterpret_cast< const " << type << "& > (x." << + umember << "." << member << ");"; + + break; + } + } + + os << "break;" + << "}"; + } + + private: + Action action_; + TypeName var_; + TypeOps delete_; + }; + + // + // Functions. + // + + struct ChoiceFunc: Traversal::Choice, Context + { + ChoiceFunc (Context& c, Boolean in_choice) + : Context (c), + in_choice_ (in_choice), + particle_free_ (c, ChoiceParticle::free), + particle_alloc_ (c, ChoiceParticle::alloc) + { + contains_free_ >> particle_free_; + contains_alloc_ >> particle_alloc_; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!in_choice_ && c.max () == 1 && c.min () == 1) + { + String const& arm_tag (earm_tag (c)); + String const& arm_member (earm_member (c)); + UnsignedLong bad_tag (arm_tag_count (c)); + + // void + // arm (arm_tag) + // + os << "void " << scope (c) << "::" << endl + << earm (c) << " (" << arm_tag << " x)" + << "{" + << "if (this->" << arm_member << " == x)" << endl + << "return;" + << endl + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_free_); + + os << "default:" << endl + << "break;" + << "}" + << "this->" << arm_member << " = " << + arm_tag << " (" << bad_tag << ");" + << endl + << "switch (x)" + << "{"; + + Choice::contains (c, contains_alloc_); + + os << "default:" << endl + << "break;" + << "}" + << "this->" << arm_member << " = x;" + << "}"; + } + } + + private: + Boolean in_choice_; + + ChoiceParticle particle_free_; + Traversal::ContainsParticle contains_free_; + + ChoiceParticle particle_alloc_; + Traversal::ContainsParticle contains_alloc_; + }; + + struct SequenceFunc: Traversal::Sequence, Context + { + SequenceFunc (Context& c, Boolean in_choice) + : Context (c), in_choice_ (in_choice) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we generate nested class even + // for min == max == 1. + // + if (!in_choice_ && s.max () == 1 && s.min () == 1) + Sequence::contains (s); + } + + private: + Boolean in_choice_; + }; + + // + // C-tor initialization. + // + + struct AttributeCtor: Traversal::Attribute, Context + { + AttributeCtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + Boolean fl (fixed_length (a.type ())); + + if (!fl) + os << "this->" << emember (a) << " = 0;"; + + if (fl && a.optional ()) + os << "this->" << epresent_member (a) << " = false;"; + } + }; + + + struct ElementCtor: Traversal::Element, Context + { + ElementCtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () == 1) + { + Boolean fl (fixed_length (e.type ())); + + if (!fl) + os << "this->" << emember (e) << " = 0;"; + + if (fl && e.min () == 0) + os << "this->" << epresent_member (e) << " = false;"; + } + } + }; + + struct AllCtor: Traversal::All, Context + { + AllCtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + if (fixed_length (a)) + os << "this->" << epresent_member (a) << " = false;"; + else + os << "this->" << emember (a) << " = 0;"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceCtor: Traversal::Choice, Context + { + ChoiceInSequenceCtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () == 1) + { + if (c.min () == 0) + { + if (fixed_length (c)) + os << "this->" << epresent_member (c) << " = false;"; + else + os << "this->" << emember (c) << " = 0;"; + } + else + { + os << "this->" << earm_member (c) << " = " << + earm_tag (c) << " (" << arm_tag_count (c) << ");"; + } + } + } + }; + + struct SequenceInSequenceCtor: Traversal::Sequence, Context + { + SequenceInSequenceCtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () == 1) + { + if (s.min () == 0) + { + if (fixed_length (s)) + os << "this->" << epresent_member (s) << " = false;"; + else + os << "this->" << emember (s) << " = 0;"; + } + else + Sequence::contains (s); + } + } + }; + + // + // D-tor cleanup. + // + + struct AttributeDtor: Traversal::Attribute, Context + { + AttributeDtor (Context& c) + : Context (c), delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + SemanticGraph::Type& t (a.type ()); + + if (!fixed_length (t)) + { + delete_.dispatch (t); + os << " this->" << emember (a) << ";"; + } + } + + private: + TypeOps delete_; + }; + + + struct ElementDtor: Traversal::Element, Context + { + ElementDtor (Context& c) + : Context (c), delete_ (c, TypeOps::delete_) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.max () == 1) + { + SemanticGraph::Type& t (e.type ()); + + if (!fixed_length (t)) + { + delete_.dispatch (t); + os << " this->" << emember (e) << ";"; + } + } + } + + private: + TypeOps delete_; + }; + + struct AllDtor: Traversal::All, Context + { + AllDtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + if (!fixed_length (a)) + os << "delete this->" << emember (a) << ";"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceDtor: Traversal::Choice, Context + { + ChoiceInSequenceDtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () == 1) + { + if (c.min () == 0) + { + if (!fixed_length (c)) + os << "delete this->" << emember (c) << ";"; + } + else + { + os << "this->" << earm (c) << " (" << + earm_tag (c) << " (" << arm_tag_count (c) << "));"; + } + } + } + }; + + struct SequenceInSequenceDtor: Traversal::Sequence, Context + { + SequenceInSequenceDtor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () == 1) + { + if (s.min () == 0) + { + if (!fixed_length (s)) + os << "delete this->" << emember (s) << ";"; + } + else + Sequence::contains (s); + } + } + }; + + // + // Copy c-tor. + // + + struct AttributeCopy: Traversal::Attribute, Context + { + AttributeCopy (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& member (emember (a)); + + if (a.optional ()) + { + String const& present_member (epresent_member (a)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl; + } + + os << "this->" << member << " = x." << member << ";"; + } + }; + + struct ElementCopy: Traversal::Element, Context + { + ElementCopy (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& member (emember (e)); + + if (e.min () == 0) + { + String const& present_member (epresent_member (e)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl; + } + + os << "this->" << member << " = x." << member << ";"; + } + }; + + struct AllCopy: Traversal::All, Context + { + AllCopy (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (a.min () == 0) + { + String const& member (emember (a)); + String const& present_member (epresent_member (a)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceCopy: Traversal::Choice, Context + { + ChoiceInSequenceCopy (Context& c) + : Context (c), particle_copy_ (c, ChoiceParticle::copy) + { + contains_copy_ >> particle_copy_; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.min () == 0) + { + String const& member (emember (c)); + String const& present_member (epresent_member (c)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + { + String const& arm_member (earm_member (c)); + + os << "this->" << arm_member << " = x." << arm_member << ";" + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_copy_); + + os << "default:" << endl + << "break;" + << "}"; + } + } + + private: + ChoiceParticle particle_copy_; + Traversal::ContainsParticle contains_copy_; + }; + + struct SequenceInSequenceCopy: Traversal::Sequence, Context + { + SequenceInSequenceCopy (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.min () == 0) + { + String const& member (emember (s)); + String const& present_member (epresent_member (s)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + Sequence::contains (s); + } + }; + + // + // Assign c-tor. + // + + struct AttributeAssign: Traversal::Attribute, Context + { + AttributeAssign (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& member (emember (a)); + + if (a.optional ()) + { + String const& present_member (epresent_member (a)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl; + } + + os << "this->" << member << " = x." << member << ";"; + } + }; + + struct ElementAssign: Traversal::Element, Context + { + ElementAssign (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& member (emember (e)); + + if (e.min () == 0) + { + String const& present_member (epresent_member (e)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl; + } + + os << "this->" << member << " = x." << member << ";"; + } + }; + + struct AllAssign: Traversal::All, Context + { + AllAssign (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (a.min () == 0) + { + String const& member (emember (a)); + String const& present_member (epresent_member (a)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + All::contains (a); + } + }; + + struct ChoiceInSequenceAssign: Traversal::Choice, Context + { + ChoiceInSequenceAssign (Context& c) + : Context (c), particle_assign_ (c, ChoiceParticle::assign) + { + contains_assign_ >> particle_assign_; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.min () == 0) + { + String const& member (emember (c)); + String const& present_member (epresent_member (c)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + { + String const& arm_member (earm_member (c)); + + os << "this->" << earm (c) << " (x." << arm_member << ");" + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_assign_); + + os << "default:" << endl + << "break;" + << "}"; + } + } + + private: + ChoiceParticle particle_assign_; + Traversal::ContainsParticle contains_assign_; + }; + + struct SequenceInSequenceAssign: Traversal::Sequence, Context + { + SequenceInSequenceAssign (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.min () == 0) + { + String const& member (emember (s)); + String const& present_member (epresent_member (s)); + + os << "this->" << present_member << " = x." << present_member << ";" + << "if (this->" << present_member << ")" << endl + << "this->" << member << " = x." << member << ";"; + } + else + Sequence::contains (s); + } + }; + + // + // Nested classes. + // + + struct All: Traversal::All, Context + { + All (Context& c, + Traversal::ContainsParticle& contains_ctor, + Traversal::ContainsParticle& contains_dtor, + Traversal::ContainsParticle& contains_copy, + Traversal::ContainsParticle& contains_assign) + : Context (c), + contains_ctor_ (contains_ctor), + contains_dtor_ (contains_dtor), + contains_copy_ (contains_copy), + contains_assign_ (contains_assign) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + String const& type (etype (a)); + String const& scope (Context::scope (a)); + + // c-tor + // + os << scope << "::" << type << "::" << endl + << type << " ()" + << "{"; + + All::contains (a, contains_ctor_); + + os << "}"; + + // d-tor + // + os << scope << "::" << type << "::" << endl + << "~" << type << " ()" + << "{"; + + All::contains (a, contains_dtor_); + + os << "}"; + + if (fixed_length (a)) + { + // copy c-tor + // + os << scope << "::" << type << "::" << endl + << type << " (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + All::contains (a, contains_copy_); + + os << "}"; + + // operator= + // + os << scope << "::" << type << "& " << scope << "::" << + type << "::" << endl + << "operator= (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + All::contains (a, contains_assign_); + + os << "return *this;" + << "}"; + } + } + } + + private: + Traversal::ContainsParticle& contains_ctor_; + Traversal::ContainsParticle& contains_dtor_; + Traversal::ContainsParticle& contains_copy_; + Traversal::ContainsParticle& contains_assign_; + }; + + struct Choice: Traversal::Choice, Context + { + Choice (Context& c, + Boolean in_choice, + Traversal::ContainsParticle& contains_func) + : Context (c), + in_choice_ (in_choice), + contains_func_ (contains_func), + particle_free_ (c, ChoiceParticle::free), + particle_alloc_ (c, ChoiceParticle::alloc), + particle_copy_ (c, ChoiceParticle::copy), + particle_assign_ (c, ChoiceParticle::assign) + { + contains_free_ >> particle_free_; + contains_alloc_ >> particle_alloc_; + contains_copy_ >> particle_copy_; + contains_assign_ >> particle_assign_; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // When choice is in choice we generate nested class even + // for min == max == 1. + // + if (in_choice_ || c.max () != 1 || c.min () == 0) + { + String const& type (etype (c)); + String const& arm (earm (c)); + String const& arm_tag (earm_tag (c)); + String const& arm_member (earm_member (c)); + UnsignedLong bad_tag (arm_tag_count (c)); + + String const& scope (Context::scope (c)); + + // c-tor () + // + os << scope << "::" << type << "::" << endl + << type << " ()" + << "{" + << "this->" << arm_member << " = " << + arm_tag << " (" << bad_tag << ");" + << "}"; + + // d-tor () + // + os << scope << "::" << type << "::" << endl + << "~" << type << " ()" + << "{" + << "this->" << arm << " (" << + arm_tag << " (" << bad_tag << "));" + << "}"; + + if (fixed_length (c)) + { + // copy c-tor + // + os << scope << "::" << type << "::" << endl + << type << " (const " << type << "& x)" + << "{" + << "this->" << arm_member << " = x." << arm_member << ";" + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_copy_); + + os << "default:" << endl + << "break;" + << "}" + << "}"; + + // operator= + // + os << scope << "::" << type << "& " << scope << "::" << + type << "::" << endl + << "operator= (const " << type << "& x)" + << "{" + << "this->" << arm << " (x." << arm_member << ");" + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_assign_); + + os << "default:" << endl + << "break;" + << "}" + << "return *this;" + << "}"; + } + + // void + // arm (arm_tag) + // + os << "void " << scope << "::" << type << "::" << endl + << arm << " (" << arm_tag << " x)" + << "{" + << "if (this->" << arm_member << " == x)" << endl + << "return;" + << endl + << "switch (this->" << arm_member << ")" + << "{"; + + Choice::contains (c, contains_free_); + + os << "default:" << endl + << "break;" + << "}" + << "this->" << arm_member << " = " << + arm_tag << " (" << bad_tag << ");" + << endl + << "switch (x)" + << "{"; + + Choice::contains (c, contains_alloc_); + + os << "default:" << endl + << "break;" + << "}" + << "this->" << arm_member << " = x;" + << "}"; + + Choice::contains (c, contains_func_); + } + + Choice::contains (c); + } + + private: + Boolean in_choice_; + Traversal::ContainsParticle& contains_func_; + + ChoiceParticle particle_free_; + Traversal::ContainsParticle contains_free_; + + ChoiceParticle particle_alloc_; + Traversal::ContainsParticle contains_alloc_; + + ChoiceParticle particle_copy_; + Traversal::ContainsParticle contains_copy_; + + ChoiceParticle particle_assign_; + Traversal::ContainsParticle contains_assign_; + }; + + + struct Sequence: Traversal::Sequence, Context + { + Sequence (Context& c, + Boolean in_choice, + Traversal::ContainsParticle& contains_ctor, + Traversal::ContainsParticle& contains_dtor, + Traversal::ContainsParticle& contains_copy, + Traversal::ContainsParticle& contains_assign, + Traversal::ContainsParticle& contains_func) + : Context (c), + in_choice_ (in_choice), + contains_ctor_ (contains_ctor), + contains_dtor_ (contains_dtor), + contains_copy_ (contains_copy), + contains_assign_ (contains_assign), + contains_func_ (contains_func) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // When sequence is in choice we generate nested class even + // for min == max == 1. + // + if (in_choice_ || s.max () != 1 || s.min () == 0) + { + String const& type (etype (s)); + String const& scope (Context::scope (s)); + + // c-tor () + // + os << scope << "::" << type << "::" << endl + << type << " ()" + << "{"; + + Sequence::contains (s, contains_ctor_); + + os << "}"; + + // d-tor () + // + os << scope << "::" << type << "::" << endl + << "~" << type << " ()" + << "{"; + + Sequence::contains (s, contains_dtor_); + + os << "}"; + + if (fixed_length (s)) + { + // copy c-tor + // + os << scope << "::" << type << "::" << endl + << type << " (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + Sequence::contains (s, contains_copy_); + + os << "}"; + + // operator= + // + os << scope << "::" << type << "& " << scope << "::" << + type << "::" << endl + << "operator= (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + Sequence::contains (s, contains_assign_); + + os << "return *this;" + << "}"; + } + + Sequence::contains (s, contains_func_); + } + + Sequence::contains (s); + } + + private: + Boolean in_choice_; + Traversal::ContainsParticle& contains_ctor_; + Traversal::ContainsParticle& contains_dtor_; + Traversal::ContainsParticle& contains_copy_; + Traversal::ContainsParticle& contains_assign_; + Traversal::ContainsParticle& contains_func_; + }; + + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + base_name_ (c, TypeName::base), + + // Functions. + // + choice_in_choice_func_ (c, true), + choice_in_sequence_func_ (c, false), + sequence_in_choice_func_ (c, true), + sequence_in_sequence_func_ (c, false), + + // C-tor initialization. + // + attribute_ctor_ (c), + element_ctor_ (c), + all_ctor_ (c), + choice_in_sequence_ctor_ (c), + sequence_in_sequence_ctor_ (c), + + // D-tor cleanup. + // + attribute_dtor_ (c), + element_dtor_ (c), + all_dtor_ (c), + choice_in_sequence_dtor_ (c), + sequence_in_sequence_dtor_ (c), + + // Copy. + // + attribute_copy_ (c), + element_copy_ (c), + all_copy_ (c), + choice_in_sequence_copy_ (c), + sequence_in_sequence_copy_ (c), + + // Assign. + // + attribute_assign_ (c), + element_assign_ (c), + all_assign_ (c), + choice_in_sequence_assign_ (c), + sequence_in_sequence_assign_ (c), + + // Nested c-tors, etc. + // + all_ (c, + all_contains_ctor_, + all_contains_dtor_, + all_contains_copy_, + all_contains_assign_), + choice_in_choice_ (c, true, choice_contains_func_), + choice_in_sequence_ (c, false, choice_contains_func_), + sequence_in_choice_ ( + c, + true, + sequence_contains_ctor_, + sequence_contains_dtor_, + sequence_contains_copy_, + sequence_contains_assign_, + sequence_contains_func_), + sequence_in_sequence_ ( + c, + false, + sequence_contains_ctor_, + sequence_contains_dtor_, + sequence_contains_copy_, + sequence_contains_assign_, + sequence_contains_func_) + { + // Functions. + // + sequence_in_choice_func_ >> sequence_contains_func_; + sequence_in_sequence_func_ >> sequence_contains_func_; + sequence_contains_func_ >> choice_in_sequence_func_; + sequence_contains_func_ >> sequence_in_sequence_func_; + + choice_in_choice_func_ >> choice_contains_func_; + choice_in_sequence_func_ >> choice_contains_func_; + choice_contains_func_ >> sequence_in_choice_func_; + choice_contains_func_ >> choice_in_choice_func_; + + contains_compositor_func_ >> choice_in_sequence_func_; + contains_compositor_func_ >> sequence_in_sequence_func_; + + // C-tor initialization. + // + attribute_names_ctor_ >> attribute_ctor_; + + all_ctor_ >> all_contains_ctor_ >> element_ctor_; + + sequence_in_sequence_ctor_ >> sequence_contains_ctor_; + sequence_contains_ctor_ >> element_ctor_; + sequence_contains_ctor_ >> choice_in_sequence_ctor_; + sequence_contains_ctor_ >> sequence_in_sequence_ctor_; + + contains_compositor_ctor_ >> all_ctor_; + contains_compositor_ctor_ >> choice_in_sequence_ctor_; + contains_compositor_ctor_ >> sequence_in_sequence_ctor_; + + // D-tor cleanup. + // + attribute_names_dtor_ >> attribute_dtor_; + + all_dtor_ >> all_contains_dtor_ >> element_dtor_; + + sequence_in_sequence_dtor_ >> sequence_contains_dtor_; + sequence_contains_dtor_ >> element_dtor_; + sequence_contains_dtor_ >> choice_in_sequence_dtor_; + sequence_contains_dtor_ >> sequence_in_sequence_dtor_; + + contains_compositor_dtor_ >> all_dtor_; + contains_compositor_dtor_ >> choice_in_sequence_dtor_; + contains_compositor_dtor_ >> sequence_in_sequence_dtor_; + + // Copy. + // + attribute_names_copy_ >> attribute_copy_; + + all_copy_ >> all_contains_copy_ >> element_copy_; + + sequence_in_sequence_copy_ >> sequence_contains_copy_; + sequence_contains_copy_ >> element_copy_; + sequence_contains_copy_ >> choice_in_sequence_copy_; + sequence_contains_copy_ >> sequence_in_sequence_copy_; + + contains_compositor_copy_ >> all_copy_; + contains_compositor_copy_ >> choice_in_sequence_copy_; + contains_compositor_copy_ >> sequence_in_sequence_copy_; + + // Assign. + // + attribute_names_assign_ >> attribute_assign_; + + all_assign_ >> all_contains_assign_ >> element_assign_; + + sequence_in_sequence_assign_ >> sequence_contains_assign_; + sequence_contains_assign_ >> element_assign_; + sequence_contains_assign_ >> choice_in_sequence_assign_; + sequence_contains_assign_ >> sequence_in_sequence_assign_; + + contains_compositor_assign_ >> all_assign_; + contains_compositor_assign_ >> choice_in_sequence_assign_; + contains_compositor_assign_ >> sequence_in_sequence_assign_; + + // Nested c-tors, etc. + // + all_ >> all_contains_; + + choice_in_choice_ >> choice_contains_; + choice_in_sequence_ >> choice_contains_; + choice_contains_ >> choice_in_choice_; + choice_contains_ >> sequence_in_choice_; + + sequence_in_choice_ >> sequence_contains_; + sequence_in_sequence_ >> sequence_contains_; + sequence_contains_ >> choice_in_sequence_; + sequence_contains_ >> sequence_in_sequence_; + + contains_compositor_ >> all_; + contains_compositor_ >> choice_in_sequence_; + contains_compositor_ >> sequence_in_sequence_; + } + + virtual Void + traverse (Type& c) + { + Boolean restriction (restriction_p (c)); + + String name (ename (c)); + + os << "// " << comment (c.name ()) << endl + << "//" << endl + << endl; + + // c-tor () + // + os << name << "::" << endl + << name << " ()" + << "{"; + + if (!restriction) + { + Complex::names (c, attribute_names_ctor_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_ctor_); + } + + os << "}"; + + + if (!restriction) + { + // d-tor () + // + os << name << "::" << endl + << "~" << name << " ()" + << "{"; + + Complex::names (c, attribute_names_dtor_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_dtor_); + + os << "}"; + + if (fixed_length (c)) + { + // copy c-tor + // + os << name << "::" << endl + << name << " (const " << name << "& x)"; + + if (c.inherits_p ()) + { + os << endl + << ": "; + base_name_.dispatch (c.inherits ().base ()); + os << " (x)"; + } + + os << "{" + << "XSDE_UNUSED (x);"; + + Complex::names (c, attribute_names_copy_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_copy_); + + os << "}"; + + // operator= + // + os << name << "& " << name << "::" << endl + << "operator= (const " << name << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + if (c.inherits_p ()) + { + os << "static_cast< "; + base_name_.dispatch (c.inherits ().base ()); + os << "& > (*this) = x;"; + } + + Complex::names (c, attribute_names_assign_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_assign_); + + os << "return *this;" + << "}"; + } + + // Functions. + // + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_func_); + + // Nested c-tors, etc. + // + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); + } + } + + private: + TypeName base_name_; + + // Functions. + // + ChoiceFunc choice_in_choice_func_; + ChoiceFunc choice_in_sequence_func_; + SequenceFunc sequence_in_choice_func_; + SequenceFunc sequence_in_sequence_func_; + Traversal::ContainsParticle choice_contains_func_; + Traversal::ContainsParticle sequence_contains_func_; + + Traversal::ContainsCompositor contains_compositor_func_; + + // C-tor initialization. + // + AttributeCtor attribute_ctor_; + Traversal::Names attribute_names_ctor_; + + ElementCtor element_ctor_; + AllCtor all_ctor_; + ChoiceInSequenceCtor choice_in_sequence_ctor_; + SequenceInSequenceCtor sequence_in_sequence_ctor_; + Traversal::ContainsParticle all_contains_ctor_; + Traversal::ContainsParticle sequence_contains_ctor_; + + Traversal::ContainsCompositor contains_compositor_ctor_; + + // D-tor cleanup. + // + AttributeDtor attribute_dtor_; + Traversal::Names attribute_names_dtor_; + + ElementDtor element_dtor_; + AllDtor all_dtor_; + ChoiceInSequenceDtor choice_in_sequence_dtor_; + SequenceInSequenceDtor sequence_in_sequence_dtor_; + Traversal::ContainsParticle all_contains_dtor_; + Traversal::ContainsParticle sequence_contains_dtor_; + + Traversal::ContainsCompositor contains_compositor_dtor_; + + // Copy. + // + AttributeCopy attribute_copy_; + Traversal::Names attribute_names_copy_; + + ElementCopy element_copy_; + AllCopy all_copy_; + ChoiceInSequenceCopy choice_in_sequence_copy_; + SequenceInSequenceCopy sequence_in_sequence_copy_; + Traversal::ContainsParticle all_contains_copy_; + Traversal::ContainsParticle sequence_contains_copy_; + + Traversal::ContainsCompositor contains_compositor_copy_; + + // Assign. + // + AttributeAssign attribute_assign_; + Traversal::Names attribute_names_assign_; + + ElementAssign element_assign_; + AllAssign all_assign_; + ChoiceInSequenceAssign choice_in_sequence_assign_; + SequenceInSequenceAssign sequence_in_sequence_assign_; + Traversal::ContainsParticle all_contains_assign_; + Traversal::ContainsParticle sequence_contains_assign_; + + Traversal::ContainsCompositor contains_compositor_assign_; + + // Nested c-tors, etc. + // + All all_; + Choice choice_in_choice_; + Choice choice_in_sequence_; + Sequence sequence_in_choice_; + Sequence sequence_in_sequence_; + Traversal::ContainsParticle all_contains_; + Traversal::ContainsParticle choice_contains_; + Traversal::ContainsParticle sequence_contains_; + + Traversal::ContainsCompositor contains_compositor_; + }; + } + + Void + generate_tree_source (Context& ctx) + { + // Needed for placement new. + // + ctx.os << "#include " << endl + << endl; + + Traversal::Schema schema; + Traversal::Sources sources; + Traversal::Names names_ns, names; + + Namespace ns (ctx); + + //Union union_ (ctx); + Complex complex (ctx); + //Enumeration enumeration (ctx); + + schema >> sources >> schema; + schema >> names_ns >> ns >> names; + + //names >> union_; + names >> complex; + //names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/hybrid/tree-source.hxx b/xsde/cxx/hybrid/tree-source.hxx new file mode 100644 index 0000000..7bd6b9e --- /dev/null +++ b/xsde/cxx/hybrid/tree-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/hybrid/tree-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_SOURCE_HXX +#define CXX_HYBRID_TREE_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + Void + generate_tree_source (Context&); + } +} + +#endif // CXX_HYBRID_TREE_SOURCE_HXX diff --git a/xsde/cxx/hybrid/tree-type-map.cxx b/xsde/cxx/hybrid/tree-type-map.cxx new file mode 100644 index 0000000..990d62e --- /dev/null +++ b/xsde/cxx/hybrid/tree-type-map.cxx @@ -0,0 +1,248 @@ +// file : xsde/cxx/hybrid/tree-type-map.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + namespace + { + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, SemanticGraph::Schema& root) + : CXX::Context (std::wcerr, + root, + "name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()) + { + } + + protected: + Context (Context& c) + : CXX::Context (c) + { + } + }; + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, + TypeMap::Namespace* parser, + TypeMap::Namespace* serializer) + : Context (c), parser_ (parser), serializer_ (serializer) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + String const& xn (t.name ()); + String qn (fq_name (t)); + + if (parser_ != 0) + { + if (t.context ().get ("fixed")) + parser_->types_push_back (xn, qn); + else + parser_->types_push_back (xn, qn + L"*"); + } + + if (serializer_ != 0) + serializer_->types_push_back (xn, L"const " + qn + L"&"); + } + + private: + TypeMap::Namespace* parser_; + TypeMap::Namespace* serializer_; + }; + + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c, + String const* hxx_name, + TypeMap::Namespaces* parser_map, + TypeMap::Namespaces* serializer_map) + : Context (c), + hxx_name_ (hxx_name), + parser_map_ (parser_map), + serializer_map_ (serializer_map) + { + } + + virtual Void + traverse (Type& ns) + { + String include; + + if (hxx_name_ != 0) + include = process_include_path (*hxx_name_); + + String const& name (ns.name ()); + + if (parser_map_ != 0) + { + if (name) + parser_map_->push_back (TypeMap::Namespace (name)); + else + parser_map_->push_back ( + TypeMap::Namespace (TypeMap::Pattern ())); + + if (include) + parser_map_->back ().includes_push_back (include); + } + + if (serializer_map_ != 0) + { + if (name) + serializer_map_->push_back (TypeMap::Namespace (name)); + else + serializer_map_->push_back ( + TypeMap::Namespace (TypeMap::Pattern ())); + + if (include) + serializer_map_->back ().includes_push_back (include); + } + + GlobalType type (*this, + (parser_map_ ? &parser_map_->back () : 0), + (serializer_map_ ? &serializer_map_->back () : 0)); + + Traversal::Names names (type); + Namespace::names (ns, names); + } + + private: + String const* hxx_name_; + TypeMap::Namespaces* parser_map_; + TypeMap::Namespaces* serializer_map_; + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + Uses (SemanticGraph::Schema& root) + { + schema_set_.insert (&root); + } + + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + SemanticGraph::Context& sc (s.context ()); + + if (!sc.count ("cxx-hybrid-tree-type-map-seen")) + { + sc.set ("cxx-hybrid-tree-type-map-seen", true); + Traversal::Sources::traverse (sr); + sc.remove ("cxx-hybrid-tree-type-map-seen"); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (schema_set_.find (&s) == schema_set_.end ()) + { + schema_set_.insert (&s); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (schema_set_.find (&s) == schema_set_.end ()) + { + schema_set_.insert (&s); + Traversal::Imports::traverse (i); + } + } + + private: + Containers::Set schema_set_; + }; + } + + Void + generate_tree_type_map (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& tu, + String const& hxx_name, + TypeMap::Namespaces& parser_map, + TypeMap::Namespaces& serializer_map) + { + if (tu.names_begin ()->named ().name () != + L"http://www.w3.org/2001/XMLSchema") + { + Context ctx (ops, tu); + + // We don't want include in the included/imported/sources + // schema so split the traversal into two part. + // + Traversal::Schema schema; + Traversal::Schema used_schema; + Uses uses (tu); + + schema >> uses >> used_schema >> uses; + + Traversal::Names schema_names; + Namespace ns ( + ctx, &hxx_name, + (ops.value () ? &parser_map : 0), + (ops.value () ? &serializer_map : 0)); + + schema >> schema_names >> ns; + + Traversal::Names used_schema_names; + Namespace used_ns ( + ctx, 0, + (ops.value () ? &parser_map : 0), + (ops.value () ? &serializer_map : 0)); + + used_schema >> used_schema_names >> used_ns; + + // Some twisted schemas do recusive self-inclusion. + // + SemanticGraph::Context& tuc (tu.context ()); + + tuc.set ("cxx-hybrid-tree-type-map-seen", true); + schema.dispatch (tu); + tuc.remove ("cxx-hybrid-tree-type-map-seen"); + } + } + } +} diff --git a/xsde/cxx/hybrid/tree-type-map.hxx b/xsde/cxx/hybrid/tree-type-map.hxx new file mode 100644 index 0000000..e5ad7f5 --- /dev/null +++ b/xsde/cxx/hybrid/tree-type-map.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/hybrid/tree-type-map.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_TREE_TYPE_MAP_HXX +#define CXX_HYBRID_TREE_TYPE_MAP_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + Void + generate_tree_type_map (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + String const& hxx_name, + TypeMap::Namespaces& parser_type_map, + TypeMap::Namespaces& serializer_type_map); + } +} + +#endif // CXX_HYBRID_TREE_TYPE_MAP_HXX diff --git a/xsde/cxx/hybrid/validator.cxx b/xsde/cxx/hybrid/validator.cxx new file mode 100644 index 0000000..65dd3e2 --- /dev/null +++ b/xsde/cxx/hybrid/validator.cxx @@ -0,0 +1,584 @@ +// file : xsde/cxx/hybrid/validator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +#include + +using std::wcerr; + +namespace CXX +{ + namespace Hybrid + { + namespace + { + class ValidationContext: public Context + { + public: + ValidationContext (SemanticGraph::Schema& root, + CLI::Options const& options, + const WarningSet& disabled_warnings, + Boolean& valid_) + : Context (std::wcerr, root, options, 0, 0, 0), + disabled_warnings_ (disabled_warnings), + disabled_warnings_all_ (false), + valid (valid_), + subst_group_warning_issued (subst_group_warning_issued_), + subst_group_warning_issued_ (false) + { + } + + public: + Boolean + is_disabled (Char const* w) + { + return disabled_warnings_all_ || + disabled_warnings_.find (w) != disabled_warnings_.end (); + } + + public: + String + xpath (SemanticGraph::Nameable& n) + { + if (n.is_a ()) + return L""; // There is a bug if you see this. + + assert (n.named ()); + + SemanticGraph::Scope& scope (n.scope ()); + + if (scope.is_a ()) + return n.name (); + + return xpath (scope) + L"/" + n.name (); + } + + protected: + ValidationContext (ValidationContext& c) + : Context (c), + disabled_warnings_ (c.disabled_warnings_), + disabled_warnings_all_ (c.disabled_warnings_all_), + valid (c.valid), + subst_group_warning_issued (c.subst_group_warning_issued) + { + } + + protected: + const WarningSet& disabled_warnings_; + Boolean disabled_warnings_all_; + Boolean& valid; + Boolean& subst_group_warning_issued; + Boolean subst_group_warning_issued_; + }; + + // + // + struct Traverser : Traversal::Schema, + Traversal::Complex, + Traversal::Type, + Traversal::Element, + ValidationContext + { + Traverser (ValidationContext& c) + : ValidationContext (c) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + using SemanticGraph::Schema; + + traverse (static_cast (c)); + + if (c.inherits_p ()) + { + SemanticGraph::Type& t (c.inherits ().base ()); + + if (t.named () && + types_.find ( + t.scope ().name () + L"#" + t.name ()) == types_.end ()) + { + // Don't worry about types that are in included/imported + // schemas. + // + Schema& s (dynamic_cast (t.scope ().scope ())); + + if (&s == &schema_root || sources_p (schema_root, s)) + { + valid = false; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: type '" << xpath (c) << "' inherits from " + << "yet undefined type '" << xpath (t) << "'" << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: '" << xpath (t) << "' is defined here" + << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: inheritance from a yet-undefined type is " + << "not supported" << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: re-arrange your schema and try again" + << endl; + } + } + } + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (t.named ()) + { + types_.insert (t.scope ().name () + L"#" + t.name ()); + } + } + + /* + virtual Void + traverse (SemanticGraph::Element& e) + { + if (is_disabled ("H001")) + return; + + if (e.substitutes_p () && + !options.value () && + !subst_group_warning_issued) + { + subst_group_warning_issued = true; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": warning H001: substitution groups are used but " + << "--generate-polymorphic was not specified" << endl; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": info: generated code may not be able to serialize " + << "some conforming instances" << endl; + } + } + */ + + // Return true if root sources s. + // + Boolean + sources_p (SemanticGraph::Schema& root, SemanticGraph::Schema& s) + { + using SemanticGraph::Schema; + using SemanticGraph::Sources; + + for (Schema::UsesIterator i (root.uses_begin ()); + i != root.uses_end (); ++i) + { + if (i->is_a ()) + { + if (&i->schema () == &s || sources_p (i->schema (), s)) + return true; + } + } + + return false; + } + + private: + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + + Traversal::Names names_; + }; + + // + // + struct AnonymousMember: protected ValidationContext + { + AnonymousMember (ValidationContext& c, Boolean& error_issued) + : ValidationContext (c), error_issued_ (error_issued) + { + } + + Boolean + traverse_common (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + if (!t.named () + && !t.is_a () + && !t.is_a ()) + { + if (!error_issued_) + { + valid = false; + error_issued_ = true; + + wcerr << t.file () + << ": error: anonymous types detected" + << endl; + + wcerr << t.file () + << ": info: " + << "anonymous types are not supported in this mapping" + << endl; + + wcerr << t.file () + << ": info: consider explicitly naming these types or " + << "remove the --preserve-anonymous option to " + << "automatically name them" + << endl; + + if (!options.value ()) + wcerr << t.file () + << ": info: use --show-anonymous option to see these " + << "types" << endl; + } + + return true; + } + + return false; + } + + private: + Boolean& error_issued_; + }; + + struct AnonymousElement: Traversal::Element, + AnonymousMember + { + AnonymousElement (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (traverse_common (e)) + { + if (options.value ()) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: element '" << xpath (e) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Element::traverse (e); + } + }; + + struct AnonymousAttribute: Traversal::Attribute, + AnonymousMember + { + AnonymousAttribute (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (Type& a) + { + if (traverse_common (a)) + { + if (options.value ()) + { + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: attribute '" << xpath (a) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Attribute::traverse (a); + } + }; + + struct AnonymousType : Traversal::Schema, + Traversal::Complex, + ValidationContext + { + AnonymousType (ValidationContext& c) + : ValidationContext (c), + error_issued_ (false), + element_ (c, error_issued_), + attribute_ (c, error_issued_) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + + *this >> contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> element_; + + *this >> names_attribute_ >> attribute_; + } + + private: + Boolean error_issued_; + + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + Traversal::Names names_; + + Traversal::Compositor compositor_; + AnonymousElement element_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + AnonymousAttribute attribute_; + Traversal::Names names_attribute_; + }; + + struct GlobalElementCount: Traversal::Element + { + GlobalElementCount (UnsignedLong& count) + : count_ (count) + { + } + + virtual Void + traverse (SemanticGraph::Element&) + { + count_++; + } + + private: + UnsignedLong& count_; + }; + + struct ParserValidation: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Traversal::Complex, + ValidationContext + + { + ParserValidation (ValidationContext& c) + : ValidationContext (c), issued_ (false) + { + contains_compositor_ >> *this; + *this >> contains_particle_ >> *this; + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (!issued_ && a.min () == 0) + { + valid = false; + issued_ = true; + + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: complex type '" << type (a).name () << "' " + << "contains optional all compositor" << endl; + + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: parser validation is required to handle this " + << "construct" << endl; + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!issued_) + { + valid = false; + issued_ = true; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: complex type '" << type (c).name () << "' " + << "contains choice compositor" << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: parser validation is required to handle this " + << "construct" << endl; + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!issued_) + { + if (s.max () != 1) + { + issued_ = true; + wcerr << s.file () << ":" << s.line () << ":" << s.column () + << ": error: complex type '" << type (s).name () << "' " + << "contains sequence of sequence compositor" << endl; + } + else if (s.min () == 0) + { + issued_ = true; + wcerr << s.file () << ":" << s.line () << ":" << s.column () + << ": error: complex type '" << type (s).name () << "' " + << "contains optional sequence compositor" << endl; + } + + if (issued_) + { + valid = false; + wcerr << s.file () << ":" << s.line () << ":" << s.column () + << ": error: parser validation is required to handle " + << "this construct" << endl; + } + } + + Traversal::Sequence::traverse (s); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (!issued_ && !restriction_p (c)) + contains_compositor (c, contains_compositor_); + } + + private: + SemanticGraph::Complex& + type (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + + private: + Boolean issued_; + + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + }; + } + + Boolean Validator:: + validate (CLI::Options const& options, + SemanticGraph::Schema& root, + SemanticGraph::Path const&, + const WarningSet& disabled_warnings) + { + Boolean valid (true); + ValidationContext ctx (root, options, disabled_warnings, valid); + + Boolean par (options.value ()); + Boolean ser (options.value ()); + Boolean agg (options.value ()); + + if (agg && !par && !ser && !ctx.is_disabled ("H002")) + { + wcerr << root.file () << ": warning H002: --generate-aggregate " << + "is specified but neither parsing nor serialization code is " << + "generated" << endl; + } + + // Issue a warning if there are more than one global element and we + // are generating aggregate types. + // + if (agg && + !options.value () && + !options.value () && + !options.value () && + !options.value () && + options.value ().empty () && + !ctx.is_disabled ("H003")) + { + UnsignedLong count (0); + + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + GlobalElementCount element (count); + + names >> element; + + schema.dispatch (root); + } + + if (count > 1) + { + wcerr << root.file () << ": warning H003: generating aggregate " << + "types for " << count << " global elements" << endl; + + wcerr << root.file () << ": info: use --root-element-* options " + << "to specify document root(s)" << endl; + } + } + + // Test for anonymout types. + // + { + AnonymousType traverser (ctx); + traverser.dispatch (root); + } + + // Test for constructs that require validation in parser. + // + if (valid && par && + (options.value () || + options.value ())) + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + + schema >> schema_names >> ns >> names; + + ParserValidation type (ctx); + + names >> type; + + schema.dispatch (root); + } + + // Test the rest. + // + if (valid) + { + Traverser traverser (ctx); + traverser.dispatch (root); + } + + return valid; + } + } +} diff --git a/xsde/cxx/hybrid/validator.hxx b/xsde/cxx/hybrid/validator.hxx new file mode 100644 index 0000000..0fb6df6 --- /dev/null +++ b/xsde/cxx/hybrid/validator.hxx @@ -0,0 +1,35 @@ +// file : xsde/cxx/hybrid/validator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_VALIDATOR_HXX +#define CXX_HYBRID_VALIDATOR_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + using namespace Cult::Types; + + class Validator + { + public: + Boolean + validate (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& tu, + const WarningSet& disabled_warnings); + }; + } +} + +#endif // CXX_HYBRID_VALIDATOR_HXX diff --git a/xsde/cxx/parser/attribute-validation-source.cxx b/xsde/cxx/parser/attribute-validation-source.cxx new file mode 100644 index 0000000..19c94fa --- /dev/null +++ b/xsde/cxx/parser/attribute-validation-source.cxx @@ -0,0 +1,468 @@ +// file : xsde/cxx/parser/attribute-validation-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Test: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + Test (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& name (a.name ()); + + if (a.qualified () && a.namespace_ ().name ()) + { + String const& ns (a.namespace_ ().name ()); + + os << "n == " << L << strlit (name) << " &&" << endl + << "ns == " << L << strlit (ns); + } + else + os << "n == " << L << strlit (name) << " && ns.empty ()"; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + String const& ns (a.definition_namespace ().name ()); + + for (SemanticGraph::AnyAttribute::NamespaceIterator + i (a.namespace_begin ()), e (a.namespace_end ()); i != e;) + { + if (*i == L"##any") + { + os << "!n.empty ()"; + } + else if (*i == L"##other") + { + if (ns) + { + // Note that here I assume that ##other does not include + // unqualified names in a schema with target namespace. + // This is not what the spec says but that seems to be + // the consensus. + // + os << "(!ns.empty () && ns != " << L << strlit (ns) << ")"; + } + else + os << "!ns.empty ()"; + } + else if (*i == L"##local") + { + os << "(ns.empty () && !n.empty ())"; + } + else if (*i == L"##targetNamespace") + { + os << "ns == " << L << strlit (ns); + } + else + { + os << "ns == " << L << strlit (*i); + } + + if (++i != e) + os << " ||" << endl; + } + } + }; + + // + // + struct PhaseOne : Traversal::Attribute, Context + { + PhaseOne (Context& c) + : Context (c), test_ (c) + { + } + + virtual Void + traverse (Type& a) + { + String const& name (ename (a)); + String const& inst (emember (a)); + + SemanticGraph::Type& type (a.type ()); + String const& post (post_name (type)); + String const& ret (ret_type (type)); + + os << "if ("; + + test_.traverse (a); + + os << ")" + << "{" + << "if (this->" << inst << ")" + << "{" + << "this->" << inst << "->pre ();" + << endl; + + if (!exceptions) + os << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << "else" << endl; + + os << "this->" << inst << "->_pre_impl (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_characters (s);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_post_impl ();" + << endl + << "if (!ctx.error_type ())" << endl; + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << endl; + else + os << "{" + << arg_type (type) << " tmp = this->" << inst << "->" << + post << " ();" + << endl; + + if (!exceptions) + os << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << "else" << endl; + + if (ret == L"void") + os << "this->" << name << " ();"; + else + os << "this->" << name << " (tmp);" + << "}"; + + os << "}"; + + if (!a.optional ()) + os << "static_cast< v_state_attr_* > (" << + "this->v_state_attr_stack_.top ())->" << name << " = true;"; + + os << "return true;" + << "}"; + } + + private: + Test test_; + }; + + + // + // + struct PhaseTwo : Traversal::AnyAttribute, Context + { + PhaseTwo (Context& c) + : Context (c), test_ (c) + { + } + + virtual Void + traverse (Type& a) + { + os << "if ("; + + test_.traverse (a); + + os << ")" << endl + << "{" + << "this->_any_attribute (ns, n, s);" + << "return true;" + << "}"; + } + + private: + Test test_; + }; + + + // + // + struct AttributeStateInit: Traversal::Attribute, Context + { + AttributeStateInit (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + if (!a.optional ()) + os << "as." << ename (a) << " = false;"; + } + }; + + + // + // + struct AttributeStateCheck: Traversal::Attribute, Context + { + AttributeStateCheck (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + if (!a.optional ()) + { + String ns (a.qualified () ? a.namespace_ ().name () : String ()); + + os << "if (!as." << ename (a) << ")" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_attribute);" + << "return;" + << "}"; + } + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + phase_one_ (c), + phase_two_ (c), + attribute_state_init_ (c), + attribute_state_check_ (c) + { + names_phase_one_ >> phase_one_; + names_phase_two_ >> phase_two_; + + names_attribute_state_init_ >> attribute_state_init_; + names_attribute_state_check_ >> attribute_state_check_; + } + + virtual Void + traverse (Type& c) + { + Boolean has_att (has (c)); + Boolean has_any (has (c)); + + if (!has_att && !has_any) + return; + + Boolean has_req_att (false); + if (has_att) + { + RequiredAttributeTest test (has_req_att); + Traversal::Names names_test (test); + names (c, names_test); + } + + String const& name (ename (c)); + + os <<"// Attribute validation and dispatch functions for " << + name << "." << endl + <<"//" << endl; + + if (has_att) + { + // _attribute_impl_phase_one + // + os << "bool " << name << "::" << endl + << "_attribute_impl_phase_one (const " << string_type << + "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "& s)" << endl + << "{" + << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + names (c, names_phase_one_); + + // Nothing matched - call our base (extension) or return false + // if there is no base (or restriction (even from anyType)). + // + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << "return " << base << + "::_attribute_impl_phase_one (ns, n, s);"; + } + else + os << "return false;"; + + os << "}"; + } + + + if (has_any) + { + // _attribute_impl_phase_two + // + os << "bool " << name << "::" << endl + << "_attribute_impl_phase_two (const " << string_type << + "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "& s)" + << "{"; + + names (c, names_phase_two_); + + // Nothing matched - call our base (extension) or return false + // if there is no base (or restriction (even from anyType)). + // + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << "return " << base << + "::_attribute_impl_phase_two (ns, n, s);"; + } + else + os << "return false;"; + + os << "}"; + } + + if (has_req_att) + { + // _pre_a_validate + // + os << "void " << name << "::" << endl + << "_pre_a_validate ()" + << "{"; + + if (exceptions) + os << "this->v_state_attr_stack_.push ();"; + else + os << "if (this->v_state_attr_stack_.push ())" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + + os << "v_state_attr_& as = *static_cast< v_state_attr_* > (" << + "this->v_state_attr_stack_.top ());" + << endl; + + names (c, names_attribute_state_init_); + + // Call our base (extension) last. + // + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_pre_a_validate ();"; + } + + os << "}"; + + + // _post_a_validate + // + os << "void " << name << "::" << endl + << "_post_a_validate ()" + << "{"; + + // Call our base (extension) first. + // + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_post_a_validate ();" + << endl; + + os << "if (this->_context ().error_type ())" << endl + << "return;" + << endl; + } + + os << "v_state_attr_& as = *static_cast< v_state_attr_* > (" << + "this->v_state_attr_stack_.top ());" + << endl; + + names (c, names_attribute_state_check_); + + os << endl + << "this->v_state_attr_stack_.pop ();" + << "}"; + } + } + + private: + PhaseOne phase_one_; + Traversal::Names names_phase_one_; + + PhaseTwo phase_two_; + Traversal::Names names_phase_two_; + + AttributeStateInit attribute_state_init_; + Traversal::Names names_attribute_state_init_; + + AttributeStateCheck attribute_state_check_; + Traversal::Names names_attribute_state_check_; + }; + } + + Void + generate_attribute_validation_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/attribute-validation-source.hxx b/xsde/cxx/parser/attribute-validation-source.hxx new file mode 100644 index 0000000..70101da --- /dev/null +++ b/xsde/cxx/parser/attribute-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/attribute-validation-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_ATTRIBUTE_VALIDATION_SOURCE_HXX +#define CXX_PARSER_ATTRIBUTE_VALIDATION_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_attribute_validation_source (Context&); + } +} + +#endif // CXX_PARSER_ATTRIBUTE_VALIDATION_SOURCE_HXX diff --git a/xsde/cxx/parser/characters-validation-source.cxx b/xsde/cxx/parser/characters-validation-source.cxx new file mode 100644 index 0000000..c97a859 --- /dev/null +++ b/xsde/cxx/parser/characters-validation-source.cxx @@ -0,0 +1,76 @@ +// file : xsde/cxx/parser/characters-validation-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + if (!c.mixed ()) + return; + + String const& name (ename (c)); + + os <<"// Character validation functions for " << name << "." << endl + <<"//" << endl; + + // _characters_impl + // + os << "bool " << name << "::" << endl + << "_characters_impl (const " << string_type << "& s)" + << "{" + << "this->_any_characters (s);" + << "return true;" + << "}"; + } + }; + } + + Void + generate_characters_validation_source (Context& ctx) + { + //@@ Most of the time there is no mixed content type so + // we generate an empty namespace which looks ugly. Will + // need to implement smart namespace to handle this at + // some point. + // + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} + diff --git a/xsde/cxx/parser/characters-validation-source.hxx b/xsde/cxx/parser/characters-validation-source.hxx new file mode 100644 index 0000000..5fab5cc --- /dev/null +++ b/xsde/cxx/parser/characters-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/characters-validation-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_CHARACTERS_VALIDATION_SOURCE_HXX +#define CXX_PARSER_CHARACTERS_VALIDATION_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_characters_validation_source (Context&); + } +} + +#endif // CXX_PARSER_CHARACTERS_VALIDATION_SOURCE_HXX diff --git a/xsde/cxx/parser/cli.hxx b/xsde/cxx/parser/cli.hxx new file mode 100644 index 0000000..485dd91 --- /dev/null +++ b/xsde/cxx/parser/cli.hxx @@ -0,0 +1,156 @@ +// file : xsde/cxx/parser/cli.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_CLI_HXX +#define CXX_PARSER_CLI_HXX + +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace CLI + { + using namespace Cult::Types; + + typedef Char const Key[]; + + extern Key type_map; + extern Key no_stl; + extern Key no_iostream; + extern Key no_exceptions; + extern Key no_long_long; + extern Key reuse_style_mixin; + extern Key reuse_style_none; + extern Key generate_inline; + extern Key suppress_validation; + extern Key generate_polymorphic; + extern Key runtime_polymorphic; + extern Key suppress_reset; + extern Key generate_noop_impl; + extern Key generate_print_impl; + extern Key generate_test_driver; + extern Key force_overwrite; + extern Key root_element_first; + extern Key root_element_last; + extern Key root_element; + extern Key generate_xml_schema; + extern Key extern_xml_schema; + extern Key output_dir; + extern Key skel_type_suffix; + extern Key skel_file_suffix; + extern Key impl_type_suffix; + extern Key impl_file_suffix; + extern Key namespace_map; + extern Key namespace_regex; + extern Key namespace_regex_trace; + extern Key reserved_name; + extern Key include_with_brackets; + extern Key include_prefix; + extern Key include_regex; + extern Key include_regex_trace; + extern Key guard_prefix; + extern Key hxx_suffix; + extern Key ixx_suffix; + extern Key cxx_suffix; + extern Key hxx_regex; + extern Key ixx_regex; + extern Key cxx_regex; + extern Key hxx_prologue; + extern Key ixx_prologue; + extern Key cxx_prologue; + extern Key prologue; + extern Key hxx_epilogue; + extern Key ixx_epilogue; + extern Key cxx_epilogue; + extern Key epilogue; + extern Key hxx_prologue_file; + extern Key ixx_prologue_file; + extern Key cxx_prologue_file; + extern Key prologue_file; + extern Key hxx_epilogue_file; + extern Key ixx_epilogue_file; + extern Key cxx_epilogue_file; + extern Key epilogue_file; + extern Key show_anonymous; + extern Key show_sloc; + extern Key proprietary_license; + + typedef Cult::CLI::Options< + type_map, Cult::Containers::Vector, + no_stl, Boolean, + no_iostream, Boolean, + no_exceptions, Boolean, + no_long_long, Boolean, + reuse_style_mixin, Boolean, + reuse_style_none, Boolean, + generate_inline, Boolean, + suppress_validation, Boolean, + generate_polymorphic, Boolean, + runtime_polymorphic, Boolean, + suppress_reset, Boolean, + generate_noop_impl, Boolean, + generate_print_impl, Boolean, + generate_test_driver, Boolean, + force_overwrite, Boolean, + root_element_first, Boolean, + root_element_last, Boolean, + root_element, NarrowString, + generate_xml_schema, Boolean, + extern_xml_schema, NarrowString, + output_dir, NarrowString, + skel_type_suffix, NarrowString, + skel_file_suffix, NarrowString, + impl_type_suffix, NarrowString, + impl_file_suffix, NarrowString, + namespace_map, Cult::Containers::Vector, + namespace_regex, Cult::Containers::Vector, + namespace_regex_trace, Boolean, + reserved_name, Cult::Containers::Vector, + include_with_brackets, Boolean, + include_prefix, NarrowString, + include_regex, Cult::Containers::Vector, + include_regex_trace, Boolean, + guard_prefix, NarrowString, + hxx_suffix, NarrowString, + ixx_suffix, NarrowString, + cxx_suffix, NarrowString, + hxx_regex, NarrowString, + ixx_regex, NarrowString, + cxx_regex, NarrowString, + hxx_prologue, Cult::Containers::Vector, + ixx_prologue, Cult::Containers::Vector, + cxx_prologue, Cult::Containers::Vector, + prologue, Cult::Containers::Vector, + hxx_epilogue, Cult::Containers::Vector, + ixx_epilogue, Cult::Containers::Vector, + cxx_epilogue, Cult::Containers::Vector, + epilogue, Cult::Containers::Vector, + hxx_prologue_file, NarrowString, + ixx_prologue_file, NarrowString, + cxx_prologue_file, NarrowString, + prologue_file, NarrowString, + hxx_epilogue_file, NarrowString, + ixx_epilogue_file, NarrowString, + cxx_epilogue_file, NarrowString, + epilogue_file, NarrowString, + show_anonymous, Boolean, + show_sloc, Boolean, + proprietary_license, Boolean + + > Options; + + struct OptionsSpec: Cult::CLI::OptionsSpec {}; + } + } +} + +#endif // CXX_PARSER_CLI_HXX diff --git a/xsde/cxx/parser/driver-source.cxx b/xsde/cxx/parser/driver-source.cxx new file mode 100644 index 0000000..7221741 --- /dev/null +++ b/xsde/cxx/parser/driver-source.cxx @@ -0,0 +1,1139 @@ +// file : xsde/cxx/parser/driver-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + typedef Cult::Containers::Set InstanceSet; + + // For base types we only want member's types, but not the + // base itself. + // + struct BaseType: Traversal::Complex, Context + { + BaseType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + }; + + struct ParserDef: Traversal::Type, + Traversal::List, + Traversal::Complex, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + ParserDef (Context& c, TypeInstanceMap& map, InstanceSet& set) + : Context (c), map_ (map), set_ (set), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (t)); + map_[&t] = inst; + + os << fq_name (t, "p:impl") << " " << inst << ";"; + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (map_.find (&l) == map_.end ()) + { + String inst (find_instance_name (l)); + map_[&l] = inst; + + os << fq_name (l, "p:impl") << " " << inst << ";"; + + dispatch (l.argumented ().type ()); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (map_.find (&c) == map_.end ()) + { + String inst (find_instance_name (c)); + map_[&c] = inst; + + os << fq_name (c, "p:impl") << " " << inst << ";"; + + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + fund_type (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + fund_type (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + fund_type (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + fund_type (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + fund_type (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + fund_type (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + fund_type (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + fund_type (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + fund_type (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + fund_type (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + fund_type (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + fund_type (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + fund_type (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + fund_type (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + fund_type (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + fund_type (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + fund_type (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + fund_type (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + fund_type (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + fund_type (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + fund_type (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + fund_type (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + fund_type (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + fund_type (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + fund_type (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + fund_type (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + fund_type (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + fund_type (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + fund_type (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + fund_type (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + fund_type (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + fund_type (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + fund_type (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + fund_type (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + fund_type (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + fund_type (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + fund_type (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + fund_type (t, "day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + fund_type (t, "month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + fund_type (t, "month_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + fund_type (t, "year"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + fund_type (t, "year_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + fund_type (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + fund_type (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + fund_type (t, "entities"); + } + + private: + virtual Void + fund_type (SemanticGraph::Type& t, String const& name) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (name)); + map_[&t] = inst; + + os << fq_name (t, "p:impl") << " " << inst << ";"; + } + } + + String + find_instance_name (String const& raw_name) + { + String base_name (escape (raw_name + L"_p")); + String name (base_name); + + for (UnsignedLong i (1); set_.find (name) != set_.end (); ++i) + { + std::wostringstream os; + os << i; + name = base_name + os.str (); + } + + set_.insert (name); + return name; + } + + String + find_instance_name (SemanticGraph::Type& t) + { + return find_instance_name (t.name ()); + } + + TypeInstanceMap& map_; + InstanceSet& set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + // + // + struct ParticleArg: Traversal::Element, Context + { + ParticleArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&e.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct AttributeArg: Traversal::Attribute, Context + { + AttributeArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&a.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct ArgList : Traversal::Complex, + Traversal::List, + Context + { + ArgList (Context& c, TypeInstanceMap& map) + : Context (c), + map_ (map), + particle_ (c, map, first_), + attribute_ (c, map, first_), + first_ (true) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&l.argumented ().type ()]; + } + + private: + TypeInstanceMap& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleArg particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + AttributeArg attribute_; + + Boolean first_; + }; + + struct ParserConnect: Traversal::List, + Traversal::Complex, + Context + { + ParserConnect (Context& c, TypeInstanceMap& map) + : Context (c), map_ (map), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (type_set_.find (&l) == type_set_.end ()) + { + os << map_[&l] << ".parsers (" << + map_[&l.argumented ().type ()] << ");" + << endl; + + type_set_.insert (&l); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (type_set_.find (&c) == type_set_.end ()) + { + if (has_members (c)) + { + os << map_[&c] << ".parsers ("; + + ArgList args (*this, map_); + args.dispatch (c); + + os << ");" + << endl; + } + + type_set_.insert (&c); + + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + private: + Boolean + has_members (SemanticGraph::Complex& c) + { + using SemanticGraph::Complex; + + if (has (c)) + return true; + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&b)) + return has_members (*cb); + + return b.is_a (); + } + + return false; + } + + private: + TypeInstanceMap& map_; + Cult::Containers::Set type_set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c, SemanticGraph::Element*& element) + : Context (c), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (options.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (String name = options.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + element_ = &e; // Cover root-element-last and no option. + } + + private: + SemanticGraph::Element*& element_; + }; + } + + Void + generate_driver_source (Context& ctx) + { + // Figure out the root element. Validator should have made sure + // it is unique. + // + SemanticGraph::Element* root (0); + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + RootElement global_element (ctx.options, root); + + schema >> schema_names >> ns >> ns_names >> global_element; + + schema.dispatch (ctx.schema_root); + } + + String xs (ctx.xs_ns_name ()); + std::wostream& os (ctx.os); + + InstanceSet set; + TypeInstanceMap map; + SemanticGraph::Type& root_type (root->type ()); + + set.insert ("doc_p"); + + if (ctx.options.value ()) + os << "#include " << endl; + else + os << "#include " << endl; + + os << endl + << "int" << endl + << "main (int argc, char* argv[])" + << "{" + << "const char* input;" + << endl + << "if (argc < 2)" + << "{" + << "input = \"STDIN\";"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"XML file not specified, reading " << + "from STDIN\\n\");"; + else + os << "std::cerr << \"XML file not specified, reading " << + "from STDIN\" << std::endl;"; + + os << "}" + << "else" << endl + << "input = argv[1];" + << endl; + + if (ctx.options.value ()) + { + os << "FILE* f = argc > 1 ? fopen (argv[1], \"rb\") : stdin;" + << endl + << "if (f == 0)" + << "{" + << "fprintf (stderr, \"%s: unable to open\\n\", input);" + << "return 1;" + << "}"; + } + + if (ctx.options.value () || + ctx.options.value ()) + os << "int r = 0;" + << endl; + + if (!ctx.options.value ()) + os << "try" + << "{"; + + os << "// Instantiate individual parsers." << endl + << "//" << endl; + + { + ParserDef def (ctx, map, set); + def.dispatch (root_type); + } + + os << endl + << "// Connect the parsers together." << endl + << "//" << endl; + + { + // @@ I can simply iterate over the map instead of traversing + // the tree all over again. + // + ParserConnect connect (ctx, map); + connect.dispatch (root_type); + } + + String const& root_p (map[&root_type]); + + os << "// Parse the XML document." << endl + << "//" << endl; + + if (ctx.options.value ()) + os << "bool io_error = false;"; + + if (ctx.options.value ()) + os << xs << "::parser_error e;" + << endl + << "do" + << "{"; + + if (root->namespace_().name ()) + os << xs << "::document_pimpl doc_p (" << endl + << root_p << "," << endl + << ctx.strlit (root->namespace_().name ()) << "," << endl + << ctx.strlit (root->name ()) << ");" + << endl; + else + os << xs << "::document_pimpl doc_p (" << root_p << ", " << + ctx.strlit (root->name ()) << ");" + << endl; + + if (ctx.options.value ()) + os << "if (e = doc_p._error ())" << endl + << "break;" + << endl; + + os << root_p << ".pre ();"; + + if (ctx.options.value ()) + os << endl + << "if (e = " << root_p << "._error ())" << endl + << "break;"; + + + if (ctx.options.value ()) + { + os << endl + << "char buf[4096];" + << endl + << "do" + << "{" + << "size_t s = fread (buf, 1, sizeof (buf), f);" + << endl + << "if (s != sizeof (buf) && ferror (f))" + << "{" + << "io_error = true;" + << "break;" + << "}"; + + if (ctx.options.value ()) + os << "doc_p.parse (buf, s, feof (f) != 0);" + << "e = doc_p._error ();" + << "}" + << "while (!e && !feof (f));" + << endl + << "if (io_error || e)" << endl + << "break;" + << endl; + else + os << "doc_p.parse (buf, s, feof (f) != 0);" + << "}" + << "while (!feof (f));" + << endl + << "if (!io_error)" + << "{"; + } + else + { + os << endl + << "if (argc < 2)" << endl + << "doc_p.parse (std::cin);" + << "else" << endl + << "doc_p.parse (argv[1]);" + << endl; + + if (ctx.options.value ()) + os << "if (e = doc_p._error ())" << endl + << "break;" + << endl; + } + + String const& ret (Context::ret_type (root_type)); + String const& post (Context::post_name (root_type)); + + if (ret == L"void") + { + os << root_p << "." << post << " ();"; + + if (ctx.options.value ()) + os << "e = " << root_p << "._error ();"; + } + else + { + os << Context::arg_type (root_type) << " v = " << + root_p << "." << post << " ());" + << endl; + + if (ctx.options.value ()) + os << "if (e = " << root_p << "._error ())" << endl + << "break;" + << endl; + + if (ctx.options.value ()) + { + PrintCall t (ctx, root->name (), "v"); + t.dispatch (root_type); + } + else + { + os << "// TODO" << endl + << "//" << endl; + } + + { + DeleteCall t (ctx, "v"); + t.dispatch (root_type); + } + } + + if (ctx.options.value ()) + os << "}" + << "while (false);" + << endl; + else if (ctx.options.value ()) + os << "}" // if (!io_error) + << "else" + << "{" + << "fprintf (stderr, \"%s: read failure\\n\", input);" + << "r = 1;" + << "}"; + + // Error handling. + // + + if (ctx.options.value ()) + { + os << "// Handle errors." << endl + << "//" << endl; + + if (ctx.options.value ()) + { + os << "if (io_error)" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s: read failure\\n\", input);"; + else + os << "std::cerr << input << \": read failure\" << std::endl;"; + + os << "r = 1;" + << "}" + << "else "; + } + + os << "if (e)" + << "{" + << "switch (e.type ())" + << "{" + << "case " << xs << "::parser_error::sys:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s: %s\\n\", input, e.sys_text ());"; + else + os << "std::cerr << input << \": \" << e.sys_text () << std::endl;"; + + os << "break;" + << "}" + << "case " << xs << "::parser_error::xml:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s:%lu:%lu: %s\\n\"," << endl + << "input, e.line (), e.column (), e.xml_text ());"; + else + os << "std::cerr << input << ':' << e.line () << ':'" << endl + << " << e.column () << \": \" << e.xml_text () << std::endl;"; + + os << "break;" + << "}"; + + if (!ctx.options.value ()) + { + os << "case " << xs << "::parser_error::schema:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s:%lu:%lu: %s\\n\"," << endl + << "input, e.line (), e.column (), e.schema_text ());"; + else + os << "std::cerr << input << ':' << e.line () << ':'" << endl + << " << e.column () << \": \" << e.schema_text () << std::endl;"; + + os << "break;" + << "}"; + } + + os << "case " << xs << "::parser_error::app:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s:%lu:%lu: application error %d\\n\"," << endl + << "input, e.line (), e.column (), e.app_code ());"; + else + os << "std::cerr << input << ':' << e.line () << ':'" << endl + << " << e.column () << \": application error \"" << endl + << " << e.app_code () << std::endl;"; + + os << "break;" + << "}" + << "default:" + << "{" + << "break;" + << "}" + << "}" //switch + << "r = 1;" + << "}"; // else if (e) + } + else + { + os << "}" // try + << "catch (const " << xs << "::parser_exception& e)" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s:%lu:%lu: %s\\n\"," << endl + << "input, e.line (), e.column (), e.text ());" + << "r = 1;"; + else + os << "std::cerr << input << ':' << e.line () << ':'" << endl + << " << e.column () << \": \" << e.text () << std::endl;" + << "return 1;"; + + os << "}"; + + if (!ctx.options.value ()) + { + os << "catch (const std::ios_base::failure&)" + << "{" + << "std::cerr << input << \": unable to open or " << + "read failure\" << std::endl;" + << "return 1;" + << "}"; + } + } + + if (ctx.options.value ()) + os << "if (argc > 1)" << endl + << "fclose (f);" + << endl; + + if (ctx.options.value () || + ctx.options.value ()) + os << "return r;"; + else + os << "return 0;"; + + os << "}"; // main + } + } +} diff --git a/xsde/cxx/parser/driver-source.hxx b/xsde/cxx/parser/driver-source.hxx new file mode 100644 index 0000000..f829d41 --- /dev/null +++ b/xsde/cxx/parser/driver-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/driver-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_DRIVER_SOURCE_HXX +#define CXX_PARSER_DRIVER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_driver_source (Context&); + } +} + +#endif // CXX_PARSER_DRIVER_SOURCE_HXX diff --git a/xsde/cxx/parser/element-validation-source.cxx b/xsde/cxx/parser/element-validation-source.cxx new file mode 100644 index 0000000..e5d3589 --- /dev/null +++ b/xsde/cxx/parser/element-validation-source.cxx @@ -0,0 +1,2120 @@ +// file : xsde/cxx/parser/element-validation-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + typedef Cult::Containers::Vector Particles; + + // Find particle that can be absent. + // + struct OptionalParticleTest: Traversal::Choice + { + OptionalParticleTest (SemanticGraph::Particle*& result) + : is_optional_ (optional_), result_ (result) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Choice; + result_ = 0; + optional_ = false; + + for (Choice::ContainsIterator i (c.contains_begin ()); + result_ == 0 && i != c.contains_end (); + ++i) + { + is_optional_.dispatch (i->particle ()); + if (optional_) + result_ = &i->particle (); + } + } + + struct IsOptional: Traversal::Choice, + Traversal::Sequence, + Traversal::Element, + Traversal::Any + { + IsOptional (Boolean& r) + : r_ (r) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!r_ && c.min () == 0) + r_ = true; + + // We need at least one particle to be optional for the whole + // choice to be optional. + // + using SemanticGraph::Choice; + + for (Choice::ContainsIterator i (c.contains_begin ()); + !r_ && i != c.contains_end (); + ++i) + { + dispatch (i->particle ()); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!r_ && s.min () == 0) + r_ = true; + + // We need all particles to be optional for the whole sequence + // to be optional. + // + using SemanticGraph::Sequence; + + for (Sequence::ContainsIterator i (s.contains_begin ()); + !r_ && i != s.contains_end (); + ++i) + { + Boolean r (false); + IsOptional test (r); + test.dispatch (i->particle ()); + if (!r) + return; + } + + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!r_ && e.min () == 0) + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + if (!r_ && a.min () == 0) + r_ = true; + } + + private: + Boolean& r_; + }; + + private: + Boolean optional_; + IsOptional is_optional_; + SemanticGraph::Particle*& result_; + }; + + // + // + Void + choice_arm_call (SemanticGraph::Particle* p, + SemanticGraph::Choice* c, + Context* ctx) + { + using SemanticGraph::Choice; + + ctx->os << "this->" << Context::earm (*c) << " (" << + Context::etag (*p) << ");"; + + if ((c = dynamic_cast (p))) + { + OptionalParticleTest test (p); + test.traverse (*c); + + if (p) + choice_arm_call (p, c, ctx); + } + } + + // + // + struct ParticleTest: Traversal::Compositor, + Traversal::Element, + Traversal::Any, + Context + { + ParticleTest (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& name (e.name ()); + Boolean subst (poly_code && e.global ()); + + if (subst) + os << "("; + + if (e.qualified () && e.namespace_ ().name ()) + { + String const& ns (e.namespace_ ().name ()); + + os << "n == " << L << strlit (name) << " &&" << endl + << "ns == " << L << strlit (ns); + } + else + os << "n == " << L << strlit (name) << " && ns.empty ()"; + + + // Only a globally-defined element can be a subst-group root. + // + if (subst) + { + String root_id (e.name ()); + + if (String const& ns = e.namespace_ ().name ()) + { + root_id += L' '; + root_id += ns; + } + + os << ") ||" << endl + << "::xsde::cxx::parser::substitution_map_instance ()" << + ".check (" << endl + << "ns, n, " << strlit (root_id) << ", t)"; + } + + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + String const& ns (a.definition_namespace ().name ()); + + // Note that we need to make sure the "flush" element (both name + // and namespace are empty) does not match any compositor. + // + for (SemanticGraph::Any::NamespaceIterator i (a.namespace_begin ()), + e (a.namespace_end ()); i != e;) + { + if (*i == L"##any") + { + os << "!n.empty ()"; + } + else if (*i == L"##other") + { + if (ns) + { + // Note that here I assume that ##other does not include + // unqualified names in a schema with target namespace. + // This is not what the spec says but that seems to be + // the consensus. + // + os << "(!ns.empty () && ns != " << L << strlit (ns) << ")"; + } + else + os << "!ns.empty ()"; + } + else if (*i == L"##local") + { + os << "(ns.empty () && !n.empty ())"; + } + else if (*i == L"##targetNamespace") + { + os << "ns == " << L << strlit (ns); + } + else + { + os << "ns == " << L << strlit (*i); + } + + if (++i != e) + os << " ||" << endl; + } + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + // This compositor should already have been tested for + // triviality (empty). + // + Particles const& p (c.context ().get ("p:prefixes")); + + Boolean paren (p.size () != 1); + + for (Particles::ConstIterator i (p.begin ()), e (p.end ()); + i != e;) + { + if (paren) + os << "("; + + dispatch (**i); + + if (paren) + os << ")"; + + if (++i != e) + os << " ||" << endl; + } + } + }; + + + // Generates particle namespace-name pair. Used to generate + // the _expected_element call. + // + struct ParticleName: Traversal::Compositor, + Traversal::Element, + Traversal::Any, + Context + { + ParticleName (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String ns (e.qualified () ? e.namespace_ ().name () : String ()); + + os << L << strlit (ns) << ", " << L << strlit (e.name ()); + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + String const& ns (*a.namespace_begin ()); + + os << L << strlit (ns) << ", " << L << "\"*\""; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + Particles const& p (c.context ().get ("p:prefixes")); + + dispatch (**p.begin ()); + } + }; + + + // Common base for the ParticleIn{All, Choice, Sequence} treversers. + // + struct ParticleInCompositor: protected Context + { + protected: + ParticleInCompositor (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type), particle_test_ (c) + { + } + + + // Generate sub-parser setup code as well as the pre/post calls. + // + Void + pre_post_calls (SemanticGraph::Particle& p) + { + using SemanticGraph::Element; + using SemanticGraph::Complex; + + if (Element* e = dynamic_cast (&p)) + { + SemanticGraph::Type& type (e->type ()); + Boolean poly (poly_code && !anonymous (type)); + + String const& name (ename (*e)); + String inst (poly ? emember_cache (*e) : emember (*e)); + + String def_parser, map; + + if (poly) + { + def_parser = emember (*e); + map = emember_map (*e); + } + + if (poly) + { + String cast (mixin ? L"dynamic_cast" : L"static_cast"); + String fq_type (fq_name (type)); + + os << "if (t == 0 && this->" << def_parser << " != 0)" << endl + << "this->" << inst << " = this->" << def_parser << ";" + << "else" + << "{" + << "const char* ts = " << fq_type << "::_static_type ();" + << endl + << "if (t == 0)" << endl + << "t = ts;" + << endl + << "if (this->" << def_parser << " != 0 && " << + "strcmp (t, ts) == 0)" << endl + << "this->" << inst << " = this->" << def_parser << ";" + << "else" + << "{"; + + // Check that the types are related by inheritance. + // + os << "if (t != ts &&" << endl + << "!::xsde::cxx::parser::validating::" << + "inheritance_map_instance ().check (t, ts))" + << "{" + << "ctx.schema_error (::xsde::cxx::schema_error::not_derived);" + << "return;" + << "}"; + + os << "if (this->" << map << " != 0)" << endl + << "this->" << inst << " = " << cast << "< " << + fq_type << "* > (" << endl + << "this->" << map << "->find (t));" + << "else" << endl + << "this->" << inst << " = 0;" + << "}" + << "}"; + } + + String const& post (post_name (type)); + + os << "if (this->" << inst << ")" + << "{" + << "this->" << inst << "->pre ();"; + + if (!exceptions) + { + // Note that after pre() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl; + } + + os << "this->" << inst << "->_pre_impl (ctx);" + << "}" + << "else" << endl + << "ctx.current_.depth_++;" // Ignoring document fragment. + << endl + << "}" + << "else" // start + << "{" + << "if (this->" << inst << ")" + << "{"; + + String const& ret (ret_type (type)); + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();"; + else + os << arg_type (type) << " tmp = this->" << inst << "->" << + post << " ();"; + + if (!exceptions) + { + // Note that after post() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl; + } + + if (ret == L"void") + os << "this->" << name << " ();"; + else + os << "this->" << name << " (tmp);"; + + os << "}"; + } + else + { + os << "ctx.current_.any_ = true;" + << "ctx.current_.depth_++;" + << endl + << "this->_start_any_element (ns, n" << + (poly_runtime ? (poly_code ? ", t" : ", 0") : "") << ");" + << "}" + << "else" // start + << "{" + << "this->_end_any_element (ns, n);"; + } + } + + + protected: + SemanticGraph::Complex& type_; + ParticleTest particle_test_; + }; + + + + // The 'all' compositor can only contain elements with min={0,1}, max=1. + // + struct ParticleInAll: Traversal::Element, + ParticleInCompositor + { + ParticleInAll (Context& c, SemanticGraph::Complex& type) + : ParticleInCompositor (c, type) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong state (e.context ().get ("p:state")); + + SemanticGraph::Compositor& c ( + e.contained_particle ().compositor ()); + + if (state != 0) + os << "else "; + + os << "if ("; + + particle_test_.traverse (e); + + os << ")" + << "{" + << "if (count[" << state << "UL] == 0)" + << "{" + << "if (start)" + << "{"; + + if (c.min () == 0) + { + // Make the call to _present if we haven't seen any + // elements yet. + // + UnsignedLong state_count ( + c.context().get ("p:state-count")); + + if (state_count > 1) + { + os << "if ("; + + Boolean sub (false); + + for (UnsignedLong i (0); i < state_count; ++i) + { + if (i == state) + continue; + + if (sub) + os << " &&" << endl; + else + sub = true; + + os << "count[" << i << "UL] == 0"; + } + + os << ")" << endl + << "this->" << epresent (c) << " ();" + << endl; + } + } + + pre_post_calls (e); + + os << "count[" << state << "UL] = 1;" + << "}" + << "}" + << "else" // count != 0 + << "{" + << "assert (start);" // Assuming well-formed XML. + + // Since there is never more content after 'all', we could have + // as well thrown here. But instead we will let the code in + // start_element handle this along with other unexpected + // elements. + // + << "state = ~0UL;" + << "}" + << "}"; + } + }; + + + // + // + struct ParticleInChoice: Traversal::Particle, + Traversal::Compositor, + ParticleInCompositor + { + ParticleInChoice (Context& c, SemanticGraph::Complex& type) + : ParticleInCompositor (c, type), particle_name_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Particle& p) + { + using SemanticGraph::Element; + + UnsignedLong state (p.context ().get ("p:state")); + + UnsignedLong min (p.min ()), max (p.max ()); + + os << "case " << state << "UL:" << endl + << "{"; + + if (max != 1) // We don't need the test if max == 1. + { + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" + << "{"; + } + + os << "if (start)" + << "{"; + + pre_post_calls (p); + + switch (max) + { + case 0: + { + os << "count++;"; + break; + } + case 1: + { + // We do not need to increment count because min <= max and + // we do not generate min check for min <= 1 (see below). + // + os << "state = ~0UL;"; + break; + } + default: + { + os << "if (++count == " << max << "UL)" << endl + << "state = ~0UL;"; + } + }; + + os << "}"; // start + + // We've already moved to the final state if max == 1. + // + if (max != 1) + { + os << "}" + << "else" + << "{" + << "assert (start);"; // Assuming well-formed XML + + // Check if min cardinality requirements have been met. Since + // count is always >= 1, don't generate dead code if min <= 1. + // + if (min > 1) + { + os << "if (count < " << min << "UL)" << endl + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);"; + + /* + << "this->_expected_element (" << endl; + particle_name_.dispatch (p); + os << "," << endl + << "ns, n);"; + */ + } + + + os << "state = ~0UL;" + << "}"; + } + + os << "break;" + << "}"; // case + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + using SemanticGraph::Choice; + using SemanticGraph::Sequence; + using SemanticGraph::Compositor; + + Boolean choice (c.is_a ()); + SemanticGraph::Context& cc (c.context ()); + + UnsignedLong max (c.max ()); + UnsignedLong min (cc.get ("p:effective-min")); + UnsignedLong n (cc.get ("p:comp-number")); + UnsignedLong state (cc.get ("p:state")); + + String func (choice ? "choice_" : "sequence_"); + + os << "case " << state << "UL:" << endl + << "{" + << "unsigned long s = ~0UL;" + << endl; + + Boolean first (true); + + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () && !cc.count ("p:comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("p:prefix")) + break; + + UnsignedLong state (p.context ().get ("p:state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + if (!choice) + { + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + Choice* pc = dynamic_cast (&ci->particle ()); + + if (pc && pc->min () == 1 && pc->max () == 1 && + pc->context ().get ("p:effective-min") == 0) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + { + UnsignedLong state ( + pc->context ().get ("p:state")); + + os << endl + << "if (s > " << state << "UL)" << endl + << "{"; + choice_arm_call (p, pc, this); + os << "}"; + } + } + } + } + + // This compositor. + // + os << endl + << "if (s != ~0UL)" + << "{" + << "assert (start);"; // End is handled by the sub-machine. + + switch (max) + { + case 0: + { + os << "count++;"; + break; + } + case 1: + { + // We do not need to increment count because min <= max and + // we do not generate min check for min <= 1 (see below). + // + os << "state = ~0UL;"; + break; + } + default: + { + os << "if (++count == " << max << "UL)" << endl + << "state = ~0UL;"; + } + }; + + // Delegate to the sub-machine and call _arm, _present, or _next + // if necessary. + // + + os << endl + << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_& vd = vs.data[vs.size++];" // push + << endl + << "vd.func = &" << ename (type_) << "::" << func << n << ";" + << "vd.state = s;" + << "vd.count = 0;" + << endl; + + if (Choice* pc = dynamic_cast (&c)) + { + os << "this->" << earm (*pc) << " (static_cast< " << + earm_tag (*pc) << " > (s));"; + } + else + { + Sequence& s (dynamic_cast (c)); + + if (max != 1) + os << "this->" << enext (s) << " ();"; + else if (c.min () == 0) + os << "this->" << epresent (s) << " ();"; + } + + os << "this->" << func << n << " (vd.state, vd.count, ns, n, " << + (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);" + << "}"; + + + // Not this compositor. We've elready moved to the final state + // if max == 1. + // + if (max != 1) + { + os << "else" + << "{" + << "assert (start);"; // Assuming well-formed XML + + // Check if min cardinality requirements have been met. Since + // count is always >= 1, don't generate dead code if min <= 1. + // + if (min > 1) + { + os << "if (count < " << min << "UL)" << endl + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);"; + + /* + << "this->_expected_element (" << endl; + particle_name_.dispatch (c); + os << "," << endl + << "ns, n);"; + */ + } + + os << "state = ~0UL;" + << "}"; + } + + os << "break;" + << "}"; // case + } + + private: + ParticleName particle_name_; + }; + + + // + // + struct ParticleInSequence: Traversal::Particle, + Traversal::Compositor, + ParticleInCompositor + { + ParticleInSequence (Context& c, + UnsignedLong state, + UnsignedLong next_state, + SemanticGraph::Complex& type) + : ParticleInCompositor (c, type), + state_ (state), particle_name_ (c) + { + // next_state == 0 indicates the terminal state (~0UL). + // + if (next_state != 0) + { + std::wostringstream ostr; + ostr << next_state; + next_state_ = ostr.str (); + } + else + next_state_ = L"~0"; + } + + virtual Void + traverse (SemanticGraph::Particle& p) + { + UnsignedLong min (p.min ()), max (p.max ()); + + os << "case " << state_ << "UL:" << endl + << "{" + << "if ("; + + particle_test_.dispatch (p); + + os << ")" + << "{"; + + // This element. + // + + os << "if (start)" + << "{"; + + pre_post_calls (p); + + switch (max) + { + case 0: + { + os << "count++;"; + break; + } + case 1: + { + os << "count = 0;" + << "state = " << next_state_ << "UL;"; + break; + } + default: + { + os << "if (++count == " << max << "UL)" + << "{" + << "count = 0;" + << "state = " << next_state_ << "UL;" + << "}"; + } + }; + + os << "}" // start + << "break;" + << "}"; + + // Not this element. + // + + os << "else" + << "{" + << "assert (start);"; // Assuming well-formed XML. + + // Check if min cardinality requirements have been met. Since + // count is always >= 0, don't generate dead code if min == 0. + // + if (min != 0) + { + os << "if (count < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "break;" + << "}"; + + /* + << "this->_expected_element (" << endl; + particle_name_.dispatch (p); + os << "," << endl + << "ns, n);"; + */ + } + + os << "count = 0;" + << "state = " << next_state_ << "UL;" + << "// Fall through." << endl + << "}" // else + << "}"; // case + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + using SemanticGraph::Choice; + using SemanticGraph::Sequence; + using SemanticGraph::Compositor; + + Boolean choice (c.is_a ()); + SemanticGraph::Context& cc (c.context ()); + + UnsignedLong max (c.max ()); + UnsignedLong min (cc.get ("p:effective-min")); + UnsignedLong n (cc.get ("p:comp-number")); + + String func (choice ? "choice_" : "sequence_"); + + os << "case " << state_ << "UL:" << endl + << "{" + << "unsigned long s = ~0UL;" + << endl; + + Boolean first (true); + + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () && !cc.count ("p:comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("p:prefix")) + break; + + UnsignedLong state (p.context ().get ("p:state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + if (!choice) + { + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + Choice* pc = dynamic_cast (&ci->particle ()); + + if (pc && pc->min () == 1 && pc->max () == 1 && + pc->context ().get ("p:effective-min") == 0) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + { + UnsignedLong state ( + pc->context ().get ("p:state")); + + os << endl + << "if (s > " << state << "UL)" << endl + << "{"; + choice_arm_call (p, pc, this); + os << "}"; + } + } + } + } + + // This element. + // + + os << endl + << "if (s != ~0UL)" + << "{" + << "assert (start);"; // End is handled by the sub-machine. + + switch (max) + { + case 0: + { + os << "count++;" + << endl; + break; + } + case 1: + { + os << "count = 0;" + << "state = " << next_state_ << "UL;" + << endl; + break; + } + default: + { + os << "if (++count == " << max << "UL)" + << "{" + << "count = 0;" + << "state = " << next_state_ << "UL;" + << "}"; + } + }; + + // Delegate to the sub-machine and call _arm, _present, or _next + // if necessary. + // + + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_& vd = vs.data[vs.size++];" // push + << endl + << "vd.func = &" << ename (type_) << "::" << func << n << ";" + << "vd.state = s;" + << "vd.count = 0;" + << endl; + + Choice* pc = dynamic_cast (&c); + + if (pc) + { + os << "this->" << earm (*pc) << " (static_cast< " << + earm_tag (*pc) << " > (s));"; + } + else + { + Sequence& s (dynamic_cast (c)); + + if (max != 1) + os << "this->" << enext (s) << " ();"; + else if (c.min () == 0) + os << "this->" << epresent (s) << " ();"; + } + + os << "this->" << func << n << " (vd.state, vd.count, ns, n, " << + (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);" + << "break;" + << "}"; + + // Not this compositor. + // + + os << "else" + << "{" + << "assert (start);"; // Assuming well-formed XML + + if (pc && c.min () == 1 && min == 0 && max == 1) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + choice_arm_call (p, pc, this); + } + + // Check if min cardinality requirements have been met. Since + // count is always >= 0, don't generate dead code if min == 0. + // + if (min != 0) + { + os << "if (count < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "break;" + << "}"; + } + + os << "count = 0;" + << "state = " << next_state_ << "UL;" + << "// Fall through." << endl + << "}" // else + << "}"; // case + } + + private: + UnsignedLong state_; + String next_state_; + + ParticleName particle_name_; + }; + + + // + // + struct ParticleFunction: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + ParticleFunction (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type) + { + *this >> contains_particle_ >> *this; + } + + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context().count ("p:comp-number")) // Empty compositor. + return; + + using SemanticGraph::Element; + using SemanticGraph::Compositor; + + os << "void " << ename (type_) << "::" << endl + << "all_0 (unsigned long& state," << endl + << "unsigned char* count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl; + + if (poly_runtime) + os << "const char*" << (poly_code ? " t" : "") << "," << endl; + + os << "bool start)" + << "{"; + + if (poly_code) + os << "XSDE_UNUSED (t);" + << endl; + + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + for (Compositor::ContainsIterator ci (a.contains_begin ()), + ce (a.contains_end ()); ci != ce; ++ci) + { + ParticleInAll t (*this, type_); + t.dispatch (ci->particle ()); + } + + // Handle the flush. + // + os << "else if (n.empty () && ns.empty ())" + << "{"; + + for (Compositor::ContainsIterator ci (a.contains_begin ()), + ce (a.contains_end ()); ci != ce; ++ci) + { + if (ci->min () == 0) + continue; + + Element& e (dynamic_cast (ci->particle ())); + String ns (e.qualified () ? e.namespace_ ().name () : String ()); + UnsignedLong state (e.context ().get ("p:state")); + + os << "if (count[" << state << "UL] == 0)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + + /* + << "this->_expected_element (" << endl + << L << "\"" << ns << "\", " << + L << "\"" << e.name () << "\");"; + */ + } + + // Error handling code relies on the fact that there is no + // code after the if-else block. + // + os << "state = ~0UL;" + << "}" + << "else" << endl + << "state = ~0UL;" + << "}"; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Compositor; + + SemanticGraph::Context& cc (c.context ()); + + if (!cc.count ("p:comp-number")) // Empty compositor. + return; + + UnsignedLong n (cc.get ("p:comp-number")); + + os << "void " << ename (type_) << "::" << endl + << "choice_" << n << " (unsigned long& state," << endl + << "unsigned long& count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl; + + if (poly_runtime) + os << "const char*" << (poly_code ? " t" : "") << "," << endl; + + os << "bool start)" + << "{" + << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + os << "XSDE_UNUSED (count);" + << "XSDE_UNUSED (ns);" + << "XSDE_UNUSED (n);" + << "XSDE_UNUSED (ctx);"; + + if (poly_code) + os << "XSDE_UNUSED (t);"; + + + os << endl + << "switch (state)" + << "{"; + + for (Compositor::ContainsIterator ci (c.contains_begin ()), + ce (c.contains_end ()); ci != ce; ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () && !p.context().count ("p:comp-number")) + continue; // Empty compositor. + + ParticleInChoice t (*this, type_); + t.dispatch (p); + } + + // Error handling code relies on the fact that there is no + // code after the switch statement. + // + os << "}" // switch + << "}"; + + + // Generate nested compositor functions. + // + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!s.context().count ("p:comp-number")) // Empty compositor. + return; + + using SemanticGraph::Compositor; + + UnsignedLong n (s.context ().get ("p:comp-number")); + + os << "void " << ename (type_) << "::" << endl + << "sequence_" << n << " (unsigned long& state," << endl + << "unsigned long& count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl; + + if (poly_runtime) + os << "const char*" << (poly_code ? " t" : "") << "," << endl; + + os << "bool start)" + << "{" + << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + if (poly_code) + os << "XSDE_UNUSED (t);"; + + os << "XSDE_UNUSED (ctx);" + << endl; + + os << "switch (state)" + << "{"; + + UnsignedLong state (0); + + for (Compositor::ContainsIterator ci (s.contains_begin ()), + ce (s.contains_end ()); ci != ce;) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () && !p.context().count ("p:comp-number")) + { + // Empty compositor. + // + ++ci; + continue; + } + + // Find the next state. + // + do + ++ci; + while (ci != ce && + ci->particle ().is_a () && + !ci->particle ().context().count ("p:comp-number")); + + UnsignedLong next (ci == ce ? 0 : state + 1); + + ParticleInSequence t (*this, state++, next, type_); + t.dispatch (p); + } + + // Error handling code relies on the fact that there is no + // code after the switch statement. + // + os << "case ~0UL:" << endl + << "break;" + << "}" // switch + << "}"; + + // Generate nested compositor functions. + // + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Complex& type_; + Traversal::ContainsParticle contains_particle_; + }; + + // + // + struct CompositorPre: Traversal::All, + Traversal::Compositor, + Context + { + CompositorPre (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // Clear the counts and push the initial state. + // + os << "v_all_count_.push ();" + << endl; + + SemanticGraph::Compositor& c (a); + traverse (c); + } + + virtual Void + traverse (SemanticGraph::Compositor&) // Choice and sequence. + { + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_& vd = vs.data[vs.size++];" // push + << endl + << "vd.func = 0;" + << "vd.state = 0;" + << "vd.count = 0;"; + } + + private: + SemanticGraph::Complex& type_; + }; + + + // + // + struct CompositorStartElement: Traversal::All, + Traversal::Compositor, + Context + { + CompositorStartElement (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type), + particle_test_ (c), particle_name_ (c) + { + } + + virtual Void + traverse (SemanticGraph::All&) + { + // The 'all' state machine reaches the final state only + // on an unknown element, in which case we won't get here + // again (it would be a validation error). Note that 'all' + // compositor cannot contain nested compositors so we don't + // need to re-set vd. + // + os << "all_0 (vd->state, v_all_count_.top (), ns, n, " << + (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);" + << endl + << "if (vd->state != ~0UL || ctx.error_type ())" << endl + << "vd->count++;" + << "else" << endl + << "return false;" // Let our parent handle this. + << endl; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) // Choice and sequence. + { + using SemanticGraph::Choice; + using SemanticGraph::Sequence; + using SemanticGraph::Compositor; + + Boolean choice (c.is_a ()); + SemanticGraph::Context& cc (c.context ()); + + UnsignedLong max (c.max ()); + UnsignedLong min (cc.get ("p:effective-min")); + UnsignedLong n (cc.get ("p:comp-number")); + + String func (choice ? "choice_" : "sequence_"); + + // Invoke the current state machine. If it reaches its + // terminal state, pop it and invoke the next one until + // we reach the top, which requires special handling. + // + os << "while (vd->func != 0)" + << "{" + << "(this->*vd->func) (vd->state, vd->count, ns, n, " << + (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);" + << endl + << "vd = vs.data + (vs.size - 1);" // re-acquire + << endl + << "if (vd->state == ~0UL && !ctx.error_type ())" << endl + << "vd = vs.data + (--vs.size - 1);" // pop + << "else" << endl + << "break;" + << "}"; + + + // Check if we got to the top. This code is pretty much the + // same as the one found in ParticleInSequence. + // + os << "if (vd->func == 0)" + << "{" + << "if (vd->state != ~0UL)" + << "{" + << "unsigned long s = ~0UL;" + << endl; + + Boolean first (true); + + // Note that we don't need to worry about the compositor + // being empty - this case is handled by our caller. + // + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () && !cc.count ("p:comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("p:prefix")) + break; + + UnsignedLong state (p.context ().get ("p:state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + if (!choice) + { + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + Choice* pc = dynamic_cast (&ci->particle ()); + + if (pc && pc->min () == 1 && pc->max () == 1 && + pc->context ().get ("p:effective-min") == 0) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + { + UnsignedLong state ( + pc->context ().get ("p:state")); + + os << endl + << "if (s > " << state << "UL)" << endl + << "{"; + choice_arm_call (p, pc, this); + os << "}"; + } + } + } + } + + os << endl + << "if (s != ~0UL)" + << "{"; + + // This element is a prefix of the root compositor. + // + + switch (max) + { + case 0: + { + os << "vd->count++;"; + break; + } + case 1: + { + os << "vd->count++;" + << "vd->state = ~0UL;"; + break; + } + default: + { + os << "if (++vd->count == " << max << "UL)" << endl + << "vd->state = ~0UL;"; + } + }; + + // Delegate to the sub-machine and call _arm, _present, or _next + // if necessary. + // + + os << endl + << "vd = vs.data + vs.size++;" // push + << "vd->func = &" << ename (type_) << "::" << func << n << ";" + << "vd->state = s;" + << "vd->count = 0;" + << endl; + + Choice* pc (dynamic_cast (&c)); + + if (pc) + { + os << "this->" << earm (*pc) << " (static_cast< " << + earm_tag (*pc) << " > (s));"; + } + else + { + Sequence& s (dynamic_cast (c)); + + if (max != 1) + os << "this->" << enext (s) << " ();"; + else if (c.min () == 0) + os << "this->" << epresent (s) << " ();"; + } + + os << "this->" << func << n << " (vd->state, vd->count, ns, n, " << + (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);" + << "}"; + + // This element is not our prefix. + // + + os << "else" + << "{"; + + if (pc && c.min () == 1 && min == 0 && max == 1) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + choice_arm_call (p, pc, this); + } + + // Check if min cardinality requirements have been met. Since + // count is always >= 0, don't generate dead code if min == 0. + // + if (min != 0) + { + // Note that we are returning true in case of an error to + // indicate that no further search is needed. + // + os << "if (vd->count < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return true;" + << "}"; + } + + // Return false to indicate that we are not handling this element. + // + os << "return false;" + << "}" + << "}" // if (state != ~0) + << "else" << endl + << "return false;" + << "}"; // if (function == 0) + } + + private: + SemanticGraph::Complex& type_; + ParticleTest particle_test_; + ParticleName particle_name_; + }; + + + // + // + struct CompositorEndElement: Traversal::All, + Traversal::Compositor, + Context + { + CompositorEndElement (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type) + { + } + + virtual Void + traverse (SemanticGraph::All&) + { + os << "all_0 (vd.state, v_all_count_.top (), " << + "ns, n, " << (poly_runtime ? "0, " : "") << "false);" + << endl; + } + + virtual Void + traverse (SemanticGraph::Compositor&) // Choice and sequence. + { + os << "assert (vd.func != 0);" + << "(this->*vd.func) (vd.state, vd.count, ns, n, " << + (poly_runtime ? "0, " : "") << "false);" + << endl + << "if (vd.state == ~0UL)" << endl + << "vs.size--;" // pop + << endl; + } + + private: + SemanticGraph::Complex& type_; + }; + + + // + // + struct CompositorPost: Traversal::All, + Traversal::Compositor, + Context + { + CompositorPost (Context& c, SemanticGraph::Complex& type) + : Context (c), type_ (type), particle_name_ (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + using SemanticGraph::Element; + + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_& vd = vs.data[vs.size - 1];" + << endl; + + // Flush the state machine with the empty element name. This + // allows us to detect missing content. + // + os << "if (vd.count != 0)" + << "{" + << string_type << " empty;" + << "all_0 (vd.state, v_all_count_.top (), empty, empty, " << + (poly_runtime ? "0, " : "") << "true);" + << "}"; + + if (a.context ().get ("p:effective-min") != 0) + { + os << "else" << endl + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);"; + + /* + << "this->_expected_element (" << endl; + particle_name_.dispatch (a); + os << ");"; + */ + } + + os << endl + << "vs.size--;" // pop + << "v_all_count_.pop ();"; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) // Choice and sequence. + { + using SemanticGraph::Choice; + + UnsignedLong min ( + c.context ().get ("p:effective-min")); + + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_* vd = vs.data + (vs.size - 1);" + << endl; + + + // Flush unfinished state machines with the empty element name. + // This allows us to detect missing content. Note that I am + // not re-setting vd since no new compositors are pushed on + // flush. + // + os << string_type << " empty;" + << "while (vd->func != 0)" + << "{" + << "(this->*vd->func) (vd->state, vd->count, empty, empty, " << + (poly_runtime ? "0, " : "") << "true);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "assert (vd->state == ~0UL);" + << "vd = vs.data + (--vs.size - 1);" // pop + << "}"; + + + Choice* pc (dynamic_cast (&c)); + + if (pc && c.min () == 1 && min == 0 && c.max () == 1) + { + // This is a required choice with effective-min == 0 (i.e., + // it contains optional particle). We need to call the arm + // callback with that optional particle's tag. + // + SemanticGraph::Particle* p (0); + OptionalParticleTest test (p); + test.traverse (*pc); + + if (p) + { + os << "if (vd->count == 0)" << endl + << "{"; + choice_arm_call (p, pc, this); + os << "}"; + } + } + + // Check if min cardinality requirements have been met. Since + // count is always >= 0, don't generate dead code if min == 0. + // + if (min != 0) + { + os << "if (vd->count < " << min << "UL)" << endl + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);"; + } + } + + private: + SemanticGraph::Complex& type_; + ParticleName particle_name_; + }; + + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + // Nothing to generate if we don't have any elements and wildcards. + // + if (!has (c) && + !has_particle (c)) + return; + + using SemanticGraph::Compositor; + + String const& name (ename (c)); + Compositor& comp (c.contains_compositor ().compositor ()); + + // Don't use restriction_p here since we don't want special + // treatment of anyType. + // + Boolean restriction ( + c.inherits_p () && + c.inherits ().is_a ()); + + os <<"// Element validation and dispatch functions for " << + name << "." << endl + <<"//" << endl; + + // _start_element_impl + // + + os << "bool " << name << "::" << endl + << "_start_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n"; + + if (poly_runtime) + os << "," << endl + << "const char*" << (poly_code ? " t" : ""); + + os << ")" + << "{"; + + if (poly_code) + os << "XSDE_UNUSED (t);" + << endl; + + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_* vd = vs.data + (vs.size - 1);" + << endl; + + //@@ OPT: I don't really need to call parser_base since it always + // returns false. + // + // In case of an inheritance-by-extension, call our base first. + // We don't need to generate this code for the 'all' compositor + // because it can only inherit from the empty content model. + // Sattes of the root machine for sequence and choice: + // + // 0 - calling base + // 1 - base returned false + // ~0 - terminal state + // + if (!restriction && !comp.is_a ()) + { + os << "if (vd->func == 0 && vd->state == 0)" + << "{"; + + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << "if (" << base << "::"; + + if (poly_runtime) + os << "_start_element_impl (ns, n, " << + (poly_code ? "t" : "0") << "))" << endl; + else + os << "_start_element_impl (ns, n))" << endl; + + os << "return true;" + << "else" << endl + << "vd->state = 1;" + << "}"; + } + + { + CompositorStartElement t (*this, c); + t.dispatch (comp); + } + + os << "return true;" + << "}"; + + + // _end_element_impl + // + + os << "bool " << name << "::" << endl + << "_end_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n)" + << "{"; + + os << "v_state_& vs = *static_cast< v_state_* > (" << + "this->v_state_stack_.top ());" + << "v_state_descr_& vd = vs.data[vs.size - 1];" + << endl; + + //@@ OPT: I don't really need to call parser_base since it always + // returns false. + // + // In case of an inheritance-by-extension, call our base first. + // We don't need to generate this code for the 'all' compositor + // because it can only inherit from the empty content model. + // + if (!restriction && !comp.is_a ()) + { + os << "if (vd.func == 0 && vd.state == 0)" + << "{"; + + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << "if (!" << base << "::_end_element_impl (ns, n))" << endl + << "assert (false);" // Start and end should match. + << "return true;" + << "}"; + } + + { + CompositorEndElement t (*this, c); + t.dispatch (comp); + } + + os << "return true;" + << "}"; + + + // _pre_e_validate + // + os << "void " << name << "::" << endl + << "_pre_e_validate ()" + << "{"; + + if (exceptions) + os << "this->v_state_stack_.push ();"; + else + os << "if (this->v_state_stack_.push ())" + << "{" + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);" + << "return;" + << "}"; + + os << "static_cast< v_state_* > (this->v_state_stack_.top ())->" << + "size = 0;" + << endl; + + { + // Assuming that this code cannot trigger an error. + // + CompositorPre t (*this, c); + t.dispatch (comp); + } + + // In case of an inheritance-by-extension, call our base + // _pre_e_validate. We don't need to generate this code for the + // 'all' compositor because it can only inherit from the empty + // content model. + // + if (!restriction && !comp.is_a ()) + { + // We don't need to call parser_base's implementation + // since it does nothing. + // + if (c.inherits_p ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_pre_e_validate ();"; + } + } + + os << "}"; + + + // _post_e_validate + // + os << "void " << name << "::" << endl + << "_post_e_validate ()" + << "{"; + + if (!comp.is_a ()) + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + // In case of an inheritance-by-extension, call our base + // _post_e_validate. We don't need to generate this code for + // the 'all' compositor because it can only inherit from + // the empty content model. + // + if (!restriction && !comp.is_a ()) + { + // We don't need to call parser_base's implementation + // since it does nothing. + // + if (c.inherits_p ()) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_post_e_validate ();" + << endl; + + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + { + CompositorPost t (*this, c); + t.dispatch (c.contains_compositor ().compositor ()); + } + + os << endl + << "this->v_state_stack_.pop ();" + << "}"; + + // + // + ParticleFunction t (*this, c); + t.dispatch (c.contains_compositor ().compositor ()); + } + }; + } + + Void + generate_element_validation_source (Context& ctx) + { + ctx.os << "#include " << endl + << endl; + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/element-validation-source.hxx b/xsde/cxx/parser/element-validation-source.hxx new file mode 100644 index 0000000..4dbf5e3 --- /dev/null +++ b/xsde/cxx/parser/element-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/element-validation-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_ELEMENT_VALIDATION_SOURCE_HXX +#define CXX_PARSER_ELEMENT_VALIDATION_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_element_validation_source (Context&); + } +} + +#endif // CXX_PARSER_ELEMENT_VALIDATION_SOURCE_HXX diff --git a/xsde/cxx/parser/elements.cxx b/xsde/cxx/parser/elements.cxx new file mode 100644 index 0000000..e4d9cde --- /dev/null +++ b/xsde/cxx/parser/elements.cxx @@ -0,0 +1,258 @@ +// file : xsde/cxx/parser/elements.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace CXX +{ + namespace Parser + { + Context:: + Context (std::wostream& o, + SemanticGraph::Schema& root, + CLI::Options const& ops, + Regex const* he, + Regex const* ie, + Regex const* hie) + : CXX::Context (o, + root, + "p:name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + options (ops), + xml_parser (xml_parser_), + simple_base (simple_base_), + complex_base (complex_base_), + list_base (list_base_), + parser_map (parser_map_), + validation (!ops.value ()), + exceptions (!ops.value ()), + poly_code (ops.value ()), + poly_runtime (poly_code || ops.value ()), + reset (!ops.value ()), + mixin (ops.value ()), + tiein (!mixin && !ops.value ()), + hxx_expr (he), + ixx_expr (ie), + hxx_impl_expr (hie), + xml_parser_ ("expat") + { + string_type = L"::xsde::cxx::ro_string"; + + simple_base_ = L"::xsde::cxx::parser::"; + simple_base_ += (validation ? L"validating" : L"non_validating"); + simple_base_ += L"::simple_content"; + + complex_base_ = L"::xsde::cxx::parser::"; + complex_base_ += (validation ? L"validating" : L"non_validating"); + complex_base_ += L"::complex_content"; + + list_base_ = L"::xsde::cxx::parser::"; + list_base_ += (validation ? L"validating" : L"non_validating"); + list_base_ += L"::list_base"; + + if (poly_code) + parser_map_ = xs_ns_name () + L"::parser_map"; + } + + String Context:: + real_fq_name (SemanticGraph::Nameable& n) + { + SemanticGraph::Context& c (n.context ()); + + if (c.count ("p:real-name")) + return c.get ("p:real-name"); + else + return fq_name (n); + } + + Content::Value Context:: + content (SemanticGraph::Complex& c) + { + using namespace SemanticGraph; + + if (c.mixed ()) + return Content::mixed; + + if (c.inherits_p ()) + { + Type& base (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&base)) + return content (*cb); + + if (base.is_a ()) + return Content::complex; + + // Everyhting else (built-in type and AnySimpleType) is simple + // content. + // + return Content::simple; + } + else + return Content::complex; + } + + + String const& Context:: + ret_type (SemanticGraph::Type& t) + { + return t.context ().get ("p:ret-type"); + } + + String const& Context:: + arg_type (SemanticGraph::Type& t) + { + return t.context ().get ("p:arg-type"); + } + + String const& Context:: + post_name (SemanticGraph::Type& t) + { + return t.context ().get ("p:post"); + } + + String const& Context:: + epresent (SemanticGraph::Compositor& c) + { + return c.context ().get ("p:present"); + } + + String const& Context:: + enext (SemanticGraph::Sequence& s) + { + return s.context ().get ("p:next"); + } + + String const& Context:: + etag (SemanticGraph::Particle& p) + { + return p.context ().get ("p:tag"); + } + + String const& Context:: + earm (SemanticGraph::Choice& c) + { + return c.context ().get ("p:arm"); + } + + String const& Context:: + earm_tag (SemanticGraph::Choice& c) + { + return c.context ().get ("p:arm-tag"); + } + + String const& Context:: + eparser (SemanticGraph::Member& m) + { + return m.context ().get ("p:parser"); + } + + String const& Context:: + emember (SemanticGraph::Member& m) + { + return m.context ().get ("p:member"); + } + + String const& Context:: + emember_cache (SemanticGraph::Member& m) + { + return m.context ().get ("p:member-cache"); + } + + String const& Context:: + emember_map (SemanticGraph::Member& m) + { + return m.context ().get ("p:member-map"); + } + + String const& Context:: + etiein (SemanticGraph::Type& t) + { + return t.context ().get ("p:tiein"); + } + + String const& Context:: + eimpl (SemanticGraph::Type& t) + { + return t.context ().get ("p:impl"); + } + + // Includes + // + Void TypeForward:: + traverse (SemanticGraph::Type& t) + { + os << "class " << t.context ().get (name_key_) << ";"; + } + + Void Includes:: + traverse_ (SemanticGraph::Uses& u) + { + // Support for weak (forward) inclusion used in the file-per-type + // compilation model. + // + Boolean weak (u.context ().count ("weak")); + + if (weak && (type_ == header || type_ == impl_header)) + { + // Generate forward declarations. We don't really need them + // in the impl files. + // + if (type_ == header) + schema_.dispatch (u.schema ()); + + return; + } + + if (type_ == source && !weak) + return; + + SemanticGraph::Path path (u.path ()); + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + NarrowString path_str; + try + { + path_str = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + path_str = path.native_file_string (); + } + + String inc_path; + + switch (type_) + { + case header: + case source: + { + inc_path = ctx_.hxx_expr->merge (path_str); + break; + } + case impl_header: + { + inc_path = ctx_.hxx_impl_expr->merge (path_str); + break; + } + } + + ctx_.os << "#include " << ctx_.process_include_path (inc_path) << endl + << endl; + } + } +} diff --git a/xsde/cxx/parser/elements.hxx b/xsde/cxx/parser/elements.hxx new file mode 100644 index 0000000..0bb226e --- /dev/null +++ b/xsde/cxx/parser/elements.hxx @@ -0,0 +1,431 @@ +// file : xsde/cxx/parser/elements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_ELEMENTS_HXX +#define CXX_PARSER_ELEMENTS_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Parser + { + struct Content + { + enum Value + { + simple, + complex, + mixed + }; + }; + + // + // + class Context: public CXX::Context + { + public: + typedef BackendElements::Regex::Expression Regex; + + public: + Context (std::wostream&, + SemanticGraph::Schema&, + CLI::Options const&, + Regex const* hxx_expr, + Regex const* ixx_expr, + Regex const* hxx_impl_expr); + + protected: + Context (Context& c) + : CXX::Context (c), + options (c.options), + xml_parser (c.xml_parser), + simple_base (c.simple_base), + complex_base (c.complex_base), + list_base (c.list_base), + parser_map (c.parser_map), + validation (c.validation), + exceptions (c.exceptions), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + Context (Context& c, std::wostream& o) + : CXX::Context (c, o), + options (c.options), + xml_parser (c.xml_parser), + simple_base (c.simple_base), + complex_base (c.complex_base), + list_base (c.list_base), + parser_map (c.parser_map), + validation (c.validation), + exceptions (c.exceptions), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + public: + Boolean + restriction_p (SemanticGraph::Complex& c) const + { + if (c.inherits_p () && + c.inherits ().is_a ()) + { + // Restriction of anyType is a special case. + // + return !c.inherits ().base ().is_a (); + } + + return false; + } + + // Real (e.g., non-typedef) fq-name. + // + String + real_fq_name (SemanticGraph::Nameable& n); + + public: + static Content::Value + content (SemanticGraph::Complex&); + + public: + static String const& + ret_type (SemanticGraph::Type&); + + static String const& + arg_type (SemanticGraph::Type&); + + static String const& + post_name (SemanticGraph::Type&); + + public: + // Optional. + // + static String const& + epresent (SemanticGraph::Compositor&); + + // Sequence. + // + static String const& + enext (SemanticGraph::Sequence&); + + // Choice. + // + static String const& + etag (SemanticGraph::Particle&); + + static String const& + earm (SemanticGraph::Choice&); + + static String const& + earm_tag (SemanticGraph::Choice&); + + public: + static String const& + eparser (SemanticGraph::Member&); + + static String const& + emember (SemanticGraph::Member&); + + static String const& + emember_cache (SemanticGraph::Member&); + + static String const& + emember_map (SemanticGraph::Member&); + + static String const& + etiein (SemanticGraph::Type&); + + public: + static String const& + eimpl (SemanticGraph::Type&); + + public: + CLI::Options const& options; + String& xml_parser; + String& simple_base; + String& complex_base; + String& list_base; + String& parser_map; + + Boolean validation; + Boolean exceptions; + Boolean poly_code; + Boolean poly_runtime; + Boolean reset; + Boolean mixin; + Boolean tiein; + + Regex const* hxx_expr; + Regex const* ixx_expr; + Regex const* hxx_impl_expr; + + private: + String xml_parser_; + String simple_base_; + String complex_base_; + String list_base_; + String parser_map_; + }; + + // + // + struct RequiredAttributeTest: Traversal::Attribute + { + RequiredAttributeTest (Boolean& result) + : result_ (result) + { + } + + virtual Void + traverse (Type& a) + { + if (!result_ && !a.optional ()) + result_ = true; + } + + private: + Boolean& result_; + }; + + + // + // + struct ParticleParamDecl: Traversal::Element, Context + { + ParticleParamDecl (Context& c, Boolean& first, Boolean name_arg) + : Context (c), first_ (first), name_arg_ (name_arg) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (e.type ()) << "&"; + + if (name_arg_) + os << " " << ename (e); + else + os << " /* " << comment (e.name ()) << " */"; + } + + private: + Boolean& first_; + Boolean name_arg_; + }; + + struct AttributeParamDecl: Traversal::Attribute, Context + { + AttributeParamDecl (Context& c, Boolean& first, Boolean name_arg) + : Context (c), first_ (first), name_arg_ (name_arg) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (a.type ()) << "&"; + + if (name_arg_) + os << " " << ename (a); + else + os << " /* " << comment (a.name ()) << " */"; + } + + private: + Boolean& first_; + Boolean name_arg_; + }; + + struct ParserParamDecl : Traversal::Complex, + Traversal::List, + Context + { + ParserParamDecl (Context& c, Boolean name_arg) + : Context (c), + particle_ (c, first_, name_arg), + attribute_ (c, first_, name_arg), + first_ (true), + name_arg_ (name_arg) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_ >> contains_particle_; + contains_particle_ >> particle_; + contains_particle_ >> compositor_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (l.argumented ().type ()) << "&"; + + if (name_arg_) + os << " " << ename (l) << "_item"; + else + os << " /* " << comment (l.name ()) << " item */"; + } + + private: + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleParamDecl particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + AttributeParamDecl attribute_; + Traversal::Names names_; + + Boolean first_; + Boolean name_arg_; + }; + + // + // + struct TypeForward: Traversal::Type, Context + { + TypeForward (Context& c, Char const* name_key) + : Context (c), name_key_ (name_key) + { + } + + virtual Void + traverse (SemanticGraph::Type& t); + + private: + Char const* name_key_; + }; + + struct Includes : Traversal::Imports, + Traversal::Includes + { + enum Type + { + header, + source, + impl_header + }; + + Includes (Context& c, Type t) + : ctx_ (c), + type_ (t), + namespace_ (c), + type_forward_ (c, t == header ? "p:name" : "p:impl") + { + schema_ >> schema_names_ >> namespace_ >> names_ >> type_forward_; + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + traverse_ (i); + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + traverse_ (i); + } + + private: + Void + traverse_ (SemanticGraph::Uses&); + + private: + Context& ctx_; + Type type_; + + Traversal::Schema schema_; + Traversal::Names schema_names_; + Namespace namespace_; + Traversal::Names names_; + TypeForward type_forward_; + }; + + // Find root element for the test driver. + // + struct RootElement: Traversal::Element + { + RootElement (CLI::Options const& options, + SemanticGraph::Element*& element) + : options_ (options), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (options_.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (String name = options_.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + element_ = &e; // Cover root-element-last and no option. + } + + private: + CLI::Options const& options_; + SemanticGraph::Element*& element_; + }; + } +} + +#endif // CXX_PARSER_ELEMENTS_HXX diff --git a/xsde/cxx/parser/generator.cxx b/xsde/cxx/parser/generator.cxx new file mode 100644 index 0000000..e552c92 --- /dev/null +++ b/xsde/cxx/parser/generator.cxx @@ -0,0 +1,1615 @@ +// file : xsde/cxx/parser/generator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "../../../libxsde/xsde/cxx/version.hxx" + +using std::endl; +using std::wcerr; + +using namespace XSDFrontend::SemanticGraph; + +// +// +typedef +boost::filesystem::wifstream +WideInputFileStream; + +typedef +boost::filesystem::wofstream +WideOutputFileStream; + +typedef +boost::filesystem::ifstream +NarrowInputFileStream; + +namespace CXX +{ + namespace + { + Char const copyright_gpl[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema\n" + "// to C++ data binding compiler for embedded systems.\n" + "//\n" + "// This program is free software; you can redistribute it and/or modify\n" + "// it under the terms of the GNU General Public License version 2 as\n" + "// published by the Free Software Foundation.\n" + "//\n" + "// This program is distributed in the hope that it will be useful,\n" + "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "// GNU General Public License for more details.\n" + "//\n" + "// You should have received a copy of the GNU General Public License\n" + "// along with this program; if not, write to the Free Software\n" + "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" + "//\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema to\n" + "// C++ data binding compiler for embedded systems, in the Proprietary\n" + "// License mode. You should have received a proprietary license from\n" + "// Code Synthesis Tools CC prior to generating this code. See the\n" + "// license text for conditions.\n" + "//\n\n"; + + Char const copyright_impl[] = + "// Not copyrighted - public domain.\n" + "//\n" + "// This sample parser implementation was generated by CodeSynthesis XSD/e,\n" + "// an XML Schema to C++ data binding compiler for embedded systems. You\n" + "// may use it in your programs without any restrictions.\n" + "//\n\n"; + } + + namespace Parser + { + namespace CLI + { + extern Key type_map = "type-map"; + extern Key no_stl = "no-stl"; + extern Key no_iostream = "no-iostream"; + extern Key no_exceptions = "no-exceptions"; + extern Key no_long_long = "no-long-long"; + extern Key reuse_style_mixin = "reuse-style-mixin"; + extern Key reuse_style_none = "reuse-style-none"; + extern Key generate_inline = "generate-inline"; + extern Key suppress_validation = "suppress-validation"; + extern Key generate_polymorphic = "generate-polymorphic"; + extern Key runtime_polymorphic = "runtime-polymorphic"; + extern Key suppress_reset = "suppress-reset"; + extern Key generate_noop_impl = "generate-noop-impl"; + extern Key generate_print_impl = "generate-print-impl"; + extern Key generate_test_driver = "generate-test-driver"; + extern Key force_overwrite = "force-overwrite"; + extern Key root_element_first = "root-element-first"; + extern Key root_element_last = "root-element-last"; + extern Key root_element = "root-element"; + extern Key generate_xml_schema = "generate-xml-schema"; + extern Key extern_xml_schema = "extern-xml-schema"; + extern Key output_dir = "output-dir"; + extern Key skel_type_suffix = "skel-type-suffix"; + extern Key skel_file_suffix = "skel-file-suffix"; + extern Key impl_type_suffix = "impl-type-suffix"; + extern Key impl_file_suffix = "impl-file-suffix"; + extern Key namespace_map = "namespace-map"; + extern Key namespace_regex = "namespace-regex"; + extern Key namespace_regex_trace = "namespace-regex-trace"; + extern Key reserved_name = "reserved-name"; + extern Key include_with_brackets = "include-with-brackets"; + extern Key include_prefix = "include-prefix"; + extern Key include_regex = "include-regex"; + extern Key include_regex_trace = "include-regex-trace"; + extern Key guard_prefix = "guard-prefix"; + extern Key hxx_suffix = "hxx-suffix"; + extern Key ixx_suffix = "ixx-suffix"; + extern Key cxx_suffix = "cxx-suffix"; + extern Key hxx_regex = "hxx-regex"; + extern Key ixx_regex = "ixx-regex"; + extern Key cxx_regex = "cxx-regex"; + extern Key hxx_prologue = "hxx-prologue"; + extern Key ixx_prologue = "ixx-prologue"; + extern Key cxx_prologue = "cxx-prologue"; + extern Key prologue = "prologue"; + extern Key hxx_epilogue = "hxx-epilogue"; + extern Key ixx_epilogue = "ixx-epilogue"; + extern Key cxx_epilogue = "cxx-epilogue"; + extern Key epilogue = "epilogue"; + extern Key hxx_prologue_file = "hxx-prologue-file"; + extern Key ixx_prologue_file = "ixx-prologue-file"; + extern Key cxx_prologue_file = "cxx-prologue-file"; + extern Key prologue_file = "prologue-file"; + extern Key hxx_epilogue_file = "hxx-epilogue-file"; + extern Key ixx_epilogue_file = "ixx-epilogue-file"; + extern Key cxx_epilogue_file = "cxx-epilogue-file"; + extern Key epilogue_file = "epilogue-file"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + } + } + + Void Parser::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--type-map " << endl + << " Read XML Schema to C++ type mapping information\n" + << " from . Repeat this option to specify\n" + << " several type maps. Type maps are considered in\n" + << " order of appearance and the first match is used." + << endl; + + e << "--no-stl" << endl + << " Generate code that does not use STL." + << endl; + + e << "--no-iostream" << endl + << " Generate code that does not use the iostream\n" + << " library." + << endl; + + e << "--no-exceptions" << endl + << " Generate code that does not use C++ exceptions." + << endl; + + e << "--no-long-long" << endl + << " Generate code that does not use the long long\n" + << " and unsigned long long types." + << endl; + + e << "--reuse-style-mixin" << endl + << " Generate code that supports the mixin base parser\n" + << " implementation reuse style." + << endl; + + e << "--reuse-style-none" << endl + << " Do not generate any support for base parser\n" + << " implementation reuse." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--suppress-validation" << endl + << " Suppress the generation of validation code." + << endl; + + e << "--generate-polymorphic" << endl + << " Generate polymorphism-aware code. Specify this\n" + << " option if you use substitution groups or xsi:type." + << endl; + + e << "--runtime-polymorphic" << endl + << " Generate non-polymorphic code that uses the\n" + << " runtime library configured with polymorphism\n" + << " support." + << endl; + + e << "--suppress-reset" << endl + << " Suppress the generation of parser reset code." + << endl; + + e << "--generate-noop-impl" << endl + << " Generate a sample parser implementation that\n" + << " does nothing (no operation)." + << endl; + + e << "--generate-print-impl" << endl + << " Generate a sample parser implementation that\n" + << " prints the XML data to STDOUT." + << endl; + + e << "--generate-test-driver" << endl + << " Generate a test driver for the sample parser\n" + << " implementation." + << endl; + + e << "--force-overwrite" << endl + << " Force overwriting of the existing implementation\n" + << " and test driver files." + << endl; + + e << "--root-element-first" << endl + << " Indicate that the first global element is the\n" + << " document root." + << endl; + + e << "--root-element-last" << endl + << " Indicate that the last global element is the\n" + << " document root." + << endl; + + e << "--root-element " << endl + << " Indicate that is the document root." + << endl; + + e << "--generate-xml-schema" << endl + << " Generate a C++ header file as if the schema being\n" + << " compiled defines the XML Schema namespace." + << endl; + + e << "--extern-xml-schema " << endl + << " Generate code as if the XML Schema namespace was\n" + << " defined in and xsd:included in the schema\n" + << " being compiled." + << endl; + + e << "--output-dir " << endl + << " Write generated files to instead of the\n" + << " current directory." + << endl; + + e << "--skel-type-suffix " << endl + << " Use instead of the default '_pskel' to\n" + << " construct the names of generated parser skeletons." + << endl; + + e << "--skel-file-suffix " << endl + << " Use instead of the default '-pskel' to\n" + << " construct the names of generated parser skeleton\n" + << " files." + << endl; + + e << "--impl-type-suffix " << endl + << " Use instead of the default '_pimpl' to\n" + << " construct the names of parser implementations for\n" + << " the built-in XML Schema types and sample parser\n" + << " implementations." + << endl; + + e << "--impl-file-suffix " << endl + << " Use instead of the default '-pimpl' to\n" + << " construct the names of generated sample parser\n" + << " implementation files." + << endl; + + e << "--namespace-map =" << endl + << " Map XML Schema namespace to C++ namespace\n" + << " . Repeat this option to specify mapping for\n" + << " more than one XML Schema namespace." + << endl; + + e << "--namespace-regex " << endl + << " Add to the list of regular expressions\n" + << " used to translate XML Schema namespace names to\n" + << " C++ namespace names." + << endl; + + e << "--namespace-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --namespace-regex option." + << endl; + + e << "--reserved-name " << endl + << " Add to the list of names that should not\n" + << " be used as identifiers. The name can optionally\n" + << " be followed by '=' and the replacement name that\n" + << " should be used instead." + << endl; + + e << "--include-with-brackets" << endl + << " Use angle brackets (<>) instead of quotes (\"\") in\n" + << " generated #include directives." + << endl; + + e << "--include-prefix " << endl + << " Add to generated #include directive\n" + << " paths." + << endl; + + e << "--include-regex " << endl + << " Add to the list of regular expressions\n" + << " used to transform #include directive paths." + << endl; + + e << "--include-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --include-regex option." + << endl; + + e << "--guard-prefix " << endl + << " Add to generated header inclusion guards." + << endl; + + e << "--hxx-suffix " << endl + << " Use instead of the default '.hxx' to\n" + << " construct the name of the header file." + << endl; + + e << "--ixx-suffix " << endl + << " Use instead of the default '.ixx' to\n" + << " construct the name of the inline file." + << endl; + + e << "--cxx-suffix " << endl + << " Use instead of the default '.cxx' to\n" + << " construct the name of the source file." + << endl; + + e << "--hxx-regex " << endl + << " Use to construct the name of the header\n" + << " file." + << endl; + + e << "--ixx-regex " << endl + << " Use to construct the name of the inline\n" + << " file." + << endl; + + e << "--cxx-regex " << endl + << " Use to construct the name of the source\n" + << " file." + << endl; + + + // Prologues. + // + e << "--hxx-prologue " << endl + << " Insert at the beginning of the header file." + << endl; + + e << "--ixx-prologue " << endl + << " Insert at the beginning of the inline file." + << endl; + + e << "--cxx-prologue " << endl + << " Insert at the beginning of the source file." + << endl; + + e << "--prologue " << endl + << " Insert at the beginning of each generated\n" + << " file for which there is no file-specific prologue." + << endl; + + + // Epilogues. + // + e << "--hxx-epilogue " << endl + << " Insert at the end of the header file." + << endl; + + e << "--ixx-epilogue " << endl + << " Insert at the end of the inline file." + << endl; + + e << "--cxx-epilogue " << endl + << " Insert at the end of the source file." + << endl; + + e << "--epilogue " << endl + << " Insert at the end of each generated file\n" + << " for which there is no file-specific epilogue." + << endl; + + + // Prologue files. + // + e << "--hxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the header file." + << endl; + + e << "--ixx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the inline file." + << endl; + + e << "--cxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the source file." + << endl; + + e << "--prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of each generated file for which there is no file-\n" + << " specific prologue file." + << endl; + + + // Epilogue files. + // + e << "--hxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the header file." + << endl; + + e << "--ixx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the inline file." + << endl; + + e << "--cxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the source file." + << endl; + + e << "--epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " each generated file for which there is no file-\n" + << " specific epilogue file." + << endl; + + + // Misc. + // + e << "--show-anonymous" << endl + << " Show elements and attributes that are of anonymous\n" + << " types." + << endl; + + e << "--show-sloc" << endl + << " Show the number of generated physical source lines\n" + << " of code (SLOC)." + << endl; + + e << "--sloc-limit " << endl + << " Check that the number of generated physical source\n" + << " lines of code (SLOC) does not exceed ." + << endl; + + e << "--options-file " << endl + << " Read additional options from . Each option\n" + << " should appear on a separate line optionally\n" + << " followed by space and an argument." + << endl; + + e << "--proprietary-license" << endl + << " Indicate that the generated code is licensed under\n" + << " a proprietary license instead of the GPL." + << endl; + } + + Parser::CLI::OptionsSpec Parser::Generator:: + options_spec () + { + CLI::OptionsSpec spec; + + spec.option ().default_value ("-pskel"); + spec.option ().default_value ("_pskel"); + spec.option ().default_value ("-pimpl"); + spec.option ().default_value ("_pimpl"); + + spec.option ().default_value (".hxx"); + spec.option ().default_value (".ixx"); + spec.option ().default_value (".cxx"); + + return spec; + } + + + namespace + { + template + Void + open (S& ifs, NarrowString const& path) + { + try + { + Path fs_path (path, boost::filesystem::native); + ifs.open (fs_path, std::ios_base::in | std::ios_base::binary); + + if (!ifs.is_open ()) + { + wcerr << path.c_str () << ": error: unable to open in read mode" + << endl; + + throw Parser::Generator::Failed (); + } + } + catch (InvalidPath const&) + { + wcerr << "error: '" << path.c_str () << "' is not a valid " + << "filesystem path" << endl; + + throw Parser::Generator::Failed (); + } + } + + Void + append (WideOutputFileStream& os, + NarrowString const& path, + WideInputFileStream& default_is) + { + using std::ios_base; + + if (path) + { + WideInputFileStream is; + open (is, path); + os << is.rdbuf (); + } + else if (default_is.is_open ()) + { + os << default_is.rdbuf (); + default_is.seekg (0, ios_base::beg); + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector const& primary, + Cult::Containers::Vector const& def) + { + Cult::Containers::Vector const& v ( + primary.empty () ? def : primary); + + for (Containers::Vector::ConstIterator + i (v.begin ()), e (v.end ()); i != e; ++i) + { + os << i->c_str () << endl; + } + } + } + + + UnsignedLong Parser::Generator:: + generate (Parser::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + TypeMap::Namespaces& type_map, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression Regex; + + try + { + Boolean generate_xml_schema (ops.value ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (generate_xml_schema) + { + if (NarrowString name = ops.value ()) + { + if (file_path.native_file_string () != name) + generate_xml_schema = false; + } + } + + Boolean impl (!generate_xml_schema && + (ops.value () || + ops.value ())); + + Boolean driver (gen_driver && !generate_xml_schema && + ops.value ()); + + + // Evaluate the graph for possibility of generating something useful. + // + { + Validator validator; + if (!validator.validate ( + ops, schema, file_path, driver, disabled_warnings)) + throw Failed (); + } + + // Process names. + // + { + NameProcessor proc; + proc.process (ops, schema, file_path); + } + + Boolean validation (!ops.value ()); + + // Compute state machine info. + // + if (validation) + { + StateProcessor proc; + proc.process (schema, file_path); + } + + // Read-in type maps. + // + { + using namespace TypeMap; + typedef Containers::Vector Files; + + Files const& files (ops.value ()); + + for (Files::ConstIterator f (files.begin ()); f != files.end (); ++f ) + { + NarrowInputFileStream ifs; + open (ifs, *f); + + Lexer l (ifs, *f); + TypeMap::Parser p (l, *f); + + if (!p.parse (type_map)) + throw Failed (); + } + + // Add the built-in mappings at the end. + // + String xns; + { + Context ctx (std::wcerr, schema, ops, 0, 0, 0); + xns = ctx.xs_ns_name (); + } + + if (ops.value ()) + { + TypeMap::Namespace xsd_std ("http://www\\.w3\\.org/2001/XMLSchema"); + + String qname (xns + L"::qname*"); + String string_seq (xns + L"::string_sequence*"); + + xsd_std.types_push_back ("string", "char*", "char*"); + xsd_std.types_push_back ("normalizedString", "char*", "char*"); + xsd_std.types_push_back ("token", "char*", "char*"); + xsd_std.types_push_back ("Name", "char*", "char*"); + xsd_std.types_push_back ("NMTOKEN", "char*", "char*"); + xsd_std.types_push_back ("NMTOKENS", string_seq, string_seq); + xsd_std.types_push_back ("NCName", "char*", "char*"); + + xsd_std.types_push_back ("ID", "char*", "char*"); + xsd_std.types_push_back ("IDREF", "char*", "char*"); + xsd_std.types_push_back ("IDREFS", string_seq, string_seq); + + xsd_std.types_push_back ("language", "char*", "char*"); + xsd_std.types_push_back ("anyURI", "char*", "char*"); + xsd_std.types_push_back ("QName", qname, qname); + + type_map.push_back (xsd_std); + } + else + { + TypeMap::Namespace xsd_std ("http://www\\.w3\\.org/2001/XMLSchema"); + + String qname (xns + L"::qname"); + String string_seq (xns + L"::string_sequence*"); + + xsd_std.types_push_back ("string", "::std::string"); + xsd_std.types_push_back ("normalizedString", "::std::string"); + xsd_std.types_push_back ("token", "::std::string"); + xsd_std.types_push_back ("Name", "::std::string"); + xsd_std.types_push_back ("NMTOKEN", "::std::string"); + xsd_std.types_push_back ("NMTOKENS", string_seq, string_seq); + xsd_std.types_push_back ("NCName", "::std::string"); + + xsd_std.types_push_back ("ID", "::std::string"); + xsd_std.types_push_back ("IDREF", "::std::string"); + xsd_std.types_push_back ("IDREFS", string_seq, string_seq); + + xsd_std.types_push_back ("language", "::std::string"); + xsd_std.types_push_back ("anyURI", "::std::string"); + xsd_std.types_push_back ("QName", qname); + + type_map.push_back (xsd_std); + } + + String buffer (xns + L"::buffer*"); + + TypeMap::Namespace xsd ("http://www\\.w3\\.org/2001/XMLSchema"); + + xsd.types_push_back ("boolean", "bool", "bool"); + + xsd.types_push_back ("byte", "signed char", "signed char"); + xsd.types_push_back ("unsignedByte", "unsigned char", "unsigned char"); + + xsd.types_push_back ("short", "short", "short"); + xsd.types_push_back ("unsignedShort", "unsigned short", "unsigned short"); + + xsd.types_push_back ("int", "int", "int"); + xsd.types_push_back ("unsignedInt", "unsigned int", "unsigned int"); + + if (ops.value ()) + { + xsd.types_push_back ("long", "long", "long"); + xsd.types_push_back ("unsignedLong", "unsigned long", "unsigned long"); + } + else + { + xsd.types_push_back ("long", "long long", "long long"); + xsd.types_push_back ("unsignedLong", "unsigned long long", "unsigned long long"); + } + + xsd.types_push_back ("integer", "long", "long"); + + xsd.types_push_back ("negativeInteger", "long", "long"); + xsd.types_push_back ("nonPositiveInteger", "long", "long"); + + xsd.types_push_back ("positiveInteger", "unsigned long", "unsigned long"); + xsd.types_push_back ("nonNegativeInteger", "unsigned long", "unsigned long"); + + xsd.types_push_back ("float", "float", "float"); + xsd.types_push_back ("double", "double", "double"); + xsd.types_push_back ("decimal", "double", "double"); + + xsd.types_push_back ("base64Binary", buffer, buffer); + xsd.types_push_back ("hexBinary", buffer, buffer); + + xsd.types_push_back ("gDay", xns + L"::gday"); + xsd.types_push_back ("gMonth", xns + L"::gmonth"); + xsd.types_push_back ("gYear", xns + L"::gyear"); + xsd.types_push_back ("gMonthDay", xns + L"::gmonth_day"); + xsd.types_push_back ("gYearMonth", xns + L"::gyear_month"); + xsd.types_push_back ("date", xns + L"::date"); + xsd.types_push_back ("time", xns + L"::time"); + xsd.types_push_back ("dateTime", xns + L"::date_time"); + xsd.types_push_back ("duration", xns + L"::duration"); + + type_map.push_back (xsd); + + // Everyhting else maps to void. + // + TypeMap::Namespace rest (".*"); + rest.types_push_back (".*", "void", "void"); + type_map.push_back (rest); + } + + // Process types. + // + { + TypeProcessor proc; + proc.process (ops, schema, type_map); + } + + // Generate code. + // + Boolean inline_ (ops.value () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value ()); + NarrowString impl_suffix (ops.value ()); + + NarrowString hxx_suffix (ops.value ()); + NarrowString ixx_suffix (ops.value ()); + NarrowString cxx_suffix (ops.value ()); + + Regex hxx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : ops.value ()); + + Regex ixx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + ixx_suffix + "#" + : ops.value ()); + + Regex cxx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + cxx_suffix + "#" + : ops.value ()); + + Regex hxx_impl_expr; + Regex cxx_impl_expr; + Regex cxx_driver_expr; + + if (impl || driver) + { + hxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#"; + + cxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#"; + + cxx_driver_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1-pdriver" + cxx_suffix + "#"; + } + + if (!hxx_expr.match (name)) + { + wcerr << "error: header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (inline_ && !ixx_expr.match (name)) + { + wcerr << "error: inline expression '" << + ixx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (source && !cxx_expr.match (name)) + { + wcerr << "error: source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (impl || driver) + { + if (!hxx_impl_expr.match (name)) + { + wcerr << "error: implementation header expression '" << + hxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_impl_expr.match (name)) + { + wcerr << "error: implementation source expression '" << + cxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_driver_expr.match (name)) + { + wcerr << "error: driver source expression '" << + cxx_driver_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + } + + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString ixx_name (inline_ ? ixx_expr.merge (name) : NarrowString ()); + NarrowString cxx_name (source ? cxx_expr.merge (name) : NarrowString ()); + + NarrowString hxx_impl_name; + NarrowString cxx_impl_name; + NarrowString cxx_driver_name; + + if (impl || driver) + { + hxx_impl_name = hxx_impl_expr.merge (name); + cxx_impl_name = cxx_impl_expr.merge (name); + cxx_driver_name = cxx_driver_expr.merge (name); + } + + Path hxx_path (hxx_name, boost::filesystem::native); + Path ixx_path (ixx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + Path hxx_impl_path; + Path cxx_impl_path; + Path cxx_driver_path; + + if (impl || driver) + { + hxx_impl_path = Path (hxx_impl_name, boost::filesystem::native); + cxx_impl_path = Path (cxx_impl_name, boost::filesystem::native); + cxx_driver_path = Path (cxx_driver_name, boost::filesystem::native); + } + + if (NarrowString dir = ops.value ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + ixx_path = path / ixx_path; + cxx_path = path / cxx_path; + + if (impl || driver) + { + hxx_impl_path = path / hxx_impl_path; + cxx_impl_path = path / cxx_impl_path; + cxx_driver_path = path /cxx_driver_path; + } + + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + // Open the impl files first so that if open fails, the skel files + // are not deleted. + // + WideOutputFileStream hxx_impl; + WideOutputFileStream cxx_impl; + WideOutputFileStream cxx_driver; + + if (impl) + { + if (!ops.value ()) + { + WideInputFileStream tmp (hxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << hxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + hxx_impl.open (hxx_impl_path, ios_base::out); + + if (!hxx_impl.is_open ()) + { + wcerr << hxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (hxx_impl_path); + file_list.push_back (hxx_impl_path.native_file_string ()); + + if (!ops.value ()) + { + WideInputFileStream tmp (cxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_impl.open (cxx_impl_path, ios_base::out); + + if (!cxx_impl.is_open ()) + { + wcerr << cxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (cxx_impl_path); + file_list.push_back (cxx_impl_path.native_file_string ()); + } + + if (driver) + { + if (!ops.value ()) + { + WideInputFileStream tmp (cxx_driver_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_driver_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_driver.open (cxx_driver_path, ios_base::out); + + if (!cxx_driver.is_open ()) + { + wcerr << cxx_driver_path << ": error: unable to open in write " << + "mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_driver_path); + file_list.push_back (cxx_driver_path.native_file_string ()); + } + + // Open the skel files. + // + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream ixx; + WideOutputFileStream cxx; + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (inline_) + { + ixx.open (ixx_path, ios_base::out); + + if (!ixx.is_open ()) + { + wcerr << ixx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (ixx_path); + file_list.push_back (ixx_path.native_file_string ()); + } + + if (source) + { + cxx.open (cxx_path, ios_base::out); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + } + + // Print copyright and license. + // + Char const* copyright ( + ops.value () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + + if (inline_) + ixx << copyright; + + if (source) + cxx << copyright; + + if (impl) + { + hxx_impl << copyright_impl; + cxx_impl << copyright_impl; + } + + if (driver) + cxx_driver << copyright_impl; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name (ops.value ()); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name (ops.value ()); + + if (name) + open (epilogue, name); + } + + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value ()); + + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value ()); + + if (!guard_prefix) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + hxx, ops.value (), ops.value ()); + append (hxx, ops.value (), prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + hxx << "#include " << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + // Runtime/generated code compatibility checks. + // + + hxx << "#include " << endl + << endl; + + if (ops.value ()) + { + hxx << "#ifdef XSDE_STL" << endl + << "#error the XSD/e runtime uses STL while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-stl)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_STL" << endl + << "#error the generated code uses STL while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-stl)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_IOSTREAM" << endl + << "#error the XSD/e runtime uses iostream while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-iostream)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_IOSTREAM" << endl + << "#error the generated code uses iostream while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-iostream)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_EXCEPTIONS" << endl + << "#error the XSD/e runtime uses exceptions while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_EXCEPTIONS" << endl + << "#error the generated code uses exceptions while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_LONGLONG" << endl + << "#error the XSD/e runtime uses long long while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-long-long)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_LONGLONG" << endl + << "#error the generated code uses long long while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-long-long)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_PARSER_VALIDATION" << endl + << "#error the XSD/e runtime uses validation while the " << + "generated code does not (reconfigure the runtime or " << + "remove --suppress-validation)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_PARSER_VALIDATION" << endl + << "#error the generated code uses validation while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --suppress-validation)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value () || + ops.value ()) + { + hxx << "#ifndef XSDE_POLYMORPHIC" << endl + << "#error the generated code expects XSD/e runtime with " << + "polymorphism support (reconfigure the runtime or remove " << + "--generate-polymorphic/--runtime-polymorphic)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifdef XSDE_POLYMORPHIC" << endl + << "#error the generated code expects XSD/e runtime " << + "without polymorphism support (reconfigure the runtime or " << + "add --generate-polymorphic/--runtime-polymorphic)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifndef XSDE_REUSE_STYLE_MIXIN" << endl + << "#error the generated code uses the mixin reuse style " << + "while the XSD/e runtime does not (reconfigure the runtime " << + "or remove --reuse-style-mixin)" << endl + << "#endif" << endl + << endl; + } + else if (ops.value ()) + { + hxx << "#ifndef XSDE_REUSE_STYLE_NONE" << endl + << "#error the generated code does not provide support " << + "for parser reuse while the XSD/e runtime does (reconfigure " << + "the runtime or remove --reuse-style-none)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_REUSE_STYLE_TIEIN" << endl + << "#error the generated code uses the tiein reuse style " << + "while the XSD/e runtime does not (reconfigure the runtime " << + "or add --reuse-style-mixin or --reuse-style-none)" << endl + << "#endif" << endl + << endl; + } + + // + // + + hxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip hxx_clip (hxx); + + // Generate. + // + if (!generate_xml_schema) + generate_parser_forward (ctx); + + generate_parser_header (ctx, generate_xml_schema); + + if (inline_) + hxx << "#include " << ctx.process_include_path (ixx_name) << endl + << endl; + + hxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, ops.value (), epilogue); + append ( + hxx, ops.value (), ops.value ()); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + + // IXX + // + if (inline_) + { + Context ctx (ixx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip ixx_sloc (ixx); + + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + + append ( + ixx, ops.value (), ops.value ()); + append (ixx, ops.value (), prologue); + + ixx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip ixx_clip (ixx); + + + // Generate. + // + generate_parser_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + + append (ixx, ops.value (), epilogue); + append ( + ixx, ops.value (), ops.value ()); + + ixx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << ixx_path << ": " + << ixx_sloc.buffer ().count () << endl; + + sloc += ixx_sloc.buffer ().count (); + } + } + + + // CXX + // + if (source) + { + Context ctx (cxx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + cxx, ops.value (), ops.value ()); + append (cxx, ops.value (), prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + if (!inline_) + generate_parser_inline (ctx); + + generate_parser_source (ctx); + + if (validation) + { + generate_element_validation_source (ctx); + generate_attribute_validation_source (ctx); + generate_characters_validation_source (ctx); + } + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, ops.value (), epilogue); + append ( + cxx, ops.value (), ops.value ()); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + // HXX impl + // + if (impl) + { + Context ctx (hxx_impl, schema, ops, + &hxx_expr, &ixx_expr, &hxx_impl_expr); + + String guard (guard_expr.merge (guard_prefix + hxx_impl_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx_impl << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip clip (hxx_impl); + + hxx_impl << "#include " << ctx.process_include_path (hxx_name) + << endl << endl; + + generate_impl_header (ctx); + } + + hxx_impl << "#endif // " << guard << endl; + } + + // CXX impl + // + if (impl) + { + Context ctx (cxx_impl, schema, ops, + &hxx_expr, &ixx_expr, &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip clip (cxx_impl); + + cxx_impl << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_impl_source (ctx); + } + + // CXX driver + // + if (driver) + { + Context ctx (cxx_driver, schema, ops, + &hxx_expr, &ixx_expr, &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip clip (cxx_driver); + + cxx_driver << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_driver_source (ctx); + } + + return sloc; + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } +} diff --git a/xsde/cxx/parser/generator.hxx b/xsde/cxx/parser/generator.hxx new file mode 100644 index 0000000..a261eca --- /dev/null +++ b/xsde/cxx/parser/generator.hxx @@ -0,0 +1,56 @@ +// file : xsde/cxx/parser/generator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_GENERATOR_HXX +#define CXX_PARSER_GENERATOR_HXX + +#include + +#include + +#include +#include + +#include // Path +#include + +#include +#include +#include + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class Generator + { + public: + static Void + usage (); + + static CLI::OptionsSpec + options_spec (); + + struct Failed {}; + + static UnsignedLong + generate (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file, + TypeMap::Namespaces& type_map, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks); + + private: + Generator (); + }; + } +} + +#endif // CXX_PARSER_GENERATOR_HXX diff --git a/xsde/cxx/parser/impl-header.cxx b/xsde/cxx/parser/impl-header.cxx new file mode 100644 index 0000000..5d15ed2 --- /dev/null +++ b/xsde/cxx/parser/impl-header.cxx @@ -0,0 +1,309 @@ +// file : xsde/cxx/parser/impl-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (eimpl (e)); + String const& ret (ret_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + + os << "class " << name << ": " << "public " << + (mixin ? "virtual " : "") << ename (e); + + if (mixin) + os << "," << endl + << " public " << fq_name (base, "p:impl"); + + os << "{" + << "public:" << endl; + + if (tiein) + os << name << " ();" + << endl; + + os << "virtual void" << endl + << "pre ();" + << endl + << "virtual " << ret << endl + << post_name (e) << " ();"; + + if (tiein) + os << endl + << "private:" << endl + << fq_name (base, "p:impl") << " base_impl_;"; + + os << "};"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (eimpl (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + + String item (unclash (ename (l), "item")); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (l) + << "{" + << "public:" << endl + << "virtual void" << endl + << "pre ();" + << endl; + + // item + // + String const& arg (arg_type (t)); + + os << "virtual void" << endl + << item; + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + + // post + // + String const& ret (ret_type (l)); + + os << "virtual " << ret << endl + << post_name (l) << " ();" + << "};"; + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (eimpl (u)); + String const& ret (ret_type (u)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (u) + << "{" + << "public:" << endl + << "virtual void" << endl + << "pre ();" + << endl + << "virtual void" << endl + << "_characters (const " << string_type << "&);" + << endl + << "virtual " << ret << endl + << post_name (u) << " ();" + << "};"; + } + }; + + + // + // + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& arg (arg_type (e.type ())); + + os << "virtual void" << endl + << ename (e); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& arg (arg_type (a.type ())); + + os << "virtual void" << endl + << ename (a); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + }; + + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + String const& name (eimpl (c)); + String const& ret (ret_type (c)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (c); + + if (mixin && hb) + os << "," << endl + << " public " << fq_name (c.inherits ().base (), "p:impl"); + + os << "{" + << "public:" << endl; + + if (tiein && hb) + os << name << " ();" + << endl; + + os << "virtual void" << endl + << "pre ();" + << endl; + + // In case of an inheritance-by-restriction, we don't need to + // generate parser callbacks, etc. since they are the same as + // in the base. + // + if (!restriction_p (c)) + { + if (ha) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + + if (he) + { + os << "// Elements." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_callback_); + } + } + + os << "virtual " << ret << endl + << post_name (c) << " ();"; + + if (tiein && hb) + os << endl + << "private:" << endl + << fq_name (c.inherits ().base (), "p:impl") << " base_impl_;"; + + os << "};"; + } + + private: + Traversal::Compositor compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_impl_header (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::impl_header); + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/impl-header.hxx b/xsde/cxx/parser/impl-header.hxx new file mode 100644 index 0000000..43a7584 --- /dev/null +++ b/xsde/cxx/parser/impl-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/impl-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_IMPL_HEADER_HXX +#define CXX_PARSER_IMPL_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_impl_header (Context&); + } +} + +#endif // CXX_PARSER_IMPL_HEADER_HXX diff --git a/xsde/cxx/parser/impl-source.cxx b/xsde/cxx/parser/impl-source.cxx new file mode 100644 index 0000000..6b02425 --- /dev/null +++ b/xsde/cxx/parser/impl-source.cxx @@ -0,0 +1,543 @@ +// file : xsde/cxx/parser/impl-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (eimpl (e)); + String const& ret (ret_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + String const& base_ret (ret_type (base)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein) + os << name << "::" << endl + << name << " ()" << endl + << ": " << ename (e) << " (&base_impl_)" + << "{" + << "}"; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "}"; + + // post + // + os << ret << " " << name << "::" << endl + << post_name (e) << " ()" + << "{"; + + if (ret == base_ret) + { + os << (ret != L"void" ? "return " : "") << + post_name (base) << " ();"; + } + else if (ret == L"void") + { + os << arg_type (base) << " v = " << post_name (base) << " ();" + << endl; + + if (options.value ()) + os << "if (!_error ())" + << "{"; + + if (options.value ()) + { + PrintCall t (*this, e.name (), "v"); + t.dispatch (base); + } + else + os << "// TODO" << endl + << "//" << endl; + + { + DeleteCall t (*this, "v"); + t.dispatch (base); + } + + if (options.value ()) + os << "}"; + } + else + { + if (base_ret == L"void") + os << post_name (base) << " ();"; + else + { + os << arg_type (base) << " v = " << post_name (base) << " ();" + << endl; + + if (options.value ()) + os << "if (!_error ())" + << "{"; + + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + + { + DeleteCall t (*this, "v"); + t.dispatch (base); + } + + if (options.value ()) + os << "}"; + } + } + + os << "}"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (eimpl (l)); + SemanticGraph::Type& type (l.argumented ().type ()); + + String item (unclash (ename (l), "item")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "}"; + + // item + // + String const& arg (arg_type (type)); + + os << "void " << name << "::" << endl + << item; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << " " << item << ")"; + + os << "{"; + + if (arg != L"void") + { + if (options.value ()) + { + PrintCall t (*this, type.name (), item); + t.dispatch (type); + } + else + os << "// TODO" << endl + << "//" << endl; + + { + DeleteCall t (*this, item); + t.dispatch (type); + } + } + + os << "}"; + + // post + // + String const& ret (ret_type (l)); + + os << ret << " " << name << "::" << endl + << post_name (l) << " ()" + << "{"; + + if (ret != L"void") + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + + os << "}"; + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (eimpl (u)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "}"; + + // _characters + // + os << "void " << name << "::" << endl + << "_characters (const " << string_type << "& s)" + << "{"; + + if (options.value ()) + { + if (options.value ()) + os << "if (s.size () != 0)" + << "{" + << "printf (" << strlit (u.name () + L": ") << ");" + << "fwrite (s.data (), s.size (), 1, stdout);" + << "printf (\"\\n\");" + << "}"; + else + os << "std::cout << " << strlit (u.name () + L": ") << + " << s << std::endl;"; + } + else + os << "// TODO" << endl + << "//" << endl; + + os << "}"; + + // post + // + String const& ret (ret_type (u)); + + os << ret << " " << name << "::" << endl + << post_name (u) << " ()" + << "{"; + + if (ret != L"void") + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + + os << "}"; + } + }; + + // + // + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Complex; + + String const& name (ename (e)); + String const& arg (arg_type (e.type ())); + Complex& c (dynamic_cast (e.scope ())); + + os << "void " << eimpl (c) << "::" << endl + << name; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << " " << name << ")"; + + os << "{"; + + if (arg != L"void") + { + if (options.value ()) + { + PrintCall t (*this, e.name (), name); + t.dispatch (e.type ()); + } + else + os << "// TODO" << endl + << "//" << endl; + + { + DeleteCall t (*this, name); + t.dispatch (e.type ()); + } + } + + os << "}"; + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Complex; + + String const& name (ename (a)); + String const& arg (arg_type (a.type ())); + Complex& c (dynamic_cast (a.scope ())); + + os << "void " << eimpl (c) << "::" << endl + << name; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << " " << name << ")"; + + os << "{"; + + if (arg != L"void") + { + if (options.value ()) + { + PrintCall t (*this, a.name (), name); + t.dispatch (a.type ()); + } + else + os << "// TODO" << endl + << "//" << endl; + + { + DeleteCall t (*this, name); + t.dispatch (a.type ()); + } + } + + os << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + + String const& name (eimpl (c)); + String const& ret (ret_type (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein && hb) + os << name << "::" << endl + << name << " ()" << endl + << ": " << ename (c) << " (&base_impl_)" + << "{" + << "}"; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "}"; + + // Parser callbacks. + // + if (!restriction_p (c)) + { + names (c, names_attribute_callback_); + contains_compositor (c, contains_compositor_callback_); + } + + // post + // + os << ret << " " << name << "::" << endl + << post_name (c) << " ()" + << "{"; + + if (hb) + { + SemanticGraph::Type& base (c.inherits ().base ()); + String const& base_ret (ret_type (base)); + + if (ret == base_ret) + { + os << (ret != L"void" ? "return " : "") << + post_name (base) << " ();"; + } + else if (ret == L"void") + { + os << arg_type (base) << " v = " << post_name (base) << " ();" + << endl; + + if (options.value ()) + os << "if (!_error ())" + << "{"; + + if (options.value ()) + { + PrintCall t (*this, c.name (), "v"); + t.dispatch (base); + } + else + os << "// TODO" << endl + << "//" << endl; + + { + DeleteCall t (*this, "v"); + t.dispatch (base); + } + + if (options.value ()) + os << "}"; + } + else + { + if (base_ret == L"void") + os << post_name (base) << " ();"; + else + { + os << arg_type (base) << " v = " << post_name (base) << " ();" + << endl; + + if (options.value ()) + os << "if (!_error ())" + << "{"; + + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + + { + DeleteCall t (*this, "v"); + t.dispatch (base); + } + + if (options.value ()) + os << "}"; + } + } + } + else + { + if (ret != L"void") + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + } + + os << "}"; + } + + private: + Traversal::Compositor compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_impl_source (Context& ctx) + { + if (ctx.options.value ()) + { + if (ctx.options.value ()) + ctx.os << "#include " << endl + << endl; + else + ctx.os << "#include " << endl + << endl; + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/impl-source.hxx b/xsde/cxx/parser/impl-source.hxx new file mode 100644 index 0000000..98c7961 --- /dev/null +++ b/xsde/cxx/parser/impl-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/impl-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_IMPL_SOURCE_HXX +#define CXX_PARSER_IMPL_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_impl_source (Context&); + } +} + +#endif // CXX_PARSER_IMPL_SOURCE_HXX diff --git a/xsde/cxx/parser/name-processor.cxx b/xsde/cxx/parser/name-processor.cxx new file mode 100644 index 0000000..bc0e7a5 --- /dev/null +++ b/xsde/cxx/parser/name-processor.cxx @@ -0,0 +1,1326 @@ +// file : xsde/cxx/parser/name-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + // + // + typedef Cult::Containers::Set NameSet; + + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, + SemanticGraph::Schema& root, + SemanticGraph::Path const& file) + : CXX::Context (std::wcerr, + root, + "p:name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + schema_path_ (file), + skel_suffix_ (ops.value ()), + impl_suffix_ (ops.value ()), + schema (root), + schema_path (schema_path_), + impl (ops.value () || + ops.value () || + ops.value ()), + tiein (!ops.value () && + !ops.value ()), + skel_suffix (skel_suffix_), + impl_suffix (impl_suffix_), + global_type_names (global_type_names_), + validation (!ops.value ()), + polymorphic (ops.value ()) + { + } + + protected: + Context (Context& c) + : CXX::Context (c), + schema (c.schema), + schema_path (c.schema_path), + impl (c.impl), + tiein (c.tiein), + skel_suffix (c.skel_suffix), + impl_suffix (c.impl_suffix), + global_type_names (c.global_type_names), + validation (c.validation), + polymorphic (c.polymorphic) + { + } + + public: + String + find_name (String const& n, String const& suffix, NameSet& set) + { + String name (escape (n + suffix)); + + for (UnsignedLong i (1); set.find (name) != set.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + String + find_name (String const& n, NameSet& set) + { + return find_name (n, L"", set); + } + + private: + SemanticGraph::Path const schema_path_; + String const skel_suffix_; + String const impl_suffix_; + + Cult::Containers::Map global_type_names_; + + public: + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + Boolean const impl; + Boolean const tiein; + String const& skel_suffix; + String const& impl_suffix; + + Cult::Containers::Map& global_type_names; + + Boolean validation; + Boolean polymorphic; + }; + + // Primary names. + // + struct PrimaryParticle: Traversal::Element, Context + { + PrimaryParticle (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Element; + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + { + ec.set ("p:name", find_name (e.name (), set_)); + } + else + { + Element* prot ( + ec.get ("xsd-frontend-restriction-correspondence")); + + ec.set ("p:name", prot->context ().get ("p:name")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct PrimaryAttribute: Traversal::Attribute, Context + { + PrimaryAttribute (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Attribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + ac.set ("p:name", find_name (a.name (), set_)); + } + else + { + Attribute* prot ( + ac.get ("xsd-frontend-restriction-correspondence")); + + ac.set ("p:name", prot->context ().get ("p:name")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + + // + // Secondary names. + // + + struct ParticleTag: Traversal::Element, + Traversal::Any, + Traversal::Choice, + Traversal::Sequence, + Context + { + ParticleTag (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Element; + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + { + String const base (ec.get ("p:name")); + ec.set ("p:tag", find_name (base, L"_tag", set_)); + } + else + { + Element* prot = ec.get ( + "xsd-frontend-restriction-correspondence"); + + ec.set ("p:tag", prot->context ().get ("p:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + using SemanticGraph::Any; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + ac.set ("p:tag", find_name (L"any", L"_tag", set_)); + else + { + Any* prot = ac.get ( + "xsd-frontend-restriction-correspondence"); + + ac.set ("p:tag", prot->context ().get ("p:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Compositor; + + SemanticGraph::Context& cc (c.context ()); + + if (!restriction_) + { + cc.set ("p:tag", find_name (L"choice", L"_tag", set_)); + } + else + { + Compositor* prot = cc.get ( + "xsd-frontend-restriction-correspondence"); + + cc.set ("p:tag", prot->context ().get ("p:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + using SemanticGraph::Compositor; + + SemanticGraph::Context& sc (s.context ()); + + if (!restriction_) + { + sc.set ("p:tag", find_name (L"sequence", L"_tag", set_)); + } + else + { + Compositor* prot = sc.get ( + "xsd-frontend-restriction-correspondence"); + + sc.set ("p:tag", prot->context ().get ("p:tag")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct SecondaryCompositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + SecondaryCompositor (Context& c, NameSet& set, Boolean restriction) + : Context (c), + set_ (set), + restriction_ (restriction), + particle_tag_ (c, set, restriction) + { + contain_particle_tag_ >> particle_tag_; + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it cannot be used in restriction. + // + if (a.min () == 0) + { + a.context ().set ( + "p:present", find_name (L"all", L"_present", set_)); + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () == c.contains_end ()) + return; + + SemanticGraph::Context& cc (c.context ()); + + if (!restriction_) + { + cc.set ("p:arm-tag", find_name (L"choice", L"_arm_tag", set_)); + Traversal::Choice::contains (c, contain_particle_tag_); + cc.set ("p:arm", find_name (L"choice", L"_arm", set_)); + } + else + { + SemanticGraph::Compositor& b ( + *cc.get ( + "xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + + cc.set ("p:arm-tag", bc.get ("p:arm-tag")); + Traversal::Choice::contains (c, contain_particle_tag_); + cc.set ("p:arm", bc.get ("p:arm")); + } + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + SemanticGraph::Context& sc (s.context ()); + + if (!restriction_) + { + if (s.max () != 1) + sc.set ("p:next", find_name (L"sequence", L"_next", set_)); + else if (s.min () == 0) + sc.set ("p:present", find_name (L"sequence", L"_present", set_)); + } + else + { + // Root compositor that models inheritance by extension + // may not have an association. + // + if (sc.count ("xsd-frontend-restriction-correspondence")) + { + SemanticGraph::Compositor& b ( + *sc.get ( + "xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + + if (b.max () != 1) + { + sc.set ("p:next", bc.get ("p:next")); + + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (s.min () == 0) + sc.set ("p:present", + find_name (L"sequence", L"_present", set_)); + } + else if (b.min () == 0) + sc.set ("p:present", bc.get ("p:present")); + } + } + + Traversal::Sequence::traverse (s); + } + + private: + NameSet& set_; + Boolean restriction_; + + ParticleTag particle_tag_; + Traversal::ContainsParticle contain_particle_tag_; + }; + + struct SecondaryParticle: Traversal::Element, Context + { + SecondaryParticle (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + Boolean poly ( + polymorphic && !e.type ().context ().count ("anonymous")); + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + { + String const& base (ec.get ("p:name")); + + ec.set ("p:parser", find_name (base + L"_parser", set_)); + ec.set ("p:member", find_name (base + L"_parser_", set_)); + + if (poly) + { + ec.set ( + "p:member-cache", find_name (base + L"_parser_cache_", set_)); + + ec.set ( + "p:member-map", find_name (base + L"_parser_map_", set_)); + } + } + else + { + SemanticGraph::Context& bc ( + ec.get ( + "xsd-frontend-restriction-correspondence")->context ()); + + ec.set ("p:parser", bc.get ("p:parser")); + ec.set ("p:member", bc.get ("p:member")); + + if (poly) + { + ec.set ("p:member-cache", bc.get ("p:member-cache")); + ec.set ("p:member-map", bc.get ("p:member-map")); + } + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct SecondaryAttribute: Traversal::Attribute, Context + { + SecondaryAttribute (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Attribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + String const& base (ac.get ("p:name")); + + a.context ().set ( + "p:parser", find_name (base + L"_parser", set_)); + + a.context ().set ( + "p:member", find_name (base + L"_parser_", set_)); + } + else + { + SemanticGraph::Context& bc ( + ac.get ( + "xsd-frontend-restriction-correspondence")->context ()); + + ac.set ("p:parser", bc.get ("p:parser")); + ac.set ("p:member", bc.get ("p:member")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + SemanticGraph::Context& cc (c.context ()); + + // Use processed name. + // + String const& name (cc.get ("p:name")); + + // We leave this set around to allow other mappings to use + // this information. + // + cc.set ("cxx-parser-name-processor-member-set", NameSet ()); + NameSet& member_set ( + cc.get ("cxx-parser-name-processor-member-set")); + + member_set.insert (name); + + // Add our base's members to the initial list unless we are + // inheriting by restriction in which case we need to have + // the same names as our base. + // + Boolean restriction (false); + + if (c.inherits_p ()) + { + // @@ What if this types name is the same as one of base's + // members? + // + SemanticGraph::Type& base (c.inherits ().base ()); + + if (base.is_a ()) + { + if (!base.context ().count ( + "cxx-parser-name-processor-member-set")) + { + dispatch (base); + } + + NameSet const& base_set ( + base.context ().get ( + "cxx-parser-name-processor-member-set")); + + member_set.insert (base_set.begin (), base_set.end ()); + + // Inheritance by restriction from anyType is a special case. + // + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + } + } + + // First assign the "primary" names. + // + { + if (c.contains_compositor_p ()) + { + PrimaryParticle particle (*this, member_set, restriction); + Traversal::Compositor compositor; + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + + // + // + PrimaryAttribute attribute (*this, member_set, restriction); + Traversal::Names names (attribute); + + Complex::names (c, names); + } + + // Assign "secondary" names. + // + { + if (c.contains_compositor_p ()) + { + // In case of validation we generate some extra callbacks + // for compositors. + // + if (validation) + { + SecondaryParticle particle (*this, member_set, restriction); + SecondaryCompositor compositor (*this, member_set, restriction); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + else + { + SecondaryParticle particle (*this, member_set, restriction); + Traversal::Compositor compositor; + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + } + + // + // + SecondaryAttribute attribute (*this, member_set, restriction); + Traversal::Names names (attribute); + + Complex::names (c, names); + } + } + }; + + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + SemanticGraph::Context& c (t.context ()); + String const& n (t.name ()); + + String name (find_name (n + skel_suffix, set_)); + c.set ("p:name", name); + + // Assign the post_* name. + // + c.set ("p:post", find_post_name (t)); + + if (tiein) + c.set ("p:tiein", escape (n + L"_impl_")); + + // Note that we do not add this name to the set so that it + // does not influence other names. + // + if (impl) + c.set ("p:impl", escape (n + impl_suffix)); + } + + private: + String + find_post_name (SemanticGraph::Type& t) + { + String const& n (t.name ()); + + // It is possible that our base has the same type name (just + // in a different namespaces). Avoid name clash in this case. + // + using SemanticGraph::Complex; + + Complex* c = dynamic_cast (&t); + + if (c == 0 || !c->inherits_p ()) + { + return escape (L"post_" + n); + } + else + { + NameSet set; + + // Collect all base's post_*. In some mutual inclusion cases it + // is possible that our base won't have the post name assigned + // yet. In this situation will will have to figure it out + // ourselves (we can do it since we use the "raw" type name). + // + SemanticGraph::Type* b (&c->inherits ().base ()); + + while (true) + { + if (b->context ().count ("p:post")) + set.insert (b->context ().get ("p:post")); + else + set.insert (find_post_name (*b)); + + Complex* cb (dynamic_cast (b)); + + if (cb != 0 && cb->inherits_p ()) + { + b = &cb->inherits ().base (); + continue; + } + + break; + } + + String base_name (escape (L"post_" + n)); + String post (base_name); + + for (UnsignedLong i (1); set.find (post) != set.end (); ++i) + { + std::wostringstream os; + os << i; + post = base_name + os.str (); + } + + return post; + } + } + + private: + NameSet& set_; + }; + + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& ns) + { + SemanticGraph::Context& nsc (ns.context ()); + String const& name (ns.name ()); + + // Use a name set associated with this namespace if present. + // This will make sure that we don't get any conflicts in the + // multi-mapping translation case. Note that here we assume + // that all mappings traverse schemas in the same order which + // is currently the case. + // + if (global_type_names.find (name) == global_type_names.end ()) + { + if (!nsc.count ("name-set")) + nsc.set ("name-set", NameSet ()); + + NameSet& s (nsc.get ("name-set")); + global_type_names[name] = &s; + } + + NameSet& type_set (*global_type_names[name]); + + GlobalType type (*this, type_set); + Traversal::Names names (type); + + Traversal::Namespace::names (ns, names); + } + }; + + struct FundType : Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + + { + FundType (Context& c) + : Context (c) + { + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + set_names (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + set_names (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + set_names (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + set_names (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + set_names (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + set_names (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + set_names (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + set_names (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + set_names (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + set_names (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + set_names (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + set_names (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + set_names (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + set_names (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + set_names (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + set_names (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + set_names (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + set_names (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + set_names (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + set_names (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + set_names (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + set_names (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + set_names (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + set_names (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + set_names (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + set_names (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + set_names (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + set_names (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + set_names (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + set_names (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + set_names (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + set_names (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + set_names (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + set_names (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + set_names (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + set_names (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + set_names (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + set_names (t, "gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + set_names (t, "gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + set_names (t, "gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + set_names (t, "gyear");; + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + set_names (t, "gyear_month"); + + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + set_names (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + set_names (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + set_names (t, "entities"); + } + + private: + String + make_skel_name (String const& base) + { + return escape (base + skel_suffix); + } + + String + make_impl_name (String const& base) + { + return escape (base + impl_suffix); + } + + Void + set_names (SemanticGraph::Type& t, String const& name) + { + SemanticGraph::Context& c (t.context ()); + + WideChar const* ns = validation + ? L"::xsde::cxx::parser::validating::" + : L"::xsde::cxx::parser::non_validating::"; + + String skel (make_skel_name (name)); + c.set ("p:name", skel); + c.set ("p:real-name", ns + skel); + + String impl (make_impl_name (name)); + c.set ("p:impl", impl); + c.set ("p:real-impl", ns + impl); + + c.set ("p:post", L"post_" + name); + + if (tiein) + c.set ("p:tiein", name + L"_impl_"); + } + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count ("cxx-parser-name-processor-seen")) + { + s.context ().set ("cxx-parser-name-processor-seen", true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-parser-name-processor-seen")) + { + s.context ().set ("cxx-parser-name-processor-seen", true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-parser-name-processor-seen")) + { + s.context ().set ("cxx-parser-name-processor-seen", true); + Traversal::Imports::traverse (i); + } + } + }; + + // Go into implied schemas while making sure we don't process + // the same stuff more than once. + // + struct Implies: Traversal::Implies + { + virtual Void + traverse (SemanticGraph::Implies& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-parser-name-processor-seen")) + { + s.context ().set ("cxx-parser-name-processor-seen", true); + Traversal::Implies::traverse (i); + } + } + }; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + Context ctx (ops, tu, file); + + if (tu.names_begin ()->named ().name () == + L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + schema >> schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + else + { + // Pass one - assign names to fundamental types. + // + { + Traversal::Schema schema; + Implies implies; + Traversal::Schema xs_schema; + + schema >> implies >> xs_schema; + + Traversal::Names xs_schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + xs_schema >> xs_schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + + // Pass two - assign names to global types. This pass cannot + // be combined with pass three because of possible recursive + // schema inclusions. Also note that we check first if this + // schema has already been processed which may happen in the + // file-per-type compilation mode. + // + if (!tu.context ().count ("cxx-parser-name-processor-seen")) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + + schema >> schema_names >> ns; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("cxx-parser-name-processor-seen", true); + + schema.dispatch (tu); + } + + // Pass three - assign names inside complex types. Here we don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + Complex complex (ctx); + + ns_names >> complex; + + schema.dispatch (tu); + } + } + } + } + + Void NameProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/parser/name-processor.hxx b/xsde/cxx/parser/name-processor.hxx new file mode 100644 index 0000000..8d55f30 --- /dev/null +++ b/xsde/cxx/parser/name-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/parser/name-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_NAME_PROCESSOR_HXX +#define CXX_PARSER_NAME_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class NameProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_PARSER_NAME_PROCESSOR_HXX diff --git a/xsde/cxx/parser/parser-forward.cxx b/xsde/cxx/parser/parser-forward.cxx new file mode 100644 index 0000000..3ce73de --- /dev/null +++ b/xsde/cxx/parser/parser-forward.cxx @@ -0,0 +1,112 @@ +// file : xsde/cxx/parser/parser-forward.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + os << "class " << ename (e) << ";"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + os << "class " << ename (l) << ";"; + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + os << "class " << ename (u) << ";"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + os << "class " << ename (c) << ";"; + } + }; + } + + Void + generate_parser_forward (Context& ctx) + { + ctx.os << "// Forward declarations" << endl + << "//" << endl; + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + + ctx.os << endl; + } + } +} diff --git a/xsde/cxx/parser/parser-forward.hxx b/xsde/cxx/parser/parser-forward.hxx new file mode 100644 index 0000000..1ddeb39 --- /dev/null +++ b/xsde/cxx/parser/parser-forward.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/parser-forward.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_PARSER_FORWARD_HXX +#define CXX_PARSER_PARSER_FORWARD_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_parser_forward (Context&); + } +} + +#endif // CXX_PARSER_PARSER_FORWARD_HXX diff --git a/xsde/cxx/parser/parser-header.cxx b/xsde/cxx/parser/parser-header.cxx new file mode 100644 index 0000000..95642ab --- /dev/null +++ b/xsde/cxx/parser/parser-header.cxx @@ -0,0 +1,1818 @@ +// file : xsde/cxx/parser/parser-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + String fq_base (fq_name (base)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << fq_base + << "{" + << "public:" << endl + << "// Parser callbacks. Override them in your " << + "implementation." << endl + << "//" << endl; + + os << "// virtual void" << endl + << "// pre ();" << endl + << endl; + + String const& ret (ret_type (e)); + String const& base_ret (ret_type (base)); + + Boolean same (ret == base_ret); + + os << "virtual " << ret << endl + << post_name (e) << " ()" << + (same || ret == L"void" ? ";" : " = 0;"); + + if (poly_code) + { + os << endl + << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;"; + } + + if (tiein) + { + os << endl + << "// Constructor." << endl + << "//" << endl + << name << " (" << fq_base << "* tiein);" + << endl; + + os << "// Implementation details." << endl + << "//" << endl; + + // If our base has pure virtual post, override it here. + // + Boolean base_same ( + base.inherits_p () && + base_ret == ret_type (base.inherits ().base ())); + + if (!(base_same || base_ret == L"void")) + os << "virtual " << base_ret << endl + << post_name (base) << " ();" + << endl; + + os << "protected:" << endl + << name << "* " << etiein (e) << ";" + << name << " (" << name << "*, void*);"; + } + + os << "};"; + } + }; + + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + String item_type (fq_name (t)); + + String item (unclash (name, "item")); + + os << "class " << name << ": public " << list_base + << "{" + << "public:" << endl + << "// Parser callbacks. Override them in your " << + "implementation." << endl + << "//" << endl; + + // pre + // + os << "// virtual void" << endl + << "// pre ();" << endl + << endl; + + // item + // + String const& arg (arg_type (t)); + + os << "virtual void" << endl + << item; + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + + // post + // + String const& ret (ret_type (l)); + + os << "virtual " << ret << endl + << post_name (l) << " ()" << (ret == L"void" ? ";" : " = 0;") + << endl; + + + // + // + os << "// Parser construction API." << endl + << "//" << endl; + + // item_parser + // + os << "void" << endl + << unclash (name, "item_parser") << " (" << item_type << "&);" + << endl; + + // parsers + // + os << "void" << endl + << "parsers (" << item_type << "& /* item */);" + << endl; + + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + + // c-tor + // + os << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + + if (poly_code) + { + os << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;" + << endl; + } + + // + // + os << "// Implementation details." << endl + << "//" << endl + << "protected:" << endl; + + if (tiein) + { + os << name << "* " << etiein (l) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + os << "virtual void" << endl + << "_xsde_parse_item (const " << string_type << "&);" + << endl; + + os << "protected:" << endl + << item_type << "* _xsde_" << item << "_;" + << "};"; + } + }; + + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename (u)); + + os << "class " << name << ": public " << simple_base + << "{" + << "public:" << endl + << "// Parser callbacks. Override them in your " << + "implementation." << endl + << "//" << endl; + + os << "// virtual void" << endl + << "// pre ();" << endl + << "//" << endl + << "// virtual void" << endl + << "// _characters (const " << string_type << "&);" << endl + << endl; + + String const& ret (ret_type (u)); + + os << "virtual " << ret << endl + << post_name (u) << " ()" << (ret == L"void" ? ";" : " = 0;"); + + if (poly_code) + { + os << endl + << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;"; + } + + if (tiein) + { + // c-tor + // + os << endl + << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + + // + // + os << "// Implementation details." << endl + << "//" << endl + << "protected:" << endl + << name << "* " << etiein (u) << ";" + << name << " (" << name << "*, void*);"; + } + + os << "};"; + } + }; + + // + // Callbacks. + // + + struct ParticleTag: Traversal::Particle, Context + { + ParticleTag (Context& c) + : Context (c), first_ (true) + { + } + + virtual Void + traverse (Type& p) + { + if (first_) + first_ = false; + else + os << "," << endl; + + os << etag (p); + } + + private: + Boolean first_; + }; + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (correspondent (a) == 0) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + os << "virtual void" << endl + << epresent (a) << " ();" + << endl; + } + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () == c.contains_end ()) + return; + + if (correspondent (c) == 0) + { + os << "enum " << earm_tag (c) + << "{"; + + { + ParticleTag particle (*this); + Traversal::ContainsParticle contain_particle (particle); + Traversal::Choice::contains (c, contain_particle); + } + + os << "};"; + + os << "virtual void" << endl + << earm (c) << " (" << earm_tag (c) << ");" + << endl; + } + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // Root compositor that models inheritance by extension + // may not have an association so we may fall through + // in to the 'if' case even though this is a restriction. + // This is ok since such a compositor always has max == + // min == 1 and so nothing is generated. + // + if (SemanticGraph::Compositor* b = correspondent (s)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (b->max () != 1 && s.min () == 0) + { + os << "virtual void" << endl + << epresent (s) << " ();" + << endl; + } + } + else + { + if (s.max () != 1) + { + os << "virtual void" << endl + << enext (s) << " ();" + << endl; + } + else if (s.min () == 0) + { + os << "virtual void" << endl + << epresent (s) << " ();" + << endl; + } + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (correspondent (e) == 0) + { + String const& arg (arg_type (e.type ())); + + os << "virtual void" << endl + << ename (e); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& arg (arg_type (a.type ())); + + os << "virtual void" << endl + << ename (a); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + }; + + + // + // + struct ParticleAccessor: Traversal::Element, Context + { + ParticleAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& parser (eparser (e)); + + os << "void" << endl + << parser << " (" << fq_name (e.type ()) << "&);" + << endl; + + if (poly_code && !anonymous (e.type ())) + { + os << "void" << endl + << parser << " (" << parser_map << "&);" + << endl; + } + } + }; + + struct AttributeAccessor: Traversal::Attribute, Context + { + AttributeAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << "void" << endl + << eparser (a) << " (" << fq_name (a.type ()) << "&);" + << endl; + } + }; + + + // + // + struct ParticleMember: Traversal::Element, Context + { + ParticleMember (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String type (fq_name (e.type ())); + + os << type << "* " << emember (e) << ";"; + + if (poly_code && !anonymous (e.type ())) + { + os << type << "* " << emember_cache (e) << ";" + << parser_map << "* " << emember_map (e) << ";" + << endl; + } + } + }; + + struct AttributeMember: Traversal::Attribute, Context + { + AttributeMember (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << fq_name (a.type ()) << "* " << emember (a) << ";"; + } + }; + + // + // + struct Particle: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + Particle (Context& c) + : Context (c) + { + *this >> contains_particle_ >> *this; + } + + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context().count ("p:comp-number")) + return; + + UnsignedLong state_count ( + a.context().get ("p:state-count")); + + os << "void" << endl + << "all_0 (unsigned long&," << endl + << "unsigned char*," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&," << endl; + + if (poly_runtime) + os << "const char*," << endl; + + os << "bool);" + << endl + << "unsigned char v_all_first_[" << state_count << "UL];" + << "::xsde::cxx::parser::validating::all_stack v_all_count_;" + << endl; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!c.context().count ("p:comp-number")) + return; + + UnsignedLong n (c.context ().get ("p:comp-number")); + + os << "void" << endl + << "choice_" << n << " (unsigned long&," << endl + << "unsigned long&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&," << endl; + + if (poly_runtime) + os << "const char*," << endl; + + os << "bool);" + << endl; + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!s.context().count ("p:comp-number")) + return; + + UnsignedLong n (s.context ().get ("p:comp-number")); + + os << "void" << endl + << "sequence_" << n << " (unsigned long&," << endl + << "unsigned long&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&," << endl; + + if (poly_runtime) + os << "const char*," << endl; + + os << "bool);" + << endl; + + Traversal::Sequence::traverse (s); + } + + private: + Traversal::ContainsParticle contains_particle_; + }; + + + // + // + struct AttributeValidationState: Traversal::Attribute, Context + { + AttributeValidationState (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + if (!a.optional ()) + { + os << "bool " << ename (a) << ";"; + } + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_val_ (c), + particle_callback_ (c), + attribute_callback_ (c), + particle_accessor_ (c), + attribute_accessor_ (c), + particle_member_ (c), + attribute_member_ (c), + attribute_validation_state_ (c) + { + // Callback. + // + if (validation) + { + contains_compositor_callback_ >> compositor_callback_val_; + compositor_callback_val_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_val_; + } + else + { + contains_compositor_callback_ >> compositor_callback_non_val_; + compositor_callback_non_val_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_non_val_; + } + + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + + // Accessor. + // + contains_compositor_accessor_ >> compositor_accessor_; + compositor_accessor_ >> contains_particle_accessor_; + contains_particle_accessor_ >> compositor_accessor_; + contains_particle_accessor_ >> particle_accessor_; + + names_attribute_accessor_ >> attribute_accessor_; + + // Member. + // + contains_compositor_member_ >> compositor_member_; + compositor_member_ >> contains_particle_member_; + contains_particle_member_ >> compositor_member_; + contains_particle_member_ >> particle_member_; + + names_attribute_member_ >> attribute_member_; + + // + // + names_attribute_validation_state_ >> attribute_validation_state_; + } + + virtual Void + traverse (Type& c) + { + String const& name (ename (c)); + + // In case of an inheritance-by-restriction, we don't need to + // generate parser callbacks, etc. since they are the same as + // in the base. We only need the parsing/validation code. + // + Boolean hb (c.inherits_p ()); + Boolean restriction (restriction_p (c)); + + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + Boolean haa (has (c)); + + Boolean hra (false); // Has required attribute. + if (ha) + { + RequiredAttributeTest test (hra); + Traversal::Names names_test (test); + names (c, names_test); + } + + // + // + os << "class " << name << ": public "; + + if (hb) + os << (mixin ? "virtual " : "") << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "{" + << "public:" << endl + << "// Parser callbacks. Override them in your " << + "implementation." << endl + << "//" << endl; + + // pre + // + os << "// virtual void" << endl + << "// pre ();" << endl + << endl; + + // Member callbacks. + // + if (!restriction) + { + if (ha) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + } + + if (!restriction || validation) + { + if (he || hae) + { + if (!restriction) + os << "// Elements." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_callback_); + } + } + + // post + // + String const& ret (ret_type (c)); + Boolean same (hb && ret == ret_type (c.inherits ().base ())); + + os << "virtual " << ret << endl + << post_name (c) << " ()" << + (same || ret == L"void" ? ";" : " = 0;") + << endl; + + // + // + if (!restriction && (he || ha)) + { + os << "// Parser construction API." << endl + << "//" << endl; + + os << "void" << endl + << "parsers ("; + + { + ParserParamDecl decl (*this, false); + decl.traverse (c); + } + + os << ");" + << endl; + + if (ha) + { + os << "// Individual attribute parsers." << endl + << "//" << endl; + + names (c, names_attribute_accessor_); + } + + if (he) + { + os << "// Individual element parsers." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_accessor_); + } + } + + if (!restriction && (he || ha) && reset) + { + os << "virtual void" << endl + << "_reset ();" + << endl; + } + + // Default c-tor. + // + if (tiein || + (!restriction && (he || ha)) || + (validation && (he || hae || hra))) + { + os << "// Constructor." << endl + << "//" << endl; + + if (hb && tiein) + os << name << " (" << fq_name (c.inherits ().base ()) << + "* tiein);" + << endl; + else + os << name << " ();" + << endl; + } + + if (poly_code) + { + os << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;" + << endl; + } + + // Implementation. + // + if (tiein || he || ha || (validation && (hae || haa))) + { + os << "// Implementation details." << endl + << "//" << endl; + } + + if (tiein) + { + if (hb) + { + // If our base has pure virtual post, override it here. + // + SemanticGraph::Type& base (c.inherits ().base ()); + + String const& base_ret (ret_type (base)); + + Boolean base_same ( + base.inherits_p () && + base_ret == ret_type (base.inherits ().base ())); + + if (!(base_same || base_ret == L"void")) + os << "virtual " << base_ret << endl + << post_name (base) << " ();" + << endl; + } + + os << "protected:" << endl + << name << "* " << etiein (c) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + // element + // + if (he || (validation && hae)) + { + os << "protected:" << endl; + + // _start_element_impl + // + os << "virtual bool" << endl + << "_start_element_impl (const " << string_type << "&," << endl + << "const " << string_type << "&"; + + if (poly_runtime) + os << "," << endl + << "const char*"; + + os << ");" + << endl; + + // end_element + // + os << "virtual bool" << endl + << "_end_element_impl (const " << string_type << "&," << endl + << "const " << string_type << "&);" + << endl; + } + + // attribute + // + if (validation) + { + if (ha || haa) + os << "protected:" << endl; + + if (ha) + { + os << "virtual bool" << endl + << "_attribute_impl_phase_one (const " << string_type << + "&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&);" << endl + << endl; + } + + if (haa) + { + os << "virtual bool" << endl + << "_attribute_impl_phase_two (const " << string_type << + "&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&);" + << endl; + } + } + else + { + if (ha) + { + os << "protected:" << endl + << "virtual bool" << endl + << "_attribute_impl (const " << string_type << "&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&);" + << endl; + } + } + + // characters + // + if (validation && c.mixed ()) + { + os << "protected:" << endl + << "virtual bool" << endl + << "_characters_impl (const " << string_type << "&);" + << endl; + } + + if (!restriction && (he || ha)) + { + os << "protected:" << endl; + + if (ha) + names (c, names_attribute_member_); + + if (he) + contains_compositor (c, contains_compositor_member_); + + os << endl; + } + + if (validation && (he || hae)) + { + UnsignedLong depth (c.context ().get ("p:depth")); + + os << "protected:" << endl; + + os << "struct v_state_descr_" + << "{" + << "void (" << fq_name (c) << "::*func) (" << endl + << "unsigned long&," << endl + << "unsigned long&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&," << endl; + + if (poly_runtime) + os << "const char*," << endl; + + os << "bool);" + << "unsigned long state;" + << "unsigned long count;" + << "};"; + + // Allocate one extra slot for the special state. + // + os << "struct v_state_" + << "{" + << "v_state_descr_ data[" << depth + 1 << "UL];" + << "unsigned long size;" + << "};"; + + os << "v_state_ v_state_first_;" + << "::xsde::cxx::parser::stack v_state_stack_;" + << endl; + + os << "virtual void" << endl + << "_pre_e_validate ();" + << endl; + + os << "virtual void" << endl + << "_post_e_validate ();" + << endl; + + Particle t (*this); + t.dispatch (c.contains_compositor ().compositor ()); + } + + if (validation && hra) + { + os << "protected:" << endl; + + os << "struct v_state_attr_" + << "{"; + + names (c, names_attribute_validation_state_); + + os << "};"; + + os << "v_state_attr_ v_state_attr_first_;" + << "::xsde::cxx::parser::stack v_state_attr_stack_;" + << endl; + + os << "virtual void" << endl + << "_pre_a_validate ();" + << endl; + + os << "virtual void" << endl + << "_post_a_validate ();" + << endl; + } + + os << "};"; + } + + private: + // + // + CompositorCallback compositor_callback_val_; + Traversal::Compositor compositor_callback_non_val_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + + // + // + Traversal::Compositor compositor_accessor_; + ParticleAccessor particle_accessor_; + Traversal::ContainsCompositor contains_compositor_accessor_; + Traversal::ContainsParticle contains_particle_accessor_; + + AttributeAccessor attribute_accessor_; + Traversal::Names names_attribute_accessor_; + + // + // + Traversal::Compositor compositor_member_; + ParticleMember particle_member_; + Traversal::ContainsCompositor contains_compositor_member_; + Traversal::ContainsParticle contains_particle_member_; + + AttributeMember attribute_member_; + Traversal::Names names_attribute_member_; + + // + // + AttributeValidationState attribute_validation_state_; + Traversal::Names names_attribute_validation_state_; + }; + + struct FundType : Context, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities + { + FundType (Context& c) + : Context (c), xs_ns_ (xs_ns_name ()) + { + impl_ns_ = "::xsde::cxx::parser::"; + impl_ns_ += (validation ? L"validating" : L"non_validating"); + + if (options.value ()) + { + qname_type_ = xs_ns_ + L"::qname*"; + string_type_ = L"char*"; + } + else + { + qname_type_ = xs_ns_ + L"::qname"; + string_type_ = L"::std::string"; + } + + string_seq_type_ = xs_ns_ + L"::string_sequence*"; + buffer_type_ = xs_ns_ + L"::buffer*"; + + if (options.value ()) + { + long_type_ = L"long"; + unsigned_long_type_ = L"unsigned long"; + } + else + { + long_type_ = L"long long"; + unsigned_long_type_ = L"unsigned long long"; + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + gen_typedef (t, "void"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + gen_typedef (t, "void"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + gen_typedef (t, "bool"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + gen_typedef (t, "signed char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + gen_typedef (t, "unsigned char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + gen_typedef (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + gen_typedef (t, "unsigned short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + gen_typedef (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + gen_typedef (t, "unsigned int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + gen_typedef (t, long_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + gen_typedef (t, unsigned_long_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + gen_typedef (t, "unsigned long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + gen_typedef (t, "unsigned long"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + gen_typedef (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + gen_typedef (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + gen_typedef (t, "double"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + nmtoken_ = gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + // NMTOKENS uses NMTOKEN implementation to parse individual items. + // As a result, we don't generate NMTOKENS if we didn't generate + // NMTOKEN. Here we assume NMTOKEN is handled before NMTOKENS. + // + if(nmtoken_) + gen_typedef (t, string_seq_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + gen_typedef (t, string_type_); + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + gen_typedef (t, qname_type_); + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + idref_ = gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + // IDREFS uses IDREF implementation to parse individual items. + // As a result, we don't generate IDREFS if we didn't generate + // IDREF. Here we assume IDREF is handled before IDREFS. + // + if (idref_) + gen_typedef (t, string_seq_type_); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + gen_typedef (t, string_type_); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + gen_typedef (t, buffer_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + gen_typedef (t, buffer_type_); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + gen_typedef (t, xs_ns_ + L"::date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + gen_typedef (t, xs_ns_ + L"::date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + gen_typedef (t, xs_ns_ + L"::duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + gen_typedef (t, xs_ns_ + L"::gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + gen_typedef (t, xs_ns_ + L"::gyear"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + gen_typedef (t, xs_ns_ + L"::gyear_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + gen_typedef (t, xs_ns_ + L"::time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities&) + { + } + + private: + Boolean + gen_typedef (SemanticGraph::Type& t, String const& type) + { + if (ret_type (t) == type) + { + SemanticGraph::Context& c (t.context ()); + + String const& real_name (c.get ("p:real-name")); + String const& name (c.get ("p:name")); + + os << "typedef " << real_name << " " << name << ";"; + + String const& real_impl (c.get ("p:real-impl")); + String const& impl (c.get ("p:impl")); + + os << "typedef " << real_impl << " " << impl << ";" + << endl; + + return true; + } + + return false; + } + + String xs_ns_; + String impl_ns_; + String qname_type_; + String string_type_; + String buffer_type_; + String string_seq_type_; + String long_type_; + String unsigned_long_type_; + + Boolean idref_; + Boolean nmtoken_; + }; + + struct FundNamespace : Namespace, Context + { + FundNamespace (Context& c) + : Namespace (c), Context (c) + { + } + + void + traverse (Type& ns) + { + pre (ns); + + String impl ("::xsde::cxx::parser::"); + impl += (validation ? L"validating" : L"non_validating"); + + String const c (char_type); + + os << "// Built-in XML Schema types mapping." << endl + << "//" << endl + << "using ::xsde::cxx::string_sequence;" + << "using ::xsde::cxx::qname;" + << "using ::xsde::cxx::buffer;" + << "using ::xsde::cxx::time_zone;" + << "using ::xsde::cxx::gday;" + << "using ::xsde::cxx::gmonth;" + << "using ::xsde::cxx::gyear;" + << "using ::xsde::cxx::gmonth_day;" + << "using ::xsde::cxx::gyear_month;" + << "using ::xsde::cxx::date;" + << "using ::xsde::cxx::time;" + << "using ::xsde::cxx::date_time;" + << "using ::xsde::cxx::duration;" + << endl; + + os << "// Base parser skeletons." << endl + << "//" << endl + << "using ::xsde::cxx::parser::parser_base;" + << "typedef " << impl << "::empty_content " << + "parser_empty_content;" + << "typedef " << impl << "::simple_content " << + "parser_simple_content;" + << "typedef " << impl << "::complex_content " << + "parser_complex_content;" + << "typedef " << impl << "::list_base parser_list_base;" + << endl; + + if (poly_code) + { + os << "// Parser map interface and default implementation." << endl + << "//" << endl + << "using ::xsde::cxx::parser::parser_map;" + << "using ::xsde::cxx::parser::parser_map_impl;" + << endl; + + os << "// Substitution and inheritance hashmaps load querying." << endl + << "//" << endl + << "using ::xsde::cxx::parser::parser_smap_buckets;" + << "using ::xsde::cxx::parser::parser_smap_elements;"; + + if (validation) + os << "using ::xsde::cxx::parser::validating::parser_imap_buckets;" + << "using ::xsde::cxx::parser::validating::parser_imap_elements;"; + + os << endl; + } + + os << "// Parser skeletons and implementations for the XML Schema" << endl + << "// built-in types." << endl + << "//" << endl; + + names (ns); + + os << "// Read-only string." << endl + << "//" << endl + << "using ::xsde::cxx::ro_string;" + << endl; + + os << "// Error codes." << endl + << "//" << endl; + + if (!exceptions) + os << "using xsde::cxx::sys_error;"; + + os << "typedef xsde::cxx::parser::expat::xml_error " << + "parser_xml_error;"; + + if (validation) + os << "typedef xsde::cxx::schema_error parser_schema_error;"; + + os << endl; + + if (exceptions) + { + os << "// Exceptions." << endl + << "//" << endl + << "typedef xsde::cxx::parser::exception parser_exception;" + << "typedef xsde::cxx::parser::xml parser_xml;"; + + if (validation) + os << "typedef xsde::cxx::parser::schema parser_schema;"; + + os << endl; + } + else + os << "// Error object." << endl + << "//" << endl + << "typedef xsde::cxx::parser::error parser_error;" + << endl; + + os << "// Document parser." << endl + << "//" << endl + << "using xsde::cxx::parser::expat::document_pimpl;" + << endl; + + os << "// Parser context." << endl + << "//" << endl + << "typedef xsde::cxx::parser::context parser_context;" + << endl; + + post (ns); + } + }; + } + + Void + generate_parser_header (Context& ctx, Boolean generate_xml_schema) + { + NarrowString extern_xml_schema; + + if (!generate_xml_schema) + extern_xml_schema = ctx.options.value (); + + if (extern_xml_schema) + { + String name (ctx.hxx_expr->merge (extern_xml_schema)); + + ctx.os << "#include " << ctx.process_include_path (name) << endl + << endl; + + // Generate includes that came from the type map. + // + if (ctx.schema_root.context ().count ("p:includes")) + { + typedef Cult::Containers::Set Includes; + + Includes& is ( + ctx.schema_root.context ().get ("p:includes")); + + for (Includes::ConstReverseIterator i (is.rbegin ()); + i != is.rend (); ++i) + { + ctx.os << "#include " << *i << endl; + } + + ctx.os << endl; + } + } + else + { + ctx.os << "#include " << endl + << "#include " << endl + << endl; + + // Data types. + // + ctx.os << "#include " << endl + << endl; + + // Error handling. + // + if (ctx.exceptions) + ctx.os << "#include " << endl + << endl; + else + { + ctx.os << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl; + + ctx.os << "#include " << endl + << "#include " << endl + << endl; + } + + // Polymorphism support. + // + if (ctx.poly_code) + { + ctx.os << "#include " << endl + << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl; + + ctx.os << endl; + } + + // Parsers. + // + if (ctx.validation) + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + else + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + + // Document. + // + ctx.os << "#include " << endl + << endl; + + // Generate includes that came from the type map. + // + if (ctx.schema_root.context ().count ("p:includes")) + { + typedef Cult::Containers::Set Includes; + + Includes& is ( + ctx.schema_root.context ().get ("p:includes")); + + for (Includes::ConstReverseIterator i (is.rbegin ()); + i != is.rend (); ++i) + { + ctx.os << "#include " << *i << endl; + } + + ctx.os << endl; + } + + // Generate fundamental types. + // + if (generate_xml_schema) + { + Traversal::Schema schema; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + } + else + { + Traversal::Schema schema, xsd; + Traversal::Implies implies; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> implies >> xsd >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + } + } + + // Generate user type mapping. + // + if (!generate_xml_schema) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::header); + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/parser/parser-header.hxx b/xsde/cxx/parser/parser-header.hxx new file mode 100644 index 0000000..0baf7bc --- /dev/null +++ b/xsde/cxx/parser/parser-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/parser-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_PARSER_HEADER_HXX +#define CXX_PARSER_PARSER_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_parser_header (Context&, Boolean generate_xml_schema); + } +} + +#endif // CXX_PARSER_PARSER_HEADER_HXX diff --git a/xsde/cxx/parser/parser-inline.cxx b/xsde/cxx/parser/parser-inline.cxx new file mode 100644 index 0000000..689f95f --- /dev/null +++ b/xsde/cxx/parser/parser-inline.cxx @@ -0,0 +1,721 @@ +// file : xsde/cxx/parser/parser-inline.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (tiein) + { + String const& name (ename (e)); + String const& impl (etiein (e)); + + // We have to use "real" (non-typedef) base name in base + // initializer because of some broken compilers (EVC 4.0). + // + SemanticGraph::Type& base (e.inherits ().base ()); + String fq_base (fq_name (base)); + String real_fq_base (real_fq_name (base)); + + os << "// " << name << endl + << "//" << endl + << endl; + + os << inl + << name << "::" << endl + << name << " (" << fq_base << "* tiein)" << endl + << ": " << real_fq_base << " (tiein, 0)," << endl + << " " << impl << " (0)" + << "{" + << "}"; + + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << real_fq_base << " (impl, 0)," << endl + << " " << impl << " (impl)" + << "{" + << "}"; + } + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + String item_type (fq_name (t)); + + String item (unclash (name, "item")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // item_parser + // + os << inl + << "void " << name << "::" << endl + << unclash (name, "item_parser") << " (" << + item_type << "& " << item << ")" + << "{" + << "this->_xsde_" << item << "_ = &" << item << ";" + << "}"; + + // parsers + // + os << inl + << "void " << name << "::" << endl + << "parsers (" << item_type << "& " << item << ")" + << "{" + << "this->_xsde_" << item << "_ = &" << item << ";" + << "}"; + + // c-tor + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": "; + + if (tiein) + os << etiein (l) << " (0)," << endl + << " "; + + os << "_xsde_" << item << "_ (0)" + << "{" + << "}"; + + if (tiein) + { + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << list_base << " (impl, 0)," << endl + << " " << etiein (l) << " (impl)," << endl + << " _xsde_" << item << "_ (0)" + << "{" + << "}"; + } + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + if (tiein) + { + String const& name (ename (u)); + String const& impl (etiein (u)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": " << impl << " (0)" + << "{" + << "}"; + + // + // + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << simple_base << " (impl, 0)," << endl + << " " << impl << " (impl)" + << "{" + << "}"; + } + } + }; + + // + // + struct ParticleAccessor: Traversal::Element, Context + { + ParticleAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& scope (ename (e.scope ())); + String const& parser (eparser (e)); + + os << inl + << "void " << scope << "::" << endl + << parser << " (" << fq_name (e.type ()) << "& p)" + << "{" + << "this->" << emember (e) << " = &p;" + << "}"; + + if (poly_code && !anonymous (e.type ())) + { + os << inl + << "void " << scope << "::" << endl + << parser << " (" << parser_map << "& m)" + << "{" + << "this->" << emember_map (e) << " = &m;" + << "}"; + } + } + }; + + struct AttributeAccessor: Traversal::Attribute, Context + { + AttributeAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << inl + << "void " << ename (a.scope ()) << "::" << endl + << eparser (a) << " (" << fq_name (a.type ()) << "& p)" + << "{" + << "this->" << emember (a) << " = &p;" + << "}"; + } + }; + + // + // + struct ParticleMemberSet: Traversal::Element, Context + { + ParticleMemberSet (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + os << "this->" << emember (e) << " = &" << ename (e) << ";"; + } + }; + + struct AttributeMemberSet: Traversal::Attribute, Context + { + AttributeMemberSet (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << "this->" << emember (a) << " = &" << ename (a) << ";"; + } + }; + + struct BaseMemberSet: Traversal::Complex, + Traversal::List, + Context + { + BaseMemberSet (Context& c) + : Context (c) + { + inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + String const& name (ename (l)); + String item (unclash (name, "item")); + + os << "this->_xsde_" << item << "_ = &" << name << "_item;"; + } + + private: + Traversal::Inherits inherits_; + }; + + // + // + struct ParticleMemberInit: Traversal::Element, Context + { + ParticleMemberInit (Context& c, Boolean comma) + : Context (c), first_ (!comma) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (first_) + first_ = false; + else + os << "," << endl << " "; + + os << emember (e) << " (0)"; + + if (poly_code && !anonymous (e.type ())) + { + os << "," << endl + << " " << emember_map (e) << " (0)"; + } + } + + Boolean + comma () const + { + return !first_; + } + + private: + Boolean first_; + }; + + struct AttributeMemberInit: Traversal::Attribute, Context + { + AttributeMemberInit (Context& c, Boolean comma) + : Context (c), first_ (!comma) + { + } + + virtual Void + traverse (Type& a) + { + if (first_) + first_ = false; + else + os << "," << endl << " "; + + os << emember (a) << " (0)"; + } + + Boolean + comma () const + { + return !first_; + } + + private: + Boolean first_; + }; + + // + // + struct Particle: Traversal::All, Context + { + Particle (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context().count ("p:comp-number")) + return; + + UnsignedLong state_count ( + a.context().get ("p:state-count")); + + os << "," << endl + << " v_all_count_ (" << state_count << "UL, v_all_first_)"; + } + }; + + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + particle_accessor_ (c), + attribute_accessor_ (c), + base_set_ (c), + particle_set_ (c), + attribute_set_ (c), + particle_ (c) + { + // Accessor. + // + contains_compositor_accessor_ >> compositor_accessor_; + compositor_accessor_ >> contains_particle_accessor_; + contains_particle_accessor_ >> compositor_accessor_; + contains_particle_accessor_ >> particle_accessor_; + + names_attribute_accessor_ >> attribute_accessor_; + + // Member set. + // + inherits_base_set_ >> base_set_; + base_set_ >> contains_compositor_set_; + base_set_ >> names_attribute_set_; + + contains_compositor_set_ >> compositor_set_; + compositor_set_ >> contains_particle_set_; + contains_particle_set_ >> compositor_set_; + contains_particle_set_ >> particle_set_; + + names_attribute_set_ >> attribute_set_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + + Boolean hra (false); // Has required attribute. + if (ha) + { + RequiredAttributeTest test (hra); + Traversal::Names names_test (test); + names (c, names_test); + } + + Boolean restriction (restriction_p (c)); + + if (!(tiein || + (!restriction && (he || ha)) || + (validation && (he || hae || hra)))) + return; + + String const& name (ename (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + if (!restriction && (he || ha)) + { + // _parser () + // + if (ha) + names (c, names_attribute_accessor_); + + if (he) + contains_compositor (c, contains_compositor_accessor_); + + + // parsers () + // + + os << inl + << "void " << name << "::" << endl + << "parsers ("; + + { + ParserParamDecl decl (*this, true); + decl.traverse (c); + } + + os << ")" + << "{"; + + inherits (c, inherits_base_set_); + + if (ha) + names (c, names_attribute_set_); + + if (he) + contains_compositor (c, contains_compositor_set_); + + os << "}"; + } + + // We have to use "real" (non-typedef) base name in base + // initializer because of some broken compilers (EVC 4.0). + // + String real_fq_base; + + if (hb && tiein) + real_fq_base = real_fq_name (c.inherits ().base ()); + + // Default c-tor. + // + os << inl + << name << "::" << endl; + + if (hb && tiein) + os << name << " (" << fq_name (c.inherits ().base ()) << + "* tiein)" << endl; + else + os << name << " ()" << endl; + + os << ": "; + + Boolean comma (false); + + if (hb && tiein) + { + os << real_fq_base << " (tiein, 0)"; + comma = true; + } + + if (tiein) + { + if (comma) + os << "," << endl << " "; + + os << etiein (c) << " (0)"; + comma = true; + } + + if (!restriction && (he || ha)) + { + if (ha) + { + AttributeMemberInit attribute_init (*this, comma); + Traversal::Names names_attribute_init; + + names_attribute_init >> attribute_init; + + names (c, names_attribute_init); + + comma = attribute_init.comma (); + } + + if (he) + { + Traversal::Compositor compositor_init; + ParticleMemberInit particle_init (*this, comma); + Traversal::ContainsCompositor contains_compositor_init; + Traversal::ContainsParticle contains_particle_init; + + contains_compositor_init >> compositor_init; + compositor_init >> contains_particle_init; + contains_particle_init >> compositor_init; + contains_particle_init >> particle_init; + + contains_compositor (c, contains_compositor_init); + + comma = particle_init.comma (); + } + } + + if (validation && (he || hae)) + { + if (comma) + os << "," << endl << " "; + + os << "v_state_stack_ (sizeof (v_state_), &v_state_first_)"; + + particle_.dispatch (c.contains_compositor ().compositor ()); + + comma = true; + } + + if (validation && (hra)) + { + if (comma) + os << "," << endl << " "; + + os << "v_state_attr_stack_ (sizeof (v_state_attr_), " << + "&v_state_attr_first_)"; + } + + os << "{" + << "}"; + + // Tiein c-tor. + // + if (tiein) + { + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": "; + + if (hb) + os << real_fq_base << " (impl, 0)," << endl; + else + os << complex_base << " (impl, 0)," << endl; + + os << " " << etiein (c) << " (impl)"; + + Boolean comma (true); + + if (!restriction && (he || ha)) + { + if (ha) + { + AttributeMemberInit attribute_init (*this, comma); + Traversal::Names names_attribute_init; + + names_attribute_init >> attribute_init; + + names (c, names_attribute_init); + + comma = attribute_init.comma (); + } + + if (he) + { + Traversal::Compositor compositor_init; + ParticleMemberInit particle_init (*this, comma); + Traversal::ContainsCompositor contains_compositor_init; + Traversal::ContainsParticle contains_particle_init; + + contains_compositor_init >> compositor_init; + compositor_init >> contains_particle_init; + contains_particle_init >> compositor_init; + contains_particle_init >> particle_init; + + contains_compositor (c, contains_compositor_init); + + comma = particle_init.comma (); + } + } + + if (validation && (he || hae)) + { + if (comma) + os << "," << endl << " "; + + os << "v_state_stack_ (sizeof (v_state_), &v_state_first_)"; + + particle_.dispatch (c.contains_compositor ().compositor ()); + + comma = true; + } + + if (validation && (hra)) + { + if (comma) + os << "," << endl << " "; + + os << "v_state_attr_stack_ (sizeof (v_state_attr_), " << + "&v_state_attr_first_)"; + } + + os << "{" + << "}"; + } + } + + private: + // + // + Traversal::Compositor compositor_accessor_; + ParticleAccessor particle_accessor_; + Traversal::ContainsCompositor contains_compositor_accessor_; + Traversal::ContainsParticle contains_particle_accessor_; + + AttributeAccessor attribute_accessor_; + Traversal::Names names_attribute_accessor_; + + // + // + BaseMemberSet base_set_; + Traversal::Inherits inherits_base_set_; + + Traversal::Compositor compositor_set_; + ParticleMemberSet particle_set_; + Traversal::ContainsCompositor contains_compositor_set_; + Traversal::ContainsParticle contains_particle_set_; + + AttributeMemberSet attribute_set_; + Traversal::Names names_attribute_set_; + + // + // + Particle particle_; + }; + } + + Void + generate_parser_inline (Context& ctx) + { + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + if (!ctx.options.value ()) + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Enumeration enumeration (ctx); + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> enumeration; + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/parser-inline.hxx b/xsde/cxx/parser/parser-inline.hxx new file mode 100644 index 0000000..c54f537 --- /dev/null +++ b/xsde/cxx/parser/parser-inline.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/parser-inline.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_PARSER_INLINE_HXX +#define CXX_PARSER_PARSER_INLINE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_parser_inline (Context&); + } +} + +#endif // CXX_PARSER_PARSER_INLINE_HXX diff --git a/xsde/cxx/parser/parser-source.cxx b/xsde/cxx/parser/parser-source.cxx new file mode 100644 index 0000000..5e1e9bd --- /dev/null +++ b/xsde/cxx/parser/parser-source.cxx @@ -0,0 +1,1626 @@ +// file : xsde/cxx/parser/parser-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + String const& ret (ret_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + String const& base_ret (ret_type (base)); + + Boolean same (ret == base_ret); + Boolean base_same ( + base.inherits_p () && + base_ret == ret_type (base.inherits ().base ())); + + if (same || ret == L"void" || poly_code || + (tiein && !(base_same || base_ret == L"void"))) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (same || ret == L"void") + { + String const& post (post_name (e)); + + os << ret << " " << name << "::" << endl + << post << " ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (e)); + + os << "if (this->" << impl << ")" << endl + << (ret != L"void" ? "return " : "") << "this->" << + impl << "->" << post << " ();"; + } + + if (same) + { + if (tiein) + os << "else" << endl; + + if (ret == L"void") + os << post_name (base) << " ();"; + else + os << "return " << post_name (base) << " ();"; + } + + os << "}"; + } + + if (poly_code) + { + String id (e.name ()); + + if (String ns = xml_ns_name (e)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + + if (validation) + { + Boolean gen (!anonymous (e)); + + // We normally don't need to enter anonymous types into + // the inheritance map. The only exception is when an + // anonymous types is defined inside an element that + // is a member of a substitution group. + // + if (!gen) + { + // The first instance that this anonymous type classifies + // is the prototype for others if any. + // + SemanticGraph::Instance& i ( + e.classifies_begin ()->instance ()); + + if (SemanticGraph::Element* e = + dynamic_cast (&i)) + { + if (e->substitutes_p ()) + gen = true; + } + } + + if (gen) + { + os << "static" << endl + << "const ::xsde::cxx::parser::validating::" << + "inheritance_map_entry" << endl + << "_xsde_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + + if (tiein && !(base_same || base_ret == L"void")) + { + String const& impl (etiein (base)); + String const& base_post (post_name (base)); + + os << base_ret << " " << name << "::" << endl + << base_post << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << base_post << " ();" + << "}"; + } + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + + String item (unclash (name, "item")); + String inst (L"_xsde_" + item + L"_"); + String const& post (post_name (t)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // item + // + String const& arg (arg_type (t)); + + os << "void " << name << "::" << endl + << item; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << (tiein ? " x" : "") << ")"; + + os << "{"; + + if (tiein) + { + String const& impl (etiein (l)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << item << " (" << + (arg != L"void" ? "x" : "") << ");"; + } + + os << "}"; + + // post + // + if (ret_type (l) == L"void") + { + String const& post (post_name (l)); + + os << "void " << name << "::" << endl + << post << " ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (l)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << post << " ();"; + } + + os << "}"; + } + + // reset + // + if (reset) + { + os << "void " << name << "::" << endl + << "_reset ()" + << "{" + << list_base << "::_reset ();" + << endl + << "if (this->" << inst << ")" << endl + << "this->" << inst << "->_reset ();" + << "}"; + } + + // parse_item + // + os << "void " << name << "::" << endl + << "_xsde_parse_item (const " << string_type << "& v)" + << "{" + << "if (this->" << inst << ")" + << "{" + << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + // This implementation should work for both validating + // and non-validating cases. + // + if (!exceptions || validation) + { + String const& ret (ret_type (t)); + + os << "this->" << inst << "->pre ();"; + + if (!exceptions) + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << "else" << endl; + + os << "this->" << inst << "->_pre_impl (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_characters (v);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_post_impl ();" + << endl + << "if (!ctx.error_type ())" << endl; + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << endl; + else + os << "{" + << arg_type (t) << " tmp = this->" << inst << "->" << + post << " ();" + << endl; + + if (!exceptions) + os << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << "else" << endl; + + if (ret == L"void") + os << "this->" << item << " ();"; + else + os << "this->" << item << " (tmp);" + << "}"; + } + else + { + os << "this->" << inst << "->pre ();" + << "this->" << inst << "->_pre_impl (ctx);" + << "this->" << inst << "->_characters (v);" + << "this->" << inst << "->_post_impl ();"; + + if (ret_type (t) == L"void") + os << "this->" << inst << "->" << post << " ();" + << "this->" << item << " ();"; + else + os << "this->" << item << " (this->" << inst << "->" << + post << " ());"; + } + + os << "}" + << "}"; + + // + // + if (poly_code) + { + String id (l.name ()); + + if (String ns = xml_ns_name (l)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename (u)); + String const& ret (ret_type (u)); + + if (ret == L"void" || poly_code) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (ret == L"void") + { + String const& post (post_name (u)); + + os << "void " << name << "::" << endl + << post << " ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (u)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << post << " ();"; + } + + os << "}"; + } + + if (poly_code) + { + String id (u.name ()); + + if (String ns = xml_ns_name (u)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + // + // + struct ParticleReset: Traversal::Element, Context + { + ParticleReset (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& m (emember (e)); + + os << "if (this->" << m << ")" << endl + << "this->" << m << "->_reset ();" + << endl; + + if (poly_code && !anonymous (e.type ())) + { + String const& map (emember_map (e)); + + os << "if (this->" << map << ")" << endl + << "this->" << map << "->reset ();" + << endl; + } + } + }; + + struct AttributeReset: Traversal::Attribute, Context + { + AttributeReset (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + String const& m (emember (a)); + + os << "if (this->" << m << ")" << endl + << "this->" << m << "->_reset ();" + << endl; + } + }; + + // + // + struct StartElement : Traversal::Element, Context + { + StartElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + Boolean poly (poly_code && !anonymous (e.type ())); + Boolean subst (poly && e.global ()); + String const& inst (poly ? emember_cache (e) : emember (e)); + + if (e.qualified () && e.namespace_ ().name ()) + { + os << "if (" << (subst ? "(" : "") << + "n == " << strlit (e.name ()) << " &&" << endl + << "ns == " << strlit (e.namespace_ ().name ()); + } + else + { + os << "if (" << (subst ? "(" : "") << + "n == " << L << strlit (e.name ()) << " && ns.empty ()"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (subst) + { + String root_id (e.name ()); + + if (String const& ns = e.namespace_ ().name ()) + { + root_id += L' '; + root_id += ns; + } + + os << ") ||" << endl + << "::xsde::cxx::parser::substitution_map_instance ()" << + ".check (" << endl + << "ns, n, " << strlit (root_id) << ", t)"; + } + + os << ")" + << "{"; + + if (poly) + { + // In case of mixin we use virtual inheritance and only + // dynamic_cast can be used. + // + String cast (mixin ? L"dynamic_cast" : L"static_cast"); + String fq_type (fq_name (e.type ())); + String const& member (emember (e)); + String const& member_map (emember_map (e)); + + os << "if (t == 0 && this->" << member << " != 0)" << endl + << "this->" << inst << " = this->" << member << ";" + << "else" + << "{" + << "const char* ts = " << fq_type << "::_static_type ();" + << endl + << "if (t == 0)" << endl + << "t = ts;" + << endl + << "if (this->" << member << " != 0 && " << + "strcmp (t, ts) == 0)" << endl + << "this->" << inst << " = this->" << member << ";" + << "else if (this->" << member_map << " != 0)" << endl + << "this->" << inst << " = " << cast << "< " << fq_type << + "* > (" << endl + << "this->" << member_map << "->find (t));" + << "else" << endl + << "this->" << inst << " = 0;" + << "}"; + } + + os << "if (this->" << inst << ")" + << "{"; + + if (exceptions) + { + os << "this->" << inst << "->pre ();" + << "this->" << inst << "->_pre_impl (ctx);"; + } + else + { + // Note that after pre() we need to check both parser and + // context error states because of the recursive parsing. + // + os << "this->" << inst << "->pre ();" + << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_pre_impl (ctx);"; + } + + os << "}" + << "else" << endl + << "ctx.current_.depth_++;" // Ignoring document fragment. + << endl + << "return true;" + << "}"; + } + }; + + + // + // + struct EndElement : Traversal::Element, Context + { + EndElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + Boolean poly (poly_code && !anonymous (e.type ())); + Boolean subst (poly && e.global ()); + String const& inst (poly ? emember_cache (e) : emember (e)); + + if (e.qualified () && e.namespace_ ().name ()) + { + os << "if (" << (subst ? "(" : "") << + "n == " << strlit (e.name ()) << " &&" << endl + << "ns == " << strlit (e.namespace_ ().name ()); + } + else + { + os << "if (" << (subst ? "(" : "") << + "n == " << strlit (e.name ()) << " && ns.empty ()"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (subst) + { + String root_id (e.name ()); + + if (String const& ns = e.namespace_ ().name ()) + { + root_id += L' '; + root_id += ns; + } + + os << ") ||" << endl + << "::xsde::cxx::parser::substitution_map_instance ()" << + ".check (" << endl + << "ns, n, " << strlit (root_id) << ")"; + } + + os << ")" + << "{"; + + SemanticGraph::Type& type (e.type ()); + String const& post (post_name (type)); + + os << "if (this->" << inst << ")" + << "{"; + + if (exceptions) + { + if (ret_type (type) == L"void") + os << "this->" << inst << "->" << post << " ();" + << "this->" << name << " ();"; + else + os << "this->" << name << " (this->" << inst << "->" << + post << " ());"; + } + else + { + // Note that after post() we need to check both parser and + // context error states because of the recursive parsing. + // + if (ret_type (type) == L"void") + { + os << "this->" << inst << "->" << post << " ();" + << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << name << " ();"; + } + else + { + os << arg_type (type) << " tmp = this->" << inst << "->" << + post << " ();" + << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << name << " (tmp);"; + } + } + + os << "}" + << "return true;" + << "}"; + } + }; + + + // + // + struct Attribute : Traversal::Attribute, Context + { + Attribute (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + String const& name (ename (a)); + String const& inst (emember (a)); + + if (a.qualified () && a.namespace_ ().name ()) + { + os << "if (n == " << L << strlit (a.name ()) << " &&" << endl + << "ns == " << L << strlit (a.namespace_ ().name ()) << ")" + << "{"; + } + else + { + os << "if (n == " << L << strlit (a.name ()) << " && ns.empty ())" + << "{"; + } + + SemanticGraph::Type& type (a.type ()); + String const& post (post_name (type)); + String const& ret (ret_type (type)); + + os << "if (this->" << inst << ")" + << "{"; + + if (exceptions) + { + os << "this->" << inst << "->pre ();" + << "this->" << inst << "->_pre_impl (ctx);" + << "this->" << inst << "->_characters (v);" + << "this->" << inst << "->_post_impl ();"; + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << "this->" << name << " ();"; + else + os << "this->" << name << " (this->" << inst << "->" << + post << " ());"; + } + else + { + os << "this->" << inst << "->pre ();" + << endl + << "if (!this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_pre_impl (ctx);" + << "else" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_characters (v);" + << endl + << "if (!ctx.error_type ())" << endl + << "this->" << inst << "->_post_impl ();" + << endl + << "if (!ctx.error_type ())" << endl; + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << endl; + else + os << "{" + << arg_type (type) << " tmp = this->" << inst << "->" << + post << " ();" + << endl; + + os << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << "else" << endl; + + if (ret == L"void") + os << "this->" << name << " ();"; + else + os << "this->" << name << " (tmp);" + << "}"; + } + + os << "}" + << "return true;" + << "}"; + } + }; + + // + // Callbacks. + // + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (correspondent (a) == 0) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + SemanticGraph::Scope& s (scope (a)); + String const& present (epresent (a)); + + os << "void " << ename (s) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (s))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << present << " ();"; + } + + os << "}"; + } + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () == c.contains_end ()) + return; + + if (correspondent (c) == 0) + { + SemanticGraph::Scope& s (scope (c)); + String const& arm (earm (c)); + + os << "void " << ename (s) << "::" << endl + << arm << " (" << earm_tag (c) << (tiein ? " x" : "") << ")" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (s))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << arm << " (x);"; + } + + os << "}"; + + } + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // Root compositor that models inheritance by extension + // may not have an association so we may fall through + // in to the 'if' case even though this is a restriction. + // This is ok since such a compositor always has max == + // min == 1 and so nothing is generated. + // + if (SemanticGraph::Compositor* b = correspondent (s)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (b->max () != 1 && s.min () == 0) + { + SemanticGraph::Scope& ss (scope (s)); + + os << "void " << ename (ss) << "::" << endl + << epresent (s) << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (ss))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << enext (s) << " ();"; + } + else + os << "this->" << enext (s) << " ();"; + + os << "}"; + } + } + else + { + if (s.max () != 1) + { + SemanticGraph::Scope& ss (scope (s)); + String const& next (enext (s)); + + os << "void " << ename (ss) << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (ss))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << next << " ();"; + } + + os << "}"; + } + else if (s.min () == 0) + { + SemanticGraph::Scope& ss (scope (s)); + String const& present (epresent (s)); + + os << "void " << ename (ss) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (ss))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << present << " ();"; + } + + os << "}"; + } + } + + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Scope& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + }; + + struct ParticleCallback: Traversal::Element, Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (correspondent (e) == 0) + { + String const& name (ename (e)); + String const& arg (arg_type (e.type ())); + + os << "void " << ename (e.scope ()) << "::" << endl + << name; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << (tiein ? " x" : "") << ")"; + + os << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (e.scope ()))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (" << + (arg != L"void" ? "x" : "") << ");"; + } + + os << "}"; + } + } + }; + + struct AttributeCallback: Traversal::Attribute, Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& name (ename (a)); + String const& arg (arg_type (a.type ())); + + os << "void " << ename (a.scope ()) << "::" << endl + << name; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << (tiein ? " x" : "") << ")"; + + os << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (a.scope ()))); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (" << + (arg != L"void" ? "x" : "") << ");"; + } + + os << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_val_ (c), + particle_callback_ (c), + attribute_callback_ (c), + particle_reset_ (c), + attribute_reset_ (c), + start_element_ (c), + end_element_ (c), + attribute_ (c) + { + // Callback. + // + if (validation) + { + contains_compositor_callback_ >> compositor_callback_val_; + compositor_callback_val_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_val_; + } + else + { + contains_compositor_callback_ >> compositor_callback_non_val_; + compositor_callback_non_val_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_non_val_; + } + + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + + // Reset. + // + contains_compositor_reset_ >> compositor_reset_; + compositor_reset_ >> contains_particle_reset_; + contains_particle_reset_ >> compositor_reset_; + contains_particle_reset_ >> particle_reset_; + + names_attribute_reset_ >> attribute_reset_; + + // + // + contains_compositor_start_ >> start_compositor_; + start_compositor_ >> contains_particle_start_; + contains_particle_start_ >> start_compositor_; + contains_particle_start_ >> start_element_; + + // + // + contains_compositor_end_ >> end_compositor_; + end_compositor_ >> contains_particle_end_; + contains_particle_end_ >> end_compositor_; + contains_particle_end_ >> end_element_; + + // + // + names_attribute_ >> attribute_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + Boolean restriction (restriction_p (c)); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + + Boolean hra (false); // Has required attribute. + if (ha) + { + RequiredAttributeTest test (hra); + Traversal::Names names_test (test); + names (c, names_test); + } + + String const& name (ename (c)); + String const& ret (ret_type (c)); + Boolean same (hb && ret == ret_type (c.inherits ().base ())); + + String base_ret; + Boolean base_same (true); + + if (tiein && hb) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + base_ret = ret_type (base); + base_same = base.inherits_p () && + base_ret == ret_type (base.inherits ().base ()); + } + + if (he || ha || same || ret == L"void" || poly_code || + (tiein && !(base_same || base_ret == L"void"))) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + // Member callbacks. + // + if (!restriction) + { + if (ha) + names (c, names_attribute_callback_); + } + + if (!restriction || validation) + { + if (he || hae) + contains_compositor (c, contains_compositor_callback_); + } + + // post + // + if (same || ret == L"void") + { + String const& post (post_name (c)); + + os << ret << " " << name << "::" << endl + << post << " ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (c)); + + os << "if (this->" << impl << ")" << endl + << (ret != L"void" ? "return " : "") << "this->" << + impl << "->" << post << " ();"; + } + + if (same) + { + if (tiein) + os << "else" << endl; + + SemanticGraph::Type& base (c.inherits ().base ()); + + if (ret == L"void") + os << post_name (base) << " ();"; + else + os << "return " << post_name (base) << " ();"; + } + + os << "}"; + } + + // reset + // + if (!restriction && (he || ha) && reset) + { + os << "void " << name << "::" << endl + << "_reset ()" + << "{"; + + // Avoid recursion in case of recursive parsing. + // + if (he) + os << "if (this->resetting_)" << endl + << "return;" + << endl; + + // Reset the base. We cannot use the fully-qualified base name + // directly because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (hb) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << base << "::_reset ();" + << endl; + + // Reset validation state. + // + if (validation) + { + if (he || hae) + { + os << "this->v_state_stack_.clear ();" + << endl; + + SemanticGraph::Compositor& comp ( + c.contains_compositor ().compositor ()); + + if (comp.is_a () && + comp.context().count ("p:comp-number")) + { + os << "this->v_all_count_.clear ();" + << endl; + } + } + + if (hra) + os << "this->v_state_attr_stack_.clear ();" + << endl; + } + + // Reset member parsers. + // + + if (ha) + names (c, names_attribute_reset_); + + if (he) + { + os << "this->resetting_ = true;" + << endl; + + contains_compositor (c, contains_compositor_reset_); + + os << "this->resetting_ = false;" + << endl; + } + + os << "}"; + } + + // + // + if (poly_code) + { + String id (c.name ()); + + if (String ns = xml_ns_name (c)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + + if (hb && validation) + { + Boolean gen (!anonymous (c)); + + // We normally don't need to enter anonymous types into + // the inheritance map. The only exception is when an + // anonymous types is defined inside an element that + // is a member of a substitution group. + // + if (!gen) + { + // The first instance that this anonymous type classifies + // is the prototype for others if any. + // + SemanticGraph::Instance& i ( + c.classifies_begin ()->instance ()); + + if (SemanticGraph::Element* e = + dynamic_cast (&i)) + { + if (e->substitutes_p ()) + gen = true; + } + } + + if (gen) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + os << "static" << endl + << "const ::xsde::cxx::parser::validating::" << + "inheritance_map_entry" << endl + << "_xsde_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + + // Base post + // + if (tiein && !(base_same || base_ret == L"void")) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + String const& impl (etiein (base)); + String const& base_post (post_name (base)); + + os << base_ret << " " << name << "::" << endl + << base_post << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << base_post << " ();" + << "}"; + } + + // The rest is parsing/validation code which is generated in + // *-validation-source.cxx. + // + if (validation) + return; + + // Don't use the restriction_p result from here since we don't + // want special treatment of anyType. + // + restriction = hb && c.inherits ().is_a (); + + // _start_element_impl & _end_element_impl + // + if (he) + { + // _start_element_impl + // + + os << "bool " << name << "::" << endl + << "_start_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n"; + + if (poly_runtime) + os << "," << endl + << "const char*" << (poly_code ? " t" : ""); + + os << ")" + << "{"; + + if (poly_code) + os << "XSDE_UNUSED (t);" + << endl; + + if (!restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (hb) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << "if (" << base << "::"; + + if (poly_runtime) + os << "_start_element_impl (ns, n, " << + (poly_code ? "t" : "0") << "))" << endl; + else + os << "_start_element_impl (ns, n))" << endl; + + os << "return true;" + << endl; + } + + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + contains_compositor (c, contains_compositor_start_); + + os << "return false;" + << "}"; + + + // _end_element_impl + // + os << "bool " << name << "::" << endl + << "_end_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n)" + << "{"; + + + if (!restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (hb) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << "if (" << base << "::_end_element_impl (ns, n))" << endl + << "return true;" + << endl; + } + + if (!exceptions) + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + contains_compositor (c, contains_compositor_end_); + + os << "return false;" + << "}"; + } + + + if (ha) + { + // _attribute_impl + // + + os << "bool " << name << "::" << endl + << "_attribute_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "& v)" + << "{"; + + if (!restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (hb) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << "if (" << base << "::_attribute_impl (ns, n, v))" + << "{" + << "return true;" + << "}"; + } + + os << "::xsde::cxx::parser::context& ctx = this->_context ();" + << endl; + + names (c, names_attribute_); + + os << "return false;" + << "}"; + } + } + + private: + // + // + CompositorCallback compositor_callback_val_; + Traversal::Compositor compositor_callback_non_val_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + + // + // + Traversal::Compositor compositor_reset_; + ParticleReset particle_reset_; + Traversal::ContainsCompositor contains_compositor_reset_; + Traversal::ContainsParticle contains_particle_reset_; + + AttributeReset attribute_reset_; + Traversal::Names names_attribute_reset_; + + // + // + Traversal::Compositor start_compositor_; + StartElement start_element_; + Traversal::ContainsCompositor contains_compositor_start_; + Traversal::ContainsParticle contains_particle_start_; + + // + // + Traversal::Compositor end_compositor_; + EndElement end_element_; + Traversal::ContainsCompositor contains_compositor_end_; + Traversal::ContainsParticle contains_particle_end_; + + // + // + Attribute attribute_; + Traversal::Names names_attribute_; + }; + + // Generate substitution group map entries. + // + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (e.substitutes_p ()) + { + String name (escape (e.name ())); + Type& r (e.substitutes ().root ()); + + SemanticGraph::Type& type (e.type ()); + + String m_id (e.name ()); + String r_id (r.name ()); + + if (String const& ns = e.namespace_ ().name ()) + { + m_id += L' '; + m_id += ns; + } + + if (String const& ns = r.namespace_ ().name ()) + { + r_id += L' '; + r_id += ns; + } + + os << "// Substitution map entry for " << comment (e.name ()) << + "." << endl + << "//" << endl + << "static" << endl + << "const ::xsde::cxx::parser::substitution_map_entry" << endl + << "_xsde_" << name << "_substitution_map_entry_ (" << endl + << strlit (m_id) << "," << endl + << strlit (r_id) << "," << endl + << fq_name (type) << "::_static_type ());" + << endl; + } + } + }; + } + + Void + generate_parser_source (Context& ctx) + { + if (ctx.tiein) + ctx.os << "#include " << endl + << endl; + + if (ctx.poly_code) + { + ctx.os << "#include " << endl + << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl + << endl; + else + ctx.os << endl; + + ctx.os << "static" << endl + << "const ::xsde::cxx::parser::substitution_map_init" << endl + << "_xsde_substitution_map_init_;" + << endl; + + if (ctx.validation) + { + ctx.os << "static" << endl + << "const ::xsde::cxx::parser::validating::" << + "inheritance_map_init" << endl + << "_xsde_inheritance_map_init_;" + << endl; + } + } + + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + if (ctx.options.value ()) + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + GlobalElement global_element (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + if (ctx.poly_code) + names >> global_element; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/parser/parser-source.hxx b/xsde/cxx/parser/parser-source.hxx new file mode 100644 index 0000000..dcf07d6 --- /dev/null +++ b/xsde/cxx/parser/parser-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/parser/parser-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_PARSER_SOURCE_HXX +#define CXX_PARSER_PARSER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Parser + { + Void + generate_parser_source (Context&); + } +} + +#endif // CXX_PARSER_PARSER_SOURCE_HXX diff --git a/xsde/cxx/parser/print-impl-common.hxx b/xsde/cxx/parser/print-impl-common.hxx new file mode 100644 index 0000000..1815bb7 --- /dev/null +++ b/xsde/cxx/parser/print-impl-common.hxx @@ -0,0 +1,1063 @@ +// file : xsde/cxx/parser/print-impl-common.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_PRINT_IMPL_COMMON_HXX +#define CXX_PARSER_PRINT_IMPL_COMMON_HXX + +#include +#include + +#include + +namespace CXX +{ + namespace Parser + { + struct PrintCall: Traversal::Type, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Context + { + PrintCall (Context& c, String const& tag, String const& arg) + : Context (c), tag_ (tag), arg_ (arg) + { + } + + virtual Void + traverse (SemanticGraph::Type&) + { + gen_user_type (); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + if (default_type (t, "bool")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %u\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + if (default_type (t, "signed char")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + "static_cast (" << arg_ << ") << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + if (default_type (t, "unsigned char")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %u\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + "static_cast (" << arg_ << ") << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + if (default_type (t, "short")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + if (default_type (t, "unsigned short")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %u\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + if (default_type (t, "int")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + if (default_type (t, "unsigned int")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %u\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + if (options.value ()) + { + if (default_type (t, "long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %ld\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + else + { + if (default_type (t, "long long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %lld\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + if (options.value ()) + { + if (default_type (t, "unsigned long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %lu\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + else + { + if (default_type (t, "unsigned long long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %llu\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + if (default_type (t, "long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %ld\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + if (default_type (t, "long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %ld\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + if (default_type (t, "long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %ld\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + if (default_type (t, "unsigned long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %lu\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + if (default_type (t, "unsigned long")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %lu\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + if (default_type (t, "float")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %g\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + if (default_type (t, "double")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %g\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + if (default_type (t, "double")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %g\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + gen_string (t); + } + + // String sequences. + // + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + gen_sequence (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + gen_sequence (t); + } + + // QName + // + + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + if (options.value ()) + { + if (default_type (t, xs_ns_name () + L"::qname*")) + { + if (options.value ()) + os << "if (" << arg_ << "->prefix ()[0] == '\\0')" << endl + << "printf (" << strlit (tag_ + L": %s\n") << ", " << + arg_ << "->name ());" + << "else" << endl + << "printf (" << strlit (tag_ + L": %s:%s\n") << "," << endl + << arg_ << "->prefix ()," << endl + << arg_ << "->name ());"; + else + os << "if (" << arg_ << "->prefix ()[0] == '\\0')" << endl + << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << "->name () << std::endl;" + << "else" << endl + << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << "->prefix ()" << endl + << " << ':' << " << arg_ << "->name () << std::endl;"; + } + else + gen_user_type (); + } + else + { + if (default_type (t, xs_ns_name () + L"::qname")) + { + if (options.value ()) + os << "if (" << arg_ << ".prefix ().empty ())" << endl + << "printf (" << strlit (tag_ + L": %s\n") << ", " << + arg_ << ".name ().c_str ());" + << "else" << endl + << "printf (" << strlit (tag_ + L": %s:%s\n") << "," << endl + << arg_ << ".prefix ().c_str ()," << endl + << arg_ << ".name ().c_str ());"; + else + os << "if (" << arg_ << ".prefix ().empty ())" << endl + << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << ".name () << std::endl;" + << "else" << endl + << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << ".prefix ()" << endl + << " << ':' << " << arg_ << ".name () << std::endl;"; + } + else + gen_user_type (); + } + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + gen_buffer (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + gen_buffer (t); + } + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + if (default_type (t, xs_ns_name () + L"::date")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d-%u-%u") << "," << endl + << arg_ << ".year ()," << endl + << arg_ << ".month ()," << endl + << arg_ << ".day ());" << endl; + else + os << "std::cout << " << strlit (tag_ + L": ") << endl + << " << " << arg_ << ".year () << '-'" << endl + << " << " << arg_ << ".month () << '-'" << endl + << " << " << arg_ << ".day ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + if (default_type (t, xs_ns_name () + L"::date_time")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d-%u-%uT%u:%u:%g") << + "," << endl + << arg_ << ".year ()," << endl + << arg_ << ".month ()," << endl + << arg_ << ".day ()," << endl + << arg_ << ".hours ()," << endl + << arg_ << ".minutes ()," << endl + << arg_ << ".seconds ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << endl + << " << " << arg_ << ".year () << '-'" << endl + << " << " << arg_ << ".month () << '-'" << endl + << " << " << arg_ << ".day () << 'T'" << endl + << " << " << arg_ << ".hours () << ':'" << endl + << " << " << arg_ << ".minutes () << ':'" << endl + << " << " << arg_ << ".seconds ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + if (default_type (t, xs_ns_name () + L"::duration")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": ") << ");" + << endl + << "if (" << arg_ << ".negative ())" << endl + << "printf (\"-\");" + << endl + << "printf (\"P%uY%uM%uDT%uH%uM%gS\\n\"," << endl + << arg_ << ".years ()," << endl + << arg_ << ".months ()," << endl + << arg_ << ".days ()," << endl + << arg_ << ".hours ()," << endl + << arg_ << ".minutes ()," << endl + << arg_ << ".seconds ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << ";" + << endl + << "if (" << arg_ << ".negative ())" << endl + << "std::cout << '-';" + << endl + << "std::cout << 'P'" << endl + << " << " << arg_ << ".years () << 'Y'" << endl + << " << " << arg_ << ".months () << 'M'" << endl + << " << " << arg_ << ".days () << \"DT\"" << endl + << " << " << arg_ << ".hours () << 'H'" << endl + << " << " << arg_ << ".minutes () << 'M'" << endl + << " << " << arg_ << ".seconds () << 'S'" + << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + if (default_type (t, xs_ns_name () + L"::gday")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": ---%u") << ", " << + arg_ << ".day ());"; + else + os << "std::cout << " << strlit (tag_ + L": ---") << + " << " << arg_ << ".day ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + if (default_type (t, xs_ns_name () + L"::gmonth")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": --%u") << ", " << + arg_ << ".month ());"; + else + os << "std::cout << " << strlit (tag_ + L": --") << + " << " << arg_ << ".month ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + if (default_type (t, xs_ns_name () + L"::gmonth_day")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": --%u-%u") << "," << endl + << arg_ << ".month ()," << endl + << arg_ << ".day ());"; + else + os << "std::cout << " << strlit (tag_ + L": --") << endl + << " << " << arg_ << ".month () << '-'" << endl + << " << " << arg_ << ".day ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + if (default_type (t, xs_ns_name () + L"::gyear")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d") << ", " << + arg_ << ".year ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << + " << " << arg_ << ".year ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + if (default_type (t, xs_ns_name () + L"::gyear_month")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %d-%u") << "," << endl + << arg_ << ".year ()," << endl + << arg_ << ".month ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << endl + << " << " << arg_ << ".year () << '-'" << endl + << " << " << arg_ << ".month ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + if (default_type (t, xs_ns_name () + L"::time")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %u:%u:%g") << "," << endl + << arg_ << ".hours ()," << endl + << arg_ << ".minutes ()," << endl + << arg_ << ".seconds ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << endl + << " << " << arg_ << ".hours () << ':'" << endl + << " << " << arg_ << ".minutes () << ':'" << endl + << " << " << arg_ << ".seconds ();"; + + gen_time_zone (); + } + else + gen_user_type (); + } + + private: + bool + default_type (SemanticGraph::Type& t, String const& def_type) + { + return ret_type (t) == def_type; + } + + void + gen_user_type () + { + os << "// TODO" << endl + << "//" << endl; + } + + void + gen_string (SemanticGraph::Type& t) + { + if (options.value ()) + { + if (default_type (t, "char*")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %s\n") << ", " << + arg_ << ");"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + else + { + if (default_type (t, "::std::string")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %s\n") << ", " << + arg_ << ".c_str ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + } + + void + gen_sequence (SemanticGraph::Type& t) + { + String type (xs_ns_name () + L"::string_sequence"); + + if (default_type (t, type + L"*")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": ") << ");" + << endl; + else + os << "std::cout << " << strlit (tag_ + L": ") << ";" + << endl; + + os << "for (" << type << "::const_iterator i (" << arg_ << + "->begin ()), e (" << arg_ << "->end ());" << endl + << "i != e;)" + << "{"; + + if (options.value ()) + { + if (options.value ()) + os << "printf (\"%s\", *i++);"; + else + os << "printf (\"%s\", (i++)->c_str ());"; + + os << "if (i != e)" << endl + << "printf (\" \");" + << "}" + << "printf (\"\\n\");"; + } + else + os << "std::cout << *i++;" + << "if (i != e)" << endl + << "std::cout << ' ';" + << "}" + << "std::cout << std::endl;"; + } + else + gen_user_type (); + } + + void + gen_buffer (SemanticGraph::Type& t) + { + if (default_type (t, xs_ns_name () + L"::buffer*")) + { + if (options.value ()) + os << "printf (" << strlit (tag_ + L": %zu bytes\n") << ", " << + arg_ << "->size ());"; + else + os << "std::cout << " << strlit (tag_ + L": ") << " << " << + arg_ << "->size () << \" bytes\" << std::endl;"; + } + else + gen_user_type (); + } + + void + gen_time_zone () + { + os << endl + << "if (" << arg_ << ".zone_present ())" + << "{"; + + if (options.value ()) + os << "if (" << arg_ << ".zone_hours () < 0)" << endl + << "printf (\"%d:%d\", " << arg_ << ".zone_hours (), -" << + arg_ << ".zone_minutes ());" + << "else" << endl + << "printf (\"+%d:%d\", " << arg_ << ".zone_hours (), " << + arg_ << ".zone_minutes ());"; + else + os << "if (" << arg_ << ".zone_hours () < 0)" << endl + << "std::cout << " << arg_ << ".zone_hours () << ':' << -" << + arg_ << ".zone_minutes ();" + << "else" << endl + << "std::cout << '+' << " << arg_ << ".zone_hours () << " << + "':' << " << arg_ << ".zone_minutes ();"; + + os << "}"; + + if (options.value ()) + os << "printf (\"\\n\");"; + else + os << "std::cout << std::endl;"; + } + + private: + String tag_; + String arg_; + }; + + struct DeleteCall: Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Context + { + DeleteCall (Context& c, String const& arg) + : Context (c), arg_ (arg) + { + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + gen_string (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + gen_string (t); + } + + // String sequences. + // + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + gen_sequence (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + gen_sequence (t); + } + + // QName + // + + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + if (options.value () && + default_type (t, xs_ns_name () + L"::qname*")) + { + os << endl + << "delete " << arg_ << ";"; + } + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + gen_buffer (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + gen_buffer (t); + } + + private: + bool + default_type (SemanticGraph::Type& t, String const& def_type) + { + return ret_type (t) == def_type; + } + + void + gen_string (SemanticGraph::Type& t) + { + if (options.value () && default_type (t, "char*")) + { + os << endl + << "delete[] " << arg_ << ";"; + } + } + + void + gen_sequence (SemanticGraph::Type& t) + { + if (default_type (t, xs_ns_name () + L"::string_sequence*")) + { + os << endl + << "delete " << arg_ << ";"; + } + } + + void + gen_buffer (SemanticGraph::Type& t) + { + if (default_type (t, xs_ns_name () + L"::buffer*")) + { + os << endl + << "delete " << arg_ << ";"; + } + } + + private: + String arg_; + }; + } +} + +#endif // CXX_PARSER_PRINT_IMPL_COMMON_HXX diff --git a/xsde/cxx/parser/state-processor.cxx b/xsde/cxx/parser/state-processor.cxx new file mode 100644 index 0000000..3ecc77a --- /dev/null +++ b/xsde/cxx/parser/state-processor.cxx @@ -0,0 +1,319 @@ +// file : xsde/cxx/parser/state-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include + +#include +#include + +#include + +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + typedef Cult::Containers::Vector Particles; + + void + print (Particles const& p) + { + using std::wcerr; + using std::endl; + + wcerr << "prefixes: " << endl; + + for (Particles::ConstIterator i (p.begin ()); i != p.end (); ++i) + { + if (SemanticGraph::Element* e = + dynamic_cast (*i)) + { + wcerr << e->name () << endl; + } + else + { + wcerr << "" << endl; + } + } + + wcerr << endl; + } + + // + // + struct Particle: Traversal::All, + Traversal::Choice, + Traversal::Sequence + { + Particle (UnsignedLong& all, + UnsignedLong& choice, + UnsignedLong& sequence, + UnsignedLong& depth) + : all_ (all), + choice_ (choice), + sequence_ (sequence), + depth_ (depth) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + using SemanticGraph::Compositor; + + // Go over particles, collecting "prefix" particles in prefixes_, + // assigning state numbers and calculating effective minOccurs. + // If all prefixes of this compositor have minOccurs = 0, then + // the compositor itself effectively has minOccurs = 0 regardless + // of the actual value specified in the schema. + // + // Note that we don't need to care about depth since the 'all' + // compositor cannot contain any nested compositors. + // + + UnsignedLong state (0); + UnsignedLong min (0); + + for (Compositor::ContainsIterator ci (a.contains_begin ()); + ci != a.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + // The 'all' compositor can only include elements. + // + prefixes_.push_back (&p); + + if (min == 0 && ci->min () != 0) + min = 1; + + p.context ().set ("p:prefix", true); + p.context ().set ("p:state", state++); + } + + if (!prefixes_.empty ()) + { + a.context ().set ("p:comp-number", choice_++); + a.context ().set ("p:prefixes", prefixes_); + a.context ().set ("p:state-count", + UnsignedLong (prefixes_.size ())); + + // effective-min = min * actual-min + // + if (min == 1) + min = a.min (); + + a.context ().set ("p:effective-min", min); + + // print (prefixes_); + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Compositor; + + // Go over particles, collecting "prefix" particles in prefixes_, + // assigning state numbers and calculating effective minOccurs. + // If any prefix of this compositor have minOccurs = 0, then the + // compositor itself effectively has minOccurs = 0 regardless of + // the actual value specified in the schema. + // + + UnsignedLong state (0); + UnsignedLong min (1); + + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () || + p.is_a ()) + { + prefixes_.push_back (&p); + + if (min == 1 && ci->min () == 0) + min = 0; + } + else + { + UnsignedLong depth (0); + Particle t (all_, choice_, sequence_, depth); + t.dispatch (p); + + if (t.prefixes_.empty ()) + continue; // Skip empty compositors. + + if (++depth > depth_) // One for this compositor. + depth_ = depth; + + prefixes_.insert (prefixes_.end (), + t.prefixes_.begin ().base (), + t.prefixes_.end ().base ()); + + if (min == 1 && + p.context ().get ("p:effective-min") == 0) + min = 0; + } + + p.context ().set ("p:prefix", true); + p.context ().set ("p:state", state++); + } + + if (!prefixes_.empty ()) + { + c.context ().set ("p:comp-number", choice_++); + c.context ().set ("p:prefixes", prefixes_); + + // effective-min = min * actual-min + // + if (min == 1) + min = c.min (); + + c.context ().set ("p:effective-min", min); + + // print (prefixes_); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + using SemanticGraph::Compositor; + + // Go over particles, collecting "prefix" particles in prefixes_, + // assigning state numbers and calculating effective minOccurs. + // If all prefixes of this compositor have minOccurs = 0, then + // the compositor itself effectively has minOccurs = 0 regardless + // of the actual value specified in the schema. + // + + Boolean prefix (true); + UnsignedLong state (0); + UnsignedLong min (0); + + for (Compositor::ContainsIterator ci (s.contains_begin ()); + ci != s.contains_end (); ++ci) + { + SemanticGraph::Particle& p (ci->particle ()); + + if (p.is_a () || + p.is_a ()) + { + if (prefix) + { + prefixes_.push_back (&p); + + if (ci->min () != 0) + min = 1; + } + } + else + { + UnsignedLong depth (0); + Particle t (all_, choice_, sequence_, depth); + t.dispatch (p); + + if (t.prefixes_.empty ()) + continue; // Skip empty compositors. + + if (++depth > depth_) // One for this compositor. + depth_ = depth; + + if (prefix) + { + prefixes_.insert (prefixes_.end (), + t.prefixes_.begin ().base (), + t.prefixes_.end ().base ()); + + if (p.context ().get ("p:effective-min") != 0) + min = 1; + } + } + + p.context ().set ("p:state", state++); + + if (prefix) + p.context ().set ("p:prefix", true); + + if (prefix && min != 0) + prefix = false; + } + + if (!prefixes_.empty ()) + { + s.context ().set ("p:comp-number", sequence_++); + s.context ().set ("p:prefixes", prefixes_); + + // effective-min = min * actual-min + // + if (min == 1) + min = s.min (); + + s.context ().set ("p:effective-min", min); + + // print (prefixes_); + } + } + + private: + Particles prefixes_; + + UnsignedLong& all_; + UnsignedLong& choice_; + UnsignedLong& sequence_; + + UnsignedLong& depth_; + }; + + + // + // + struct Complex: Traversal::Complex + { + virtual Void + traverse (Type& c) + { + if (c.contains_compositor_p ()) + { + UnsignedLong all (0), choice (0), sequence (0), depth (0); + Particle t (all, choice, sequence, depth); + t.dispatch (c.contains_compositor ().compositor ()); + + // Set the maximum stack depth for this type. Used to + // allocate fixed-size state stack. + // + c.context ().set ("p:depth", depth + 1); + } + } + }; + } + + Void StateProcessor:: + process (SemanticGraph::Schema& tu, SemanticGraph::Path const&) + { + Traversal::Schema schema; + Traversal::Sources sources; + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> ns_names; + + Complex complex_type; + + ns_names >> complex_type; + + schema.dispatch (tu); + } + } +} diff --git a/xsde/cxx/parser/state-processor.hxx b/xsde/cxx/parser/state-processor.hxx new file mode 100644 index 0000000..c276d54 --- /dev/null +++ b/xsde/cxx/parser/state-processor.hxx @@ -0,0 +1,28 @@ +// file : xsde/cxx/parser/state-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_STATE_PROCESSOR_HXX +#define CXX_PARSER_STATE_PROCESSOR_HXX + +#include +#include + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class StateProcessor + { + public: + Void + process (XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_PARSER_STATE_PROCESSOR_HXX diff --git a/xsde/cxx/parser/type-processor.cxx b/xsde/cxx/parser/type-processor.cxx new file mode 100644 index 0000000..4e7f65a --- /dev/null +++ b/xsde/cxx/parser/type-processor.cxx @@ -0,0 +1,352 @@ +// file : xsde/cxx/parser/type-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Parser + { + namespace + { + // + // + struct Type: Traversal::Type + { + Type (SemanticGraph::Schema& schema, + TypeMap::Namespaces& type_map, + Boolean add_includes) + : schema_ (schema), + type_map_ (type_map), + add_includes_ (add_includes) + { + } + + virtual Void + traverse (SemanticGraph::Type& type) + { + using TypeMap::Namespace; + using TypeMap::Namespaces; + + SemanticGraph::Context& tc (type.context ()); + + // There are two situations where we may try to process the + // same type more than once. The first is when the type is + // used in several element declarations in the same schema. + // The second situation only occurs when we are in the file- + // per-type mode. In this case the type was processed as part + // of another root schema. In the second case, while the ret + // and arg types are assumed to be the same, we need to re- + // match the type in order to add include directives to the + // new root schema. + // + Boolean set (true); + + if (tc.count ("p:ret-type")) + { + SemanticGraph::Schema* s ( + tc.get ("p:root-schema")); + + if (&schema_ == s) + return; + + set = false; + } + + SemanticGraph::Namespace& ns ( + dynamic_cast (type.scope ())); + + String const& ns_name (ns.name ()); + String const& t_name (type.name ()); + + // std::wcerr << "traversing: " << ns_name << "#" << t_name << endl; + + for (Namespaces::ConstIterator n (type_map_.begin ()); + n != type_map_.end (); ++n) + { + // Check if the namespace matches. + // + Boolean ns_match; + + if (!n->xsd_name ().empty ()) + { + ns_match = n->xsd_name ().match (ns_name); + } + else + ns_match = ns_name.empty (); + + // std::wcerr << "considering ns expr: " << n->xsd_name () << endl; + + if (ns_match) + { + // Namespace matched. See if there is a type that matches. + // + for (Namespace::TypesIterator t (n->types_begin ()); + t != n->types_end (); ++t) + { + if (t->xsd_name ().match (t_name)) + { + if (set) + { + // Got a match. See if the namespace has the C++ + // namespace mapping. + // + String cxx_ns; + + if (n->has_cxx_name ()) + { + if (!n->xsd_name ().empty ()) + { + cxx_ns = n->xsd_name ().merge ( + n->cxx_name (), ns_name, true); + } + else + cxx_ns = n->cxx_name (); + + cxx_ns += L"::"; + } + + // Figure out ret and arg type names. + // + String ret_type (cxx_ns); + + ret_type += t->xsd_name ().merge ( + t->cxx_ret_name (), t_name, true); + + String arg_type; + + if (t->cxx_arg_name ()) + { + arg_type = cxx_ns; + arg_type += t->xsd_name ().merge ( + t->cxx_arg_name (), t_name, true); + } + else + { + if (ret_type == L"void") + arg_type = ret_type; + else + { + WideChar last (ret_type[ret_type.size () - 1]); + + // If it is already a pointer or reference then use + // it as is. + // + if (last == L'*' || last == L'&') + arg_type = ret_type; + else + arg_type = L"const " + ret_type + L"&"; + } + } + + tc.set ("p:ret-type", ret_type); + tc.set ("p:arg-type", arg_type); + } + + tc.set ("p:root-schema", &schema_); + + //std::wcerr << t_name << " -> " << ret_type << endl; + + // See of we need to add any includes to the translations + // unit. + // + if (add_includes_) + { + if (n->includes_begin () != n->includes_end ()) + { + typedef Cult::Containers::Set Includes; + + SemanticGraph::Context& sc (schema_.context ()); + + if (!sc.count ("p:includes")) + sc.set ("p:includes", Includes ()); + + Includes& is (sc.get ("p:includes")); + + for (Namespace::IncludesIterator i (n->includes_begin ()); + i != n->includes_end (); ++i) + { + is.insert (*i); + } + } + } + + return; + } + } + } + } + } + + private: + SemanticGraph::Schema& schema_; + TypeMap::Namespaces& type_map_; + Boolean add_includes_; + }; + + // + // + struct BaseType: Traversal::Complex + { + virtual Void + traverse (SemanticGraph::Complex& c) + { + Complex::inherits (c); + } + }; + + // + // + struct GlobalType: Traversal::Type, + Traversal::List, + Traversal::Complex, + Traversal::Enumeration + { + GlobalType (SemanticGraph::Schema& schema, + TypeMap::Namespaces& type_map, + Boolean add_includes, + Boolean tiein) + : type_ (schema, type_map, add_includes) + { + inherits_ >> type_; + names_ >> instance_ >> belongs_ >> type_; + argumented_ >> type_; + + if (tiein) + { + // In case of a tiein support, we also need to process base's + // base type. + // + inherits_base_ >> base_type_ >> inherits_level_2_ >> type_; + } + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + type_.traverse (t); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + type_.traverse (l); + Traversal::List::argumented (l, argumented_); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + type_.traverse (c); + Complex::inherits (c, inherits_); + Complex::inherits (c, inherits_base_); + Complex::names (c, names_); + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + type_.traverse (e); + Complex::inherits (e, inherits_); + } + + private: + Parser::Type type_; + BaseType base_type_; + Traversal::Names names_; + Traversal::Instance instance_; + Traversal::Inherits inherits_; + Traversal::Inherits inherits_base_; + Traversal::Inherits inherits_level_2_; + Traversal::Belongs belongs_; + Traversal::Argumented argumented_; + }; + + Void + process_impl (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& tu, + TypeMap::Namespaces& type_map) + { + Boolean tiein (!options.value () && + !options.value ()); + + if (tu.names_begin ()->named ().name () == + L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalType global_type (tu, type_map, true, tiein); + + schema >> schema_names >> ns >> ns_names >> global_type; + + schema.dispatch (tu); + } + else + { + // If --extern-xml-schema is specified, then we don't want + // includes from the XML Schema type map. + // + Boolean extern_xml_schema ( + options.value ()); + + // Besides types defined in this schema, also process those + // referenced by global elements in case we are generating + // something for them. + // + Traversal::Schema schema; + Traversal::Schema xs_schema; + Traversal::Sources sources; + Traversal::Implies implies; + + schema >> sources >> schema; + schema >> implies >> xs_schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + Traversal::Element global_element; + GlobalType global_type (tu, type_map, true, tiein); + + schema >> schema_names >> ns >> ns_names; + + ns_names >> global_element; + ns_names >> global_type; + + Traversal::Belongs element_belongs; + global_element >> element_belongs >> global_type; + + Traversal::Names xs_schema_names; + Traversal::Namespace xs_ns; + Traversal::Names xs_ns_names; + GlobalType xs_global_type (tu, type_map, !extern_xml_schema, tiein); + + xs_schema >> xs_schema_names >> xs_ns >> xs_ns_names >> + xs_global_type; + + schema.dispatch (tu); + } + } + } + + Void TypeProcessor:: + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& s, + TypeMap::Namespaces& tm) + { + process_impl (options, s, tm); + } + } +} diff --git a/xsde/cxx/parser/type-processor.hxx b/xsde/cxx/parser/type-processor.hxx new file mode 100644 index 0000000..5855569 --- /dev/null +++ b/xsde/cxx/parser/type-processor.hxx @@ -0,0 +1,34 @@ +// file : xsde/cxx/parser/type-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_TYPE_PROCESSOR_HXX +#define CXX_PARSER_TYPE_PROCESSOR_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class TypeProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + TypeMap::Namespaces&); + }; + } +} + +#endif // CXX_PARSER_TYPE_PROCESSOR_HXX diff --git a/xsde/cxx/parser/validator.cxx b/xsde/cxx/parser/validator.cxx new file mode 100644 index 0000000..570a0bf --- /dev/null +++ b/xsde/cxx/parser/validator.cxx @@ -0,0 +1,704 @@ +// file : xsde/cxx/parser/validator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +#include + +using std::wcerr; + +namespace CXX +{ + namespace Parser + { + namespace + { + class ValidationContext: public Context + { + public: + ValidationContext (SemanticGraph::Schema& root, + CLI::Options const& options, + const WarningSet& disabled_warnings, + Boolean& valid_) + : Context (std::wcerr, root, options, 0, 0, 0), + disabled_warnings_ (disabled_warnings), + disabled_warnings_all_ (false), + valid (valid_), + subst_group_warning_issued (subst_group_warning_issued_), + subst_group_warning_issued_ (false) + { + } + + public: + Boolean + is_disabled (Char const* w) + { + return disabled_warnings_all_ || + disabled_warnings_.find (w) != disabled_warnings_.end (); + } + + public: + String + xpath (SemanticGraph::Nameable& n) + { + if (n.is_a ()) + return L""; // There is a bug if you see this. + + assert (n.named ()); + + SemanticGraph::Scope& scope (n.scope ()); + + if (scope.is_a ()) + return n.name (); + + return xpath (scope) + L"/" + n.name (); + } + + protected: + ValidationContext (ValidationContext& c) + : Context (c), + disabled_warnings_ (c.disabled_warnings_), + disabled_warnings_all_ (c.disabled_warnings_all_), + valid (c.valid), + subst_group_warning_issued (c.subst_group_warning_issued) + { + } + + protected: + const WarningSet& disabled_warnings_; + Boolean disabled_warnings_all_; + Boolean& valid; + Boolean& subst_group_warning_issued; + Boolean subst_group_warning_issued_; + }; + + // + // + struct Any : Traversal::Any, ValidationContext + { + Any (ValidationContext& c) + : ValidationContext (c) + { + } + + struct Element: Traversal::Element, ValidationContext + { + Element (ValidationContext& c, SemanticGraph::Any& any) + : ValidationContext (c), + any_ (any), + ns_ (any.definition_namespace ().name ()) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Any; + + Boolean q (e.qualified ()); + String ns (q ? e.namespace_ ().name () : ""); + + for (Any::NamespaceIterator i (any_.namespace_begin ()); + i != any_.namespace_end (); ++i) + { + Boolean failed (false); + + if (*i == L"##any") + { + failed = true; + } + else if (*i == L"##other") + { + if (ns_) + { + // Note that here I assume that ##other does not + // include names without target namespace. This + // is not what the spec says but that seems to be + // the consensus. + // + failed = q && ns != ns_; + } + else + { + // No target namespace. + // + failed = q && ns != L""; + } + } + else if (*i == L"##local") + { + failed = !q || ns == L""; + } + else if (*i == L"##targetNamespace") + { + failed = (q && ns_ == ns) || (!q && ns_ == L""); + } + else + { + failed = q && *i == ns; + } + + if (failed) + { + Any& a (any_); + + os << a.file () << ":" << a.line () << ":" << a.column () + << ": warning P001: namespace '" << *i << "' allows for " + << "element '" << e.name () << "'" << endl; + + os << a.file () << ":" << a.line () << ":" << a.column () + << ": warning P001: generated code may not associate " + << "element '" << e.name () << "' correctly if it appears " + << "in place of this wildcard" << endl; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": info: element '" << e.name () << "' is defined " + << "here" << endl; + + os << a.file () << ":" << a.line () << ":" << a.column () + << ": info: turn on validation to ensure correct " + << "association" << endl; + } + } + } + + private: + SemanticGraph::Any& any_; + String ns_; + }; + + struct Complex: Traversal::Complex + { + Complex () + : up_ (true), down_ (true) + { + } + + virtual Void + post (Type& c) + { + // Go down the inheritance hierarchy. + // + if (down_) + { + Boolean up = up_; + up_ = false; + + if (c.inherits_p ()) + dispatch (c.inherits ().base ()); + + up_ = up; + } + + // Go up the inheritance hierarchy. + // + if (up_) + { + Boolean down = down_; + down_ = false; + + for (Type::BegetsIterator i (c.begets_begin ()); + i != c.begets_end (); ++i) + { + dispatch (i->derived ()); + } + + down_ = down; + } + } + + private: + Boolean up_, down_; + }; + + virtual Void + traverse (SemanticGraph::Any& a) + { + using SemanticGraph::Compositor; + + // Find our complex type. + // + Compositor* c (&a.contained_particle ().compositor ()); + + while(!c->contained_compositor_p ()) + c = &c->contained_particle ().compositor (); + + SemanticGraph::Complex& type ( + dynamic_cast ( + c->contained_compositor ().container ())); + + Complex complex; + Traversal::Compositor compositor; + Element element (*this, a); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + complex >> contains_compositor; + contains_compositor >> compositor; + compositor >> contains_particle; + contains_particle >> compositor; + contains_particle >> element; + + complex.dispatch (type); + } + }; + + + // + // + struct Traverser : Traversal::Schema, + Traversal::Complex, + Traversal::Type, + Traversal::Element, + ValidationContext + { + Traverser (ValidationContext& c) + : ValidationContext (c), + any_ (c) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + + // Any + // + if (!validation && !is_disabled ("P001")) + { + *this >> contains_compositor_ >> compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> any_; + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + using SemanticGraph::Schema; + + traverse (static_cast (c)); + + if (c.inherits_p ()) + { + SemanticGraph::Type& t (c.inherits ().base ()); + + if (t.named () && + types_.find ( + t.scope ().name () + L"#" + t.name ()) == types_.end ()) + { + // Don't worry about types that are in included/imported + // schemas. + // + Schema& s (dynamic_cast (t.scope ().scope ())); + + if (&s == &schema_root || sources_p (schema_root, s)) + { + valid = false; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: type '" << xpath (c) << "' inherits from " + << "yet undefined type '" << xpath (t) << "'" << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: '" << xpath (t) << "' is defined here" + << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: inheritance from a yet-undefined type is " + << "not supported" << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: re-arrange your schema and try again" + << endl; + } + } + } + + Complex::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (t.named ()) + { + types_.insert (t.scope ().name () + L"#" + t.name ()); + } + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (is_disabled ("P002")) + return; + + if (e.substitutes_p () && + !options.value () && + !subst_group_warning_issued) + { + subst_group_warning_issued = true; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": warning P002: substitution groups are used but " + << "--generate-polymorphic was not specified" << endl; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": info: generated code may not be able to parse " + << "some conforming instances" << endl; + } + } + + // Return true if root sources s. + // + Boolean + sources_p (SemanticGraph::Schema& root, SemanticGraph::Schema& s) + { + using SemanticGraph::Schema; + using SemanticGraph::Sources; + + for (Schema::UsesIterator i (root.uses_begin ()); + i != root.uses_end (); ++i) + { + if (i->is_a ()) + { + if (&i->schema () == &s || sources_p (i->schema (), s)) + return true; + } + } + + return false; + } + + private: + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + + Traversal::Names names_; + + // Any. + // + Any any_; + Traversal::Compositor compositor_; + Traversal::ContainsParticle contains_particle_; + Traversal::ContainsCompositor contains_compositor_; + }; + + // + // + struct AnonymousMember: protected ValidationContext + { + AnonymousMember (ValidationContext& c, Boolean& error_issued) + : ValidationContext (c), error_issued_ (error_issued) + { + } + + Boolean + traverse_common (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + if (!t.named () + && !t.is_a () + && !t.is_a ()) + { + if (!error_issued_) + { + valid = false; + error_issued_ = true; + + wcerr << t.file () + << ": error: anonymous types detected" + << endl; + + wcerr << t.file () + << ": info: " + << "anonymous types are not supported in this mapping" + << endl; + + wcerr << t.file () + << ": info: consider explicitly naming these types or " + << "remove the --preserve-anonymous option to " + << "automatically name them" + << endl; + + if (!options.value ()) + wcerr << t.file () + << ": info: use --show-anonymous option to see these " + << "types" << endl; + } + + return true; + } + + return false; + } + + private: + Boolean& error_issued_; + }; + + struct AnonymousElement: Traversal::Element, + AnonymousMember + { + AnonymousElement (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (traverse_common (e)) + { + if (options.value ()) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: element '" << xpath (e) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Element::traverse (e); + } + }; + + struct AnonymousAttribute: Traversal::Attribute, + AnonymousMember + { + AnonymousAttribute (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (Type& a) + { + if (traverse_common (a)) + { + if (options.value ()) + { + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: attribute '" << xpath (a) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Attribute::traverse (a); + } + }; + + struct AnonymousType : Traversal::Schema, + Traversal::Complex, + ValidationContext + { + AnonymousType (ValidationContext& c) + : ValidationContext (c), + error_issued_ (false), + element_ (c, error_issued_), + attribute_ (c, error_issued_) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + + *this >> contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> element_; + + *this >> names_attribute_ >> attribute_; + } + + private: + Boolean error_issued_; + + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + Traversal::Names names_; + + Traversal::Compositor compositor_; + AnonymousElement element_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + AnonymousAttribute attribute_; + Traversal::Names names_attribute_; + }; + + struct GlobalElement: Traversal::Element, ValidationContext + { + GlobalElement (ValidationContext& c, SemanticGraph::Element*& element) + : ValidationContext (c), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (!valid) + return; + + if (options.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (options.value ()) + { + element_ = &e; + } + else if (String name = options.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + { + if (element_ == 0) + element_ = &e; + else + { + wcerr << schema_root.file () << ": error: unable to generate " + << "the test driver without a unique document root" + << endl; + + wcerr << schema_root.file () << ": info: use --root-element-* " + << "options to specify the document root" << endl; + + valid = false; + } + } + } + + private: + SemanticGraph::Element*& element_; + }; + } + + Boolean Validator:: + validate (CLI::Options const& options, + SemanticGraph::Schema& root, + SemanticGraph::Path const&, + Boolean gen_driver, + const WarningSet& disabled_warnings) + { + Boolean valid (true); + ValidationContext ctx (root, options, disabled_warnings, valid); + + // + // + if (options.value () && + options.value ()) + { + wcerr << "error: mutually exclusive options specified: " + << "--generate-noop-impl and --generate-print-impl" + << endl; + + return false; + } + + // + // + { + Boolean ref (options.value ()); + Boolean rel (options.value ()); + Boolean re (options.value ()); + + if ((ref && rel) || (ref && re) || (rel && re)) + { + wcerr << "error: mutually exclusive options specified: " + << "--root-element-last, --root-element-first, and " + << "--root-element" + << endl; + + return false; + } + } + + // + // + if (options.value () && + options.value ()) + { + wcerr << "error: mutually exclusive options specified: " + << "--reuse-style-mixin and --reuse-style-none" + << endl; + + return false; + } + + // + // + if (options.value () && + (options.value () || + options.value ()) && + !ctx.is_disabled ("P003")) + { + wcerr << "warning P003: generating sample implementation without " + << "parser reuse support: the resulting code may not compile" + << endl; + + return false; + } + + // Test for anonymout types. + // + { + AnonymousType traverser (ctx); + traverser.dispatch (root); + } + + // Test the rest. + // + if (valid) + { + Traverser traverser (ctx); + traverser.dispatch (root); + } + + // Test that the document root is unique. + // + if (valid && gen_driver) + { + SemanticGraph::Element* element (0); + + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalElement global_element (ctx, element); + + schema >> schema_names >> ns >> ns_names >> global_element; + + schema.dispatch (root); + + if (valid && element == 0) + { + wcerr << root.file () << ": error: unable to generate the " + << "test driver without a global element (document root)" + << endl; + + valid = false; + } + } + + return valid; + } + } +} diff --git a/xsde/cxx/parser/validator.hxx b/xsde/cxx/parser/validator.hxx new file mode 100644 index 0000000..d602aae --- /dev/null +++ b/xsde/cxx/parser/validator.hxx @@ -0,0 +1,36 @@ +// file : xsde/cxx/parser/validator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_PARSER_VALIDATOR_HXX +#define CXX_PARSER_VALIDATOR_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class Validator + { + public: + Boolean + validate (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& tu, + Boolean gen_driver, + const WarningSet& disabled_warnings); + }; + } +} + +#endif // CXX_PARSER_VALIDATOR_HXX diff --git a/xsde/cxx/serializer/attribute-validation-source.cxx b/xsde/cxx/serializer/attribute-validation-source.cxx new file mode 100644 index 0000000..59d3cb5 --- /dev/null +++ b/xsde/cxx/serializer/attribute-validation-source.cxx @@ -0,0 +1,463 @@ +// file : xsde/cxx/serializer/attribute-validation-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct AnyAttributeTest: Traversal::AnyAttribute, Context + { + AnyAttributeTest (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + String const& ns (a.definition_namespace ().name ()); + + for (SemanticGraph::AnyAttribute::NamespaceIterator + i (a.namespace_begin ()), e (a.namespace_end ()); i != e;) + { + if (*i == L"##any") + { + if (stl) + os << "!name.empty ()"; + else + os << "(name != 0 && *name != '\\0')"; + } + else if (*i == L"##other") + { + if (ns) + { + // Note that here I assume that ##other does not include + // unqualified names in a schema with target namespace. + // This is not what the spec says but that seems to be + // the consensus. + // + if (stl) + os << "(!ns.empty () && ns != " << strlit (ns) << ")"; + else + os << "(ns != 0 && *ns != '\\0' && " << + "strcmp (ns, " << strlit (ns) << ") != 0)"; + } + else + { + if (stl) + os << "!ns.empty ()"; + else + os << "(ns != 0 && *ns != '\\0')"; + } + } + else if (*i == L"##local") + { + if (stl) + os << "(ns.empty () && !name.empty ())"; + else + os << "((ns == 0 || *ns == '\\0') && " << + "name != 0 && *name != '\\0')"; + } + else if (*i == L"##targetNamespace") + { + if (stl) + os << "ns == " << strlit (ns); + else + os << "(ns != 0 && strcmp (ns, " << strlit (ns) << ") == 0)"; + } + else + { + if (stl) + os << "ns == " << strlit (*i); + else + os << "(ns != 0 && strcmp (ns, " << strlit (*i) << ") == 0)"; + } + + if (++i != e) + os << " ||" << endl; + } + } + }; + + struct Attribute: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + Attribute (Context& c) + : Context (c), any_attribute_test_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& name (ename (a)); + + os << "// " << name << endl + << "//" << endl; + + if (a.optional ()) + { + os << "if (this->" << epresent (a) << " ())"; + } + + os << "{"; + + String const& inst (emember (a)); + String const& ret (ret_type (a.type ())); + String const& arg (arg_type (a.type ())); + + if (ret == L"void") + os << "this->" << name << " ();" + << endl; + else + os << arg << " r = this->" << name << " ();" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if (this->" << inst << ")" + << "{"; + + if (ret == L"void") + os << "this->" << inst << "->pre ();"; + else + os << "this->" << inst << "->pre (r);"; + + if (!exceptions) + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + { + if (a.qualified () && a.namespace_ ().name ()) + os << "this->_start_attribute (" << + strlit (a.namespace_ ().name ()) << ", " << + strlit (a.name ()) << ");"; + else + os << "this->_start_attribute (" << strlit (a.name ()) << ");"; + } + else + { + os << "if (!"; + + if (a.qualified () && a.namespace_ ().name ()) + os << "this->_start_attribute (" << + strlit (a.namespace_ ().name ()) << ", " << + strlit (a.name ()) << ")"; + else + os << "this->_start_attribute (" << strlit (a.name ()) << ")"; + + os << ")" << endl + << "return;" + << endl; + } + + os << "this->" << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_attribute ();"; + else + os << "if (!this->_end_attribute ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->post ();"; + + if (!exceptions) + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;"; + + os << "}"; // if (inst) + + if (!a.optional ()) + { + os << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_attribute);" + << "return;" + << "}"; + } + + os << "}"; + + if (a.optional () && !exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + os << "while (this->" << enext (a) << " ())" + << "{"; + + if (stl) + { + os << "::std::string ns, name;" + << "this->" << ename (a) << " (ns, name);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if ("; + + any_attribute_test_.dispatch (a); + + os << ")" + << "{"; + + os << "if (ns.empty ())" + << "{"; + + if (exceptions) + os << "this->_start_attribute (name.c_str ());"; + else + os << "if (!this->_start_attribute (name.c_str ()))" << endl + << "return;"; + + os << "}" + << "else" + << "{"; + + if (exceptions) + os << "this->_start_attribute (ns.c_str (), name.c_str ());"; + else + os << "if (!this->_start_attribute (ns.c_str (), " << + "name.c_str ()))" << endl + << "return;"; + + os << "}" + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_attribute ();"; + else + os << "if (!this->_end_attribute ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_attribute);" + << "return;" + << "}"; + } + else + { + os << "const char* ns = 0;" + << "const char* name;" + << "bool free;" + << "this->" << ename (a) << " (ns, name, free);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + else + os << "::xsde::cxx::string auto_ns, auto_name;" + << "if (free)" + << "{" + << "auto_ns.attach (const_cast< char* > (ns));" + << "auto_name.attach (const_cast< char* > (name));" + << "}"; + + os << "if ("; + + any_attribute_test_.dispatch (a); + + os << ")" + << "{"; + + if (exceptions) + os << "if (ns == 0 || *ns == '\\0')" << endl + << "this->_start_attribute (name);" + << "else" << endl + << "this->_start_attribute (ns, name);" + << endl; + else + os << "bool r;" + << "if (ns == 0 || *ns == '\\0')" << endl + << "r = this->_start_attribute (name);" + << "else" << endl + << "r = this->_start_attribute (ns, name);" + << endl + << "if (free)" + << "{" + << "delete[] ns;" + << "delete[] name;" + << "}" + << "if (!r)" << endl + << "return;" + << endl; + + os << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_attribute ();"; + else + os << "if (!this->_end_attribute ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_attribute);" + << "return;" + << "}"; + } + + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + private: + AnyAttributeTest any_attribute_test_; + }; + + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + attribute_ (c) + { + names_attribute_ >> attribute_; + } + + virtual Void + traverse (Type& c) + { + if (!has (c) && + !has (c)) + return; + + // Don't use restriction_p here since we don't want special + // treatment of anyType. + // + Boolean restriction ( + c.inherits_p () && + c.inherits ().is_a ()); + + String const& name (ename (c)); + + os <<"// Attribute validation and serialization for " << + name << "." << endl + <<"//" << endl; + + os << "void " << name << "::" << endl + << "_serialize_attributes ()" + << "{" + << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (c.inherits_p () && !restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_serialize_attributes ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + names (c, names_attribute_); + + os << "}"; + } + + private: + Attribute attribute_; + Traversal::Names names_attribute_; + }; + } + + Void + generate_attribute_validation_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/attribute-validation-source.hxx b/xsde/cxx/serializer/attribute-validation-source.hxx new file mode 100644 index 0000000..d06890d --- /dev/null +++ b/xsde/cxx/serializer/attribute-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/attribute-validation-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_ATTRIBUTE_VALIDATION_SOURCE_HXX +#define CXX_SERIALIZER_ATTRIBUTE_VALIDATION_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_attribute_validation_source (Context&); + } +} + +#endif // CXX_SERIALIZER_ATTRIBUTE_VALIDATION_SOURCE_HXX diff --git a/xsde/cxx/serializer/cli.hxx b/xsde/cxx/serializer/cli.hxx new file mode 100644 index 0000000..5b1b7fa --- /dev/null +++ b/xsde/cxx/serializer/cli.hxx @@ -0,0 +1,154 @@ +// file : xsde/cxx/serializer/cli.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_CLI_HXX +#define CXX_SERIALIZER_CLI_HXX + +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace CLI + { + using namespace Cult::Types; + + typedef Char const Key[]; + + extern Key type_map; + extern Key no_stl; + extern Key no_iostream; + extern Key no_exceptions; + extern Key no_long_long; + extern Key reuse_style_mixin; + extern Key reuse_style_none; + extern Key generate_inline; + extern Key suppress_validation; + extern Key generate_polymorphic; + extern Key runtime_polymorphic; + extern Key suppress_reset; + extern Key generate_empty_impl; + extern Key generate_test_driver; + extern Key force_overwrite; + extern Key root_element_first; + extern Key root_element_last; + extern Key root_element; + extern Key generate_xml_schema; + extern Key extern_xml_schema; + extern Key output_dir; + extern Key skel_type_suffix; + extern Key skel_file_suffix; + extern Key impl_type_suffix; + extern Key impl_file_suffix; + extern Key namespace_map; + extern Key namespace_regex; + extern Key namespace_regex_trace; + extern Key reserved_name; + extern Key include_with_brackets; + extern Key include_prefix; + extern Key include_regex; + extern Key include_regex_trace; + extern Key guard_prefix; + extern Key hxx_suffix; + extern Key ixx_suffix; + extern Key cxx_suffix; + extern Key hxx_regex; + extern Key ixx_regex; + extern Key cxx_regex; + extern Key hxx_prologue; + extern Key ixx_prologue; + extern Key cxx_prologue; + extern Key prologue; + extern Key hxx_epilogue; + extern Key ixx_epilogue; + extern Key cxx_epilogue; + extern Key epilogue; + extern Key hxx_prologue_file; + extern Key ixx_prologue_file; + extern Key cxx_prologue_file; + extern Key prologue_file; + extern Key hxx_epilogue_file; + extern Key ixx_epilogue_file; + extern Key cxx_epilogue_file; + extern Key epilogue_file; + extern Key show_anonymous; + extern Key show_sloc; + extern Key proprietary_license; + + typedef Cult::CLI::Options< + type_map, Cult::Containers::Vector, + no_stl, Boolean, + no_iostream, Boolean, + no_exceptions, Boolean, + no_long_long, Boolean, + reuse_style_mixin, Boolean, + reuse_style_none, Boolean, + generate_inline, Boolean, + suppress_validation, Boolean, + generate_polymorphic, Boolean, + runtime_polymorphic, Boolean, + suppress_reset, Boolean, + generate_empty_impl, Boolean, + generate_test_driver, Boolean, + force_overwrite, Boolean, + root_element_first, Boolean, + root_element_last, Boolean, + root_element, NarrowString, + generate_xml_schema, Boolean, + extern_xml_schema, NarrowString, + output_dir, NarrowString, + skel_type_suffix, NarrowString, + skel_file_suffix, NarrowString, + impl_type_suffix, NarrowString, + impl_file_suffix, NarrowString, + namespace_map, Cult::Containers::Vector, + namespace_regex, Cult::Containers::Vector, + namespace_regex_trace, Boolean, + reserved_name, Cult::Containers::Vector, + include_with_brackets, Boolean, + include_prefix, NarrowString, + include_regex, Cult::Containers::Vector, + include_regex_trace, Boolean, + guard_prefix, NarrowString, + hxx_suffix, NarrowString, + ixx_suffix, NarrowString, + cxx_suffix, NarrowString, + hxx_regex, NarrowString, + ixx_regex, NarrowString, + cxx_regex, NarrowString, + hxx_prologue, Cult::Containers::Vector, + ixx_prologue, Cult::Containers::Vector, + cxx_prologue, Cult::Containers::Vector, + prologue, Cult::Containers::Vector, + hxx_epilogue, Cult::Containers::Vector, + ixx_epilogue, Cult::Containers::Vector, + cxx_epilogue, Cult::Containers::Vector, + epilogue, Cult::Containers::Vector, + hxx_prologue_file, NarrowString, + ixx_prologue_file, NarrowString, + cxx_prologue_file, NarrowString, + prologue_file, NarrowString, + hxx_epilogue_file, NarrowString, + ixx_epilogue_file, NarrowString, + cxx_epilogue_file, NarrowString, + epilogue_file, NarrowString, + show_anonymous, Boolean, + show_sloc, Boolean, + proprietary_license, Boolean + + > Options; + + struct OptionsSpec: Cult::CLI::OptionsSpec {}; + } + } +} + +#endif // CXX_SERIALIZER_CLI_HXX diff --git a/xsde/cxx/serializer/driver-source.cxx b/xsde/cxx/serializer/driver-source.cxx new file mode 100644 index 0000000..4a3c7db --- /dev/null +++ b/xsde/cxx/serializer/driver-source.cxx @@ -0,0 +1,1047 @@ +// file : xsde/cxx/serializer/driver-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + typedef Cult::Containers::Set InstanceSet; + + // For base types we only want member's types, but not the + // base itself. + // + struct BaseType: Traversal::Complex, Context + { + BaseType (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + }; + + struct SerializerDef: Traversal::Type, + Traversal::List, + Traversal::Complex, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + { + SerializerDef (Context& c, TypeInstanceMap& map, InstanceSet& set) + : Context (c), map_ (map), set_ (set), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (t)); + map_[&t] = inst; + + os << fq_name (t, "s:impl") << " " << inst << ";"; + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (map_.find (&l) == map_.end ()) + { + String inst (find_instance_name (l)); + map_[&l] = inst; + + os << fq_name (l, "s:impl") << " " << inst << ";"; + + dispatch (l.argumented ().type ()); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (map_.find (&c) == map_.end ()) + { + String inst (find_instance_name (c)); + map_[&c] = inst; + + os << fq_name (c, "s:impl") << " " << inst << ";"; + + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + fund_type (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + fund_type (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + fund_type (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + fund_type (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + fund_type (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + fund_type (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + fund_type (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + fund_type (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + fund_type (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + fund_type (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + fund_type (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + fund_type (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + fund_type (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + fund_type (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + fund_type (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + fund_type (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + fund_type (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + fund_type (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + fund_type (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + fund_type (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + fund_type (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + fund_type (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + fund_type (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + fund_type (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + fund_type (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + fund_type (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + fund_type (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + fund_type (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + fund_type (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + fund_type (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + fund_type (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + fund_type (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + fund_type (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + fund_type (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + fund_type (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + fund_type (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + fund_type (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + fund_type (t, "day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + fund_type (t, "month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + fund_type (t, "month_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + fund_type (t, "year"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + fund_type (t, "year_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + fund_type (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + fund_type (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + fund_type (t, "entities"); + } + + private: + virtual Void + fund_type (SemanticGraph::Type& t, String const& name) + { + if (map_.find (&t) == map_.end ()) + { + String inst (find_instance_name (name)); + map_[&t] = inst; + + os << fq_name (t, "s:impl") << " " << inst << ";"; + } + } + + String + find_instance_name (String const& raw_name) + { + String base_name (escape (raw_name + L"_s")); + String name (base_name); + + for (UnsignedLong i (1); set_.find (name) != set_.end (); ++i) + { + std::wostringstream os; + os << i; + name = base_name + os.str (); + } + + set_.insert (name); + return name; + } + + String + find_instance_name (SemanticGraph::Type& t) + { + return find_instance_name (t.name ()); + } + + TypeInstanceMap& map_; + InstanceSet& set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + // + // + struct ParticleArg: Traversal::Element, Context + { + ParticleArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&e.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct AttributeArg: Traversal::Attribute, Context + { + AttributeArg (Context& c, TypeInstanceMap& map, Boolean& first) + : Context (c), map_ (map), first_ (first) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&a.type ()]; + } + + private: + TypeInstanceMap& map_; + Boolean& first_; + }; + + struct ArgList : Traversal::Complex, + Traversal::List, + Context + { + ArgList (Context& c, TypeInstanceMap& map) + : Context (c), + map_ (map), + particle_ (c, map, first_), + attribute_ (c, map, first_), + first_ (true) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&l.argumented ().type ()]; + } + + private: + TypeInstanceMap& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleArg particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + AttributeArg attribute_; + + Boolean first_; + }; + + struct SerializerConnect: Traversal::List, + Traversal::Complex, + Context + { + SerializerConnect (Context& c, TypeInstanceMap& map) + : Context (c), map_ (map), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (type_set_.find (&l) == type_set_.end ()) + { + os << map_[&l] << ".serializers (" << + map_[&l.argumented ().type ()] << ");" + << endl; + + type_set_.insert (&l); + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (type_set_.find (&c) == type_set_.end ()) + { + if (has_members (c)) + { + os << map_[&c] << ".serializers ("; + + ArgList args (*this, map_); + args.dispatch (c); + + os << ");" + << endl; + } + + type_set_.insert (&c); + + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + } + + private: + Boolean + has_members (SemanticGraph::Complex& c) + { + using SemanticGraph::Complex; + + if (has (c)) + return true; + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&b)) + return has_members (*cb); + + return b.is_a (); + } + + return false; + } + + private: + TypeInstanceMap& map_; + Cult::Containers::Set type_set_; + + BaseType base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c, SemanticGraph::Element*& element) + : Context (c), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (options.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (String name = options.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + element_ = &e; // Cover root-element-last and no option. + } + + private: + SemanticGraph::Element*& element_; + }; + } + + Void + generate_driver_source (Context& ctx) + { + // Figure out the root element. Validator should have made sure + // it is unique. + // + SemanticGraph::Element* root (0); + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + RootElement global_element (ctx.options, root); + + schema >> schema_names >> ns >> ns_names >> global_element; + + schema.dispatch (ctx.schema_root); + } + + String xs (ctx.xs_ns_name ()); + std::wostream& os (ctx.os); + + InstanceSet set; + TypeInstanceMap map; + SemanticGraph::Type& root_type (root->type ()); + + set.insert ("doc_s"); + + if (ctx.options.value ()) + os << "#include " << endl + << endl; + else + os << "#include " << endl + << endl; + + if (ctx.options.value ()) + { + if (ctx.options.value ()) + { + os << "struct writer: " << xs << "::writer" + << "{" + << "virtual bool" << endl + << "write (const char* s, size_t n)" + << "{" + << "return fwrite (s, n, 1, stdout) == 1;" + << "}" + << "virtual bool" << endl + << "flush ()" + << "{" + << "return fflush (stdout) == 0;" + << "}" + << "};"; + } + else + { + os << "struct io_failure" + << "{" + << "};"; + + os << "struct writer: " << xs << "::writer" + << "{" + << "virtual void" << endl + << "write (const char* s, size_t n)" + << "{" + << "if (fwrite (s, n, 1, stdout) != 1)" << endl + << "throw io_failure ();" + << "}" + << "virtual void" << endl + << "flush ()" + << "{" + << "if (fflush (stdout) != 0)" << endl + << "throw io_failure ();" + << "}" + << "};"; + } + } + + os << "int" << endl + << "main ()" + << "{"; + + if (!ctx.options.value ()) + os << "try" + << "{"; + + os << "// Instantiate individual serializers." << endl + << "//" << endl; + + { + SerializerDef def (ctx, map, set); + def.dispatch (root_type); + } + + os << endl + << "// Connect the serializers together." << endl + << "//" << endl; + + { + // @@ I can simply iterate over the map instead of traversing + // the tree all over again. + // + SerializerConnect connect (ctx, map); + connect.dispatch (root_type); + } + + String const& root_s (map[&root_type]); + + os << "// Serialize the XML document." << endl + << "//" << endl; + + if (ctx.options.value ()) + os << "writer w;"; + + if (ctx.options.value ()) + os << xs << "::serializer_error e;" + << endl + << "do" + << "{"; + + if (root->namespace_().name ()) + os << xs << "::document_simpl doc_s (" << endl + << root_s << "," << endl + << ctx.strlit (root->namespace_().name ()) << "," << endl + << ctx.strlit (root->name ()) << ");" + << endl; + else + os << xs << "::document_simpl doc_s (" << root_s << ", " << + ctx.strlit (root->name ()) << ");" + << endl; + + if (ctx.options.value ()) + os << "if (e = doc_s._error ())" << endl + << "break;" + << endl; + + if (Context::arg_type (root->type ()) != L"void") + os << "// TODO: pass the " << root->name () << " element data " << + "to pre()" << endl + << "//" << endl; + + os << root_s << ".pre ();" + << endl; + + if (ctx.options.value ()) + os << "if (e = " << root_s << "._error ())" << endl + << "break;" + << endl; + + if (ctx.options.value ()) + os << "doc_s.serialize (w);" + << endl; + else + os << "doc_s.serialize (std::cout);" + << endl; + + if (ctx.options.value ()) + os << "if (e = doc_s._error ())" << endl + << "break;" + << endl; + + os << root_s << ".post ();"; + + if (ctx.options.value ()) + os << endl + << "e = " << root_s << "._error ();"; + + if (ctx.options.value ()) + os << "}" + << "while (false);" + << endl; + + // Error handling. + // + + if (ctx.options.value ()) + { + os << "// Handle errors." << endl + << "//" << endl + << "if (e)" + << "{" + << "switch (e.type ())" + << "{" + << "case " << xs << "::serializer_error::sys:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s\\n\", e.sys_text ());"; + else + os << "std::cerr << e.sys_text () << std::endl;"; + + os << "break;" + << "}" + << "case " << xs << "::serializer_error::xml:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s\\n\", e.xml_text ());"; + else + os << "std::cerr << e.xml_text () << std::endl;"; + + os << "break;" + << "}"; + + if (!ctx.options.value ()) + { + os << "case " << xs << "::serializer_error::schema:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"%s\\n\", e.schema_text ());"; + else + os << "std::cerr << e.schema_text () << std::endl;"; + + os << "break;" + << "}"; + } + + os << "case " << xs << "::serializer_error::app:" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"application error %d\\n\", e.app_code ());"; + else + os << "std::cerr << \"application error \" << e.app_code () " << + "<< std::endl;"; + + os << "break;" + << "}" + << "default:" + << "{" + << "break;" + << "}" + << "}" //switch + << "return 1;" + << "}"; // if (e) + } + else + { + os << "}" // try + << "catch (const " << xs << "::serializer_exception& e)" + << "{"; + + if (ctx.options.value ()) + os << "fprintf (stderr, \"error: %s\\n\", e.text ());"; + else + os << "std::cerr << \"error: \" << e.text () << std::endl;"; + + os << "return 1;" + << "}"; + + if (ctx.options.value ()) + os << "catch (const io_failure&)" + << "{" + << "fprintf (stderr, \"error: write failure\\n\");" + << "return 1;" + << "}"; + else + os << "catch (const std::ios_base::failure&)" + << "{" + << "std::cerr << \"error: write failure\" << std::endl;" + << "return 1;" + << "}"; + } + + os << "return 0;" + << "}"; // main + } + } +} diff --git a/xsde/cxx/serializer/driver-source.hxx b/xsde/cxx/serializer/driver-source.hxx new file mode 100644 index 0000000..b29cf34 --- /dev/null +++ b/xsde/cxx/serializer/driver-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/driver-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_DRIVER_SOURCE_HXX +#define CXX_SERIALIZER_DRIVER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_driver_source (Context&); + } +} + +#endif // CXX_SERIALIZER_DRIVER_SOURCE_HXX diff --git a/xsde/cxx/serializer/element-validation-source.cxx b/xsde/cxx/serializer/element-validation-source.cxx new file mode 100644 index 0000000..fd0dfb4 --- /dev/null +++ b/xsde/cxx/serializer/element-validation-source.cxx @@ -0,0 +1,903 @@ +// file : xsde/cxx/serializer/element-validation-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct AnyTest: Traversal::Any, Context + { + AnyTest (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + String const& ns (a.definition_namespace ().name ()); + + for (SemanticGraph::Any::NamespaceIterator i (a.namespace_begin ()), + e (a.namespace_end ()); i != e;) + { + if (*i == L"##any") + { + if (stl) + os << "!name.empty ()"; + else + os << "(name != 0 && *name != '\\0')"; + } + else if (*i == L"##other") + { + if (ns) + { + // Note that here I assume that ##other does not include + // unqualified names in a schema with target namespace. + // This is not what the spec says but that seems to be + // the consensus. + // + if (stl) + os << "(!ns.empty () && ns != " << strlit (ns) << ")"; + else + os << "(ns != 0 && *ns != '\\0' && " << + "strcmp (ns, " << strlit (ns) << ") != 0)"; + } + else + { + if (stl) + os << "!ns.empty ()"; + else + os << "(ns != 0 && *ns != '\\0')"; + } + } + else if (*i == L"##local") + { + if (stl) + os << "(ns.empty () && !name.empty ())"; + else + os << "((ns == 0 || *ns == '\\0') && " << + "name != 0 && *name != '\\0')"; + } + else if (*i == L"##targetNamespace") + { + if (stl) + os << "ns == " << strlit (ns); + else + os << "(ns != 0 && strcmp (ns, " << strlit (ns) << ") == 0)"; + } + else + { + if (stl) + os << "ns == " << strlit (*i); + else + os << "(ns != 0 && strcmp (ns, " << strlit (*i) << ") == 0)"; + } + + if (++i != e) + os << " ||" << endl; + } + } + }; + + struct Compositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + Compositor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + UnsignedLong min (a.min ()); + + if (min == 0) + os << "if (this->" << epresent (a) << " ())" + << "{"; + + Traversal::All::traverse (a); + + if (min == 0) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (c) << " ())" + << "{"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (c) << " (); ++i)" + << "{"; + } + else + os << "while (this->" << enext (c) << " ())" + << "{"; + } + else if (!exceptions) + { + // Only sequence can have several choice compositors in a row. + // + os << "{"; + } + + if (exceptions) + os << "switch (this->" << earm (c) << " ())"; + else + os << earm_tag (c) << " t = this->" << earm (c) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "switch (t)"; + + + os << "{"; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()); i != c.contains_end (); ++i) + { + os << "case " << etag (i->particle ()) << ":" + << "{"; + + edge_traverser ().dispatch (*i); + + os << "break;" + << "}"; + } + + os << "default:" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}" + << "}"; // switch + + if (min == 0 && max == 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + else if (!exceptions) + { + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (s) << " ())" + << "{"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (s) << " (); ++i)" + << "{"; + } + else + os << "while (this->" << enext (s) << " ())" + << "{"; + } + + Traversal::Sequence::traverse (s); + + if (min == 0 && max == 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + os << "}"; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + }; + + struct Particle: Traversal::Element, + Traversal::Any, + Context + { + Particle (Context& c) + : Context (c), any_test_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& name (ename (e)); + + os << "// " << name << endl + << "//" << endl; + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (e) << " ())"; + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (e) << " (); ++i)"; + } + else + os << "while (this->" << enext (e) << " ())"; + } + + os << "{"; + + String const& ret (ret_type (e.type ())); + String const& arg (arg_type (e.type ())); + String fq_type (fq_name (e.type ())); + + Boolean poly (poly_code && !anonymous (e.type ())); + String inst (poly ? String (L"s") : L"this->" + emember (e)); + + if (poly) + os << "ctx.type_id (0);"; + + if (ret == L"void") + os << "this->" << name << " ();" + << endl; + else + os << arg << " r = this->" << name << " ();" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (poly) + { + // In case of mixin we use virtual inheritance and only + // dynamic_cast can be used. + // + String cast (mixin ? L"dynamic_cast" : L"static_cast"); + + os << "const void* t = ctx.type_id ();" + << "const char* dt = 0;" + << fq_type << "* " << inst << " = 0;" + << endl + << "if (t == 0 && this->" << emember (e) << " != 0)" << endl + << inst << " = this->" << emember (e) << ";" + << "else if (this->" << emember_map (e) << " != 0)" + << "{" + << serializer_base << "* b = this->" << emember_map (e) << + "->find (t);" + << endl + << "if (b != 0)" + << "{" + << "dt = b->_dynamic_type ();" + << "const char* st = " << fq_type << "::_static_type ();" + << endl + << "if (strcmp (dt, st) == 0)" << endl + << "dt = 0;" + << endl; + + // Check that the types are related by inheritance. + // + os << "if (dt != 0 && !::xsde::cxx::serializer::validating::" << + "inheritance_map_instance ().check (dt, st))" + << "{" + << "ctx.schema_error (::xsde::cxx::schema_error::not_derived);" + << "return;" + << "}"; + + os << inst << " = " << cast << "< " << fq_type << "* > (b);" + << "}" + << "}"; + } + + os << "if (" << inst << ")" + << "{"; + + if (ret == L"void") + os << inst << "->pre ();"; + else + os << inst << "->pre (r);"; + + if (!exceptions) + { + // Note that after pre() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "const char* ns = " << + strlit (e.namespace_ ().name ()) << ";"; + else + os << "const char* ns = 0;"; + + os << "const char* n = " << strlit (e.name ()) << ";" + << endl; + + os << "if (dt != 0 && " << + "::xsde::cxx::serializer::substitution_map_instance ()" << + ".check (ns, n, dt))" << endl + << "dt = 0;" + << endl; + + if (exceptions) + { + os << "if (ns != 0)" << endl + << "this->_start_element (ns, n);" + << "else" << endl + << "this->_start_element (n);" + << endl; + } + else + { + os << "if (ns != 0)" + << "{" + << "if (!this->_start_element (ns, n))" << endl + << "return;" + << "}" + << "else" + << "{" + << "if (!this->_start_element (n))" << endl + << "return;" + << "}"; + } + } + else + { + if (exceptions) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << ");"; + else + os << "this->_start_element (" << strlit (e.name ()) << ");"; + } + else + { + os << "if (!"; + + if (e.qualified () && e.namespace_ ().name ()) + os << "this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << ")"; + else + os << "this->_start_element (" << strlit (e.name ()) << ")"; + + os << ")" << endl + << "return;" + << endl; + } + } + + if (poly) + { + // Set xsi:type if necessary. + // + if (exceptions) + os << "if (dt != 0)" << endl + << "this->_set_type (dt);" + << endl; + else + os << "if (dt != 0)" + << "{" + << "if (!this->_set_type (dt))" << endl + << "return;" + << "}"; + } + + os << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_attributes ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;" + << endl; + + os << inst << "->post ();"; + + if (!exceptions) + { + // Note that after post() we need to check both parser and + // context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl + << "if (ctx.error_type ())" << endl + << "return;"; + } + + os << "}"; // if (inst) + + if (min != 0) + { + os << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + + if (min == 0 && max == 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (a) << " ())"; + + } + else if (max != 1) + { + // We only need to count if max != unbounded || min != 0. + // + if (max != 0 || min != 0) + { + os << "{" + << "size_t i = 0;" + << "for (; "; + + if (max != 0) + os << "i < " << max << "UL && "; + + os << "this->" << enext (a) << " (); ++i)"; + } + else + os << "while (this->" << enext (a) << " ())"; + } + + os << "{"; + + if (stl) + { + os << "::std::string ns, name;" + << "this->" << ename (a) << " (ns, name);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if ("; + + any_test_.dispatch (a); + + os << ")" + << "{"; + + os << "if (ns.empty ())" + << "{"; + + if (exceptions) + os << "this->_start_element (name.c_str ());"; + else + os << "if (!this->_start_element (name.c_str ()))" << endl + << "return;"; + + os << "}" + << "else" + << "{"; + + if (exceptions) + os << "this->_start_element (ns.c_str (), name.c_str ());"; + else + os << "if (!this->_start_element (ns.c_str (), " << + "name.c_str ()))" << endl + << "return;"; + + os << "}" + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}"; + } + else + { + os << "const char* ns = 0;" + << "const char* name;" + << "bool free;" + << "this->" << ename (a) << " (ns, name, free);" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + else + os << "::xsde::cxx::string auto_ns, auto_name;" + << "if (free)" + << "{" + << "auto_ns.attach (const_cast< char* > (ns));" + << "auto_name.attach (const_cast< char* > (name));" + << "}"; + + os << "if ("; + + any_test_.dispatch (a); + + os << ")" + << "{"; + + if (exceptions) + os << "if (ns == 0 || *ns == '\\0')" << endl + << "this->_start_element (name);" + << "else" << endl + << "this->_start_element (ns, name);" + << endl; + else + os << "bool r;" + << "if (ns == 0 || *ns == '\\0')" << endl + << "r = this->_start_element (name);" + << "else" << endl + << "r = this->_start_element (ns, name);" + << endl + << "if (free)" + << "{" + << "delete[] ns;" + << "delete[] name;" + << "}" + << "if (!r)" << endl + << "return;" + << endl; + + os << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (exceptions) + os << "this->_end_element ();"; + else + os << "if (!this->_end_element ())" << endl + << "return;"; + + os << "}" // test + << "else" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::unexpected_element);" + << "return;" + << "}"; + } + + os << "}"; + + if (min == 0 && max == 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + else if (max != 1) + { + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (max != 0 || min != 0) + { + if (min != 0) + { + os << "if (i < " << min << "UL)" + << "{" + << "this->_schema_error (" << + "::xsde::cxx::schema_error::expected_element);" + << "return;" + << "}"; + } + + os << "}"; + } + } + } + + private: + AnyTest any_test_; + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_ (c), + particle_ (c) + { + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + } + + virtual Void + traverse (Type& c) + { + if (!has (c) && + !has_particle (c)) + return; + + // Don't use restriction_p here since we don't want special + // treatment of anyType. + // + Boolean restriction ( + c.inherits_p () && + c.inherits ().is_a ()); + + String const& name (ename (c)); + + os <<"// Element validation and serialization for " << + name << "." << endl + <<"//" << endl; + + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{" + << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (c.inherits_p () && !restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_serialize_content ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + + contains_compositor (c, contains_compositor_); + + os << "}"; + } + + private: + Compositor compositor_; + Particle particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + }; + } + + Void + generate_element_validation_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Complex complex (ctx); + + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/element-validation-source.hxx b/xsde/cxx/serializer/element-validation-source.hxx new file mode 100644 index 0000000..5649457 --- /dev/null +++ b/xsde/cxx/serializer/element-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/element-validation-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_ELEMENT_VALIDATION_SOURCE_HXX +#define CXX_SERIALIZER_ELEMENT_VALIDATION_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_element_validation_source (Context&); + } +} + +#endif // CXX_SERIALIZER_ELEMENT_VALIDATION_SOURCE_HXX diff --git a/xsde/cxx/serializer/elements.cxx b/xsde/cxx/serializer/elements.cxx new file mode 100644 index 0000000..f130254 --- /dev/null +++ b/xsde/cxx/serializer/elements.cxx @@ -0,0 +1,278 @@ +// file : xsde/cxx/serializer/elements.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace CXX +{ + namespace Serializer + { + Context:: + Context (std::wostream& o, + SemanticGraph::Schema& root, + CLI::Options const& ops, + Regex const* he, + Regex const* ie, + Regex const* hie) + : CXX::Context (o, + root, + "s:name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + options (ops), + xml_serializer (xml_serializer_), + serializer_base (serializer_base_), + simple_base (simple_base_), + complex_base (complex_base_), + serializer_map (serializer_map_), + validation (!ops.value ()), + exceptions (!ops.value ()), + stl (!ops.value ()), + poly_code (ops.value ()), + poly_runtime (poly_code || ops.value ()), + reset (!ops.value ()), + mixin (ops.value ()), + tiein (!mixin && !ops.value ()), + hxx_expr (he), + ixx_expr (ie), + hxx_impl_expr (hie), + xml_serializer_ ("genx") + { + String xs_ns (xs_ns_name ()); + + string_type = L"::xsde::cxx::ro_string"; + + serializer_base_ = xs_ns + L"::serializer_base"; + + simple_base_ = L"::xsde::cxx::serializer::"; + simple_base_ += (validation ? L"validating" : L"non_validating"); + simple_base_ += L"::simple_content"; + + complex_base_ = L"::xsde::cxx::serializer::"; + complex_base_ += (validation ? L"validating" : L"non_validating"); + complex_base_ += L"::complex_content"; + + if (poly_code) + serializer_map_ = xs_ns + L"::serializer_map"; + } + + String Context:: + real_fq_name (SemanticGraph::Nameable& n) + { + SemanticGraph::Context& c (n.context ()); + + if (c.count ("s:real-name")) + return c.get ("s:real-name"); + else + return fq_name (n); + } + + Content::Value Context:: + content (SemanticGraph::Complex& c) + { + using namespace SemanticGraph; + + if (c.mixed ()) + return Content::mixed; + + if (c.inherits_p ()) + { + Type& base (c.inherits ().base ()); + + if (Complex* cb = dynamic_cast (&base)) + return content (*cb); + + if (base.is_a ()) + return Content::complex; + + // Everyhting else (built-in type and AnySimpleType) is simple + // content. + // + return Content::simple; + } + else + return Content::complex; + } + + String const& Context:: + ret_type (SemanticGraph::Type& t) + { + return t.context ().get ("s:ret-type"); + } + + String const& Context:: + arg_type (SemanticGraph::Type& t) + { + return t.context ().get ("s:arg-type"); + } + + // + // + String const& Context:: + epresent (SemanticGraph::Particle& p) + { + return p.context ().get ("s:present"); + } + + String const& Context:: + epresent (SemanticGraph::Attribute& a) + { + return a.context ().get ("s:present"); + } + + String const& Context:: + enext (SemanticGraph::Particle& p) + { + return p.context ().get ("s:next"); + } + + String const& Context:: + enext (SemanticGraph::AnyAttribute& a) + { + return a.context ().get ("s:next"); + } + + String const& Context:: + etag (SemanticGraph::Particle& p) + { + return p.context ().get ("s:tag"); + } + + String const& Context:: + earm (SemanticGraph::Choice& c) + { + return c.context ().get ("s:arm"); + } + + String const& Context:: + earm_tag (SemanticGraph::Choice& c) + { + return c.context ().get ("s:arm-tag"); + } + + // + // + String const& Context:: + eserializer (SemanticGraph::Member& m) + { + return m.context ().get ("s:serializer"); + } + + String const& Context:: + emember (SemanticGraph::Member& m) + { + return m.context ().get ("s:member"); + } + + String const& Context:: + emember_map (SemanticGraph::Member& m) + { + return m.context ().get ("s:member-map"); + } + + String const& Context:: + etiein (SemanticGraph::Type& t) + { + return t.context ().get ("s:tiein"); + } + + // + // + String const& Context:: + eserialize (SemanticGraph::Any& a) + { + return a.context ().get ("s:serialize"); + } + + String const& Context:: + eserialize (SemanticGraph::AnyAttribute& a) + { + return a.context ().get ("s:serialize"); + } + + // + // + String const& Context:: + eimpl (SemanticGraph::Type& t) + { + return t.context ().get ("s:impl"); + } + + // Includes + // + Void TypeForward:: + traverse (SemanticGraph::Type& t) + { + os << "class " << t.context ().get (name_key_) << ";"; + } + + Void Includes:: + traverse_ (SemanticGraph::Uses& u) + { + // Support for weak (forward) inclusion used in the file-per-type + // compilation model. + // + Boolean weak (u.context ().count ("weak")); + + if (weak && (type_ == header || type_ == impl_header)) + { + // Generate forward declarations. We don't really need them + // in the impl files. + // + if (type_ == header) + schema_.dispatch (u.schema ()); + + return; + } + + if (type_ == source && !weak) + return; + + SemanticGraph::Path path (u.path ()); + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + NarrowString path_str; + try + { + path_str = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + path_str = path.native_file_string (); + } + + String inc_path; + + switch (type_) + { + case header: + case source: + { + inc_path = ctx_.hxx_expr->merge (path_str); + break; + } + case impl_header: + { + inc_path = ctx_.hxx_impl_expr->merge (path_str); + break; + } + } + + ctx_.os << "#include " << ctx_.process_include_path (inc_path) << endl + << endl; + } + } +} diff --git a/xsde/cxx/serializer/elements.hxx b/xsde/cxx/serializer/elements.hxx new file mode 100644 index 0000000..c80ab5b --- /dev/null +++ b/xsde/cxx/serializer/elements.hxx @@ -0,0 +1,443 @@ +// file : xsde/cxx/serializer/elements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_ELEMENTS_HXX +#define CXX_SERIALIZER_ELEMENTS_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + struct Content + { + enum Value + { + simple, + complex, + mixed + }; + }; + + // + // + class Context: public CXX::Context + { + public: + typedef BackendElements::Regex::Expression Regex; + + public: + Context (std::wostream&, + SemanticGraph::Schema&, + CLI::Options const&, + Regex const* hxx_expr, + Regex const* ixx_expr, + Regex const* hxx_impl_expr); + + protected: + Context (Context& c) + : CXX::Context (c), + options (c.options), + xml_serializer (c.xml_serializer), + serializer_base (c.serializer_base), + simple_base (c.simple_base), + complex_base (c.complex_base), + serializer_map (c.serializer_map), + validation (c.validation), + exceptions (c.exceptions), + stl (c.stl), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + Context (Context& c, std::wostream& o) + : CXX::Context (c, o), + options (c.options), + xml_serializer (c.xml_serializer), + serializer_base (c.serializer_base), + simple_base (c.simple_base), + complex_base (c.complex_base), + serializer_map (c.serializer_map), + validation (c.validation), + exceptions (c.exceptions), + stl (c.stl), + poly_code (c.poly_code), + poly_runtime (c.poly_runtime), + reset (c.reset), + mixin (c.mixin), + tiein (c.tiein), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + public: + Boolean + restriction_p (SemanticGraph::Complex& c) const + { + if (c.inherits_p () && + c.inherits ().is_a ()) + { + // Restriction of anyType is a special case. + // + return !c.inherits ().base ().is_a (); + } + + return false; + } + + // Real (e.g., non-typedef) fq-name. + // + String + real_fq_name (SemanticGraph::Nameable& n); + + public: + static Content::Value + content (SemanticGraph::Complex&); + + public: + static String const& + ret_type (SemanticGraph::Type&); + + static String const& + arg_type (SemanticGraph::Type&); + + public: + // Optional. + // + static String const& + epresent (SemanticGraph::Particle&); + + static String const& + epresent (SemanticGraph::Attribute&); + + // Sequence. + // + static String const& + enext (SemanticGraph::Particle&); + + static String const& + enext (SemanticGraph::AnyAttribute&); + + // Choice. + // + static String const& + etag (SemanticGraph::Particle&); + + static String const& + earm (SemanticGraph::Choice&); + + static String const& + earm_tag (SemanticGraph::Choice&); + + public: + static String const& + eserializer (SemanticGraph::Member&); + + static String const& + emember (SemanticGraph::Member&); + + static String const& + emember_map (SemanticGraph::Member&); + + static String const& + etiein (SemanticGraph::Type&); + + // serialize_* + // + public: + static String const& + eserialize (SemanticGraph::Any&); + + static String const& + eserialize (SemanticGraph::AnyAttribute&); + + public: + static String const& + eimpl (SemanticGraph::Type&); + + public: + CLI::Options const& options; + String& xml_serializer; + String& serializer_base; + String& simple_base; + String& complex_base; + String& serializer_map; + + Boolean validation; + Boolean exceptions; + Boolean stl; + Boolean poly_code; + Boolean poly_runtime; + Boolean reset; + Boolean mixin; + Boolean tiein; + + Regex const* hxx_expr; + Regex const* ixx_expr; + Regex const* hxx_impl_expr; + + private: + String xml_serializer_; + String serializer_base_; + String simple_base_; + String complex_base_; + String serializer_map_; + }; + + // + // + struct RequiredAttributeTest: Traversal::Attribute + { + RequiredAttributeTest (Boolean& result) + : result_ (result) + { + } + + virtual Void + traverse (Type& a) + { + if (!result_ && !a.optional ()) + result_ = true; + } + + private: + Boolean& result_; + }; + + + // + // + struct ParticleParamDecl: Traversal::Element, Context + { + ParticleParamDecl (Context& c, Boolean& first, Boolean name_arg) + : Context (c), first_ (first), name_arg_ (name_arg) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (e.type ()) << "&"; + + if (name_arg_) + os << " " << ename (e); + else + os << " /* " << comment (e.name ()) << " */"; + } + + private: + Boolean& first_; + Boolean name_arg_; + }; + + struct AttributeParamDecl: Traversal::Attribute, Context + { + AttributeParamDecl (Context& c, Boolean& first, Boolean name_arg) + : Context (c), first_ (first), name_arg_ (name_arg) + { + } + + virtual Void + traverse (Type& a) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (a.type ()) << "&"; + + if (name_arg_) + os << " " << ename (a); + else + os << " /* " << comment (a.name ()) << " */"; + } + + private: + Boolean& first_; + Boolean name_arg_; + }; + + struct SerializerParamDecl : Traversal::Complex, + Traversal::List, + Context + { + SerializerParamDecl (Context& c, Boolean name_arg) + : Context (c), + particle_ (c, first_, name_arg), + attribute_ (c, first_, name_arg), + first_ (true), + name_arg_ (name_arg) + { + inherits_ >> *this; + + contains_compositor_ >> compositor_ >> contains_particle_; + contains_particle_ >> particle_; + contains_particle_ >> compositor_; + + names_ >> attribute_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c, names_); + contains_compositor (c, contains_compositor_); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (l.argumented ().type ()) << "&"; + + if (name_arg_) + os << " " << ename (l) << "_item"; + else + os << " /* " << comment (l.name ()) << " item */"; + } + + private: + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + ParticleParamDecl particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + AttributeParamDecl attribute_; + Traversal::Names names_; + + Boolean first_; + Boolean name_arg_; + }; + + // + // + struct TypeForward: Traversal::Type, Context + { + TypeForward (Context& c, Char const* name_key) + : Context (c), name_key_ (name_key) + { + } + + virtual Void + traverse (SemanticGraph::Type& t); + + private: + Char const* name_key_; + }; + + struct Includes : Traversal::Imports, + Traversal::Includes + { + enum Type + { + header, + source, + impl_header + }; + + Includes (Context& c, Type t) + : ctx_ (c), + type_ (t), + namespace_ (c), + type_forward_ (c, t == header ? "s:name" : "s:impl") + { + schema_ >> schema_names_ >> namespace_ >> names_ >> type_forward_; + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + traverse_ (i); + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + traverse_ (i); + } + + private: + Void + traverse_ (SemanticGraph::Uses&); + + private: + Context& ctx_; + Type type_; + + Traversal::Schema schema_; + Traversal::Names schema_names_; + Namespace namespace_; + Traversal::Names names_; + TypeForward type_forward_; + }; + + // Find root element for the test driver. + // + struct RootElement: Traversal::Element + { + RootElement (CLI::Options const& options, + SemanticGraph::Element*& element) + : options_ (options), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (options_.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (String name = options_.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + element_ = &e; // Cover root-element-last and no option. + } + + private: + CLI::Options const& options_; + SemanticGraph::Element*& element_; + }; + } +} + +#endif // CXX_SERIALIZER_ELEMENTS_HXX diff --git a/xsde/cxx/serializer/generator.cxx b/xsde/cxx/serializer/generator.cxx new file mode 100644 index 0000000..c27ef09 --- /dev/null +++ b/xsde/cxx/serializer/generator.cxx @@ -0,0 +1,1600 @@ +// file : xsde/cxx/serializer/generator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "../../../libxsde/xsde/cxx/version.hxx" + +using std::endl; +using std::wcerr; + +using namespace XSDFrontend::SemanticGraph; + +// +// +typedef +boost::filesystem::wifstream +WideInputFileStream; + +typedef +boost::filesystem::wofstream +WideOutputFileStream; + +typedef +boost::filesystem::ifstream +NarrowInputFileStream; + +namespace CXX +{ + namespace + { + Char const copyright_gpl[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema\n" + "// to C++ data binding compiler for embedded systems.\n" + "//\n" + "// This program is free software; you can redistribute it and/or modify\n" + "// it under the terms of the GNU General Public License version 2 as\n" + "// published by the Free Software Foundation.\n" + "//\n" + "// This program is distributed in the hope that it will be useful,\n" + "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "// GNU General Public License for more details.\n" + "//\n" + "// You should have received a copy of the GNU General Public License\n" + "// along with this program; if not, write to the Free Software\n" + "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" + "//\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema to\n" + "// C++ data binding compiler for embedded systems, in the Proprietary\n" + "// License mode. You should have received a proprietary license from\n" + "// Code Synthesis Tools CC prior to generating this code. See the\n" + "// license text for conditions.\n" + "//\n\n"; + + Char const copyright_impl[] = + "// Not copyrighted - public domain.\n" + "//\n" + "// This sample serializer implementation was generated by CodeSynthesis XSD/e,\n" + "// an XML Schema to C++ data binding compiler for embedded systems. You may\n" + "// use it in your programs without any restrictions.\n" + "//\n\n"; + } + + namespace Serializer + { + namespace CLI + { + extern Key type_map = "type-map"; + extern Key no_stl = "no-stl"; + extern Key no_iostream = "no-iostream"; + extern Key no_exceptions = "no-exceptions"; + extern Key no_long_long = "no-long-long"; + extern Key reuse_style_mixin = "reuse-style-mixin"; + extern Key reuse_style_none = "reuse-style-none"; + extern Key generate_inline = "generate-inline"; + extern Key suppress_validation = "suppress-validation"; + extern Key generate_polymorphic = "generate-polymorphic"; + extern Key runtime_polymorphic = "runtime-polymorphic"; + extern Key suppress_reset = "suppress-reset"; + extern Key generate_empty_impl = "generate-empty-impl"; + extern Key generate_test_driver = "generate-test-driver"; + extern Key force_overwrite = "force-overwrite"; + extern Key root_element_first = "root-element-first"; + extern Key root_element_last = "root-element-last"; + extern Key root_element = "root-element"; + extern Key generate_xml_schema = "generate-xml-schema"; + extern Key extern_xml_schema = "extern-xml-schema"; + extern Key output_dir = "output-dir"; + extern Key skel_type_suffix = "skel-type-suffix"; + extern Key skel_file_suffix = "skel-file-suffix"; + extern Key impl_type_suffix = "impl-type-suffix"; + extern Key impl_file_suffix = "impl-file-suffix"; + extern Key namespace_map = "namespace-map"; + extern Key namespace_regex = "namespace-regex"; + extern Key namespace_regex_trace = "namespace-regex-trace"; + extern Key reserved_name = "reserved-name"; + extern Key include_with_brackets = "include-with-brackets"; + extern Key include_prefix = "include-prefix"; + extern Key include_regex = "include-regex"; + extern Key include_regex_trace = "include-regex-trace"; + extern Key guard_prefix = "guard-prefix"; + extern Key hxx_suffix = "hxx-suffix"; + extern Key ixx_suffix = "ixx-suffix"; + extern Key cxx_suffix = "cxx-suffix"; + extern Key hxx_regex = "hxx-regex"; + extern Key ixx_regex = "ixx-regex"; + extern Key cxx_regex = "cxx-regex"; + extern Key hxx_prologue = "hxx-prologue"; + extern Key ixx_prologue = "ixx-prologue"; + extern Key cxx_prologue = "cxx-prologue"; + extern Key prologue = "prologue"; + extern Key hxx_epilogue = "hxx-epilogue"; + extern Key ixx_epilogue = "ixx-epilogue"; + extern Key cxx_epilogue = "cxx-epilogue"; + extern Key epilogue = "epilogue"; + extern Key hxx_prologue_file = "hxx-prologue-file"; + extern Key ixx_prologue_file = "ixx-prologue-file"; + extern Key cxx_prologue_file = "cxx-prologue-file"; + extern Key prologue_file = "prologue-file"; + extern Key hxx_epilogue_file = "hxx-epilogue-file"; + extern Key ixx_epilogue_file = "ixx-epilogue-file"; + extern Key cxx_epilogue_file = "cxx-epilogue-file"; + extern Key epilogue_file = "epilogue-file"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + } + } + + Void Serializer::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--type-map " << endl + << " Read XML Schema to C++ type mapping information\n" + << " from . Repeat this option to specify\n" + << " several type maps. Type maps are considered in\n" + << " order of appearance and the first match is used." + << endl; + + e << "--no-stl" << endl + << " Generate code that does not use STL." + << endl; + + e << "--no-iostream" << endl + << " Generate code that does not use the iostream\n" + << " library." + << endl; + + e << "--no-exceptions" << endl + << " Generate code that does not use C++ exceptions." + << endl; + + e << "--no-long-long" << endl + << " Generate code that does not use the long long\n" + << " and unsigned long long types." + << endl; + + e << "--reuse-style-mixin" << endl + << " Generate code that supports the mixin base\n" + << " serializer implementation reuse style." + << endl; + + e << "--reuse-style-none" << endl + << " Do not generate any support for base serializer\n" + << " implementation reuse." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--suppress-validation" << endl + << " Suppress the generation of validation code." + << endl; + + e << "--generate-polymorphic" << endl + << " Generate polymorphism-aware code. Specify this\n" + << " option if you use substitution groups or xsi:type." + << endl; + + e << "--runtime-polymorphic" << endl + << " Generate non-polymorphic code that uses the\n" + << " runtime library configured with polymorphism\n" + << " support." + << endl; + + e << "--suppress-reset" << endl + << " Suppress the generation of serializer reset code." + << endl; + + e << "--generate-empty-impl" << endl + << " Generate a sample serializer implementation with\n" + << " empty function bodies." + << endl; + + e << "--generate-test-driver" << endl + << " Generate a test driver for the sample serializer\n" + << " implementation." + << endl; + + e << "--force-overwrite" << endl + << " Force overwriting of the existing implementation\n" + << " and test driver files." + << endl; + + e << "--root-element-first" << endl + << " Indicate that the first global element is the\n" + << " document root." + << endl; + + e << "--root-element-last" << endl + << " Indicate that the last global element is the\n" + << " document root." + << endl; + + e << "--root-element " << endl + << " Indicate that is the document root." + << endl; + + e << "--generate-xml-schema" << endl + << " Generate a C++ header file as if the schema being\n" + << " compiled defines the XML Schema namespace." + << endl; + + e << "--extern-xml-schema " << endl + << " Generate code as if the XML Schema namespace was\n" + << " defined in and xsd:included in the schema\n" + << " being compiled." + << endl; + + e << "--output-dir " << endl + << " Write generated files to instead of the\n" + << " current directory." + << endl; + + e << "--skel-type-suffix " << endl + << " Use instead of the default '_sskel' to\n" + << " construct the names of generated serializer\n" + << " skeletons." + << endl; + + e << "--skel-file-suffix " << endl + << " Use instead of the default '-sskel' to\n" + << " construct the names of generated serializer\n" + << " skeleton files." + << endl; + + e << "--impl-type-suffix " << endl + << " Use instead of the default '_simpl' to\n" + << " construct the names of serializer implementations\n" + << " for the built-in XML Schema types and sample\n" + << " serializer implementations." + << endl; + + e << "--impl-file-suffix " << endl + << " Use instead of the default '-simpl' to\n" + << " construct the names of generated sample\n" + << " serializer implementation files." + << endl; + + e << "--namespace-map =" << endl + << " Map XML Schema namespace to C++ namespace\n" + << " . Repeat this option to specify mapping for\n" + << " more than one XML Schema namespace." + << endl; + + e << "--namespace-regex " << endl + << " Add to the list of regular expressions\n" + << " used to translate XML Schema namespace names to\n" + << " C++ namespace names." + << endl; + + e << "--namespace-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --namespace-regex option." + << endl; + + e << "--reserved-name " << endl + << " Add to the list of names that should not\n" + << " be used as identifiers. The name can optionally\n" + << " be followed by '=' and the replacement name that\n" + << " should be used instead." + << endl; + + e << "--include-with-brackets" << endl + << " Use angle brackets (<>) instead of quotes (\"\") in\n" + << " generated #include directives." + << endl; + + e << "--include-prefix " << endl + << " Add to generated #include directive\n" + << " paths." + << endl; + + e << "--include-regex " << endl + << " Add to the list of regular expressions\n" + << " used to transform #include directive paths." + << endl; + + e << "--include-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --include-regex option." + << endl; + + e << "--guard-prefix " << endl + << " Add to generated header inclusion guards." + << endl; + + e << "--hxx-suffix " << endl + << " Use instead of the default '.hxx' to\n" + << " construct the name of the header file." + << endl; + + e << "--ixx-suffix " << endl + << " Use instead of the default '.ixx' to\n" + << " construct the name of the inline file." + << endl; + + e << "--cxx-suffix " << endl + << " Use instead of the default '.cxx' to\n" + << " construct the name of the source file." + << endl; + + e << "--hxx-regex " << endl + << " Use to construct the name of the header\n" + << " file." + << endl; + + e << "--ixx-regex " << endl + << " Use to construct the name of the inline\n" + << " file." + << endl; + + e << "--cxx-regex " << endl + << " Use to construct the name of the source\n" + << " file." + << endl; + + + // Prologues. + // + e << "--hxx-prologue " << endl + << " Insert at the beginning of the header file." + << endl; + + e << "--ixx-prologue " << endl + << " Insert at the beginning of the inline file." + << endl; + + e << "--cxx-prologue " << endl + << " Insert at the beginning of the source file." + << endl; + + e << "--prologue " << endl + << " Insert at the beginning of each generated\n" + << " file for which there is no file-specific prologue." + << endl; + + + // Epilogues. + // + e << "--hxx-epilogue " << endl + << " Insert at the end of the header file." + << endl; + + e << "--ixx-epilogue " << endl + << " Insert at the end of the inline file." + << endl; + + e << "--cxx-epilogue " << endl + << " Insert at the end of the source file." + << endl; + + e << "--epilogue " << endl + << " Insert at the end of each generated file\n" + << " for which there is no file-specific epilogue." + << endl; + + + // Prologue files. + // + e << "--hxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the header file." + << endl; + + e << "--ixx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the inline file." + << endl; + + e << "--cxx-prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of the source file." + << endl; + + e << "--prologue-file " << endl + << " Insert the content of the at the beginning\n" + << " of each generated file for which there is no file-\n" + << " specific prologue file." + << endl; + + + // Epilogue files. + // + e << "--hxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the header file." + << endl; + + e << "--ixx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the inline file." + << endl; + + e << "--cxx-epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " the source file." + << endl; + + e << "--epilogue-file " << endl + << " Insert the content of the at the end of\n" + << " each generated file for which there is no file-\n" + << " specific epilogue file." + << endl; + + + // Misc. + // + e << "--show-anonymous" << endl + << " Show elements and attributes that are of anonymous\n" + << " types." + << endl; + + e << "--show-sloc" << endl + << " Show the number of generated physical source lines\n" + << " of code (SLOC)." + << endl; + + e << "--sloc-limit " << endl + << " Check that the number of generated physical source\n" + << " lines of code (SLOC) does not exceed ." + << endl; + + e << "--options-file " << endl + << " Read additional options from . Each option\n" + << " should appear on a separate line optionally\n" + << " followed by space and an argument." + << endl; + + e << "--proprietary-license" << endl + << " Indicate that the generated code is licensed under\n" + << " a proprietary license instead of the GPL." + << endl; + } + + Serializer::CLI::OptionsSpec Serializer::Generator:: + options_spec () + { + CLI::OptionsSpec spec; + + spec.option ().default_value ("-sskel"); + spec.option ().default_value ("_sskel"); + spec.option ().default_value ("-simpl"); + spec.option ().default_value ("_simpl"); + + spec.option ().default_value (".hxx"); + spec.option ().default_value (".ixx"); + spec.option ().default_value (".cxx"); + + return spec; + } + + + namespace + { + template + Void + open (S& ifs, NarrowString const& path) + { + try + { + Path fs_path (path, boost::filesystem::native); + ifs.open (fs_path, std::ios_base::in | std::ios_base::binary); + + if (!ifs.is_open ()) + { + wcerr << path.c_str () << ": error: unable to open in read mode" + << endl; + + throw Serializer::Generator::Failed (); + } + } + catch (InvalidPath const&) + { + wcerr << "error: '" << path.c_str () << "' is not a valid " + << "filesystem path" << endl; + + throw Serializer::Generator::Failed (); + } + } + + Void + append (WideOutputFileStream& os, + NarrowString const& path, + WideInputFileStream& default_is) + { + using std::ios_base; + + if (path) + { + WideInputFileStream is; + open (is, path); + os << is.rdbuf (); + } + else if (default_is.is_open ()) + { + os << default_is.rdbuf (); + default_is.seekg (0, ios_base::beg); + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector const& primary, + Cult::Containers::Vector const& def) + { + Cult::Containers::Vector const& v ( + primary.empty () ? def : primary); + + for (Containers::Vector::ConstIterator + i (v.begin ()), e (v.end ()); i != e; ++i) + { + os << i->c_str () << endl; + } + } + } + + + UnsignedLong Serializer::Generator:: + generate (Serializer::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + TypeMap::Namespaces& type_map, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression Regex; + + try + { + Boolean generate_xml_schema (ops.value ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (generate_xml_schema) + { + if (NarrowString name = ops.value ()) + { + if (file_path.native_file_string () != name) + generate_xml_schema = false; + } + } + + Boolean impl (!generate_xml_schema && + ops.value ()); + + Boolean driver (gen_driver && !generate_xml_schema && + ops.value ()); + + // Evaluate the graph for possibility of generating something useful. + // + { + Validator validator; + if (!validator.validate ( + ops, schema, file_path, driver, disabled_warnings)) + throw Failed (); + } + + // Process names. + // + { + NameProcessor proc; + proc.process (ops, schema, file_path); + } + + // + // + Boolean validation (!ops.value ()); + + // Read-in type maps. + // + { + using namespace TypeMap; + typedef Containers::Vector Files; + + Files const& files (ops.value ()); + + for (Files::ConstIterator f (files.begin ()); f != files.end (); ++f ) + { + NarrowInputFileStream ifs; + open (ifs, *f); + + Lexer l (ifs, *f); + TypeMap::Parser p (l, *f); + + if (!p.parse (type_map)) + throw Failed (); + } + + // Add the built-in mappings at the end. + // + String xns; + { + Context ctx (std::wcerr, schema, ops, 0, 0, 0); + xns = ctx.xs_ns_name (); + } + + if (ops.value ()) + { + TypeMap::Namespace xsd_std ("http://www\\.w3\\.org/2001/XMLSchema"); + + String qname (L"const " + xns + L"::qname*"); + String string_seq (L"const " + xns + L"::string_sequence*"); + + xsd_std.types_push_back ("string", "const char*", "const char*"); + xsd_std.types_push_back ("normalizedString", "const char*", "const char*"); + xsd_std.types_push_back ("token", "const char*", "const char*"); + xsd_std.types_push_back ("Name", "const char*", "const char*"); + xsd_std.types_push_back ("NMTOKEN", "const char*", "const char*"); + xsd_std.types_push_back ("NMTOKENS", string_seq, string_seq); + xsd_std.types_push_back ("NCName", "const char*", "const char*"); + + xsd_std.types_push_back ("ID", "const char*", "const char*"); + xsd_std.types_push_back ("IDREF", "const char*", "const char*"); + xsd_std.types_push_back ("IDREFS", string_seq, string_seq); + + xsd_std.types_push_back ("language", "const char*", "const char*"); + xsd_std.types_push_back ("anyURI", "const char*", "const char*"); + xsd_std.types_push_back ("QName", qname, qname); + + type_map.push_back (xsd_std); + } + else + { + TypeMap::Namespace xsd_std ("http://www\\.w3\\.org/2001/XMLSchema"); + + String qname (xns + L"::qname"); + String string_seq (L"const " + xns + L"::string_sequence*"); + + xsd_std.types_push_back ("string", "::std::string"); + xsd_std.types_push_back ("normalizedString", "::std::string"); + xsd_std.types_push_back ("token", "::std::string"); + xsd_std.types_push_back ("Name", "::std::string"); + xsd_std.types_push_back ("NMTOKEN", "::std::string"); + xsd_std.types_push_back ("NMTOKENS", string_seq, string_seq); + xsd_std.types_push_back ("NCName", "::std::string"); + + xsd_std.types_push_back ("ID", "::std::string"); + xsd_std.types_push_back ("IDREF", "::std::string"); + xsd_std.types_push_back ("IDREFS", string_seq, string_seq); + + xsd_std.types_push_back ("language", "::std::string"); + xsd_std.types_push_back ("anyURI", "::std::string"); + xsd_std.types_push_back ("QName", qname); + + type_map.push_back (xsd_std); + } + + String buffer (L"const " + xns + L"::buffer*"); + + TypeMap::Namespace xsd ("http://www\\.w3\\.org/2001/XMLSchema"); + + xsd.types_push_back ("boolean", "bool", "bool"); + + xsd.types_push_back ("byte", "signed char", "signed char"); + xsd.types_push_back ("unsignedByte", "unsigned char", "unsigned char"); + + xsd.types_push_back ("short", "short", "short"); + xsd.types_push_back ("unsignedShort", "unsigned short", "unsigned short"); + + xsd.types_push_back ("int", "int", "int"); + xsd.types_push_back ("unsignedInt", "unsigned int", "unsigned int"); + + if (ops.value ()) + { + xsd.types_push_back ("long", "long", "long"); + xsd.types_push_back ("unsignedLong", "unsigned long", "unsigned long"); + } + else + { + xsd.types_push_back ("long", "long long", "long long"); + xsd.types_push_back ("unsignedLong", "unsigned long long", "unsigned long long"); + } + + xsd.types_push_back ("integer", "long", "long"); + + xsd.types_push_back ("negativeInteger", "long", "long"); + xsd.types_push_back ("nonPositiveInteger", "long", "long"); + + xsd.types_push_back ("positiveInteger", "unsigned long", "unsigned long"); + xsd.types_push_back ("nonNegativeInteger", "unsigned long", "unsigned long"); + + xsd.types_push_back ("float", "float", "float"); + xsd.types_push_back ("double", "double", "double"); + xsd.types_push_back ("decimal", "double", "double"); + + xsd.types_push_back ("base64Binary", buffer, buffer); + xsd.types_push_back ("hexBinary", buffer, buffer); + + xsd.types_push_back ("gDay", xns + L"::gday"); + xsd.types_push_back ("gMonth", xns + L"::gmonth"); + xsd.types_push_back ("gYear", xns + L"::gyear"); + xsd.types_push_back ("gMonthDay", xns + L"::gmonth_day"); + xsd.types_push_back ("gYearMonth", xns + L"::gyear_month"); + xsd.types_push_back ("date", xns + L"::date"); + xsd.types_push_back ("time", xns + L"::time"); + xsd.types_push_back ("dateTime", xns + L"::date_time"); + xsd.types_push_back ("duration", xns + L"::duration"); + + type_map.push_back (xsd); + + // Everyhting else maps to void. + // + TypeMap::Namespace rest (".*"); + rest.types_push_back (".*", "void", "void"); + type_map.push_back (rest); + } + + // Process types. + // + { + TypeProcessor proc; + proc.process (ops, schema, type_map); + } + + // Generate code. + // + Boolean inline_ (ops.value () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value ()); + NarrowString impl_suffix (ops.value ()); + + NarrowString hxx_suffix (ops.value ()); + NarrowString ixx_suffix (ops.value ()); + NarrowString cxx_suffix (ops.value ()); + + + Regex hxx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : ops.value ()); + + Regex ixx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + ixx_suffix + "#" + : ops.value ()); + + Regex cxx_expr ( + ops.value ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + cxx_suffix + "#" + : ops.value ()); + + Regex hxx_impl_expr; + Regex cxx_impl_expr; + Regex cxx_driver_expr; + + if (impl || driver) + { + hxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#"; + + cxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#"; + + cxx_driver_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1-sdriver" + cxx_suffix + "#"; + } + + if (!hxx_expr.match (name)) + { + wcerr << "error: header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (inline_ && !ixx_expr.match (name)) + { + wcerr << "error: inline expression '" << + ixx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (source && !cxx_expr.match (name)) + { + wcerr << "error: source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (impl || driver) + { + if (!hxx_impl_expr.match (name)) + { + wcerr << "error: implementation header expression '" << + hxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_impl_expr.match (name)) + { + wcerr << "error: implementation source expression '" << + cxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_driver_expr.match (name)) + { + wcerr << "error: driver source expression '" << + cxx_driver_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + } + + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString ixx_name (inline_ ? ixx_expr.merge (name) : NarrowString ()); + NarrowString cxx_name (source ? cxx_expr.merge (name) : NarrowString ()); + + NarrowString hxx_impl_name; + NarrowString cxx_impl_name; + NarrowString cxx_driver_name; + + if (impl || driver) + { + hxx_impl_name = hxx_impl_expr.merge (name); + cxx_impl_name = cxx_impl_expr.merge (name); + cxx_driver_name = cxx_driver_expr.merge (name); + } + + Path hxx_path (hxx_name, boost::filesystem::native); + Path ixx_path (ixx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + Path hxx_impl_path; + Path cxx_impl_path; + Path cxx_driver_path; + + if (impl || driver) + { + hxx_impl_path = Path (hxx_impl_name, boost::filesystem::native); + cxx_impl_path = Path (cxx_impl_name, boost::filesystem::native); + cxx_driver_path = Path (cxx_driver_name, boost::filesystem::native); + } + + if (NarrowString dir = ops.value ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + ixx_path = path / ixx_path; + cxx_path = path / cxx_path; + + if (impl || driver) + { + hxx_impl_path = path / hxx_impl_path; + cxx_impl_path = path / cxx_impl_path; + cxx_driver_path = path /cxx_driver_path; + } + + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + // Open the impl files first so that if open fails, the skel files + // are not deleted. + // + WideOutputFileStream hxx_impl; + WideOutputFileStream cxx_impl; + WideOutputFileStream cxx_driver; + + if (impl) + { + if (!ops.value ()) + { + WideInputFileStream tmp (hxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << hxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + hxx_impl.open (hxx_impl_path, ios_base::out); + + if (!hxx_impl.is_open ()) + { + wcerr << hxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (hxx_impl_path); + file_list.push_back (hxx_impl_path.native_file_string ()); + + if (!ops.value ()) + { + WideInputFileStream tmp (cxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_impl.open (cxx_impl_path, ios_base::out); + + if (!cxx_impl.is_open ()) + { + wcerr << cxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (cxx_impl_path); + file_list.push_back (cxx_impl_path.native_file_string ()); + } + + if (driver) + { + if (!ops.value ()) + { + WideInputFileStream tmp (cxx_driver_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_driver_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_driver.open (cxx_driver_path, ios_base::out); + + if (!cxx_driver.is_open ()) + { + wcerr << cxx_driver_path << ": error: unable to open in write " << + "mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_driver_path); + file_list.push_back (cxx_driver_path.native_file_string ()); + } + + // Open the skel files. + // + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream ixx; + WideOutputFileStream cxx; + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (inline_) + { + ixx.open (ixx_path, ios_base::out); + + if (!ixx.is_open ()) + { + wcerr << ixx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (ixx_path); + file_list.push_back (ixx_path.native_file_string ()); + } + + if (source) + { + cxx.open (cxx_path, ios_base::out); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + } + + // Print copyright and license. + // + Char const* copyright ( + ops.value () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + + if (inline_) + ixx << copyright; + + if (source) + cxx << copyright; + + if (impl) + { + hxx_impl << copyright_impl; + cxx_impl << copyright_impl; + } + + if (driver) + cxx_driver << copyright_impl; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name (ops.value ()); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name (ops.value ()); + + if (name) + open (epilogue, name); + } + + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value ()); + + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value ()); + + if (!guard_prefix) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + hxx, ops.value (), ops.value ()); + append (hxx, ops.value (), prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + hxx << "#include " << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + // Runtime/generated code compatibility checks. + // + + hxx << "#include " << endl + << endl; + + if (ops.value ()) + { + hxx << "#ifdef XSDE_STL" << endl + << "#error the XSD/e runtime uses STL while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-stl)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_STL" << endl + << "#error the generated code uses STL while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-stl)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_IOSTREAM" << endl + << "#error the XSD/e runtime uses iostream while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-iostream)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_IOSTREAM" << endl + << "#error the generated code uses iostream while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-iostream)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_EXCEPTIONS" << endl + << "#error the XSD/e runtime uses exceptions while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_EXCEPTIONS" << endl + << "#error the generated code uses exceptions while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_LONGLONG" << endl + << "#error the XSD/e runtime uses long long while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-long-long)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_LONGLONG" << endl + << "#error the generated code uses long long while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-long-long)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifdef XSDE_SERIALIZER_VALIDATION" << endl + << "#error the XSD/e runtime uses validation while the " << + "generated code does not (reconfigure the runtime or " << + "remove --suppress-validation)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_SERIALIZER_VALIDATION" << endl + << "#error the generated code uses validation while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --suppress-validation)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value () || + ops.value ()) + { + hxx << "#ifndef XSDE_POLYMORPHIC" << endl + << "#error the generated code expects XSD/e runtime with " << + "polymorphism support (reconfigure the runtime or remove " << + "--generate-polymorphic/--runtime-polymorphic)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifdef XSDE_POLYMORPHIC" << endl + << "#error the generated code expects XSD/e runtime " << + "without polymorphism support (reconfigure the runtime or " << + "add --generate-polymorphic/--runtime-polymorphic)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value ()) + { + hxx << "#ifndef XSDE_REUSE_STYLE_MIXIN" << endl + << "#error the generated code uses the mixin reuse style " << + "while the XSD/e runtime does not (reconfigure the runtime " << + "or remove --reuse-style-mixin)" << endl + << "#endif" << endl + << endl; + } + else if (ops.value ()) + { + hxx << "#ifndef XSDE_REUSE_STYLE_NONE" << endl + << "#error the generated code does not provide support " << + "for serializer reuse while the XSD/e runtime does (" << + "reconfigure the runtime or remove --reuse-style-none)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_REUSE_STYLE_TIEIN" << endl + << "#error the generated code uses the tiein reuse style " << + "while the XSD/e runtime does not (reconfigure the runtime " << + "or add --reuse-style-mixin or --reuse-style-none)" << endl + << "#endif" << endl + << endl; + } + + // + // + + hxx << "#include " << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip hxx_clip (hxx); + + // Generate. + // + if (!generate_xml_schema) + generate_serializer_forward (ctx); + + generate_serializer_header (ctx, generate_xml_schema); + + + if (inline_) + hxx << "#include " << ctx.process_include_path (ixx_name) << endl + << endl; + + hxx << "#include " << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, ops.value (), epilogue); + append ( + hxx, ops.value (), ops.value ()); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + + // IXX + // + if (inline_) + { + Context ctx (ixx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip ixx_sloc (ixx); + + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + + append ( + ixx, ops.value (), ops.value ()); + append (ixx, ops.value (), prologue); + + ixx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip ixx_clip (ixx); + + + // Generate. + // + generate_serializer_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + + append (ixx, ops.value (), epilogue); + append ( + ixx, ops.value (), ops.value ()); + + ixx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << ixx_path << ": " + << ixx_sloc.buffer ().count () << endl; + + sloc += ixx_sloc.buffer ().count (); + } + } + + + // CXX + // + if (source) + { + Context ctx (cxx, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + Indentation::Clip cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + cxx, ops.value (), ops.value ()); + append (cxx, ops.value (), prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + if (!inline_) + generate_serializer_inline (ctx); + + generate_serializer_source (ctx); + + if (validation) + { + generate_element_validation_source (ctx); + generate_attribute_validation_source (ctx); + } + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, ops.value (), epilogue); + append ( + cxx, ops.value (), ops.value ()); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + // HXX impl + // + if (impl) + { + Context ctx (hxx_impl, schema, ops, &hxx_expr, &ixx_expr, &hxx_impl_expr); + + String guard (guard_expr.merge (guard_prefix + hxx_impl_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx_impl << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip clip (hxx_impl); + + hxx_impl << "#include " << ctx.process_include_path (hxx_name) + << endl << endl; + + generate_impl_header (ctx); + } + + hxx_impl << "#endif // " << guard << endl; + } + + // CXX impl + // + if (impl) + { + Context ctx (cxx_impl, schema, ops, + &hxx_expr, &ixx_expr, &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip clip (cxx_impl); + + cxx_impl << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_impl_source (ctx); + } + + // CXX driver + // + if (driver) + { + Context ctx (cxx_driver, schema, ops, + &hxx_expr, &ixx_expr, &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip clip (cxx_driver); + + cxx_driver << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_driver_source (ctx); + } + + return sloc; + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } +} diff --git a/xsde/cxx/serializer/generator.hxx b/xsde/cxx/serializer/generator.hxx new file mode 100644 index 0000000..a5b8558 --- /dev/null +++ b/xsde/cxx/serializer/generator.hxx @@ -0,0 +1,56 @@ +// file : xsde/cxx/serializer/generator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_GENERATOR_HXX +#define CXX_SERIALIZER_GENERATOR_HXX + +#include + +#include + +#include +#include + +#include // Path +#include + +#include +#include +#include + +namespace CXX +{ + namespace Serializer + { + using namespace Cult::Types; + + class Generator + { + public: + static Void + usage (); + + static CLI::OptionsSpec + options_spec (); + + struct Failed {}; + + static UnsignedLong + generate (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file, + TypeMap::Namespaces& type_map, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks); + + private: + Generator (); + }; + } +} + +#endif // CXX_SERIALIZER_GENERATOR_HXX diff --git a/xsde/cxx/serializer/impl-header.cxx b/xsde/cxx/serializer/impl-header.cxx new file mode 100644 index 0000000..d98b6af --- /dev/null +++ b/xsde/cxx/serializer/impl-header.cxx @@ -0,0 +1,488 @@ +// file : xsde/cxx/serializer/impl-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (eimpl (e)); + String const& arg (arg_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + + os << "class " << name << ": " << "public " << + (mixin ? "virtual " : "") << ename (e); + + if (mixin) + os << "," << endl + << " public " << fq_name (base, "s:impl"); + + os << "{" + << "public:" << endl; + + if (tiein) + os << name << " ();" + << endl; + + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ");"; + + os << endl + << "virtual void" << endl + << "post ();"; + + if (tiein) + os << endl + << "private:" << endl + << fq_name (base, "s:impl") << " base_impl_;"; + + os << "};"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (eimpl (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + + String const& arg (arg_type (l)); + String const& ret (ret_type (t)); + + String const& skel (ename (l)); + String item (unclash (skel, "item")); + String item_next (unclash (skel, "item_next")); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (l) + << "{" + << "public:" << endl + << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ");"; + + os << endl + << "virtual bool" << endl + << item_next << " ();" + << endl + << "virtual " << ret << endl + << item << " ();" + << endl + << "virtual void" << endl + << "post ();" + << "};"; + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (eimpl (u)); + String const& arg (arg_type (u)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (u) + << "{" + << "public:" << endl + << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ");"; + + os << endl + << "virtual void" << endl + << "_serialize_content ();" + << endl + << "virtual void" << endl + << "post ();" + << "};"; + } + }; + + + // + // + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (c) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (c) << " ();" + << endl; + } + + os << "virtual " << earm_tag (c) << endl + << earm (c) << " ();" + << endl; + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (s) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (s) << " ();" + << endl; + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallback: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (e) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (e) << " ();" + << endl; + } + + String const& ret (ret_type (e.type ())); + + os << "virtual " << ret << endl + << ename (e) << " ();" + << endl; + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (a) << " ();" + << endl; + } + + if (stl) + { + os << "virtual void" << endl + << ename (a) << " (::std::string& ns, ::std::string& name);" + << endl; + } + else + { + os << "virtual void" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free);" + << endl; + } + + os << "virtual void" << endl + << eserialize (a) << " ();" + << endl; + + } + }; + + struct AttributeCallback: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + if (a.optional ()) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + + String const& ret (ret_type (a.type ())); + + os << "virtual " << ret << endl + << ename (a) << " ();" + << endl; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + os << "virtual bool" << endl + << enext (a) << " ();" + << endl; + + if (stl) + { + os << "virtual void" << endl + << ename (a) << " (::std::string& ns, ::std::string& name);" + << endl; + } + else + { + os << "virtual void" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free);" + << endl; + } + + os << "virtual void" << endl + << eserialize (a) << " ();" + << endl; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + // In case of an inheritance-by-restriction, we don't need to + // generate serializer callbacks, etc. since they are the same + // as in the base. We only need the serialization/validation code. + // + Boolean restriction (restriction_p (c)); + + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + Boolean haa (has (c)); + + String const& name (eimpl (c)); + String const& arg (arg_type (c)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << ename (c); + + if (mixin && hb) + os << "," << endl + << " public " << fq_name (c.inherits ().base (), "s:impl"); + + os << "{" + << "public:" << endl; + + // c-tor + // + if (tiein && hb) + os << name << " ();" + << endl; + + // pre + // + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ");"; + + os << endl; + + + // Member callbacks. + // + if (!restriction && (ha || he || hae || haa)) + { + if (ha || haa) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + + if (he || hae) + { + os << "// Elements." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_callback_); + } + } + + // post + // + os << "virtual void" << endl + << "post ();"; + + if (tiein && hb) + os << endl + << "private:" << endl + << fq_name (c.inherits ().base (), "s:impl") << " base_impl_;"; + + os << "};"; + } + + private: + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_impl_header (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::impl_header); + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/impl-header.hxx b/xsde/cxx/serializer/impl-header.hxx new file mode 100644 index 0000000..a483eaa --- /dev/null +++ b/xsde/cxx/serializer/impl-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/impl-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_IMPL_HEADER_HXX +#define CXX_SERIALIZER_IMPL_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_impl_header (Context&); + } +} + +#endif // CXX_SERIALIZER_IMPL_HEADER_HXX diff --git a/xsde/cxx/serializer/impl-source.cxx b/xsde/cxx/serializer/impl-source.cxx new file mode 100644 index 0000000..cc31ced --- /dev/null +++ b/xsde/cxx/serializer/impl-source.cxx @@ -0,0 +1,664 @@ +// file : xsde/cxx/serializer/impl-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (eimpl (e)); + String const& arg (arg_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein) + os << name << "::" << endl + << name << " ()" << endl + << ": " << ename (e) << " (&base_impl_)" + << "{" + << "}"; + + // pre + // + os << "void " << name << "::" << endl; + + if (arg == L"void") + os << "pre ()"; + else + os << "pre (" << arg << " v)"; + + os << "{"; + + if (arg == arg_type (base)) + { + if (tiein) + { + os << "base_impl_.pre (" << + (arg != L"void" ? "v" : "") << ");"; + } + else if (mixin) + { + os << eimpl (base) << "::pre (" << + (arg != L"void" ? "v" : "") << ");"; + } + } + else + { + if (tiein) + { + os << "// TODO: call base_impl_.pre ()." << endl + << "//" << endl; + } + else if (mixin) + { + os << "// TODO: call " << eimpl (base) << "::pre ()." << endl + << "//" << endl; + } + } + + os << "}"; + + // post + // + os << "void " << name << "::" << endl + << "post ()" + << "{" + << "}"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (eimpl (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + + String const& arg (arg_type (l)); + String const& ret (ret_type (t)); + + String const& skel (ename (l)); + String item (unclash (skel, "item")); + String item_next (unclash (skel, "item_next")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + os << "void " << name << "::" << endl; + + if (arg == L"void") + os << "pre ()" + << "{" + << "}"; + else + os << "pre (" << arg << " v)" + << "{" + << "// TODO" << endl + << "//" << endl + << "}"; + + // item + // + os << "bool " << name << "::" << endl + << item_next << " ()" + << "{" + << "// TODO: return true if there is another item to" << endl + << "// serialize." << endl + << "//" << endl + << "}"; + + + os << ret << " " << name << "::" << endl + << item << " ()" + << "{" + << "// TODO: return the next item." << endl + << "//" << endl + << "}"; + + // post + // + os << "void " << name << "::" << endl + << "post ()" + << "{" + << "}"; + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (eimpl (u)); + String const& arg (arg_type (u)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + os << "void " << name << "::" << endl; + + if (arg == L"void") + os << "pre ()" + << "{" + << "}"; + else + os << "pre (" << arg << " v)" + << "{" + << "// TODO" << endl + << "//" << endl + << "}"; + + // _serialize_content + // + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{" + << "// TODO: call the _characters() function to serialize" << endl + << "// text content." << endl + << "//" << endl + << "}"; + + // post + // + os << "void " << name << "::" << endl + << "post ()" + << "{" + << "}"; + } + }; + + // + // + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + String const& s (eimpl (scope (a))); + + os << "bool " << s << "::" << endl + << epresent (a) << " ()" + << "{" + << "// TODO: return true if the content corresponding" << endl + << "// to the all compositor is present." << endl + << "//" << endl + << "}"; + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + SemanticGraph::Complex& t (scope (c)); + String const& s (eimpl (t)); + + if (min == 0 && max == 1) + { + os << "bool " << s << "::" << endl + << epresent (c) << " ()" + << "{" + << "// TODO: return true if the content corresponding" << endl + << "// to the choice compositor is present." << endl + << "//" << endl + << "}"; + } + else if (max != 1) + { + os << "bool " << s << "::" << endl + << enext (c) << " ()" + << "{" + << "// TODO: return true if there is another choice" << endl + << "// item to serialize." << endl + << "//" << endl + << "}"; + } + + os << ename (t) << "::" << earm_tag (c) << " " << s << "::" << endl + << earm (c) << " ()" + << "{" + << "// TODO: return the choice arm that is being" << endl + << "// serialized." << endl + << "//" << endl + << "}"; + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + String const& sc (eimpl (scope (s))); + + if (min == 0 && max == 1) + { + os << "bool " << sc << "::" << endl + << epresent (s) << " ()" + << "{" + << "// TODO: return true if the content corresponding" << endl + << "// to the sequence compositor is present." << endl + << "//" << endl + << "}"; + + } + else if (max != 1) + { + os << "bool " << sc << "::" << endl + << enext (s) << " ()" + << "{" + << "// TODO: return true if there is another sequence" << endl + << "// item to serialize." << endl + << "//" << endl + << "}"; + } + + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Complex& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + }; + + struct ParticleCallback: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& s ( + eimpl (dynamic_cast (e.scope ()))); + + if (min == 0 && max == 1) + { + os << "bool " << s << "::" << endl + << epresent (e) << " ()" + << "{" + << "// TODO: return true if the element is present." << endl + << "//" << endl + << "}"; + + } + else if (max != 1) + { + os << "bool " << s << "::" << endl + << enext (e) << " ()" + << "{" + << "// TODO: return true if there is another element" << endl + << "// to serialize." << endl + << "//" << endl + << "}"; + } + + String const& ret (ret_type (e.type ())); + + os << ret << " " << s << "::" << endl + << ename (e) << " ()" + << "{" + << "// TODO: return the element data." << endl + << "//" << endl + << "}"; + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + String const& s ( + eimpl (dynamic_cast (a.scope ()))); + + if (min == 0 && max == 1) + { + os << "bool " << s << "::" << endl + << epresent (a) << " ()" + << "{" + << "// TODO: return true if the wildcard content is" << endl + << "// present." << endl + << "//" << endl + << "}"; + } + else if (max != 1) + { + os << "bool " << s << "::" << endl + << enext (a) << " ()" + << "{" + << "// TODO: return true if there is another wildcard" << endl + << "// element to serialize." << endl + << "//" << endl + << "}"; + } + + if (stl) + { + os << "void " << s << "::" << endl + << ename (a) << " (::std::string& ns, ::std::string& name)"; + } + else + { + os << "void " << s << "::" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free)"; + } + + os << "{" + << "// TODO: return the name and namespace of the element" << endl + << "// corresponding to the wildcard." << endl + << "//" << endl + << "}"; + + os << "void " << s << "::" << endl + << eserialize (a) << " ()" + << "{" + << "// TODO: use the _start_element(), _end_element()," << endl + << "// _attribute(), and _characters() functions to" << endl + << "// serialize the wildcard content." << endl + << "//" << endl + << "}"; + + } + }; + + struct AttributeCallback: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& s ( + eimpl (dynamic_cast (a.scope ()))); + + if (a.optional ()) + { + os << "bool " << s << "::" << endl + << epresent (a) << " ()" + << "{" + << "// TODO: return true if the attribute is present." << endl + << "//" << endl + << "}"; + } + + String const& ret (ret_type (a.type ())); + + os << ret << " " << s << "::" << endl + << ename (a) << " ()" + << "{" + << "// TODO: return the attribute data." << endl + << "//" << endl + << "}"; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + String const& s ( + eimpl (dynamic_cast (a.scope ()))); + + os << "bool " << s << "::" << endl + << enext (a) << " ()" + << "{" + << "// TODO: return true if there is another wildcard" << endl + << "// attribute to serialize." << endl + << "//" << endl + << "}"; + + if (stl) + { + os << "void " << s << "::" << endl + << ename (a) << " (::std::string& ns, ::std::string& name)"; + } + else + { + os << "void " << s << "::" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free)"; + } + + os << "{" + << "// TODO: return the name and namespace of the attribute" << endl + << "// corresponding to the wildcard." << endl + << "//" << endl + << "}"; + + os << "void " << s << "::" << endl + << eserialize (a) << " ()" + << "{" + << "// TODO: use the _characters() function to serialize" << endl + << "// the wildcard content." << endl + << "//" << endl + << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + + String const& name (eimpl (c)); + String const& arg (arg_type (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein && hb) + os << name << "::" << endl + << name << " ()" << endl + << ": " << ename (c) << " (&base_impl_)" + << "{" + << "}"; + + // pre + // + os << "void " << name << "::" << endl; + + if (arg == L"void") + os << "pre ()"; + else + os << "pre (" << arg << " v)"; + + os << "{"; + + if (hb) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + if (arg == arg_type (base)) + { + if (tiein) + { + os << "base_impl_.pre (" << + (arg != L"void" ? "v" : "") << ");"; + } + else if (mixin) + { + os << eimpl (base) << "::pre (" << + (arg != L"void" ? "v" : "") << ");"; + } + } + else + { + if (tiein) + { + os << "// TODO: call " << eimpl (base) << "::pre ()." << endl + << "//" << endl; + } + else if (mixin) + { + os << "// TODO: call base_impl_.pre ()." << endl + << "//" << endl; + } + } + + } + else if (arg != L"void") + { + os << "// TODO" << endl + << "//" << endl; + } + + os << "}"; + + // Member callbacks. + // + if (!restriction_p (c)) + { + names (c, names_attribute_callback_); + contains_compositor (c, contains_compositor_callback_); + } + + // post + // + os << "void " << name << "::" << endl + << "post ()" + << "{" + << "}"; + } + + private: + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + } + + Void + generate_impl_source (Context& ctx) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/impl-source.hxx b/xsde/cxx/serializer/impl-source.hxx new file mode 100644 index 0000000..f6303ba --- /dev/null +++ b/xsde/cxx/serializer/impl-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/impl-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_IMPL_SOURCE_HXX +#define CXX_SERIALIZER_IMPL_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_impl_source (Context&); + } +} + +#endif // CXX_SERIALIZER_IMPL_SOURCE_HXX diff --git a/xsde/cxx/serializer/name-processor.cxx b/xsde/cxx/serializer/name-processor.cxx new file mode 100644 index 0000000..d68b823 --- /dev/null +++ b/xsde/cxx/serializer/name-processor.cxx @@ -0,0 +1,1409 @@ +// file : xsde/cxx/serializer/name-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + // + // + typedef Cult::Containers::Set NameSet; + + class Context: public CXX::Context + { + public: + Context (CLI::Options const& ops, + SemanticGraph::Schema& root, + SemanticGraph::Path const& file) + : CXX::Context (std::wcerr, + root, + "s:name", + "char", + ops.value (), + ops.value (), + "", // export symbol + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + schema_path_ (file), + skel_suffix_ (ops.value ()), + impl_suffix_ (ops.value ()), + schema (root), + schema_path (schema_path_), + impl (ops.value () || + ops.value ()), + tiein (!ops.value () && + !ops.value ()), + skel_suffix (skel_suffix_), + impl_suffix (impl_suffix_), + global_type_names (global_type_names_), + validation (!ops.value ()), + polymorphic (ops.value ()) + { + } + + protected: + Context (Context& c) + : CXX::Context (c), + schema (c.schema), + schema_path (c.schema_path), + impl (c.impl), + tiein (c.tiein), + skel_suffix (c.skel_suffix), + impl_suffix (c.impl_suffix), + global_type_names (c.global_type_names), + validation (c.validation), + polymorphic (c.polymorphic) + { + } + + public: + String + find_name (String const& n, String const& suffix, NameSet& set) + { + String name (escape (n + suffix)); + + for (UnsignedLong i (1); set.find (name) != set.end (); ++i) + { + std::wostringstream os; + os << i; + name = escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + String + find_name (String const& n, NameSet& set) + { + return find_name (n, L"", set); + } + + private: + SemanticGraph::Path const schema_path_; + String const skel_suffix_; + String const impl_suffix_; + + Cult::Containers::Map global_type_names_; + + public: + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + Boolean const impl; + Boolean const tiein; + String const& skel_suffix; + String const& impl_suffix; + + Cult::Containers::Map& global_type_names; + + Boolean validation; + Boolean polymorphic; + }; + + // Primary names. + // + struct PrimaryParticle: Traversal::Element, + Traversal::Any, + Context + { + PrimaryParticle (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Element; + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + ec.set ("s:name", find_name (e.name (), set_)); + else + { + Element* prot = ec.get ( + "xsd-frontend-restriction-correspondence"); + + ec.set ("s:name", prot->context ().get ("s:name")); + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + using SemanticGraph::Any; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + ac.set ("s:name", find_name (L"any", set_)); + } + else + { + Any* prot = ac.get ( + "xsd-frontend-restriction-correspondence"); + + ac.set ("s:name", prot->context ().get ("s:name")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct PrimaryAttribute: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + PrimaryAttribute (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Attribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + ac.set ("s:name", find_name (a.name (), set_)); + } + else + { + Attribute* prot = ac.get ( + "xsd-frontend-restriction-correspondence"); + + ac.set ("s:name", prot->context ().get ("s:name")); + } + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + using SemanticGraph::AnyAttribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + ac.set ("s:name", find_name (L"any_attribute", set_)); + } + else + { + AnyAttribute* prot = ac.get ( + "xsd-frontend-restriction-correspondence"); + + ac.set ("s:name", prot->context ().get ("s:name")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + // Secondary names. + // + + struct ParticleTag: Traversal::Element, + Traversal::Any, + Traversal::Choice, + Traversal::Sequence, + Context + { + ParticleTag (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + using SemanticGraph::Element; + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + { + String const base (ec.get ("s:name")); + ec.set ("s:tag", find_name (base, L"_tag", set_)); + } + else + { + Element* prot = ec.get ( + "xsd-frontend-restriction-correspondence"); + + ec.set ("s:tag", prot->context ().get ("s:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + using SemanticGraph::Any; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + String const& base (ac.get ("s:name")); + ac.set ("s:tag", find_name (base, L"_tag", set_)); + } + else + { + Any* prot = ac.get ( + "xsd-frontend-restriction-correspondence"); + + ac.set ("s:tag", prot->context ().get ("s:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Compositor; + + SemanticGraph::Context& cc (c.context ()); + + if (!restriction_) + { + cc.set ("s:tag", find_name (L"choice", L"_tag", set_)); + } + else + { + Compositor* prot = cc.get ( + "xsd-frontend-restriction-correspondence"); + + cc.set ("s:tag", prot->context ().get ("s:tag")); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + using SemanticGraph::Compositor; + + SemanticGraph::Context& sc (s.context ()); + + if (!restriction_) + { + sc.set ("s:tag", find_name (L"sequence", L"_tag", set_)); + } + else + { + Compositor* prot = sc.get ( + "xsd-frontend-restriction-correspondence"); + + sc.set ("s:tag", prot->context ().get ("s:tag")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct SecondaryCompositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + SecondaryCompositor (Context& c, NameSet& set, Boolean restriction) + : Context (c), + set_ (set), + restriction_ (restriction), + particle_tag_ (c, set, restriction) + { + contain_particle_tag_ >> particle_tag_; + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it cannot be used in restriction. + // + if (a.contained_compositor ().min () == 0) + { + a.context ().set ( + "s:present", find_name (L"all", L"_present", set_)); + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () == c.contains_end ()) + return; + + SemanticGraph::Context& cc (c.context ()); + + if (!restriction_) + { + if (c.max () != 1) + cc.set ("s:next", find_name (L"choice", L"_next", set_)); + else if (c.min () == 0) + cc.set ("s:present", find_name (L"choice", L"_present", set_)); + + // Tags. + // + cc.set ("s:arm-tag", find_name (L"choice", L"_arm_tag", set_)); + Traversal::Choice::contains (c, contain_particle_tag_); + cc.set ("s:arm", find_name (L"choice", L"_arm", set_)); + } + else + { + SemanticGraph::Compositor& b ( + *cc.get ( + "xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + + if (b.max () != 1) + { + cc.set ("s:next", bc.get ("s:next")); + + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (c.min () == 0) + cc.set ("s:present", + find_name (L"choice", L"_present", set_)); + } + else if (b.min () == 0) + cc.set ("s:present", bc.get ("s:present")); + + // Tags. + // + cc.set ("s:arm-tag", bc.get ("s:arm-tag")); + Traversal::Choice::contains (c, contain_particle_tag_); + cc.set ("s:arm", bc.get ("s:arm")); + } + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + SemanticGraph::Context& sc (s.context ()); + + if (!restriction_) + { + if (s.max () != 1) + sc.set ("s:next", find_name (L"sequence", L"_next", set_)); + else if (s.min () == 0) + sc.set ("s:present", find_name (L"sequence", L"_present", set_)); + } + else + { + // Root compositor that models inheritance by extension + // may not have an association. + // + if (sc.count ("xsd-frontend-restriction-correspondence")) + { + SemanticGraph::Compositor& b ( + *sc.get ( + "xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + + if (b.max () != 1) + { + sc.set ("s:next", bc.get ("s:next")); + + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (s.min () == 0) + sc.set ("s:present", + find_name (L"sequence", L"_present", set_)); + } + else if (b.min () == 0) + sc.set ("s:present", bc.get ("s:present")); + } + } + + Traversal::Sequence::traverse (s); + } + + private: + NameSet& set_; + Boolean restriction_; + + ParticleTag particle_tag_; + Traversal::ContainsParticle contain_particle_tag_; + }; + + struct SecondaryParticle: Traversal::Element, + Traversal::Any, + Context + { + SecondaryParticle (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + Boolean poly ( + polymorphic && !e.type ().context ().count ("anonymous")); + + SemanticGraph::Context& ec (e.context ()); + + if (!restriction_) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& base (ec.get ("s:name")); + + if (min == 0 && max == 1) + ec.set ("s:present", find_name (base + L"_present", set_)); + else if (max != 1) + ec.set ("s:next", find_name (base + L"_next", set_)); + + ec.set ("s:serializer", find_name (base + L"_serializer", set_)); + ec.set ("s:member", find_name (base + L"_serializer_", set_)); + + if (poly) + ec.set ("s:member-map", + find_name (base + L"_serializer_map_", set_)); + } + else + { + SemanticGraph::Element& b ( + *ec.get ( + "xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + UnsignedLong min (b.min ()), max (b.max ()); + + if (min == 0 && max == 1) + ec.set ("s:present", bc.get ("s:present")); + else if (max != 1) + { + ec.set ("s:next", bc.get ("s:next")); + + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (e.min () == 0) + { + String const& base (bc.get ("s:name")); + ec.set ("s:present", find_name (base + L"_present", set_)); + } + } + + ec.set ("s:serializer", bc.get ("s:serializer")); + ec.set ("s:member", bc.get ("s:member")); + + if (poly) + ec.set ("s:member-map", bc.get ("s:member-map")); + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + using SemanticGraph::Any; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + UnsignedLong min (a.min ()), max (a.max ()); + String const& base (ac.get ("s:name")); + + if (min == 0 && max == 1) + { + ac.set ("s:present", find_name (base + L"_present", set_)); + } + else if (max != 1) + { + ac.set ("s:next", find_name (base + L"_next", set_)); + } + + ac.set ("s:serialize", find_name (L"serialize_" + base, set_)); + } + else + { + Any& b ( + *ac.get ("xsd-frontend-restriction-correspondence")); + + SemanticGraph::Context& bc (b.context ()); + UnsignedLong min (b.min ()), max (b.max ()); + + if (min == 0 && max == 1) + { + ac.set ("s:present", bc.get ("s:present")); + } + else if (max != 1) + { + ac.set ("s:next", bc.get ("s:next")); + + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (a.min () == 0) + { + String const& base (bc.get ("s:name")); + ac.set ("s:present", find_name (base + L"_present", set_)); + } + } + + ac.set ("s:serialize", bc.get ("s:serialize")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + struct SecondaryAttribute: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + SecondaryAttribute (Context& c, NameSet& set, Boolean restriction) + : Context (c), set_ (set), restriction_ (restriction) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + using SemanticGraph::Attribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + String const& base (ac.get ("s:name")); + + if (a.optional ()) + ac.set ("s:present", find_name (base + L"_present", set_)); + + ac.set ("s:serializer", find_name (base + L"_serializer", set_)); + ac.set ("s:member", find_name (base + L"_serializer_", set_)); + } + else + { + Attribute& b ( + *ac.get ("xsd-frontend-restriction-correspondence")); + SemanticGraph::Context& bc (b.context ()); + + if (a.optional ()) + ac.set ("s:present", bc.get ("s:present")); + + ac.set ("s:serializer", bc.get ("s:serializer")); + ac.set ("s:member", bc.get ("s:member")); + } + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + using SemanticGraph::AnyAttribute; + + SemanticGraph::Context& ac (a.context ()); + + if (!restriction_) + { + String const& base (ac.get ("s:name")); + + ac.set ("s:next", find_name (base + L"_next", set_)); + ac.set ("s:serialize", find_name (L"serialize_" + base, set_)); + } + else + { + AnyAttribute& b ( + *ac.get ( + "xsd-frontend-restriction-correspondence")); + SemanticGraph::Context& bc (b.context ()); + + ac.set ("s:next", bc.get ("s:next")); + ac.set ("s:serialize", bc.get ("s:serialize")); + } + } + + private: + NameSet& set_; + Boolean restriction_; + }; + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + SemanticGraph::Context& cc (c.context ()); + + // Use processed name. + // + String const& name (cc.get ("s:name")); + + // We leave this set around to allow other mappings to use + // this information. + // + cc.set ("cxx-serializer-name-processor-member-set", NameSet ()); + NameSet& member_set ( + cc.get ("cxx-serializer-name-processor-member-set")); + + member_set.insert (name); + + // Add our base's members to the initial list unless we are + // inheriting by restriction in which case we need to have + // the same names as our base. + // + Boolean restriction (false); + + if (c.inherits_p ()) + { + // @@ What if this types name is the same as one of base's + // members? + // + SemanticGraph::Type& base (c.inherits ().base ()); + + if (base.is_a ()) + { + if (!base.context ().count ( + "cxx-serializer-name-processor-member-set")) + { + dispatch (base); + } + + NameSet const& base_set ( + base.context ().get ( + "cxx-serializer-name-processor-member-set")); + + member_set.insert (base_set.begin (), base_set.end ()); + + // Inheritance by restriction from anyType is a special case. + // + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + } + } + + // First assign the "primary" names. + // + { + if (c.contains_compositor_p ()) + { + PrimaryParticle particle (*this, member_set, restriction); + Traversal::Compositor compositor; + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + + // + // + PrimaryAttribute attribute (*this, member_set, restriction); + Traversal::Names names (attribute); + + Complex::names (c, names); + } + + // Assign "secondary" names. + // + { + if (c.contains_compositor_p ()) + { + SecondaryParticle particle (*this, member_set, restriction); + SecondaryCompositor compositor (*this, member_set, restriction); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + contains_compositor >> compositor >> contains_particle; + + contains_particle >> compositor; + contains_particle >> particle; + + Complex::contains_compositor (c, contains_compositor); + } + + // + // + SecondaryAttribute attribute (*this, member_set, restriction); + Traversal::Names names (attribute); + + Complex::names (c, names); + } + } + }; + + + // + // + struct GlobalType: Traversal::Type, Context + { + GlobalType (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + String const& n (t.name ()); + SemanticGraph::Context& tc (t.context ()); + + String name (find_name (n + skel_suffix, set_)); + tc.set ("s:name", name); + + if (tiein) + tc.set ("s:tiein", escape (n + L"_impl_")); + + // Note that we do not add this name to the set so that it + // does not influence other names. + // + if (impl) + tc.set ("s:impl", escape (n + impl_suffix)); + } + + private: + NameSet& set_; + }; + + + struct Namespace: Traversal::Namespace, Context + { + Namespace (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& ns) + { + SemanticGraph::Context& nsc (ns.context ()); + String const& name (ns.name ()); + + // Use a name set associated with this namespace if present. + // This will make sure that we don't get any conflicts in the + // multi-mapping translation case. Note that here we assume + // that all mappings traverse schemas in the same order which + // is currently the case. + // + if (global_type_names.find (name) == global_type_names.end ()) + { + if (!nsc.count ("name-set")) + nsc.set ("name-set", NameSet ()); + + NameSet& s (nsc.get ("name-set")); + global_type_names[name] = &s; + } + + NameSet& type_set (*global_type_names[name]); + + GlobalType type (*this, type_set); + Traversal::Names names (type); + + Traversal::Namespace::names (ns, names); + } + }; + + struct FundType : Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities, + + Context + + { + FundType (Context& c) + : Context (c) + { + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + set_names (t, "any_type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + set_names (t, "any_simple_type"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + set_names (t, "boolean"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + set_names (t, "byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + set_names (t, "unsigned_byte"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + set_names (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + set_names (t, "unsigned_short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + set_names (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + set_names (t, "unsigned_int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + set_names (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + set_names (t, "unsigned_long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + set_names (t, "integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + set_names (t, "non_positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + set_names (t, "non_negative_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + set_names (t, "positive_integer"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + set_names (t, "negative_integer"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + set_names (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + set_names (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + set_names (t, "decimal"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + set_names (t, "string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + set_names (t, "normalized_string"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + set_names (t, "token"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + set_names (t, "nmtoken"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + set_names (t, "nmtokens"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + set_names (t, "name"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + set_names (t, "ncname"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + set_names (t, "language"); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + set_names (t, "qname"); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + set_names (t, "id"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + set_names (t, "idref"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + set_names (t, "idrefs"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + set_names (t, "uri"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + set_names (t, "base64_binary"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + set_names (t, "hex_binary"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + set_names (t, "date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + set_names (t, "date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + set_names (t, "duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + set_names (t, "gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + set_names (t, "gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + set_names (t, "gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + set_names (t, "gyear"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + set_names (t, "gyear_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + set_names (t, "time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + set_names (t, "entity"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + set_names (t, "entities"); + } + + private: + String + make_skel_name (String const& base) + { + return escape (base + skel_suffix); + } + + String + make_impl_name (String const& base) + { + return escape (base + impl_suffix); + } + + Void + set_names (SemanticGraph::Type& t, String const& name) + { + SemanticGraph::Context& c (t.context ()); + + WideChar const* ns = validation + ? L"::xsde::cxx::serializer::validating::" + : L"::xsde::cxx::serializer::non_validating::"; + + String skel (make_skel_name (name)); + c.set ("s:name", skel); + c.set ("s:real-name", ns + skel); + + String impl (make_impl_name (name)); + c.set ("s:impl", impl); + c.set ("s:real-impl", ns + impl); + + c.set ("s:post", L"post_" + name); + + if (tiein) + c.set ("s:tiein", name + L"_impl_"); + } + }; + + // Go into sourced/included/imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Sources, + Traversal::Includes, + Traversal::Imports + { + virtual Void + traverse (SemanticGraph::Sources& sr) + { + SemanticGraph::Schema& s (sr.schema ()); + + if (!s.context ().count ("cxx-serializer-name-processor-seen")) + { + s.context ().set ("cxx-serializer-name-processor-seen", true); + Traversal::Sources::traverse (sr); + } + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-serializer-name-processor-seen")) + { + s.context ().set ("cxx-serializer-name-processor-seen", true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-serializer-name-processor-seen")) + { + s.context ().set ("cxx-serializer-name-processor-seen", true); + Traversal::Imports::traverse (i); + } + } + }; + + // Go into implied schemas while making sure we don't process + // the same stuff more than once. + // + struct Implies: Traversal::Implies + { + virtual Void + traverse (SemanticGraph::Implies& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("cxx-serializer-name-processor-seen")) + { + s.context ().set ("cxx-serializer-name-processor-seen", true); + Traversal::Implies::traverse (i); + } + } + }; + + Void + process_impl (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + Context ctx (ops, tu, file); + + if (tu.names_begin ()->named ().name () == + L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + schema >> schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + else + { + // Pass one - assign names to fundamental types. + // + { + Traversal::Schema schema; + Implies implies; + Traversal::Schema xs_schema; + + schema >> implies >> xs_schema; + + Traversal::Names xs_schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + FundType fund_type (ctx); + + xs_schema >> xs_schema_names >> ns >> ns_names >> fund_type; + + schema.dispatch (tu); + } + + // Pass two - assign names to global types. This pass cannot + // be combined with pass three because of possible recursive + // schema inclusions. Also note that we check first if this + // schema has already been processed which may happen in the + // file-per-type compilation mode. + // + if (!tu.context ().count ("cxx-serializer-name-processor-seen")) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx); + + schema >> schema_names >> ns; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("cxx-serializer-name-processor-seen", true); + + schema.dispatch (tu); + } + + // Pass three - assign names inside complex types. Here we don't + // need to go into included/imported schemas. + // + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + Complex complex (ctx); + + ns_names >> complex; + + schema.dispatch (tu); + } + } + } + } + + Void NameProcessor:: + process (CLI::Options const& ops, + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file) + { + process_impl (ops, tu, file); + } + } +} diff --git a/xsde/cxx/serializer/name-processor.hxx b/xsde/cxx/serializer/name-processor.hxx new file mode 100644 index 0000000..bf69ba6 --- /dev/null +++ b/xsde/cxx/serializer/name-processor.hxx @@ -0,0 +1,32 @@ +// file : xsde/cxx/serializer/name-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_NAME_PROCESSOR_HXX +#define CXX_SERIALIZER_NAME_PROCESSOR_HXX + +#include + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + using namespace Cult::Types; + + class NameProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_SERIALIZER_NAME_PROCESSOR_HXX diff --git a/xsde/cxx/serializer/serializer-forward.cxx b/xsde/cxx/serializer/serializer-forward.cxx new file mode 100644 index 0000000..60d5ce5 --- /dev/null +++ b/xsde/cxx/serializer/serializer-forward.cxx @@ -0,0 +1,112 @@ +// file : xsde/cxx/serializer/serializer-forward.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + os << "class " << ename (e) << ";"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + os << "class " << ename (l) << ";"; + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + os << "class " << ename (u) << ";"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& c) + { + os << "class " << ename (c) << ";"; + } + }; + } + + Void + generate_serializer_forward (Context& ctx) + { + ctx.os << "// Forward declarations" << endl + << "//" << endl; + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + schema.dispatch (ctx.schema_root); + + ctx.os << endl; + } + } +} diff --git a/xsde/cxx/serializer/serializer-forward.hxx b/xsde/cxx/serializer/serializer-forward.hxx new file mode 100644 index 0000000..239d82f --- /dev/null +++ b/xsde/cxx/serializer/serializer-forward.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/serializer-forward.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_SERIALIZER_FORWARD_HXX +#define CXX_SERIALIZER_SERIALIZER_FORWARD_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_serializer_forward (Context&); + } +} + +#endif // CXX_SERIALIZER_SERIALIZER_FORWARD_HXX diff --git a/xsde/cxx/serializer/serializer-header.cxx b/xsde/cxx/serializer/serializer-header.cxx new file mode 100644 index 0000000..6ba57f1 --- /dev/null +++ b/xsde/cxx/serializer/serializer-header.cxx @@ -0,0 +1,2006 @@ +// file : xsde/cxx/serializer/serializer-header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + // Override classes override pure virtual functions in the base. + // Should be in sync with declaration generators below. Used in + // tiein implementation. + // + + struct CompositorCallbackOverride: Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallbackOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (max != 1 && min != 0) + { + os << "virtual bool" << endl + << enext (c) << " ();" + << endl; + } + + if (min != 0) + { + os << "virtual " << earm_tag (c) << endl + << earm (c) << " ();" + << endl; + } + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (max != 1 && min != 0) + { + os << "virtual bool" << endl + << enext (s) << " ();" + << endl; + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallbackOverride: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallbackOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + if (max != 1 && min != 0) + { + os << "virtual bool" << endl + << enext (e) << " ();" + << endl; + } + + String const& ret (ret_type (e.type ())); + + if (ret != L"void") + { + os << "virtual " << ret << endl + << ename (e) << " ();" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min != 0 && + !a.contained_particle ().compositor ().is_a< + SemanticGraph::Choice> ()) + { + if (max != 1) + { + os << "virtual bool" << endl + << enext (a) << " ();" + << endl; + } + + if (stl) + { + os << "virtual void" << endl + << ename (a) << " (::std::string& ns, ::std::string& name);" + << endl; + } + else + { + os << "virtual void" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free);" + << endl; + } + + os << "virtual void" << endl + << eserialize (a) << " ();" + << endl; + } + } + }; + + struct AttributeCallbackOverride: Traversal::Attribute, Context + { + AttributeCallbackOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& ret (ret_type (a.type ())); + + if (ret != L"void") + { + os << "virtual " << ret << endl + << ename (a) << " ();" + << endl; + } + } + }; + + struct BaseOverride: Traversal::Type, + Traversal::Enumeration, + Traversal::List, + Traversal::Union, + Traversal::Complex, + Context + { + BaseOverride (Context& c) + : Context (c), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + // pre + // + String const& arg (arg_type (t)); + + if (arg != L"void") + { + os << "virtual void" << endl + << "pre (" << arg << ");" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + SemanticGraph::Type& t (e); + traverse (t); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + SemanticGraph::Type& t (l); + traverse (t); + + // item + // + String const& ret (ret_type (l.argumented ().type ())); + + if (ret != L"void") + { + os << "virtual " << ret << endl + << unclash (ename (l), "item") << " ();" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Union& u) + { + SemanticGraph::Type& t (u); + traverse (t); + + // serialize_content + // + os << "virtual void" << endl + << "_serialize_content ();" + << endl; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + SemanticGraph::Type& t (c); + traverse (t); + + // Member callbacks. + // + if (!restriction_p (c)) + { + Traversal::Complex::names (c, names_attribute_callback_); + Traversal::Complex::contains_compositor ( + c, contains_compositor_callback_); + } + } + + private: + CompositorCallbackOverride compositor_callback_; + ParticleCallbackOverride particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallbackOverride attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + + // + // + + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + String fq_base (fq_name (base)); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << fq_base + << "{" + << "public:" << endl + << "// Serializer callbacks. Override them in your " << + "implementation." << endl + << "//" << endl + << endl; + + // pre + // + String const& arg (arg_type (e)); + String const& base_arg (arg_type (base)); + + if (arg == base_arg) + { + os << "// virtual void" << endl; + + if (arg == L"void") + os << "// pre ();" << endl; + else + os << "// pre (" << arg << ") = 0;" << endl; + + os << endl; + } + else + { + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ") = 0;"; + + os << endl; + } + + // post + // + os << "// virtual void" << endl + << "// post ();" << endl; + + if (poly_code) + { + os << endl + << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;"; + } + + if (tiein) + { + os << endl + << "// Constructor." << endl + << "//" << endl + << name << " (" << fq_base << "* tiein);" + << endl; + + os << "// Implementation details." << endl + << "//" << endl; + + // If our base has pure virtual functions, override them here. + // + inherits (e); + + os << "protected:" << endl + << name << "* " << etiein (e) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + os << "};"; + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + String item_type (fq_name (t)); + + String item (unclash (name, "item")); + String item_next (unclash (name, "item_next")); + + os << "class " << name << ": public " << simple_base + << "{" + << "public:" << endl + << "// Serializer callbacks. Override them in your " << + "implementation." << endl + << "//" << endl + << endl; + + // pre + // + String const& arg (arg_type (l)); + + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ") = 0;"; + + os << endl; + + // item + // + os << "virtual bool" << endl + << item_next << " ();" + << endl; + + String const& ret (ret_type (t)); + + os << "virtual " << ret << endl + << item << " ()" << (ret != L"void" ? " = 0" : "") << ";" + << endl; + + // post + // + os << "// virtual void" << endl + << "// post ();" << endl + << endl; + + // + // + os << "// Serializer construction API." << endl + << "//" << endl; + + // item_serializer + // + os << "void" << endl + << unclash (name, "item_serializer") << " (" << item_type << "&);" + << endl; + + // serializers + // + os << "void" << endl + << "serializers (" << item_type << "& /* item */);" + << endl; + + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + + // c-tor + // + os << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + + if (poly_code) + { + os << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;" + << endl; + } + + // + // + os << "// Implementation." << endl + << "//" << endl + << "public:" << endl; + + os << "virtual void" << endl + << "_serialize_content ();" + << endl; + + os << "protected:" << endl; + + if (tiein) + { + os << name << "* " << etiein (l) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + os << item_type << "* _xsde_" << item << "_;" + << "};"; + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename (u)); + + os << "class " << name << ": public " << simple_base + << "{" + << "public:" << endl + << "// Serializer callbacks. Override them in your " << + "implementation." << endl + << "//" << endl + << endl; + + // pre + // + String const& arg (arg_type (u)); + + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ") = 0;"; + + os << endl; + + // serialize_content + // + os << "virtual void" << endl + << "_serialize_content () = 0;" + << endl; + + // post + // + os << "// virtual void" << endl + << "// post ();" << endl; + + if (poly_code) + { + os << endl + << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;"; + } + + if (tiein) + { + // c-tor + // + os << endl + << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + + // + // + os << "// Implementation details." << endl + << "//" << endl + << "protected:" << endl + << name << "* " << etiein (u) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + os << "};"; + } + }; + + // + // + struct ParticleTag: Traversal::Particle, Context + { + ParticleTag (Context& c) + : Context (c), first_ (true) + { + } + + virtual Void + traverse (Type& p) + { + if (first_) + first_ = false; + else + os << "," << endl; + + os << etag (p); + } + + private: + Boolean first_; + }; + + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context ().count ("xsd-frontend-restriction-correspondence")) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + if (SemanticGraph::Compositor* b = correspondent (c)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + UnsignedLong cmin (c.min ()), bmax (b->max ()); + + if (bmax != 1 && cmin == 0) + { + os << "virtual bool" << endl + << epresent (c) << " ();" + << endl; + } + } + else + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (c) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (c) << " ()" << (min != 0 ? " = 0" : "") << ";" + << endl; + } + + // + // + os << "enum " << earm_tag (c) + << "{"; + + { + ParticleTag particle (*this); + Traversal::ContainsParticle contain_particle (particle); + Traversal::Choice::contains (c, contain_particle); + } + + os << "};"; + + os << "virtual " << earm_tag (c) << endl + << earm (c) << " ()" << (min != 0 ? " = 0" : "") << ";" + << endl; + } + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // Root compositor that models inheritance by extension + // may not have an association so we may fall through + // in to the 'else' case even though this is a restriction. + // This is ok since such a compositor always has max == + // min == 1 and so nothing is generated. + // + if (SemanticGraph::Compositor* b = correspondent (s)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + UnsignedLong smin (s.min ()); + UnsignedLong bmax (b->max ()); + + if (bmax != 1 && smin == 0) + { + os << "virtual bool" << endl + << epresent (s) << " ();" + << endl; + } + } + else + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (s) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (s) << " ()" << (min != 0 ? " = 0" : "") << ";" + << endl; + } + } + + Traversal::Sequence::traverse (s); + } + }; + + struct ParticleCallback: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (SemanticGraph::Element* b = correspondent (e)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (b->max () != 1 && e.min () == 0) + { + os << "virtual bool" << endl + << epresent (e) << " ();" + << endl; + } + } + else + { + UnsignedLong min (e.min ()), max (e.max ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (e) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (e) << " ()" << (min != 0 ? " = 0" : "") << ";" + << endl; + } + + String const& ret (ret_type (e.type ())); + + // Make it non-pure-virtual only if the return type is void. + // + os << "virtual " << ret << endl + << ename (e) << " ()" << (ret != L"void" ? " = 0;" : ";") + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + if (SemanticGraph::Any* b = correspondent (a)) + { + // Add the *_present callback if this is a restriction + // of sequence to optional. + // + if (b->max () != 1 && a.min () == 0) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + } + else + { + UnsignedLong min (a.min ()), max (a.max ()); + + // Generate pure virtual callbacks unless we are optional + // or in choice. + // + Boolean pv ( + min != 0 && + !a.contained_particle ().compositor ().is_a< + SemanticGraph::Choice> ()); + + if (min == 0 && max == 1) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + else if (max != 1) + { + os << "virtual bool" << endl + << enext (a) << " ()" << (pv ? " = 0" : "") << ";" + << endl; + } + + if (stl) + { + os << "virtual void" << endl + << ename (a) << " (::std::string& ns, ::std::string& name)" << + (pv ? " = 0;" : ";") + << endl; + } + else + { + os << "virtual void" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free)" << (pv ? " = 0;" : ";") + << endl; + } + + os << "virtual void" << endl + << eserialize (a) << " ()" << (pv ? " = 0;" : ";") + << endl; + } + } + }; + + struct AttributeCallback: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + if (a.optional ()) + { + os << "virtual bool" << endl + << epresent (a) << " ();" + << endl; + } + + String const& ret (ret_type (a.type ())); + + // Make it non-pure-virtual only if the return type is void. + // + os << "virtual " << ret << endl + << ename (a) << " ()" << (ret != L"void" ? " = 0;" : ";") + << endl; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + os << "virtual bool" << endl + << enext (a) << " ();" + << endl; + + if (stl) + { + os << "virtual void" << endl + << ename (a) << " (::std::string& ns, ::std::string& name);" + << endl; + } + else + { + os << "virtual void" << endl + << ename (a) << " (const char*& ns, const char*& name, " << + "bool& free);" + << endl; + } + + os << "virtual void" << endl + << eserialize (a) << " ();" + << endl; + } + }; + + + // + // + struct ParticleAccessor: Traversal::Element, Context + { + ParticleAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& serializer (eserializer (e)); + + os << "void" << endl + << serializer << " (" << fq_name (e.type ()) << "&);" + << endl; + + if (poly_code && !anonymous (e.type ())) + { + os << "void" << endl + << eserializer (e) << " (" << serializer_map << "&);" + << endl; + } + } + }; + + struct AttributeAccessor: Traversal::Attribute, Context + { + AttributeAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << "void" << endl + << eserializer (a) << " (" << fq_name (a.type ()) << "&);" + << endl; + } + }; + + + // + // + struct ParticleMember: Traversal::Element, Context + { + ParticleMember (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String type (fq_name (e.type ())); + + os << type << "* " << emember (e) << ";"; + + if (poly_code && !anonymous (e.type ())) + { + os << serializer_map << "* " << emember_map (e) << ";" + << endl; + } + } + }; + + struct AttributeMember: Traversal::Attribute, Context + { + AttributeMember (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << fq_name (a.type ()) << "* " << emember (a) << ";"; + } + }; + + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c), + particle_accessor_ (c), + attribute_accessor_ (c), + particle_member_ (c), + attribute_member_ (c) + { + // Callback. + // + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + + // Accessor. + // + contains_compositor_accessor_ >> compositor_accessor_; + compositor_accessor_ >> contains_particle_accessor_; + contains_particle_accessor_ >> compositor_accessor_; + contains_particle_accessor_ >> particle_accessor_; + + names_attribute_accessor_ >> attribute_accessor_; + + // Member. + // + contains_compositor_member_ >> compositor_member_; + compositor_member_ >> contains_particle_member_; + contains_particle_member_ >> compositor_member_; + contains_particle_member_ >> particle_member_; + + names_attribute_member_ >> attribute_member_; + } + + virtual Void + traverse (Type& c) + { + String const& name (ename (c)); + + // In case of an inheritance-by-restriction, we don't need to + // generate serializer callbacks, etc. since they are the same + // as in the base. We only need the serialization/validation code. + // + Boolean restriction (restriction_p (c)); + + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + Boolean haa (has (c)); + + Boolean hra (false); // Has required attribute. + if (ha) + { + RequiredAttributeTest test (hra); + Traversal::Names names_test (test); + names (c, names_test); + } + + // + // + os << "class " << name << ": public "; + + if (hb) + os << (mixin ? "virtual " : "") << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "{" + << "public:" << endl + << "// Serializer callbacks. Override them in your " << + "implementation." << endl + << "//" << endl + << endl; + + // pre + // + String const& arg (arg_type (c)); + Boolean same (hb && arg == arg_type (c.inherits ().base ())); + + if (same) + { + os << "// virtual void" << endl; + + if (arg == L"void") + os << "// pre ();" << endl; + else + os << "// pre (" << arg << ") = 0;" << endl; + + os << endl; + } + else + { + os << "virtual void" << endl; + + if (arg == L"void") + os << "pre ();"; + else + os << "pre (" << arg << ") = 0;"; + + os << endl; + } + + // Member callbacks. + // + if (!restriction) + { + if (ha || haa) + { + os << "// Attributes." << endl + << "//" << endl; + + names (c, names_attribute_callback_); + } + } + + if (he || hae) + { + if (!restriction) + { + os << "// Elements." << endl + << "//" << endl; + } + + contains_compositor (c, contains_compositor_callback_); + } + + // post + // + os << "// virtual void" << endl + << "// post ();" << endl + << endl; + + // + // + if (!restriction && (he || ha)) + { + os << "// Serializer construction API." << endl + << "//" << endl; + + os << "void" << endl + << "serializers ("; + + { + SerializerParamDecl decl (*this, false); + decl.traverse (c); + } + + os << ");" + << endl; + + if (ha) + { + os << "// Individual attribute serializers." << endl + << "//" << endl; + + names (c, names_attribute_accessor_); + } + + if (he) + { + os << "// Individual element serializers." << endl + << "//" << endl; + + contains_compositor (c, contains_compositor_accessor_); + } + } + + if (!restriction && (he || ha) && reset) + { + os << "virtual void" << endl + << "_reset ();" + << endl; + } + + // Default c-tor. + // + if (tiein || (!restriction && (he || ha))) + { + os << "// Constructor." << endl + << "//" << endl; + + if (hb && tiein) + os << name << " (" << fq_name (c.inherits ().base ()) << + "* tiein);" + << endl; + else + os << name << " ();" + << endl; + } + + if (poly_code) + { + os << "public:" << endl + << "static const char*" << endl + << "_static_type ();" + << endl + << "virtual const char*" << endl + << "_dynamic_type () const;" + << endl; + } + + // Implementation. + // + if (tiein || he || ha || hae || haa) + { + os << "// Implementation." << endl + << "//" << endl + << "public:" << endl; + + // If our base has pure virtual functions, override them here. + // + if (tiein && hb) + inherits (c); + + if (ha || haa) + { + os << "virtual void" << endl + << "_serialize_attributes ();" + << endl; + } + + if (he || hae) + { + os << "virtual void" << endl + << "_serialize_content ();" + << endl; + } + } + + if (tiein) + { + os << "protected:" << endl + << name << "* " << etiein (c) << ";" + << name << " (" << name << "*, void*);" + << endl; + } + + if (!restriction && (he || ha)) + { + os << "protected:" << endl; + + if (ha) + names (c, names_attribute_member_); + + if (he) + contains_compositor (c, contains_compositor_member_); + } + + os << "};"; + } + + private: + // + // + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + + // + // + Traversal::Compositor compositor_accessor_; + ParticleAccessor particle_accessor_; + Traversal::ContainsCompositor contains_compositor_accessor_; + Traversal::ContainsParticle contains_particle_accessor_; + + AttributeAccessor attribute_accessor_; + Traversal::Names names_attribute_accessor_; + + // + // + Traversal::Compositor compositor_member_; + ParticleMember particle_member_; + Traversal::ContainsCompositor contains_compositor_member_; + Traversal::ContainsParticle contains_particle_member_; + + AttributeMember attribute_member_; + Traversal::Names names_attribute_member_; + }; + + struct FundType : Context, + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::Byte, + Traversal::Fundamental::UnsignedByte, + Traversal::Fundamental::Short, + Traversal::Fundamental::UnsignedShort, + Traversal::Fundamental::Int, + Traversal::Fundamental::UnsignedInt, + Traversal::Fundamental::Long, + Traversal::Fundamental::UnsignedLong, + Traversal::Fundamental::Integer, + Traversal::Fundamental::NonPositiveInteger, + Traversal::Fundamental::NonNegativeInteger, + Traversal::Fundamental::PositiveInteger, + Traversal::Fundamental::NegativeInteger, + + Traversal::Fundamental::Boolean, + Traversal::Fundamental::Float, + Traversal::Fundamental::Double, + Traversal::Fundamental::Decimal, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language, + + Traversal::Fundamental::QName, + + Traversal::Fundamental::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary, + + Traversal::Fundamental::Date, + Traversal::Fundamental::DateTime, + Traversal::Fundamental::Duration, + Traversal::Fundamental::Day, + Traversal::Fundamental::Month, + Traversal::Fundamental::MonthDay, + Traversal::Fundamental::Year, + Traversal::Fundamental::YearMonth, + Traversal::Fundamental::Time, + + Traversal::Fundamental::Entity, + Traversal::Fundamental::Entities + { + FundType (Context& c) + : Context (c), xs_ns_ (xs_ns_name ()) + { + impl_ns_ = "::xsde::cxx::serializer::"; + impl_ns_ += (validation ? L"validating" : L"non_validating"); + + if (options.value ()) + { + qname_type_ = L"const " + xs_ns_ + L"::qname*"; + string_type_ = L"const char*"; + } + else + { + qname_type_ = xs_ns_ + L"::qname"; + string_type_ = L"::std::string"; + } + + string_seq_type_ = L"const " + xs_ns_ + L"::string_sequence*"; + buffer_type_ = L"const " + xs_ns_ + L"::buffer*"; + + if (options.value ()) + { + long_type_ = L"long"; + unsigned_long_type_ = L"unsigned long"; + } + else + { + long_type_ = L"long long"; + unsigned_long_type_ = L"unsigned long long"; + } + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + gen_typedef (t, "void"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + gen_typedef (t, "void"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + gen_typedef (t, "bool"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + gen_typedef (t, "signed char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + gen_typedef (t, "unsigned char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + gen_typedef (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + gen_typedef (t, "unsigned short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + gen_typedef (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + gen_typedef (t, "unsigned int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + gen_typedef (t, long_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + gen_typedef (t, unsigned_long_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + gen_typedef (t, "long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + gen_typedef (t, "unsigned long"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + gen_typedef (t, "unsigned long"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + gen_typedef (t, "float"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + gen_typedef (t, "double"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + gen_typedef (t, "double"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + nmtoken_ = gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + // NMTOKENS uses NMTOKEN implementation to serialize individual + // items. As a result, we don't generate NMTOKENS if we didn't + // generate NMTOKEN. Here we assume NMTOKEN is handled before + // NMTOKENS. + // + if(nmtoken_) + gen_typedef (t, string_seq_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + gen_typedef (t, string_type_); + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + gen_typedef (t, qname_type_); + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + idref_ = gen_typedef (t, string_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + // IDREFS uses IDREF implementation to serialize individual items. + // As a result, we don't generate IDREFS if we didn't generate + // IDREF. Here we assume IDREF is handled before IDREFS. + // + if (idref_) + gen_typedef (t, string_seq_type_); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + gen_typedef (t, string_type_); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + gen_typedef (t, buffer_type_); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + gen_typedef (t, buffer_type_); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + gen_typedef (t, xs_ns_ + L"::date"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + gen_typedef (t, xs_ns_ + L"::date_time"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + gen_typedef (t, xs_ns_ + L"::duration"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + gen_typedef (t, xs_ns_ + L"::gday"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth_day"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + gen_typedef (t, xs_ns_ + L"::gyear"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + gen_typedef (t, xs_ns_ + L"::gyear_month"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + gen_typedef (t, xs_ns_ + L"::time"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities&) + { + } + + private: + Boolean + gen_typedef (SemanticGraph::Type& t, String const& type) + { + if (ret_type (t) == type) + { + SemanticGraph::Context& c (t.context ()); + + String const& real_name (c.get ("s:real-name")); + String const& name (c.get ("s:name")); + + os << "typedef " << real_name << " " << name << ";"; + + String const& real_impl (c.get ("s:real-impl")); + String const& impl (c.get ("s:impl")); + + os << "typedef " << real_impl << " " << impl << ";" + << endl; + + return true; + } + + return false; + } + + String xs_ns_; + String impl_ns_; + String qname_type_; + String string_type_; + String buffer_type_; + String string_seq_type_; + String long_type_; + String unsigned_long_type_; + + Boolean idref_; + Boolean nmtoken_; + }; + + struct FundNamespace : Namespace, Context + { + FundNamespace (Context& c) + : Namespace (c), Context (c) + { + } + + void + traverse (Type& ns) + { + pre (ns); + + String impl ("::xsde::cxx::serializer::"); + impl += (validation ? L"validating" : L"non_validating"); + + String const c (char_type); + + os << "// Built-in XML Schema types mapping." << endl + << "//" << endl + << "using ::xsde::cxx::string_sequence;" + << "using ::xsde::cxx::qname;" + << "using ::xsde::cxx::buffer;" + << "using ::xsde::cxx::time_zone;" + << "using ::xsde::cxx::gday;" + << "using ::xsde::cxx::gmonth;" + << "using ::xsde::cxx::gyear;" + << "using ::xsde::cxx::gmonth_day;" + << "using ::xsde::cxx::gyear_month;" + << "using ::xsde::cxx::date;" + << "using ::xsde::cxx::time;" + << "using ::xsde::cxx::date_time;" + << "using ::xsde::cxx::duration;" + << endl; + + os << "// Base serializer skeletons." << endl + << "//" << endl + << "using ::xsde::cxx::serializer::serializer_base;" + << "typedef " << impl << "::empty_content " << + "serializer_empty_content;" + << "typedef " << impl << "::simple_content " << + "serializer_simple_content;" + << "typedef " << impl << "::complex_content " << + "serializer_complex_content;" + << endl; + + if (poly_code) + { + os << "// Serializer map interface and default implementation." << endl + << "//" << endl + << "using ::xsde::cxx::serializer::serializer_map;" + << "using ::xsde::cxx::serializer::serializer_map_impl;" + << endl; + + os << "// Substitution and inheritance hashmaps load querying." << endl + << "//" << endl + << "using ::xsde::cxx::serializer::serializer_smap_buckets;" + << "using ::xsde::cxx::serializer::serializer_smap_elements;" + << "using ::xsde::cxx::serializer::serializer_smap_bucket_buckets;" + << "using ::xsde::cxx::serializer::serializer_smap_bucket_elements;"; + + if (validation) + os << "using ::xsde::cxx::serializer::validating::serializer_imap_buckets;" + << "using ::xsde::cxx::serializer::validating::serializer_imap_elements;"; + + os << endl; + } + + os << "// Serializer skeletons and implementations for the" << endl + << "// XML Schema built-in types." << endl + << "//" << endl; + + names (ns); + + os << "// Error codes." << endl + << "//" << endl; + + if (!exceptions) + os << "using xsde::cxx::sys_error;"; + + os << "typedef xsde::cxx::serializer::genx::xml_error " << + "serializer_xml_error;"; + + if (validation) + os << "typedef xsde::cxx::schema_error " << + "serializer_schema_error;"; + + os << endl; + + if (exceptions) + { + os << "// Exceptions." << endl + << "//" << endl + << "typedef xsde::cxx::serializer::exception " << + "serializer_exception;" + << "typedef xsde::cxx::serializer::xml serializer_xml;"; + + if (validation) + os << "typedef xsde::cxx::serializer::schema " << + "serializer_schema;"; + + os << endl; + } + else + os << "// Error object." << endl + << "//" << endl + << "typedef xsde::cxx::serializer::error serializer_error;" + << endl; + + os << "// Document serializer." << endl + << "//" << endl + << "using xsde::cxx::serializer::genx::writer;" + << "using xsde::cxx::serializer::genx::document_simpl;" + << endl; + + os << "// Serializer context." << endl + << "//" << endl + << "typedef xsde::cxx::serializer::context serializer_context;" + << endl; + + post (ns); + } + }; + } + + Void + generate_serializer_header (Context& ctx, Boolean generate_xml_schema) + { + NarrowString extern_xml_schema; + + if (!generate_xml_schema) + extern_xml_schema = ctx.options.value (); + + if (extern_xml_schema) + { + String name (ctx.hxx_expr->merge (extern_xml_schema)); + + ctx.os << "#include " << ctx.process_include_path (name) << endl + << endl; + + // Generate includes that came from the type map. + // + if (ctx.schema_root.context ().count ("s:includes")) + { + typedef Cult::Containers::Set Includes; + + Includes& is ( + ctx.schema_root.context ().get ("s:includes")); + + for (Includes::ConstReverseIterator i (is.rbegin ()); + i != is.rend (); ++i) + { + ctx.os << "#include " << *i << endl; + } + + ctx.os << endl; + } + } + else + { + ctx.os << "#include " << endl + << endl; + + // std::string or xsde::cxx::string is used in wildcard API. + // + if (ctx.stl) + { + ctx.os << "#include " << endl + << endl; + } + else + { + ctx.os << "#include " << endl + << endl; + } + + // Data types. + // + ctx.os << "#include " << endl + << endl; + + // Error handling. + // + if (ctx.exceptions) + ctx.os << "#include " << endl + << endl; + else + { + ctx.os << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl; + + ctx.os << "#include " << endl + << "#include " << endl; + + ctx.os << endl; + } + + // Polymorphism support. + // + if (ctx.poly_code) + { + ctx.os << "#include " << endl + << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl; + + ctx.os << endl; + } + + // Serializers. + // + if (ctx.validation) + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + else + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl; + + // Document. + // + ctx.os << "#include " << endl + << endl; + + // Generate includes that came from the type map. + // + if (ctx.schema_root.context ().count ("s:includes")) + { + typedef Cult::Containers::Set Includes; + + Includes& is ( + ctx.schema_root.context ().get ("s:includes")); + + for (Includes::ConstReverseIterator i (is.rbegin ()); + i != is.rend (); ++i) + { + ctx.os << "#include " << *i << endl; + } + + ctx.os << endl; + } + + // Generate fundamental types. + // + if (generate_xml_schema) + { + Traversal::Schema schema; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + } + else + { + Traversal::Schema schema, xsd; + Traversal::Implies implies; + Traversal::Names names; + FundNamespace ns (ctx); + + schema >> implies >> xsd >> names >> ns; + + Traversal::Names ns_names; + FundType type (ctx); + + ns >> ns_names >> type; + + schema.dispatch (ctx.schema_root); + } + } + + // Generate user type mapping. + // + if (!generate_xml_schema) + { + Traversal::Schema schema; + + Traversal::Sources sources; + Includes includes (ctx, Includes::header); + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> includes; + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + BaseOverride base_override (ctx); + Traversal::Inherits inherits_override; + + complex >> inherits_override; + enumeration >> inherits_override; + inherits_override >> base_override; + + schema.dispatch (ctx.schema_root); + } + } + } +} diff --git a/xsde/cxx/serializer/serializer-header.hxx b/xsde/cxx/serializer/serializer-header.hxx new file mode 100644 index 0000000..64c63ab --- /dev/null +++ b/xsde/cxx/serializer/serializer-header.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/serializer-header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_SERIALIZER_HEADER_HXX +#define CXX_SERIALIZER_SERIALIZER_HEADER_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_serializer_header (Context&, Boolean generate_xml_schema); + } +} + +#endif // CXX_SERIALIZER_SERIALIZER_HEADER_HXX diff --git a/xsde/cxx/serializer/serializer-inline.cxx b/xsde/cxx/serializer/serializer-inline.cxx new file mode 100644 index 0000000..8caa791 --- /dev/null +++ b/xsde/cxx/serializer/serializer-inline.cxx @@ -0,0 +1,631 @@ +// file : xsde/cxx/serializer/serializer-inline.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (tiein) + { + String const& name (ename (e)); + String const& impl (etiein (e)); + + // We have to use "real" (non-typedef) base name in base + // initializer because of some broken compilers (EVC 4.0). + // + SemanticGraph::Type& base (e.inherits ().base ()); + String fq_base (fq_name (base)); + String real_fq_base (real_fq_name (base)); + + os << "// " << name << endl + << "//" << endl + << endl; + + os << inl + << name << "::" << endl + << name << " (" << fq_base << "* tiein)" << endl + << ": " << real_fq_base << " (tiein, 0)," << endl + << " " << impl << " (0)" + << "{" + << "}"; + + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << real_fq_base << " (impl, 0)," << endl + << " " << impl << " (impl)" + << "{" + << "}"; + } + } + }; + + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + String item_type (fq_name (t)); + + String item (unclash (name, "item")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // item_serializer + // + os << inl + << "void " << name << "::" << endl + << unclash (name, "item_serializer") << " (" << + item_type << "& " << item << ")" + << "{" + << "this->_xsde_" << item << "_ = &" << item << ";" + << "}"; + + // serializers + // + os << inl + << "void " << name << "::" << endl + << "serializers (" << item_type << "& " << item << ")" + << "{" + << "this->_xsde_" << item << "_ = &" << item << ";" + << "}"; + + // c-tor + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": "; + + if (tiein) + os << etiein (l) << " (0)," << endl + << " "; + + os << "_xsde_" << item << "_ (0)" + << "{" + << "}"; + + if (tiein) + { + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << simple_base << " (impl, 0)," << endl + << " " << etiein (l) << " (impl)," << endl + << " _xsde_" << item << "_ (0)" + << "{" + << "}"; + } + } + }; + + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + if (tiein) + { + String const& name (ename (u)); + String const& impl (etiein (u)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": " << impl << " (0)" + << "{" + << "}"; + + // + // + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": " << simple_base << " (impl, 0)," << endl + << " " << impl << " (impl)" + << "{" + << "}"; + } + } + }; + + // + // + struct ParticleAccessor: Traversal::Element, Context + { + ParticleAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& scope (ename (e.scope ())); + String const& serializer (eserializer (e)); + + os << inl + << "void " << scope << "::" << endl + << serializer << " (" << fq_name (e.type ()) << "& s)" + << "{" + << "this->" << emember (e) << " = &s;" + << "}"; + + if (poly_code && !anonymous (e.type ())) + { + os << inl + << "void " << scope << "::" << endl + << serializer << " (" << serializer_map << "& m)" + << "{" + << "this->" << emember_map (e) << " = &m;" + << "}"; + } + } + }; + + struct AttributeAccessor: Traversal::Attribute, Context + { + AttributeAccessor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + String const& name (ename (a)); + + os << inl + << "void " << ename (a.scope ()) << "::" << endl + << eserializer (a) << " (" << fq_name (a.type ()) << "& " << + name << ")" + << "{" + << "this->" << emember (a) << " = &" << name << ";" + << "}"; + } + }; + + // + // + struct ParticleMemberSet: Traversal::Element, Context + { + ParticleMemberSet (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + os << "this->" << emember (e) << " = &" << ename (e) << ";"; + } + }; + + struct AttributeMemberSet: Traversal::Attribute, Context + { + AttributeMemberSet (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + os << "this->" << emember (a) << " = &" << ename (a) << ";"; + } + }; + + struct BaseMemberSet: Traversal::Complex, + Traversal::List, + Context + { + BaseMemberSet (Context& c) + : Context (c) + { + inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + + virtual Void + traverse (SemanticGraph::List& l) + { + String const& name (ename (l)); + String item (unclash (name, "item")); + + os << "this->_xsde_" << item << "_ = &" << name << "_item;"; + } + + private: + Traversal::Inherits inherits_; + }; + + // + // + struct ParticleMemberInit: Traversal::Element, Context + { + ParticleMemberInit (Context& c, Boolean comma) + : Context (c), first_ (!comma) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (first_) + first_ = false; + else + os << "," << endl << " "; + + os << emember (e) << " (0)"; + + if (poly_code && !anonymous (e.type ())) + { + os << "," << endl + << " " << emember_map (e) << " (0)"; + } + } + + private: + Boolean first_; + }; + + struct AttributeMemberInit: Traversal::Attribute, Context + { + AttributeMemberInit (Context& c, Boolean comma) + : Context (c), first_ (!comma) + { + } + + virtual Void + traverse (Type& a) + { + if (first_) + first_ = false; + else + os << "," << endl << " "; + + os << emember (a) << " (0)"; + } + + Boolean + comma () const + { + return !first_; + } + + private: + Boolean first_; + }; + + + // + // + struct Complex: Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + particle_accessor_ (c), + attribute_accessor_ (c), + base_set_ (c), + particle_set_ (c), + attribute_set_ (c) + { + // Accessor. + // + contains_compositor_accessor_ >> compositor_accessor_; + compositor_accessor_ >> contains_particle_accessor_; + contains_particle_accessor_ >> compositor_accessor_; + contains_particle_accessor_ >> particle_accessor_; + + names_attribute_accessor_ >> attribute_accessor_; + + // Member set. + // + inherits_base_set_ >> base_set_; + base_set_ >> contains_compositor_set_; + base_set_ >> names_attribute_set_; + + contains_compositor_set_ >> compositor_set_; + compositor_set_ >> contains_particle_set_; + contains_particle_set_ >> compositor_set_; + contains_particle_set_ >> particle_set_; + + names_attribute_set_ >> attribute_set_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + Boolean restriction (restriction_p (c)); + + if (!(tiein || (!restriction && (he || ha)))) + return; + + String const& name (ename (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + if (!restriction && (he || ha)) + { + // _serializer () + // + if (ha) + names (c, names_attribute_accessor_); + + if (he) + contains_compositor (c, contains_compositor_accessor_); + + // serializer () + // + + os << inl + << "void " << name << "::" << endl + << "serializers ("; + + { + SerializerParamDecl decl (*this, true); + decl.traverse (c); + } + + os << ")" + << "{"; + + inherits (c, inherits_base_set_); + + if (ha) + names (c, names_attribute_set_); + + if (he) + contains_compositor (c, contains_compositor_set_); + + os << "}"; + } + + // We have to use "real" (non-typedef) base name in base + // initializer because of some broken compilers (EVC 4.0). + // + String real_fq_base; + + if (hb && tiein) + real_fq_base = real_fq_name (c.inherits ().base ()); + + // Default c-tor. + // + os << inl + << name << "::" << endl; + + if (hb && tiein) + os << name << " (" << fq_name (c.inherits ().base ()) << + "* tiein)" << endl; + else + os << name << " ()" << endl; + + os << ": "; + + Boolean comma (false); + + if (hb && tiein) + { + os << real_fq_base << " (tiein, 0)"; + comma = true; + } + + if (tiein) + { + if (comma) + os << "," << endl << " "; + + os << etiein (c) << " (0)"; + comma = true; + } + + if (!restriction && (he || ha)) + { + if (ha) + { + AttributeMemberInit attribute_init (*this, comma); + Traversal::Names names_attribute_init; + + names_attribute_init >> attribute_init; + + names (c, names_attribute_init); + + comma = attribute_init.comma (); + } + + if (he) + { + Traversal::Compositor compositor_init; + ParticleMemberInit particle_init (*this, comma); + Traversal::ContainsCompositor contains_compositor_init; + Traversal::ContainsParticle contains_particle_init; + + contains_compositor_init >> compositor_init; + compositor_init >> contains_particle_init; + contains_particle_init >> compositor_init; + contains_particle_init >> particle_init; + + contains_compositor (c, contains_compositor_init); + } + } + + os << "{" + << "}"; + + // Tiein c-tor. + // + if (tiein) + { + os << inl + << name << "::" << endl + << name << " (" << name << "* impl, void*)" << endl + << ": "; + + if (hb) + os << real_fq_base << " (impl, 0)," << endl; + else + os << complex_base << " (impl, 0)," << endl; + + os << " " << etiein (c) << " (impl)"; + + Boolean comma (true); + + if (!restriction && (he || ha)) + { + if (ha) + { + AttributeMemberInit attribute_init (*this, comma); + Traversal::Names names_attribute_init; + + names_attribute_init >> attribute_init; + + names (c, names_attribute_init); + + comma = attribute_init.comma (); + } + + if (he) + { + Traversal::Compositor compositor_init; + ParticleMemberInit particle_init (*this, comma); + Traversal::ContainsCompositor contains_compositor_init; + Traversal::ContainsParticle contains_particle_init; + + contains_compositor_init >> compositor_init; + compositor_init >> contains_particle_init; + contains_particle_init >> compositor_init; + contains_particle_init >> particle_init; + + contains_compositor (c, contains_compositor_init); + } + } + + os << "{" + << "}"; + } + } + + private: + // + // + Traversal::Compositor compositor_accessor_; + ParticleAccessor particle_accessor_; + Traversal::ContainsCompositor contains_compositor_accessor_; + Traversal::ContainsParticle contains_particle_accessor_; + + AttributeAccessor attribute_accessor_; + Traversal::Names names_attribute_accessor_; + + // + // + BaseMemberSet base_set_; + Traversal::Inherits inherits_base_set_; + + Traversal::Compositor compositor_set_; + ParticleMemberSet particle_set_; + Traversal::ContainsCompositor contains_compositor_set_; + Traversal::ContainsParticle contains_particle_set_; + + AttributeMemberSet attribute_set_; + Traversal::Names names_attribute_set_; + }; + } + + Void + generate_serializer_inline (Context& ctx) + { + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + if (!ctx.options.value ()) + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + Enumeration enumeration (ctx); + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + + names >> enumeration; + names >> list; + names >> union_; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/serializer-inline.hxx b/xsde/cxx/serializer/serializer-inline.hxx new file mode 100644 index 0000000..8cde76d --- /dev/null +++ b/xsde/cxx/serializer/serializer-inline.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/serializer-inline.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_SERIALIZER_INLINE_HXX +#define CXX_SERIALIZER_SERIALIZER_INLINE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_serializer_inline (Context&); + } +} + +#endif // CXX_SERIALIZER_SERIALIZER_INLINE_HXX diff --git a/xsde/cxx/serializer/serializer-source.cxx b/xsde/cxx/serializer/serializer-source.cxx new file mode 100644 index 0000000..ec30add --- /dev/null +++ b/xsde/cxx/serializer/serializer-source.cxx @@ -0,0 +1,2703 @@ +// file : xsde/cxx/serializer/serializer-source.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + // Override classes override pure virtual functions in the base. + // Should be in sync with definition generators below. Used in + // tiein implementation. + // + + struct CompositorCallbackOverride: Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallbackOverride (Context& c, String const& scope) + : Context (c), scope_ (scope) + { + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min != 0) + { + SemanticGraph::Type& t ( + dynamic_cast (scope (c))); + + String const& impl (etiein (t)); + + if (max != 1) + { + String const& next (enext (c)); + + os << "bool " << scope_ << "::" << endl + << next << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << next << " ();" + << "}"; + } + + String const& arm (earm (c)); + + os << fq_name (t) << "::" << earm_tag (c) << " " << + scope_ << "::" << endl + << arm << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << arm << " ();" + << "}"; + } + + Traversal::Choice::traverse (c); + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (max != 1 && min != 0) + { + String const& impl ( + etiein (dynamic_cast (scope (s)))); + + String const& next (enext (s)); + + os << "bool " << scope_ << "::" << endl + << next << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << next << " ();" + << "}"; + } + + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Scope& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + + private: + String const& scope_; + }; + + struct ParticleCallbackOverride: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallbackOverride (Context& c, String const& scope) + : Context (c), scope_ (scope) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& impl ( + etiein (dynamic_cast (e.scope ()))); + + if (max != 1 && min != 0) + { + String const& next (enext (e)); + + os << "bool " << scope_ << "::" << endl + << next << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << next << " ();" + << "}"; + } + + String const& ret (ret_type (e.type ())); + + if (ret != L"void") + { + String const& name (ename (e)); + + os << ret << " " << scope_ << "::" << endl + << name << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << name << " ();" + << "}"; + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min != 0 && + !a.contained_particle ().compositor ().is_a< + SemanticGraph::Choice> ()) + { + String const& impl ( + etiein (dynamic_cast (a.scope ()))); + + if (max != 1) + { + String const& next (enext (a)); + + os << "bool " << scope_ << "::" << endl + << next << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << next << " ();" + << "}"; + } + + String const& name (ename (a)); + + if (stl) + { + os << "void " << scope_ << "::" << endl + << name << " (::std::string& ns, ::std::string& name)" + << "{" + << "assert (this->" << impl << ");" + << "this->" << impl << "->" << name << " (ns, name);" + << "}"; + } + else + { + os << "void " << scope_ << "::" << endl + << name << " (const char*& ns, const char*& name, " << + "bool& free)" + << "{" + << "assert (this->" << impl << ");" + << "this->" << impl << "->" << name << " (ns, name, free);" + << "}"; + } + + String const& serialize (eserialize (a)); + + os << "void " << scope_ << "::" << endl + << serialize << " ()" + << "{" + << "assert (this->" << impl << ");" + << "this->" << impl << "->" << serialize << " ();" + << "}"; + } + } + + private: + String const& scope_; + }; + + struct AttributeCallbackOverride: Traversal::Attribute, Context + { + AttributeCallbackOverride (Context& c, String const& scope) + : Context (c), scope_ (scope) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& ret (ret_type (a.type ())); + + if (ret != L"void") + { + String const& impl ( + etiein (dynamic_cast (a.scope ()))); + + String const& name (ename (a)); + + os << ret << " " << scope_ << "::" << endl + << name << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << name << " ();" + << "}"; + } + } + + private: + String const& scope_; + }; + + struct BaseOverride: Traversal::Type, + Traversal::Enumeration, + Traversal::List, + Traversal::Union, + Traversal::Complex, + Context + { + BaseOverride (Context& c, String const& scope) + : Context (c), + scope_ (scope), + compositor_callback_ (c, scope), + particle_callback_ (c, scope), + attribute_callback_ (c, scope) + { + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + // pre + // + String const& arg (arg_type (t)); + + if (arg != L"void") + { + String const& impl (etiein (t)); + + os << "void " << scope_ << "::" << endl + << "pre (" << arg << " x)" + << "{" + << "assert (this->" << impl << ");" + << "this->" << impl << "->pre (x);" + << "}"; + } + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + SemanticGraph::Type& t (e); + traverse (t); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + SemanticGraph::Type& t (l); + traverse (t); + + // item + // + String const& ret (ret_type (l.argumented ().type ())); + + if (ret != L"void") + { + String item (unclash (ename (l), "item")); + String const& impl (etiein (l)); + + os << ret << " " << scope_ << "::" << endl + << item << " ()" + << "{" + << "assert (this->" << impl << ");" + << "return this->" << impl << "->" << item << " ();" + << "}"; + } + } + + virtual Void + traverse (SemanticGraph::Union& u) + { + SemanticGraph::Type& t (u); + traverse (t); + + // serialize_content + // + String const& impl (etiein (u)); + + os << "void " << scope_ << "::" << endl + << "_serialize_content ()" + << "{" + << "assert (this->" << impl << ");" + << "this->" << impl << "->_serialize_content ();" + << "}"; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + SemanticGraph::Type& t (c); + traverse (t); + + // Member callbacks. + // + if (!restriction_p (c)) + { + Traversal::Complex::names (c, names_attribute_callback_); + Traversal::Complex::contains_compositor ( + c, contains_compositor_callback_); + } + } + + private: + String const& scope_; + + CompositorCallbackOverride compositor_callback_; + ParticleCallbackOverride particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallbackOverride attribute_callback_; + Traversal::Names names_attribute_callback_; + }; + + // + // + + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + String const& arg (arg_type (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + + os << "// " << name << endl + << "//" << endl + << endl; + + if (arg != arg_type (base) && arg == L"void") + { + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (e)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->pre ();"; + } + + os << "}"; + } + + if (poly_code) + { + String id (e.name ()); + + if (String ns = xml_ns_name (e)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + + if (validation) + { + Boolean gen (!anonymous (e)); + + // We normally don't need to enter anonymous types into + // the inheritance map. The only exception is when an + // anonymous types is defined inside an element that + // is a member of a substitution group. + // + if (!gen) + { + // The first instance that this anonymous type classifies + // is the prototype for others if any. + // + SemanticGraph::Instance& i ( + e.classifies_begin ()->instance ()); + + if (SemanticGraph::Element* e = + dynamic_cast (&i)) + { + if (e->substitutes_p ()) + gen = true; + } + } + + if (gen) + { + os << "static" << endl + << "const ::xsde::cxx::serializer::validating::" << + "inheritance_map_entry" << endl + << "_xsde_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + + if (tiein) + { + // If our base has pure virtual functions, override them here. + // + BaseOverride t (*this, name); + t.dispatch (base); + } + } + }; + + // + // + struct List: Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename (l)); + SemanticGraph::Type& t (l.argumented ().type ()); + + String const& ret (ret_type (t)); + String const& arg (arg_type (t)); + + String item (unclash (name, "item")); + String item_next (unclash (name, "item_next")); + String inst (L"_xsde_" + item + L"_"); + + os << "// " << name << endl + << "//" << endl + << endl; + + String impl; + + if (tiein) + impl = etiein (l); + + // pre + // + if (arg_type (l) == L"void") + { + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->pre ();"; + + os << "}"; + } + + // item + // + os << "bool " << name << "::" << endl + << item_next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << "->" << + item_next << " () : false;"; + else + os << "return false;"; + + os << "}"; + + if (ret == L"void") + { + os << ret << " " << name << "::" << endl + << item << " ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "return this->" << impl << "->" << item << " ();"; + + os << "}"; + } + + // reset + // + if (reset) + { + os << "void " << name << "::" << endl + << "_reset ()" + << "{" + << simple_base << "::_reset ();" + << endl + << "if (this->" << inst << ")" << endl + << "this->" << inst << "->_reset ();" + << "}"; + } + + // serialize_content + // + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{"; + + os << "bool first = true;" + << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (exceptions && !validation) + { + os << "while (this->" << item_next << " ())" + << "{" + << "if (this->" << inst << ")" + << "{"; + + if (ret == L"void") + os << "this->" << item << " ();" + << "this->" << inst << "->pre ();"; + else + os << arg << " r = this->" << item << " ();" + << "this->" << inst << "->pre (r);"; + + os << endl + << "if (!first)" << endl + << "this->_characters (\" \", 1);" + << "else" << endl + << "first = false;" + << endl; + + os << "this->" << inst << "->_pre_impl (ctx);" + << "this->" << inst << "->_serialize_content ();" + << "this->" << inst << "->_post_impl ();" + << "this->" << inst << "->post ();"; + + os << "}" + << "}"; + } + else + { + os << "while (this->" << item_next << " ())" + << "{" + << "if (this->" << inst << ")" + << "{"; + + if (ret == L"void") + os << "this->" << item << " ();"; + else + os << arg << " r = this->" << item << " ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "break;" + << endl; + + if (ret == L"void") + os << "this->" << inst << "->pre ();"; + else + os << "this->" << inst << "->pre (r);"; + + if (!exceptions) + { + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "break;"; + } + + if (!exceptions) + os << endl + << "if (!first)" + << "{" + << "if (!this->_characters (\" \", 1))" << endl + << "break;" + << "}"; + else + os << endl + << "if (!first)" << endl + << "this->_characters (\" \", 1);"; + + os << "else" << endl + << "first = false;" + << endl; + + os << "this->" << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "break;" + << endl; + + os << "this->" << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "break;" + << endl; + + os << "this->" << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "break;" + << endl; + + os << "this->" << inst << "->post ();"; + + if (!exceptions) + { + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "break;"; + } + + os << "}" // No check for error here since we return anyway. + << "}"; + } + + os << "}"; // _serialize_content + + // + // + if (poly_code) + { + String id (l.name ()); + + if (String ns = xml_ns_name (l)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + // + // + struct Union: Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename (u)); + String const& arg (arg_type (u)); + + if (arg == L"void" || poly_code) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (arg == L"void") + { + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (u)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->pre ();"; + } + + os << "}"; + } + + if (poly_code) + { + String id (u.name ()); + + if (String ns = xml_ns_name (u)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + // + // + struct ParticleReset: Traversal::Element, Context + { + ParticleReset (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& m (emember (e)); + + os << "if (this->" << m << ")" << endl + << "this->" << m << "->_reset ();" + << endl; + + if (poly_code && !anonymous (e.type ())) + { + String const& map (emember_map (e)); + + os << "if (this->" << map << ")" << endl + << "this->" << map << "->reset ();" + << endl; + } + } + }; + + struct AttributeReset: Traversal::Attribute, Context + { + AttributeReset (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + String const& m (emember (a)); + + os << "if (this->" << m << ")" << endl + << "this->" << m << "->_reset ();" + << endl; + } + }; + + // Complex serialization code. + // + struct Compositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + Compositor (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + UnsignedLong min (a.min ()); + + if (min == 0) + os << "if (this->" << epresent (a) << " ())" + << "{"; + + Traversal::All::traverse (a); + + if (min == 0) + { + os << "}"; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.contains_begin () != c.contains_end ()) + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (c) << " ())" + << "{"; + } + else if (max != 1) + { + os << "while (this->" << enext (c) << " ())" + << "{"; + } + else if (!exceptions) + { + os << "{"; + } + + if (exceptions) + os << "switch (this->" << earm (c) << " ())"; + else + os << earm_tag (c) << " t = this->" << earm (c) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "switch (t)"; + + + os << "{"; + + for (SemanticGraph::Choice::ContainsIterator + i (c.contains_begin ()); i != c.contains_end (); ++i) + { + os << "case " << etag (i->particle ()) << ":" + << "{"; + + edge_traverser ().dispatch (*i); + + os << "break;" + << "}"; + } + + // In case of restriction we may not handle all enumerators + // in which case default will help avoid warnings. + // + os << "default:" + << "{" + << "break;" + << "}" + << "}"; // switch + + if (min == 0 || max != 1) + { + os << "}"; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + else if (!exceptions) + { + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (s) << " ())" + << "{"; + } + else if (max != 1) + { + os << "while (this->" << enext (s) << " ())" + << "{"; + } + + Traversal::Sequence::traverse (s); + + + if (min == 0 || max != 1) + { + os << "}"; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + } + }; + + struct Particle: Traversal::Element, + Traversal::Any, + Context + { + Particle (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + UnsignedLong min (e.min ()), max (e.max ()); + + String const& name (ename (e)); + + os << "// " << name << endl + << "//" << endl; + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (e) << " ())"; + } + else if (max != 1) + { + os << "while (this->" << enext (e) << " ())"; + } + + os << "{"; + + String const& ret (ret_type (e.type ())); + String const& arg (arg_type (e.type ())); + String fq_type (fq_name (e.type ())); + + Boolean poly (poly_code && !anonymous (e.type ())); + String inst (poly ? String (L"s") : L"this->" + emember (e)); + + if (poly) + os << "ctx.type_id (0);"; + + if (ret == L"void") + os << "this->" << name << " ();" + << endl; + else + os << arg << " r = this->" << name << " ();" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (poly) + { + // In case of mixin we use virtual inheritance and only + // dynamic_cast can be used. + // + String cast (mixin ? L"dynamic_cast" : L"static_cast"); + + os << "const void* t = ctx.type_id ();" + << fq_type << "* " << inst << " = 0;" + << endl + << "if (t == 0 && this->" << emember (e) << " != 0)" << endl + << inst << " = this->" << emember (e) << ";" + << "else if (this->" << emember_map (e) << " != 0)" << endl + << inst << " = " << cast << "< " << fq_type << "* > (" << endl + << "this->" << emember_map (e) << "->find (t));" + << endl; + } + + os << "if (" << inst << ")" + << "{"; + + if (exceptions) + { + if (ret == L"void") + os << inst << "->pre ();"; + else + os << inst << "->pre (r);"; + + if (poly) + { + os << endl + << "const char* dt = 0;" + << "if (t != 0)" + << "{" + << "dt = " << inst << "->_dynamic_type ();" + << "if (strcmp (dt, " << fq_type << + "::_static_type ()) == 0)" << endl + << "dt = 0;" + << "}"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "const char* ns = " << + strlit (e.namespace_ ().name ()) << ";"; + else + os << "const char* ns = 0;"; + + os << "const char* n = " << strlit (e.name ()) << ";" + << endl; + + os << "if (dt != 0 && " << + "::xsde::cxx::serializer::substitution_map_instance ()" << + ".check (ns, n, dt))" << endl + << "dt = 0;" + << endl; + + os << "if (ns != 0)" << endl + << "this->_start_element (ns, n);" + << "else" << endl + << "this->_start_element (n);"; + } + else + { + if (e.qualified () && e.namespace_ ().name ()) + os << "this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << ");"; + else + os << "this->_start_element (" << strlit (e.name ()) << ");"; + } + + if (poly) + { + // Set xsi:type if necessary. + // + os << endl + << "if (dt != 0)" << endl + << "this->_set_type (dt);" + << endl; + } + + os << inst << "->_pre_impl (ctx);" + << inst << "->_serialize_attributes ();" + << inst << "->_serialize_content ();" + << inst << "->_post_impl ();" + << "this->_end_element ();" + << inst << "->post ();"; + } + else + { + if (ret == L"void") + os << inst << "->pre ();"; + else + os << inst << "->pre (r);"; + + // Note that after pre() we need to check both the serializer + // and context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (poly) + { + os << "const char* dt = 0;" + << "if (t != 0)" + << "{" + << "dt = " << inst << "->_dynamic_type ();" + << "if (strcmp (dt, " << fq_type << + "::_static_type ()) == 0)" << endl + << "dt = 0;" + << "}"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + if (e.qualified () && e.namespace_ ().name ()) + os << "const char* ns = " << + strlit (e.namespace_ ().name ()) << ";"; + else + os << "const char* ns = 0;"; + + os << "const char* n = " << strlit (e.name ()) << ";" + << endl; + + os << "if (dt != 0 && " << + "::xsde::cxx::serializer::substitution_map_instance ()" << + ".check (ns, n, dt))" << endl + << "dt = 0;" + << endl; + + os << "if (ns != 0)" + << "{" + << "if (!this->_start_element (ns, n))" << endl + << "return;" + << "}" + << "else" + << "{" + << "if (!this->_start_element (n))" << endl + << "return;" + << "}"; + } + else + { + if (e.qualified () && e.namespace_ ().name ()) + os << "if (!this->_start_element (" << + strlit (e.namespace_ ().name ()) << ", " << + strlit (e.name ()) << "))" << endl + << "return;" + << endl; + else + os << "if (!this->_start_element (" << + strlit (e.name ()) << "))" << endl + << "return;" + << endl; + } + + if (poly) + { + // Set xsi:type if necessary. + // + os << "if (dt != 0)" + << "{" + << "if (!this->_set_type (dt))" << endl + << "return;" + << "}"; + } + + os << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_attributes ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if (!this->_end_element ())" << endl + << "return;" + << endl; + + os << inst << "->post ();"; + + // Note that after post() we need to check both the serializer + // and context error states because of the recursive parsing. + // + os << endl + << "if (" << inst << "->_error_type ())" << endl + << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "return;"; + } + + os << "}" // if (inst) + << "}"; + + if ((min == 0 || max != 1) && !exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min == 0 && max == 1) + { + os << "if (this->" << epresent (a) << " ())"; + + } + else if (max != 1) + { + os << "while (this->" << enext (a) << " ())"; + } + + os << "{"; + + if (stl) + { + os << "::std::string ns, name;"; + + if (exceptions) + { + os << "this->" << ename (a) << " (ns, name);" + << endl + << "if (ns.empty ())" << endl + << "this->_start_element (name.c_str ());" + << "else" << endl + << "this->_start_element (ns.c_str (), name.c_str ());" + << endl + << "this->" << eserialize (a) << " ();" + << "this->_end_element ();"; + } + else + { + os << "this->" << ename (a) << " (ns, name);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (ns.empty ())" + << "{" + << "if (!this->_start_element (name.c_str ()))" << endl + << "return;" + << "}" + << "else" + << "{" + << "if (!this->_start_element (ns.c_str (), " << + "name.c_str ()))" << endl + << "return;" + << "}" + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (!this->_end_element ())" << endl + << "return;"; + } + } + else + { + os << "const char* ns = 0;" + << "const char* name;" + << "bool free;"; + + if (exceptions) + { + os << "this->" << ename (a) << " (ns, name, free);" + << endl + << "::xsde::cxx::string auto_ns, auto_name;" + << "if (free)" + << "{" + << "auto_ns.attach (const_cast< char* > (ns));" + << "auto_name.attach (const_cast< char* > (name));" + << "}" + << "if (ns == 0 || *ns == '\\0')" << endl + << "this->_start_element (name);" + << "else" << endl + << "this->_start_element (ns, name);" + << endl + << "this->" << eserialize (a) << " ();" + << "this->_end_element ();"; + } + else + { + os << "this->" << ename (a) << " (ns, name, free);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "bool r;" + << "if (ns == 0 || *ns == '\\0')" << endl + << "r = this->_start_element (name);" + << "else" << endl + << "r = this->_start_element (ns, name);" + << endl + << "if (free)" + << "{" + << "delete[] ns;" + << "delete[] name;" + << "}" + << "if (!r)" << endl + << "return;" + << endl + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (!this->_end_element ())" << endl + << "return;"; + } + } + + os << "}"; + + if (!exceptions && (min == 0 || max != 1)) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + }; + + struct Attribute: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + Attribute (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& name (ename (a)); + + os << "// " << name << endl + << "//" << endl; + + if (a.optional ()) + { + os << "if (this->" << epresent (a) << " ())"; + } + + os << "{"; + + String const& inst (emember (a)); + String const& ret (ret_type (a.type ())); + String const& arg (arg_type (a.type ())); + + if (ret == L"void") + os << "this->" << name << " ();" + << endl; + else + os << arg << " r = this->" << name << " ();" + << endl; + + if (!exceptions) + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if (this->" << inst << ")" + << "{"; + + if (exceptions) + { + if (ret == L"void") + os << "this->" << inst << "->pre ();"; + else + os << "this->" << inst << "->pre (r);"; + + if (a.qualified () && a.namespace_ ().name ()) + os << "this->_start_attribute (" << + strlit (a.namespace_ ().name ()) << ", " << + strlit (a.name ()) << ");"; + else + os << "this->_start_attribute (" << strlit (a.name ()) << ");"; + + os << "this->" << inst << "->_pre_impl (ctx);" + << "this->" << inst << "->_serialize_content ();" + << "this->" << inst << "->_post_impl ();" + << "this->_end_attribute ();" + << "this->" << inst << "->post ();"; + } + else + { + if (ret == L"void") + os << "this->" << inst << "->pre ();"; + else + os << "this->" << inst << "->pre (r);"; + + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + if (a.qualified () && a.namespace_ ().name ()) + os << "if (!this->_start_attribute (" << + strlit (a.namespace_ ().name ()) << ", " << + strlit (a.name ()) << "))" << endl + << "return;" + << endl; + else + os << "if (!this->_start_attribute (" << + strlit (a.name ()) << "))" << endl + << "return;" + << endl; + + os << "this->" << inst << "->_pre_impl (ctx);"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->_serialize_content ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->_post_impl ();"; + + os << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl; + + os << "if (!this->_end_attribute ())" << endl + << "return;" + << endl; + + os << "this->" << inst << "->post ();"; + + os << endl + << "if (this->" << inst << "->_error_type ())" << endl + << "this->" << inst << "->_copy_error (ctx);" + << endl; + + os << "if (ctx.error_type ())" << endl + << "return;"; + } + + os << "}" // if (inst) + << "}"; + + if (a.optional () && !exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + os << "while (this->" << enext (a) << " ())" + << "{"; + + if (stl) + { + os << "::std::string ns, name;"; + + if (exceptions) + { + os << "this->" << ename (a) << " (ns, name);" + << endl + << "if (ns.empty ())" << endl + << "this->_start_attribute (name.c_str ());" + << "else" << endl + << "this->_start_attribute (ns.c_str (), name.c_str ());" + << endl + << "this->" << eserialize (a) << " ();" + << "this->_end_attribute ();"; + } + else + { + os << "this->" << ename (a) << " (ns, name);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (ns.empty ())" + << "{" + << "if (!this->_start_attribute (name.c_str ()))" << endl + << "return;" + << "}" + << "else" + << "{" + << "if (!this->_start_attribute (ns.c_str (), " << + "name.c_str ()))" << endl + << "return;" + << "}" + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (!this->_end_attribute ())" << endl + << "return;"; + } + } + else + { + os << "const char* ns = 0;" + << "const char* name;" + << "bool free;"; + + if (exceptions) + { + os << "this->" << ename (a) << " (ns, name, free);" + << endl + << "::xsde::cxx::string auto_ns, auto_name;" + << "if (free)" + << "{" + << "auto_ns.attach (const_cast< char* > (ns));" + << "auto_name.attach (const_cast< char* > (name));" + << "}" + << "if (ns == 0 || *ns == '\\0')" << endl + << "this->_start_attribute (name);" + << "else" << endl + << "this->_start_attribute (ns, name);" + << endl + << "this->" << eserialize (a) << " ();" + << "this->_end_attribute ();"; + } + else + { + os << "this->" << ename (a) << " (ns, name, free);" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "bool r;" + << "if (ns == 0 || *ns == '\\0')" << endl + << "r = this->_start_attribute (name);" + << "else" << endl + << "r = this->_start_attribute (ns, name);" + << endl + << "if (free)" + << "{" + << "delete[] ns;" + << "delete[] name;" + << "}" + << "if (!r)" << endl + << "return;" + << endl + << "this->" << eserialize (a) << " ();" + << endl + << "if (ctx.error_type ())" << endl + << "return;" + << endl + << "if (!this->_end_attribute ())" << endl + << "return;"; + } + } + + os << "}"; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + }; + + // Callbacks. + // + struct CompositorCallback: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Context + { + CompositorCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context ().count ("xsd-frontend-restriction-correspondence")) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1}. + // + if (a.min () == 0) + { + SemanticGraph::Scope& s (scope (a)); + String const& present (epresent (a)); + + os << "bool " << ename (s) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (s))); + + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + } + else + os << "return false;"; + + os << "}"; + } + } + + Traversal::All::traverse (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (SemanticGraph::Compositor* b = correspondent (c)) + { + UnsignedLong smin (c.min ()); + UnsignedLong bmax (b->max ()); + + if (bmax != 1 && smin == 0) + { + String const& next (enext (c)); + String const& present (epresent (c)); + + SemanticGraph::Scope& scope (this->scope (c)); + + os << "bool " << ename (scope) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (scope))); + + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : this->" << next << " ();"; + } + else + os << "return this->" << next << " ();"; + + os << "}"; + } + } + else + { + UnsignedLong min (c.min ()), max (c.max ()); + + if (min == 0) + { + SemanticGraph::Scope& scope (this->scope (c)); + String const& s (ename (scope)); + + String impl; + + if (tiein) + impl = etiein (dynamic_cast (scope)); + + if (max == 1) + { + String const& present (epresent (c)); + + os << "bool " << s << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + else + { + String const& next (enext (c)); + + os << "bool " << s << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << next << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + + String const& arm (earm (c)); + String const& tag (etag (c.contains_begin ()->particle ())); + + os << s << "::" << earm_tag (c) << " " << s << "::" << endl + << arm << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << arm << " () : " << tag << ";"; + else + os << "return " << tag << ";"; + + os << "}"; + } + } + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (SemanticGraph::Compositor* b = correspondent (s)) + { + UnsignedLong smin (s.min ()); + UnsignedLong bmax (b->max ()); + + if (bmax != 1 && smin == 0) + { + String const& next (enext (s)); + String const& present (epresent (s)); + + SemanticGraph::Scope& scope (this->scope (s)); + + os << "bool " << ename (scope) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (scope))); + + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : this->" << next << " ();"; + } + else + os << "return this->" << next << " ();"; + + os << "}"; + } + } + else + { + UnsignedLong min (s.min ()), max (s.max ()); + + if (min == 0) + { + SemanticGraph::Scope& scope (this->scope (s)); + + String impl; + + if (tiein) + impl = etiein (dynamic_cast (scope)); + + if (max == 1) + { + String const& present (epresent (s)); + + os << "bool " << ename (scope) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + else + { + String const& next (enext (s)); + + os << "bool " << ename (scope) << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << next << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + } + } + + Traversal::Sequence::traverse (s); + } + + private: + SemanticGraph::Scope& + scope (SemanticGraph::Compositor& c) + { + SemanticGraph::Compositor* root (&c); + + while (root->contained_particle_p ()) + root = &root->contained_particle ().compositor (); + + return dynamic_cast ( + root->contained_compositor ().container ()); + } + }; + + struct ParticleCallback: Traversal::Element, + Traversal::Any, + Context + { + ParticleCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (SemanticGraph::Element* b = correspondent (e)) + { + if (b->max () != 1 && e.min () == 0) + { + String const& next (enext (e)); + String const& present (epresent (e)); + + os << "bool " << ename (e.scope ()) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (e.scope ()))); + + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : this->" << next << " ();"; + } + else + os << "return this->" << next << " ();"; + + os << "}"; + } + } + else + { + UnsignedLong min (e.min ()), max (e.max ()); + String const& s (ename (e.scope ())); + + String impl; + + if (tiein) + impl = etiein (dynamic_cast (e.scope ())); + + if (min == 0) + { + if (max == 1) + { + String const& present (epresent (e)); + + os << "bool " << s << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + else + { + String const& next (enext (e)); + + os << "bool " << s << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << next << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + } + + // The callback is non-pure-virtual only if the return type + // is void. + // + if (ret_type (e.type ()) == L"void") + { + String const& name (ename (e)); + + os << "void " << s << "::" << endl + << name << " ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " ();"; + + os << "}"; + } + } + } + + virtual Void + traverse (SemanticGraph::Any& a) + { + if (SemanticGraph::Any* b = correspondent (a)) + { + if (b->max () != 1 && a.min () == 0) + { + String const& next (enext (a)); + String const& present (epresent (a)); + + os << "bool " << ename (a.scope ()) << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + { + String const& impl ( + etiein (dynamic_cast (a.scope ()))); + + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : this->" << next << " ();"; + } + else + os << "return this->" << next << " ();"; + + os << "}"; + } + } + else + { + UnsignedLong min (a.min ()), max (a.max ()); + + if (min == 0 || + a.contained_particle ().compositor ().is_a< + SemanticGraph::Choice> ()) + { + String const& s (ename (a.scope ())); + String impl; + + if (tiein) + impl = etiein (dynamic_cast (a.scope ())); + + if (min == 0 && max == 1) + { + String const& present (epresent (a)); + + os << "bool " << s << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + else if (max != 1) + { + String const& next (enext (a)); + + os << "bool " << s << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << next << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + + String const& name (ename (a)); + + if (stl) + { + if (tiein) + os << "void " << s << "::" << endl + << name << " (::std::string& ns, ::std::string& n)" + << "{" + << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (ns, n);" + << "}"; + + else + os << "void " << s << "::" << endl + << name << " (::std::string&, ::std::string&)" + << "{" + << "}"; + } + else + { + if (tiein) + os << "void " << s << "::" << endl + << name << " (const char*& ns, const char*& n, bool& f)" + << "{" + << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (ns, n, f);" + << "}"; + else + os << "void " << s << "::" << endl + << name << " (const char*&, const char*&, bool&)" + << "{" + << "}"; + } + + String const& serialize (eserialize (a)); + + os << "void " << s << "::" << endl + << serialize << " ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << serialize << " ();"; + + os << "}"; + } + } + + } + }; + + struct AttributeCallback: Traversal::Attribute, + Traversal::AnyAttribute, + Context + { + AttributeCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + String const& s (ename (a.scope ())); + + String impl; + + if (tiein) + impl = etiein (dynamic_cast (a.scope ())); + + if (a.optional ()) + { + String const& present (epresent (a)); + + os << "bool " << s << "::" << endl + << present << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << present << " () : false;"; + else + os << "return false;"; + + os << "}"; + } + + // The callback is non-pure-virtual only if the return type + // is void. + // + if (ret_type (a.type ()) == L"void") + { + String const& name (ename (a)); + + os << "void " << s << "::" << endl + << name << " ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " ();"; + + os << "}"; + } + } + + virtual Void + traverse (SemanticGraph::AnyAttribute& a) + { + String const& s (ename (a.scope ())); + + String impl; + + if (tiein) + impl = etiein (dynamic_cast (a.scope ())); + + String const& next (enext (a)); + + os << "bool " << s << "::" << endl + << next << " ()" + << "{"; + + if (tiein) + os << "return this->" << impl << " ? this->" << impl << + "->" << next << " () : false;"; + else + os << "return false;"; + + os << "}"; + + String const& name (ename (a)); + + if (stl) + { + if (tiein) + os << "void " << s << "::" << endl + << name << " (::std::string& ns, ::std::string& n)" + << "{" + << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (ns, n);" + << "}"; + + else + os << "void " << s << "::" << endl + << name << " (::std::string&, ::std::string&)" + << "{" + << "}"; + } + else + { + if (tiein) + os << "void " << s << "::" << endl + << name << " (const char*& ns, const char*& n, bool& f)" + << "{" + << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << name << " (ns, n, f);" + << "}"; + else + os << "void " << s << "::" << endl + << name << " (const char*&, const char*&, bool&)" + << "{" + << "}"; + } + + String const& serialize (eserialize (a)); + + os << "void " << s << "::" << endl + << serialize << " ()" + << "{"; + + if (tiein) + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->" << serialize << " ();"; + + os << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, Context + { + Complex (Context& c) + : Context (c), + compositor_callback_ (c), + particle_callback_ (c), + attribute_callback_ (c), + particle_reset_ (c), + attribute_reset_ (c), + compositor_ (c), + particle_ (c), + attribute_ (c) + { + // Callback. + // + contains_compositor_callback_ >> compositor_callback_; + compositor_callback_ >> contains_particle_callback_; + contains_particle_callback_ >> compositor_callback_; + contains_particle_callback_ >> particle_callback_; + + names_attribute_callback_ >> attribute_callback_; + + // Reset. + // + contains_compositor_reset_ >> compositor_reset_; + compositor_reset_ >> contains_particle_reset_; + contains_particle_reset_ >> compositor_reset_; + contains_particle_reset_ >> particle_reset_; + + names_attribute_reset_ >> attribute_reset_; + + // Serialization code. + // + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_attribute_ >> attribute_; + } + + virtual Void + traverse (Type& c) + { + Boolean hb (c.inherits_p ()); + Boolean he (has (c)); + Boolean ha (has (c)); + + Boolean hae (has_particle (c)); + Boolean haa (has (c)); + + String const& arg (arg_type (c)); + Boolean same (hb && arg == arg_type (c.inherits ().base ())); + + String const& name (ename (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + if (!same && arg == L"void") + { + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (tiein) + { + String const& impl (etiein (c)); + + os << "if (this->" << impl << ")" << endl + << "this->" << impl << "->pre ();"; + } + + os << "}"; + } + + // Member callbacks. + // + if (!restriction_p (c)) + { + if (ha || haa) + names (c, names_attribute_callback_); + } + + if (he || hae) + contains_compositor (c, contains_compositor_callback_); + + // reset + // + if (!restriction_p (c) && (he || ha) && reset) + { + os << "void " << name << "::" << endl + << "_reset ()" + << "{"; + + // Avoid recursion in case of recursive parsing. + // + if (he) + os << "if (this->resetting_)" << endl + << "return;" + << endl; + + // Reset the base. We cannot use the fully-qualified base name + // directly because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef "; + + if (hb) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << " " << base << ";" + << base << "::_reset ();" + << endl; + + // Reset member serializer. + // + + if (ha) + names (c, names_attribute_reset_); + + if (he) + { + os << "this->resetting_ = true;" + << endl; + + contains_compositor (c, contains_compositor_reset_); + + os << "this->resetting_ = false;" + << endl; + } + + os << "}"; + } + + // + // + if (poly_code) + { + String id (c.name ()); + + if (String ns = xml_ns_name (c)) + { + id += L' '; + id += ns; + } + + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + + os << "const char* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + + if (hb && validation) + { + Boolean gen (!anonymous (c)); + + // We normally don't need to enter anonymous types into + // the inheritance map. The only exception is when an + // anonymous types is defined inside an element that + // is a member of a substitution group. + // + if (!gen) + { + // The first instance that this anonymous type classifies + // is the prototype for others if any. + // + SemanticGraph::Instance& i ( + c.classifies_begin ()->instance ()); + + if (SemanticGraph::Element* e = + dynamic_cast (&i)) + { + if (e->substitutes_p ()) + gen = true; + } + } + + if (gen) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + os << "static" << endl + << "const ::xsde::cxx::serializer::validating::" << + "inheritance_map_entry" << endl + << "_xsde_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + + if (tiein && hb) + { + // If our base has pure virtual functions, override them here. + // + BaseOverride t (*this, name); + t.dispatch (c.inherits ().base ()); + } + + // If we are validating, the rest is generated elsewere. + // + if (validation) + return; + + // Don't use restriction_p here since we don't want special + // treatment of anyType. + // + Boolean restriction ( + hb && c.inherits ().is_a ()); + + // _serialize_attributes + // + if (ha || haa) + { + os << "void " << name << "::" << endl + << "_serialize_attributes ()" + << "{"; + + // We need context for wildcards only if we are using error + // codes. + // + if (ha || !exceptions) + os << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (hb && !restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_serialize_attributes ();" + << endl; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + names (c, names_attribute_); + + os << "}"; + } + + // _serialize_content + // + if (he || hae) + { + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{"; + + // We need context for wildcards only if we are using error + // codes. + // + if (he || !exceptions) + os << "::xsde::cxx::serializer::context& ctx = this->_context ();" + << endl; + + if (hb && !restriction) + { + // We cannot use the fully-qualified base name directly + // because of some broken compilers (EVC 4.0). + // + String base (unclash (name, "base")); + + os << "typedef " << fq_name (c.inherits ().base ()) << " " << + base << ";" + << base << "::_serialize_content ();" + << endl; + + if (!exceptions) + { + os << "if (ctx.error_type ())" << endl + << "return;" + << endl; + } + } + + contains_compositor (c, contains_compositor_); + + os << "}"; + } + } + + private: + // + // + CompositorCallback compositor_callback_; + ParticleCallback particle_callback_; + Traversal::ContainsCompositor contains_compositor_callback_; + Traversal::ContainsParticle contains_particle_callback_; + + AttributeCallback attribute_callback_; + Traversal::Names names_attribute_callback_; + + // + // + Traversal::Compositor compositor_reset_; + ParticleReset particle_reset_; + Traversal::ContainsCompositor contains_compositor_reset_; + Traversal::ContainsParticle contains_particle_reset_; + + AttributeReset attribute_reset_; + Traversal::Names names_attribute_reset_; + + // + // + Compositor compositor_; + Particle particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Attribute attribute_; + Traversal::Names names_attribute_; + }; + + + // Generate substitution group map entries. + // + struct GlobalElement: Traversal::Element, Context + { + GlobalElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (e.substitutes_p ()) + { + String name (escape (e.name ())); + Type& r (e.substitutes ().root ()); + + SemanticGraph::Type& type (e.type ()); + + String r_id (r.name ()); + + if (String const& ns = r.namespace_ ().name ()) + { + r_id += L' '; + r_id += ns; + } + + os << "// Substitution map entry for " << comment (e.name ()) << + "." << endl + << "//" << endl + << "static" << endl + << "const ::xsde::cxx::serializer::substitution_map_entry" << endl + << "_xsde_" << name << "_substitution_map_entry_ (" << endl + << strlit (r_id) << "," << endl; + + if (String const& ns = e.namespace_ ().name ()) + os << strlit (ns) << "," << endl; + else + os << "0," << endl; + + os << strlit (e.name ()) << "," << endl + << fq_name (type) << "::_static_type ());" + << endl; + } + } + }; + } + + Void + generate_serializer_source (Context& ctx) + { + if (ctx.tiein) + ctx.os << "#include " << endl + << endl; + + if (ctx.poly_code) + { + ctx.os << "#include " << endl + << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl + << endl; + else + ctx.os << endl; + + ctx.os << "static" << endl + << "const ::xsde::cxx::serializer::substitution_map_init" << endl + << "_xsde_substitution_map_init_;" + << endl; + + if (ctx.validation) + { + ctx.os << "static" << endl + << "const ::xsde::cxx::serializer::validating::" << + "inheritance_map_init" << endl + << "_xsde_inheritance_map_init_;" + << endl; + } + } + + // Emit "weak" header includes that are used in the file-per-type + // compilation model. + // + if (ctx.options.value ()) + { + Traversal::Schema schema; + Includes includes (ctx, Includes::source); + + schema >> includes; + schema.dispatch (ctx.schema_root); + } + + Traversal::Schema schema; + + Traversal::Sources sources; + Traversal::Names schema_names; + + Namespace ns (ctx); + Traversal::Names names; + + schema >> sources >> schema; + schema >> schema_names >> ns >> names; + + List list (ctx); + Union union_ (ctx); + Complex complex (ctx); + Enumeration enumeration (ctx); + GlobalElement global_element (ctx); + + names >> list; + names >> union_; + names >> complex; + names >> enumeration; + + if (ctx.poly_code) + names >> global_element; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsde/cxx/serializer/serializer-source.hxx b/xsde/cxx/serializer/serializer-source.hxx new file mode 100644 index 0000000..6b1353e --- /dev/null +++ b/xsde/cxx/serializer/serializer-source.hxx @@ -0,0 +1,22 @@ +// file : xsde/cxx/serializer/serializer-source.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_SERIALIZER_SOURCE_HXX +#define CXX_SERIALIZER_SERIALIZER_SOURCE_HXX + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + Void + generate_serializer_source (Context&); + } +} + +#endif // CXX_SERIALIZER_SERIALIZER_SOURCE_HXX diff --git a/xsde/cxx/serializer/type-processor.cxx b/xsde/cxx/serializer/type-processor.cxx new file mode 100644 index 0000000..6854e2c --- /dev/null +++ b/xsde/cxx/serializer/type-processor.cxx @@ -0,0 +1,356 @@ +// file : xsde/cxx/serializer/type-processor.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +namespace CXX +{ + namespace Serializer + { + namespace + { + // + // + struct Type: Traversal::Type + { + Type (SemanticGraph::Schema& schema, + TypeMap::Namespaces& type_map, + Boolean add_includes) + : schema_ (schema), + type_map_ (type_map), + add_includes_ (add_includes) + { + } + + virtual Void + traverse (SemanticGraph::Type& type) + { + using TypeMap::Namespace; + using TypeMap::Namespaces; + + SemanticGraph::Context& tc (type.context ()); + + // There are two situations where we may try to process the + // same type more than once. The first is when the type is + // used in several element declarations in the same schema. + // The second situation only occurs when we are in the file- + // per-type mode. In this case the type was processed as part + // of another root schema. In the second case, while the ret + // and arg types are assumed to be the same, we need to re- + // match the type in order to add include directives to the + // new root schema. + // + Boolean set (true); + + if (tc.count ("s:ret-type")) + { + SemanticGraph::Schema* s ( + tc.get ("s:root-schema")); + + if (&schema_ == s) + return; + + set = false; + } + + SemanticGraph::Namespace& ns ( + dynamic_cast (type.scope ())); + + String ns_name (ns.name ()); + String t_name (type.name ()); + + // std::wcerr << "traversing: " << ns_name << "#" << t_name << endl; + + for (Namespaces::ConstIterator n (type_map_.begin ()); + n != type_map_.end (); ++n) + { + // Check if the namespace matches. + // + //@@ Should probably store precompiled regex somewhere + // instead of doing it every time. + // + boost::basic_regex ns_expr; + + Boolean ns_match; + + if (!n->xsd_name ().empty ()) + { + ns_match = n->xsd_name ().match (ns_name); + } + else + ns_match = ns_name.empty (); + + // std::wcerr << "considering ns expr: " << n->xsd_name () << endl; + + if (ns_match) + { + // Namespace matched. See if there is a type that matches. + // + for (Namespace::TypesIterator t (n->types_begin ()); + t != n->types_end (); ++t) + { + if (t->xsd_name ().match (t_name)) + { + if (set) + { + // Got a match. See if the namespace has the C++ + // namespace mapping. + // + String cxx_ns; + + if (n->has_cxx_name ()) + { + if (!n->xsd_name ().empty ()) + { + cxx_ns = n->xsd_name ().merge ( + n->cxx_name (), ns_name, true); + } + else + cxx_ns = n->cxx_name (); + + cxx_ns += L"::"; + } + + // Figure out ret and arg type names. + // + String ret_type (cxx_ns); + + ret_type += t->xsd_name ().merge ( + t->cxx_ret_name (), t_name, true); + + String arg_type; + + if (t->cxx_arg_name ()) + { + arg_type = cxx_ns; + arg_type += t->xsd_name ().merge ( + t->cxx_arg_name (), t_name, true); + } + else + { + if (ret_type == L"void") + arg_type = ret_type; + else + { + WideChar last (ret_type[ret_type.size () - 1]); + + // If it is already a pointer or reference then use + // it as is. + // + if (last == L'*' || last == L'&') + arg_type = ret_type; + else + arg_type = L"const " + ret_type + L"&"; + } + } + + tc.set ("s:ret-type", ret_type); + tc.set ("s:arg-type", arg_type); + } + + tc.set ("s:root-schema", &schema_); + + //std::wcerr << t_name << " -> " << ret_type << endl; + + // See of we need to add any includes to the translations + // unit. + // + if (add_includes_) + { + if (n->includes_begin () != n->includes_end ()) + { + typedef Cult::Containers::Set Includes; + + SemanticGraph::Context& sc (schema_.context ()); + + if (!sc.count ("s:includes")) + sc.set ("s:includes", Includes ()); + + Includes& is (sc.get ("s:includes")); + + for (Namespace::IncludesIterator i (n->includes_begin ()); + i != n->includes_end (); ++i) + { + is.insert (*i); + } + } + } + + return; + } + } + } + } + } + + private: + SemanticGraph::Schema& schema_; + TypeMap::Namespaces& type_map_; + Boolean add_includes_; + }; + + // + // + struct BaseType: Traversal::Complex + { + virtual Void + traverse (SemanticGraph::Complex& c) + { + Complex::names (c); + } + }; + + // + // + struct GlobalType: Traversal::Type, + Traversal::List, + Traversal::Complex, + Traversal::Enumeration + { + GlobalType (SemanticGraph::Schema& schema, + TypeMap::Namespaces& type_map, + Boolean add_includes, + Boolean tiein) + : type_ (schema, type_map, add_includes) + { + inherits_ >> type_; + names_ >> instance_ >> belongs_ >> type_; + argumented_ >> type_; + + if (tiein) + { + // In case of a tiein support, we also need to process base's + // members to assign ret/arg types. + // + inherits_base_ >> base_type_ >> names_; + } + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + type_.traverse (t); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + type_.traverse (l); + Traversal::List::argumented (l, argumented_); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + type_.traverse (c); + Complex::inherits (c, inherits_); + Complex::inherits (c, inherits_base_); + Complex::names (c, names_); + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + type_.traverse (e); + Complex::inherits (e, inherits_); + } + + private: + Serializer::Type type_; + BaseType base_type_; + Traversal::Names names_; + Traversal::Instance instance_; + Traversal::Inherits inherits_; + Traversal::Inherits inherits_base_; + Traversal::Belongs belongs_; + Traversal::Argumented argumented_; + }; + + Void + process_impl (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& tu, + TypeMap::Namespaces& type_map) + { + Boolean tiein (!options.value () && + !options.value ()); + + if (tu.names_begin ()->named ().name () == + L"http://www.w3.org/2001/XMLSchema") + { + // XML Schema namespace. + // + Traversal::Schema schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalType global_type (tu, type_map, true, tiein); + + schema >> schema_names >> ns >> ns_names >> global_type; + + schema.dispatch (tu); + } + else + { + // If --extern-xml-schema is specified, then we don't want + // includes from the XML Schema type map. + // + Boolean extern_xml_schema ( + options.value ()); + + // Besides types defined in this schema, also process those + // referenced by global elements in case we are generating + // something for them. + // + Traversal::Schema schema; + Traversal::Schema xs_schema; + Traversal::Sources sources; + Traversal::Implies implies; + + schema >> sources >> schema; + schema >> implies >> xs_schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + Traversal::Element global_element; + GlobalType global_type (tu, type_map, true, tiein); + + schema >> schema_names >> ns >> ns_names; + + ns_names >> global_element; + ns_names >> global_type; + + Traversal::Belongs element_belongs; + global_element >> element_belongs >> global_type; + + Traversal::Names xs_schema_names; + Traversal::Namespace xs_ns; + Traversal::Names xs_ns_names; + GlobalType xs_global_type (tu, type_map, !extern_xml_schema, tiein); + + xs_schema >> xs_schema_names >> xs_ns >> xs_ns_names >> + xs_global_type; + + schema.dispatch (tu); + } + } + } + + Void TypeProcessor:: + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& s, + TypeMap::Namespaces& tm) + { + process_impl (options, s, tm); + } + } +} diff --git a/xsde/cxx/serializer/type-processor.hxx b/xsde/cxx/serializer/type-processor.hxx new file mode 100644 index 0000000..8408a4e --- /dev/null +++ b/xsde/cxx/serializer/type-processor.hxx @@ -0,0 +1,34 @@ +// file : xsde/cxx/serializer/type-processor.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_TYPE_PROCESSOR_HXX +#define CXX_SERIALIZER_TYPE_PROCESSOR_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + using namespace Cult::Types; + + class TypeProcessor + { + public: + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + TypeMap::Namespaces&); + }; + } +} + +#endif // CXX_SERIALIZER_TYPE_PROCESSOR_HXX diff --git a/xsde/cxx/serializer/validator.cxx b/xsde/cxx/serializer/validator.cxx new file mode 100644 index 0000000..d9cc724 --- /dev/null +++ b/xsde/cxx/serializer/validator.cxx @@ -0,0 +1,501 @@ +// file : xsde/cxx/serializer/validator.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +#include + +using std::wcerr; + +namespace CXX +{ + namespace Serializer + { + namespace + { + class ValidationContext: public Context + { + public: + ValidationContext (SemanticGraph::Schema& root, + CLI::Options const& options, + const WarningSet& disabled_warnings, + Boolean& valid_) + : Context (std::wcerr, root, options, 0, 0, 0), + disabled_warnings_ (disabled_warnings), + disabled_warnings_all_ (false), + valid (valid_), + subst_group_warning_issued (subst_group_warning_issued_), + subst_group_warning_issued_ (false) + { + } + + public: + Boolean + is_disabled (Char const* w) + { + return disabled_warnings_all_ || + disabled_warnings_.find (w) != disabled_warnings_.end (); + } + + public: + String + xpath (SemanticGraph::Nameable& n) + { + if (n.is_a ()) + return L""; // There is a bug if you see this. + + assert (n.named ()); + + SemanticGraph::Scope& scope (n.scope ()); + + if (scope.is_a ()) + return n.name (); + + return xpath (scope) + L"/" + n.name (); + } + + protected: + ValidationContext (ValidationContext& c) + : Context (c), + disabled_warnings_ (c.disabled_warnings_), + disabled_warnings_all_ (c.disabled_warnings_all_), + valid (c.valid), + subst_group_warning_issued (c.subst_group_warning_issued) + { + } + + protected: + const WarningSet& disabled_warnings_; + Boolean disabled_warnings_all_; + Boolean& valid; + Boolean& subst_group_warning_issued; + Boolean subst_group_warning_issued_; + }; + + // + // + struct Traverser : Traversal::Schema, + Traversal::Complex, + Traversal::Type, + Traversal::Element, + ValidationContext + { + Traverser (ValidationContext& c) + : ValidationContext (c) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + using SemanticGraph::Schema; + + traverse (static_cast (c)); + + if (c.inherits_p ()) + { + SemanticGraph::Type& t (c.inherits ().base ()); + + if (t.named () && + types_.find ( + t.scope ().name () + L"#" + t.name ()) == types_.end ()) + { + // Don't worry about types that are in included/imported + // schemas. + // + Schema& s (dynamic_cast (t.scope ().scope ())); + + if (&s == &schema_root || sources_p (schema_root, s)) + { + valid = false; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: type '" << xpath (c) << "' inherits from " + << "yet undefined type '" << xpath (t) << "'" << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: '" << xpath (t) << "' is defined here" + << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: inheritance from a yet-undefined type is " + << "not supported" << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: re-arrange your schema and try again" + << endl; + } + } + } + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (t.named ()) + { + types_.insert (t.scope ().name () + L"#" + t.name ()); + } + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (is_disabled ("S001")) + return; + + if (e.substitutes_p () && + !options.value () && + !subst_group_warning_issued) + { + subst_group_warning_issued = true; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": warning S001: substitution groups are used but " + << "--generate-polymorphic was not specified" << endl; + + os << e.file () << ":" << e.line () << ":" << e.column () + << ": info: generated code may not be able to serialize " + << "some conforming instances" << endl; + } + } + + // Return true if root sources s. + // + Boolean + sources_p (SemanticGraph::Schema& root, SemanticGraph::Schema& s) + { + using SemanticGraph::Schema; + using SemanticGraph::Sources; + + for (Schema::UsesIterator i (root.uses_begin ()); + i != root.uses_end (); ++i) + { + if (i->is_a ()) + { + if (&i->schema () == &s || sources_p (i->schema (), s)) + return true; + } + } + + return false; + } + + private: + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + + Traversal::Names names_; + }; + + // + // + struct AnonymousMember: protected ValidationContext + { + AnonymousMember (ValidationContext& c, Boolean& error_issued) + : ValidationContext (c), error_issued_ (error_issued) + { + } + + Boolean + traverse_common (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + if (!t.named () + && !t.is_a () + && !t.is_a ()) + { + if (!error_issued_) + { + valid = false; + error_issued_ = true; + + wcerr << t.file () + << ": error: anonymous types detected" + << endl; + + wcerr << t.file () + << ": info: " + << "anonymous types are not supported in this mapping" + << endl; + + wcerr << t.file () + << ": info: consider explicitly naming these types or " + << "remove the --preserve-anonymous option to " + << "automatically name them" + << endl; + + if (!options.value ()) + wcerr << t.file () + << ": info: use --show-anonymous option to see these " + << "types" << endl; + } + + return true; + } + + return false; + } + + private: + Boolean& error_issued_; + }; + + struct AnonymousElement: Traversal::Element, + AnonymousMember + { + AnonymousElement (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (traverse_common (e)) + { + if (options.value ()) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: element '" << xpath (e) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Element::traverse (e); + } + }; + + struct AnonymousAttribute: Traversal::Attribute, + AnonymousMember + { + AnonymousAttribute (ValidationContext& c, Boolean& error_issued) + : AnonymousMember (c, error_issued) + { + } + + virtual Void + traverse (Type& a) + { + if (traverse_common (a)) + { + if (options.value ()) + { + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: attribute '" << xpath (a) << "' " + << "is of anonymous type" << endl; + } + } + else + Traversal::Attribute::traverse (a); + } + }; + + struct AnonymousType : Traversal::Schema, + Traversal::Complex, + ValidationContext + { + AnonymousType (ValidationContext& c) + : ValidationContext (c), + error_issued_ (false), + element_ (c, error_issued_), + attribute_ (c, error_issued_) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + + *this >> contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> element_; + + *this >> names_attribute_ >> attribute_; + } + + private: + Boolean error_issued_; + + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + Traversal::Names names_; + + Traversal::Compositor compositor_; + AnonymousElement element_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + AnonymousAttribute attribute_; + Traversal::Names names_attribute_; + }; + + struct GlobalElement: Traversal::Element, ValidationContext + { + GlobalElement (ValidationContext& c, SemanticGraph::Element*& element) + : ValidationContext (c), element_ (element) + { + } + + virtual Void + traverse (Type& e) + { + if (!valid) + return; + + if (options.value ()) + { + if (element_ == 0) + element_ = &e; + } + else if (options.value ()) + { + element_ = &e; + } + else if (String name = options.value ()) + { + if (e.name () == name) + element_ = &e; + } + else + { + if (element_ == 0) + element_ = &e; + else + { + wcerr << schema_root.file () << ": error: unable to generate " + << "the test driver without a unique document root" + << endl; + + wcerr << schema_root.file () << ": info: use --root-element-* " + << "options to specify the document root" << endl; + + valid = false; + } + } + } + + private: + SemanticGraph::Element*& element_; + }; + } + + Boolean Validator:: + validate (CLI::Options const& options, + SemanticGraph::Schema& root, + SemanticGraph::Path const&, + Boolean gen_driver, + const WarningSet& disabled_warnings) + { + Boolean valid (true); + ValidationContext ctx (root, options, disabled_warnings, valid); + + // + // + { + Boolean ref (options.value ()); + Boolean rel (options.value ()); + Boolean re (options.value ()); + + if ((ref && rel) || (ref && re) || (rel && re)) + { + wcerr << "error: mutually exclusive options specified: " + << "--root-element-last, --root-element-first, and " + << "--root-element" + << endl; + + return false; + } + } + + // + // + if (options.value () && + options.value ()) + { + wcerr << "error: mutually exclusive options specified: " + << "--reuse-style-mixin and --reuse-style-none" + << endl; + + return false; + } + + // + // + if (options.value () && + options.value () && + !ctx.is_disabled ("S002")) + { + wcerr << "warning S002: generating sample implementation without " + << "serializer reuse support: the resulting code may not " + << "compile" + << endl; + + return false; + } + + // Test for anonymout types. + // + { + AnonymousType traverser (ctx); + traverser.dispatch (root); + } + + // Test the rest. + // + if (valid) + { + Traverser traverser (ctx); + traverser.dispatch (root); + } + + // Test that the document root is unique. + // + if (valid && gen_driver) + { + SemanticGraph::Element* element (0); + + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalElement global_element (ctx, element); + + schema >> schema_names >> ns >> ns_names >> global_element; + + schema.dispatch (root); + + if (valid && element == 0) + { + wcerr << root.file () << ": error: unable to generate the " + << "test driver without a global element (document root)" + << endl; + + valid = false; + } + } + + return valid; + } + } +} diff --git a/xsde/cxx/serializer/validator.hxx b/xsde/cxx/serializer/validator.hxx new file mode 100644 index 0000000..03d1349 --- /dev/null +++ b/xsde/cxx/serializer/validator.hxx @@ -0,0 +1,36 @@ +// file : xsde/cxx/serializer/validator.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_SERIALIZER_VALIDATOR_HXX +#define CXX_SERIALIZER_VALIDATOR_HXX + +#include + +#include + +#include + +#include + +namespace CXX +{ + namespace Serializer + { + using namespace Cult::Types; + + class Validator + { + public: + Boolean + validate (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& tu, + Boolean gen_driver, + const WarningSet& disabled_warnings); + }; + } +} + +#endif // CXX_SERIALIZER_VALIDATOR_HXX -- cgit v1.1