From f0510d2f90467de8e8f260b47d79a9baaf9bef17 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 17 Sep 2009 07:15:29 +0200 Subject: Start tracking XSD with git --- xsd/cxx/elements.cxx | 1020 ++++++ xsd/cxx/elements.hxx | 577 ++++ xsd/cxx/parser/attribute-validation-source.cxx | 410 +++ xsd/cxx/parser/attribute-validation-source.hxx | 22 + xsd/cxx/parser/characters-validation-source.cxx | 77 + xsd/cxx/parser/characters-validation-source.hxx | 22 + xsd/cxx/parser/cli.hxx | 152 + xsd/cxx/parser/driver-source.cxx | 768 +++++ xsd/cxx/parser/driver-source.hxx | 22 + xsd/cxx/parser/element-validation-source.cxx | 1587 ++++++++++ xsd/cxx/parser/element-validation-source.hxx | 22 + xsd/cxx/parser/elements.cxx | 262 ++ xsd/cxx/parser/elements.hxx | 312 ++ xsd/cxx/parser/generator.cxx | 1450 +++++++++ xsd/cxx/parser/generator.hxx | 55 + xsd/cxx/parser/impl-header.cxx | 237 ++ xsd/cxx/parser/impl-header.hxx | 22 + xsd/cxx/parser/impl-source.cxx | 389 +++ xsd/cxx/parser/impl-source.hxx | 22 + xsd/cxx/parser/name-processor.cxx | 1205 ++++++++ xsd/cxx/parser/name-processor.hxx | 34 + xsd/cxx/parser/parser-forward.cxx | 115 + xsd/cxx/parser/parser-forward.hxx | 22 + xsd/cxx/parser/parser-header.cxx | 1440 +++++++++ xsd/cxx/parser/parser-header.hxx | 22 + xsd/cxx/parser/parser-inline.cxx | 407 +++ xsd/cxx/parser/parser-inline.hxx | 22 + xsd/cxx/parser/parser-source.cxx | 924 ++++++ xsd/cxx/parser/parser-source.hxx | 22 + xsd/cxx/parser/print-impl-common.hxx | 643 ++++ xsd/cxx/parser/state-processor.cxx | 318 ++ xsd/cxx/parser/state-processor.hxx | 28 + xsd/cxx/parser/type-processor.cxx | 352 +++ xsd/cxx/parser/type-processor.hxx | 37 + xsd/cxx/parser/validator.cxx | 714 +++++ xsd/cxx/parser/validator.hxx | 35 + xsd/cxx/tree/cli.hxx | 220 ++ xsd/cxx/tree/counter.cxx | 265 ++ xsd/cxx/tree/counter.hxx | 28 + xsd/cxx/tree/elements.cxx | 1327 ++++++++ xsd/cxx/tree/elements.hxx | 2030 ++++++++++++ xsd/cxx/tree/fundamental-header.hxx | 1186 +++++++ xsd/cxx/tree/generator.cxx | 1689 ++++++++++ xsd/cxx/tree/generator.hxx | 49 + xsd/cxx/tree/name-processor.cxx | 2100 +++++++++++++ xsd/cxx/tree/name-processor.hxx | 34 + xsd/cxx/tree/parser-header.cxx | 474 +++ xsd/cxx/tree/parser-header.hxx | 23 + xsd/cxx/tree/parser-source.cxx | 544 ++++ xsd/cxx/tree/parser-source.hxx | 24 + xsd/cxx/tree/serialization-header.cxx | 581 ++++ xsd/cxx/tree/serialization-header.hxx | 22 + xsd/cxx/tree/serialization-source.cxx | 1342 ++++++++ xsd/cxx/tree/serialization-source.hxx | 24 + xsd/cxx/tree/stream-extraction-source.cxx | 754 +++++ xsd/cxx/tree/stream-extraction-source.hxx | 22 + xsd/cxx/tree/stream-header.cxx | 183 ++ xsd/cxx/tree/stream-header.hxx | 22 + xsd/cxx/tree/stream-insertion-header.cxx | 178 ++ xsd/cxx/tree/stream-insertion-header.hxx | 22 + xsd/cxx/tree/stream-insertion-source.cxx | 532 ++++ xsd/cxx/tree/stream-insertion-source.hxx | 22 + xsd/cxx/tree/stream-source.cxx | 489 +++ xsd/cxx/tree/stream-source.hxx | 24 + xsd/cxx/tree/tree-forward.cxx | 324 ++ xsd/cxx/tree/tree-forward.hxx | 22 + xsd/cxx/tree/tree-header.cxx | 3778 +++++++++++++++++++++++ xsd/cxx/tree/tree-header.hxx | 22 + xsd/cxx/tree/tree-inline.cxx | 1025 ++++++ xsd/cxx/tree/tree-inline.hxx | 22 + xsd/cxx/tree/tree-source.cxx | 3461 +++++++++++++++++++++ xsd/cxx/tree/tree-source.hxx | 24 + xsd/cxx/tree/validator.cxx | 675 ++++ xsd/cxx/tree/validator.hxx | 33 + 74 files changed, 37364 insertions(+) create mode 100644 xsd/cxx/elements.cxx create mode 100644 xsd/cxx/elements.hxx create mode 100644 xsd/cxx/parser/attribute-validation-source.cxx create mode 100644 xsd/cxx/parser/attribute-validation-source.hxx create mode 100644 xsd/cxx/parser/characters-validation-source.cxx create mode 100644 xsd/cxx/parser/characters-validation-source.hxx create mode 100644 xsd/cxx/parser/cli.hxx create mode 100644 xsd/cxx/parser/driver-source.cxx create mode 100644 xsd/cxx/parser/driver-source.hxx create mode 100644 xsd/cxx/parser/element-validation-source.cxx create mode 100644 xsd/cxx/parser/element-validation-source.hxx create mode 100644 xsd/cxx/parser/elements.cxx create mode 100644 xsd/cxx/parser/elements.hxx create mode 100644 xsd/cxx/parser/generator.cxx create mode 100644 xsd/cxx/parser/generator.hxx create mode 100644 xsd/cxx/parser/impl-header.cxx create mode 100644 xsd/cxx/parser/impl-header.hxx create mode 100644 xsd/cxx/parser/impl-source.cxx create mode 100644 xsd/cxx/parser/impl-source.hxx create mode 100644 xsd/cxx/parser/name-processor.cxx create mode 100644 xsd/cxx/parser/name-processor.hxx create mode 100644 xsd/cxx/parser/parser-forward.cxx create mode 100644 xsd/cxx/parser/parser-forward.hxx create mode 100644 xsd/cxx/parser/parser-header.cxx create mode 100644 xsd/cxx/parser/parser-header.hxx create mode 100644 xsd/cxx/parser/parser-inline.cxx create mode 100644 xsd/cxx/parser/parser-inline.hxx create mode 100644 xsd/cxx/parser/parser-source.cxx create mode 100644 xsd/cxx/parser/parser-source.hxx create mode 100644 xsd/cxx/parser/print-impl-common.hxx create mode 100644 xsd/cxx/parser/state-processor.cxx create mode 100644 xsd/cxx/parser/state-processor.hxx create mode 100644 xsd/cxx/parser/type-processor.cxx create mode 100644 xsd/cxx/parser/type-processor.hxx create mode 100644 xsd/cxx/parser/validator.cxx create mode 100644 xsd/cxx/parser/validator.hxx create mode 100644 xsd/cxx/tree/cli.hxx create mode 100644 xsd/cxx/tree/counter.cxx create mode 100644 xsd/cxx/tree/counter.hxx create mode 100644 xsd/cxx/tree/elements.cxx create mode 100644 xsd/cxx/tree/elements.hxx create mode 100644 xsd/cxx/tree/fundamental-header.hxx create mode 100644 xsd/cxx/tree/generator.cxx create mode 100644 xsd/cxx/tree/generator.hxx create mode 100644 xsd/cxx/tree/name-processor.cxx create mode 100644 xsd/cxx/tree/name-processor.hxx create mode 100644 xsd/cxx/tree/parser-header.cxx create mode 100644 xsd/cxx/tree/parser-header.hxx create mode 100644 xsd/cxx/tree/parser-source.cxx create mode 100644 xsd/cxx/tree/parser-source.hxx create mode 100644 xsd/cxx/tree/serialization-header.cxx create mode 100644 xsd/cxx/tree/serialization-header.hxx create mode 100644 xsd/cxx/tree/serialization-source.cxx create mode 100644 xsd/cxx/tree/serialization-source.hxx create mode 100644 xsd/cxx/tree/stream-extraction-source.cxx create mode 100644 xsd/cxx/tree/stream-extraction-source.hxx create mode 100644 xsd/cxx/tree/stream-header.cxx create mode 100644 xsd/cxx/tree/stream-header.hxx create mode 100644 xsd/cxx/tree/stream-insertion-header.cxx create mode 100644 xsd/cxx/tree/stream-insertion-header.hxx create mode 100644 xsd/cxx/tree/stream-insertion-source.cxx create mode 100644 xsd/cxx/tree/stream-insertion-source.hxx create mode 100644 xsd/cxx/tree/stream-source.cxx create mode 100644 xsd/cxx/tree/stream-source.hxx create mode 100644 xsd/cxx/tree/tree-forward.cxx create mode 100644 xsd/cxx/tree/tree-forward.hxx create mode 100644 xsd/cxx/tree/tree-header.cxx create mode 100644 xsd/cxx/tree/tree-header.hxx create mode 100644 xsd/cxx/tree/tree-inline.cxx create mode 100644 xsd/cxx/tree/tree-inline.hxx create mode 100644 xsd/cxx/tree/tree-source.cxx create mode 100644 xsd/cxx/tree/tree-source.hxx create mode 100644 xsd/cxx/tree/validator.cxx create mode 100644 xsd/cxx/tree/validator.hxx (limited to 'xsd/cxx') diff --git a/xsd/cxx/elements.cxx b/xsd/cxx/elements.cxx new file mode 100644 index 0000000..a62ed5d --- /dev/null +++ b/xsd/cxx/elements.cxx @@ -0,0 +1,1020 @@ +// file : xsd/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, + 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), + 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), + 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) + { + 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 ()) + { + // Here we need to detect a special multi-schema compilation + // case where the root schemas are imported into a special + // schema that doesn't have a namespace. + // + SemanticGraph::Uses& u (*schema.used_begin ()); + SemanticGraph::Schema& s (u.user ()); + + if (s.names_begin () != s.names_end ()) + 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) + { + 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); + } + + 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; + } + + 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) + { + 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 (n, L"", ns ? false : true); + + do + { + e = ns.find (L"::", b); + + String name (ns, b, e == ns.npos ? e : e - b); + + if (!name.empty ()) + { + if (st_) + st_->enter (n, name, e == ns.npos); + + ctx_.os << "namespace " << 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 (); + } +} diff --git a/xsd/cxx/elements.hxx b/xsd/cxx/elements.hxx new file mode 100644 index 0000000..dba9665 --- /dev/null +++ b/xsd/cxx/elements.hxx @@ -0,0 +1,577 @@ +// file : xsd/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, + 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), + 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), + 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&); + + // 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&); + + // 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 = "name"); + + public: + static SemanticGraph::Type& + ultimate_base (SemanticGraph::Complex&); + + public: + String + process_include_path (String const&) const; + + public: + static Boolean + skip (SemanticGraph::Member& m) + { + // "Subsequent" local element. + // + return !m.scope ().is_a () && + m.context ().count ("min") == 0; + } + + static UnsignedLong + min (SemanticGraph::Member const& m) + { + return m.context ().get ("min"); + } + + static UnsignedLong + min (SemanticGraph::Any const& a) + { + return a.context ().get ("min"); + } + + static UnsignedLong + max (SemanticGraph::Member const& m) + { + return m.context ().get ("max"); + } + + static UnsignedLong + max (SemanticGraph::Any const& a) + { + return a.context ().get ("max"); + } + + public: + // Get escaped name. + // + static String const& + ename (SemanticGraph::Nameable const& n) + { + return n.context ().get ("name"); + } + + public: + std::wostream& os; + + SemanticGraph::Schema& schema_root; + + 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_; + + 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 + { + // First scope name if always empty (global scope). The last flag + // signals the last scope. + // + virtual Void + enter (Type&, String const& name, Boolean last) = 0; + + virtual Void + leave () = 0; + }; + + + Namespace (Context& c) + : ctx_ (c), st_ (0) + { + } + + 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); + } + }; +} + +#endif // CXX_TREE_ELEMENTS_HXX diff --git a/xsd/cxx/parser/attribute-validation-source.cxx b/xsd/cxx/parser/attribute-validation-source.cxx new file mode 100644 index 0000000..52c51b1 --- /dev/null +++ b/xsd/cxx/parser/attribute-validation-source.cxx @@ -0,0 +1,410 @@ +// file : xsd/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, + protected virtual 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, + protected virtual 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 ();" + << "this->" << inst << "->_pre_impl ();" + << "this->" << inst << "->_characters (s);" + << "this->" << inst << "->_post_impl ();"; + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << "this->" << name << " ();"; + else + os << arg_type (type) << " tmp (this->" << inst << "->" << + post << " ());" + << "this->" << name << " (tmp);" + << endl; + + 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, + protected virtual 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, + protected virtual Context + { + AttributeStateInit (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + if (!a.optional ()) + os << "as." << ename (a) << " = false;"; + } + }; + + + // + // + struct AttributeStateCheck: Traversal::Attribute, + protected virtual 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) << ")" << endl + << "this->_expected_attribute (" << endl + << L << strlit (ns) << ", " << L << strlit (a.name ()) << ");"; + } + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual 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 + << "{"; + + names (c, names_phase_one_); + + // Nothing matched - call our base (extension) or return false + // if there is no base (or restriction (even from anyType)). + // + os << "return "; + + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + os << "this->" << fq_name (c.inherits ().base ()) << + "::_attribute_impl_phase_one (ns, n, s);"; + } + else + os << "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)). + // + os << "return "; + + if (c.inherits_p () && + !c.inherits ().is_a ()) + { + os << "this->" << fq_name (c.inherits ().base ()) << + "::_attribute_impl_phase_two (ns, n, s);"; + } + else + os << "false;"; + + os << "}"; + } + + if (has_req_att) + { + // _pre_a_validate + // + os << "void " << name << "::" << endl + << "_pre_a_validate ()" + << "{" + << "this->v_state_attr_stack_.push ();" + << "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 ()) + { + os << "this->" << fq_name (c.inherits ().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 ()) + { + os << "this->" << fq_name (c.inherits ().base ()) << + "::_post_a_validate ();" + << 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/xsd/cxx/parser/attribute-validation-source.hxx b/xsd/cxx/parser/attribute-validation-source.hxx new file mode 100644 index 0000000..400e460 --- /dev/null +++ b/xsd/cxx/parser/attribute-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/characters-validation-source.cxx b/xsd/cxx/parser/characters-validation-source.cxx new file mode 100644 index 0000000..ec698f8 --- /dev/null +++ b/xsd/cxx/parser/characters-validation-source.cxx @@ -0,0 +1,77 @@ +// file : xsd/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, + protected virtual 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/xsd/cxx/parser/characters-validation-source.hxx b/xsd/cxx/parser/characters-validation-source.hxx new file mode 100644 index 0000000..c9e9889 --- /dev/null +++ b/xsd/cxx/parser/characters-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/cli.hxx b/xsd/cxx/parser/cli.hxx new file mode 100644 index 0000000..504de43 --- /dev/null +++ b/xsd/cxx/parser/cli.hxx @@ -0,0 +1,152 @@ +// file : xsd/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 char_type; + extern Key output_dir; + extern Key xml_parser; + extern Key generate_inline; + extern Key generate_validation; + extern Key suppress_validation; + extern Key generate_polymorphic; + 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 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 export_symbol; + extern Key export_maps; + extern Key import_maps; + extern Key show_anonymous; + extern Key show_sloc; + extern Key proprietary_license; + + typedef Cult::CLI::Options< + type_map, Cult::Containers::Vector, + char_type, NarrowString, + output_dir, NarrowString, + xml_parser, NarrowString, + generate_inline, Boolean, + generate_validation, Boolean, + suppress_validation, Boolean, + generate_polymorphic, 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, + 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, + export_symbol, NarrowString, + export_maps, Boolean, + import_maps, Boolean, + show_anonymous, Boolean, + show_sloc, Boolean, + proprietary_license, Boolean + + > Options; + + struct OptionsSpec: Cult::CLI::OptionsSpec {}; + } + } +} + +#endif // CXX_PARSER_CLI_HXX diff --git a/xsd/cxx/parser/driver-source.cxx b/xsd/cxx/parser/driver-source.cxx new file mode 100644 index 0000000..91c4cca --- /dev/null +++ b/xsd/cxx/parser/driver-source.cxx @@ -0,0 +1,768 @@ +// file : xsd/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); + } + }; + + 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 >> names_; + base_ >> names_; + + names_ >> member_ >> 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, "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, "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, "impl") << " " << inst << ";"; + + inherits (c); + + if (!restriction_p (c)) + names (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, "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::Names names_; + Traversal::Member member_; + Traversal::Belongs belongs_; + }; + + struct ArgList : Traversal::Complex, + Traversal::List, + Traversal::Member, + Context + { + ArgList (Context& c, TypeInstanceMap& map) + : Context (c), map_ (map), first_ (true) + { + inherits_ >> *this; + names_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + names (c, names_); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&l.argumented ().type ()]; + } + + virtual Void + traverse (SemanticGraph::Member& m) + { + if (skip (m)) + return; + + if (!first_) + os << "," << endl; + else + first_ = false; + + os << map_[&m.type ()]; + } + + private: + TypeInstanceMap& map_; + + Traversal::Inherits inherits_; + Traversal::Names names_; + + 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 >> names_; + base_ >> names_; + + names_ >> member_ >> 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); + } + } + + 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::Names names_; + Traversal::Member member_; + Traversal::Belongs belongs_; + }; + } + + 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 root_element (ctx.options, root); + + schema >> schema_names >> ns >> ns_names >> root_element; + + schema.dispatch (ctx.schema_root); + } + + std::wostream& os (ctx.os); + String const& L (ctx.L); + String const& cerr (ctx.cerr_inst); + + InstanceSet set; + TypeInstanceMap map; + SemanticGraph::Type& root_type (root->type ()); + + set.insert ("doc_p"); + + os << "#include " << endl + << endl + << "int" << endl + << "main (int argc, char* argv[])" + << "{" + << "if (argc != 2)" + << "{" + << cerr << " << " << L << "\"usage: \" << argv[0] << " << + L << "\" file.xml\" << std::endl;" + << "return 1;" + << "}" + << "try" + << "{" + << "// Instantiate individual parsers." << endl + << "//" << endl; + + { + ParserDef def (ctx, map, set); + def.dispatch (root_type); + } + + os << endl + << "// Connect the parsers together." << endl + << "//" << endl; + + { + ParserConnect connect (ctx, map); + connect.dispatch (root_type); + } + + String const& root_p (map[&root_type]); + + os << "// Parse the XML document." << endl + << "//" << endl; + + if (root->namespace_().name ()) + os << ctx.xs_ns_name () << "::document doc_p (" << endl + << root_p << "," << endl + << L << ctx.strlit (root->namespace_().name ()) << "," << endl + << L << ctx.strlit (root->name ()) << ");" + << endl; + else + os << ctx.xs_ns_name () << "::document doc_p (" << root_p << ", " << + L << ctx.strlit (root->name ()) << ");" + << endl; + + os << root_p << ".pre ();" + << "doc_p.parse (argv[1]);"; + + String const& ret (Context::ret_type (root_type)); + String const& post (Context::post_name (root_type)); + + if (ret == L"void") + os << root_p << "." << post << " ();"; + else + { + os << Context::arg_type (root_type) << " v (" << + root_p << "." << post << " ());" + << endl; + + if (ctx.options.value ()) + { + PrintCall t (ctx, root->name (), "v"); + t.dispatch (root_type); + } + else + os << "// TODO" << endl + << "//" << endl; + } + + os << "}" // try + << "catch (const " << ctx.xs_ns_name () << "::exception& e)" + << "{" + << cerr << " << e << std::endl;" + << "return 1;" + << "}" + << "catch (const std::ios_base::failure&)" + << "{" + << cerr << " << argv[1] << " << + L << "\": error: io failure\" << std::endl;" + << "return 1;" + << "}" + << "}"; + } + } +} diff --git a/xsd/cxx/parser/driver-source.hxx b/xsd/cxx/parser/driver-source.hxx new file mode 100644 index 0000000..9e0912f --- /dev/null +++ b/xsd/cxx/parser/driver-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/element-validation-source.cxx b/xsd/cxx/parser/element-validation-source.cxx new file mode 100644 index 0000000..949f491 --- /dev/null +++ b/xsd/cxx/parser/element-validation-source.cxx @@ -0,0 +1,1587 @@ +// file : xsd/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; + + + // + // + struct ParticleTest: Traversal::Compositor, + Traversal::Element, + Traversal::Any, + protected virtual Context + { + ParticleTest (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& name (e.name ()); + + if (polymorphic && e.global ()) + 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 (polymorphic && e.global ()) + { + os << ") ||" << endl + << "::xsd::cxx::parser::substitution_map_instance< " << + char_type << " > ().check (" << endl + << "ns, n, " << L << strlit (e.namespace_ ().name ()) << + ", " << L << strlit (name) << ", 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 ("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, + protected virtual 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 ("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 (polymorphic && !anonymous (type)); + + String name, inst, def_parser, map; + + if (e->context ().count("name")) + { + name = ename (*e); + inst = poly ? emember_cache (*e) : emember (*e); + + if (poly) + { + def_parser = emember (*e); + map = emember_map (*e); + } + } + else + { + // This is the subsequent mentioning of this element in the + // content. We need to find the first one in order to get + // to the escaped names. + // + Complex::NamesIteratorPair ip (type_.find (e->name ())); + assert (ip.first != ip.second); + Element& fe (dynamic_cast(ip.first->named ())); + + name = ename (fe); + inst = poly ? emember_cache (fe) : emember (fe); + + if (poly) + { + def_parser = emember (fe); + map = emember_map (fe); + } + } + + if (poly) + { + // For pre-computing length. + // + String type_id (type.name ()); + + if (String type_ns = xml_ns_name (type)) + { + type_id += L' '; + type_id += type_ns; + } + + os << "if (t == 0 && this->" << def_parser << " != 0)" << endl + << "this->" << inst << " = this->" << def_parser << ";" + << "else" + << "{" + << string_type << " ts (" << fq_name (type) << + "::_static_type (), " << type_id.size () << "UL);" + << endl + << "if (t == 0)" << endl + << "t = &ts;" + << endl + << "if (this->" << def_parser << " != 0 && *t == ts)" << endl + << "this->" << inst << " = this->" << def_parser << ";" + << "else" + << "{"; + + // Check that the types are related by inheritance. + // + os << "if (t != &ts &&" << endl + << "!::xsd::cxx::parser::validating::" << + "inheritance_map_instance< " << char_type << + " > ().check (" << endl + << "t->data (), ts))" << endl + << "throw ::xsd::cxx::parser::dynamic_type< " << char_type << + " > (*t);" + << endl + << "if (this->" << map << " != 0)" << endl + << "this->" << inst << " = dynamic_cast< " << + fq_name (type) << "* > (" << endl + << "this->" << map << "->find (*t));" + << "else" << endl + << "this->" << inst << " = 0;" + << "}" + << "}"; + } + + os << "this->" << complex_base << "::context_.top ()." << + "parser_ = this->" << inst << ";" + << endl + << "if (this->" << inst << ")" << endl + << "this->" << inst << "->pre ();" + << "}" + << "else" // start + << "{" + << "if (this->" << inst << ")" + << "{"; + + String const& ret (ret_type (type)); + String const& post (post_name (type)); + + if (ret == L"void") + os << "this->" << inst << "->" << post << " ();" + << "this->" << name << " ();"; + else + os << arg_type (type) << " tmp (this->" << inst << "->" << + post << " ());" + << "this->" << name << " (tmp);"; + + os << "}"; + } + else + { + os << "this->_start_any_element (ns, n, t);" + << "this->" << complex_base << "::context_.top ().any_ = true;" + << "}" + << "else" // start + << "{" + << "this->" << complex_base << "::context_.top ().any_ = false;" + << "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 ("state")); + + if (state != 0) + os << "else "; + + os << "if ("; + + particle_test_.traverse (e); + + os << ")" + << "{" + << "if (count[" << state << "UL] == 0)" + << "{" + << "if (start)" + << "{"; + + 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 ("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->_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::Compositor; + + UnsignedLong max (c.max ()); + UnsignedLong min (c.context ().get ("effective-min")); + UnsignedLong n (c.context ().get ("comp-number")); + UnsignedLong state (c.context ().get ("state")); + + String func (c.is_a () ? + "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 () && !c.context ().count ("comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("prefix")) + break; + + UnsignedLong state (p.context ().get ("state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + // 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. + // + + 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 + << "this->" << func << n << " (vd.state, vd.count, ns, n, t, 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->_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)" << endl + << "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::Compositor; + + UnsignedLong max (c.max ()); + UnsignedLong min (c.context ().get ("effective-min")); + UnsignedLong n (c.context ().get ("comp-number")); + + String func (c.is_a () ? + "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 () && !c.context ().count ("comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("prefix")) + break; + + UnsignedLong state (p.context ().get ("state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + // 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. + // + + 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 + << "this->" << func << n << " (vd.state, vd.count, ns, n, t, true);" + << "break;" + << "}"; + + // Not this compositor. + // + + 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)" << endl + << "this->_expected_element (" << endl; + + particle_name_.dispatch (c); + + os << "," << endl + << "ns, n);"; + } + + 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, + protected virtual 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 ("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 + << "const " << string_type << "* t," << endl + << "bool start)" + << "{" + << "XSD_UNUSED (t);" + << 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 ("state")); + + os << "if (count[" << state << "UL] == 0)" << endl + << "this->_expected_element (" << endl + << L << strlit (ns) << ", " << + L << strlit (e.name ()) << ");" + << endl; + } + + os << "state = ~0UL;" + << "}" + << "else" << endl + << "state = ~0UL;" + << "}"; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!c.context().count ("comp-number")) // Empty compositor. + return; + + using SemanticGraph::Compositor; + + UnsignedLong n (c.context ().get ("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 + << "const " << string_type << "* t," << endl + << "bool start)" + << "{" + << "XSD_UNUSED (count);" + << "XSD_UNUSED (ns);" + << "XSD_UNUSED (n);" + << "XSD_UNUSED (t);" + << 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 ("comp-number")) + continue; // Empty compositor. + + ParticleInChoice t (*this, type_); + t.dispatch (p); + } + + os << "}" // switch + << "}"; + + // Generate nested compositor functions. + // + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!s.context().count ("comp-number")) // Empty compositor. + return; + + using SemanticGraph::Compositor; + + UnsignedLong n (s.context ().get ("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 + << "const " << string_type << "* t," << endl + << "bool start)" + << "{" + << "XSD_UNUSED (t);" + << endl + << "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 ("comp-number")) + { + // Empty compositor. + // + ++ci; + continue; + } + + // Find the next state. + // + do + ++ci; + while (ci != ce && + ci->particle ().is_a () && + !ci->particle ().context().count ("comp-number")); + + UnsignedLong next (ci == ce ? 0 : state + 1); + + ParticleInSequence t (*this, state++, next, type_); + t.dispatch (p); + } + + 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, + protected virtual 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, + protected virtual 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, t, true);" + << endl + << "if (vd->state != ~0UL)" << endl + << "vd->count++;" + << "else" << endl + << "return false;" // Let our parent handle this. + << endl; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) // Choice and sequence. + { + using SemanticGraph::Compositor; + + UnsignedLong max (c.max ()); + UnsignedLong min (c.context ().get ("effective-min")); + UnsignedLong n (c.context ().get ("comp-number")); + + String func (c.is_a () ? + "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, t, true);" + << endl + << "vd = vs.data + (vs.size - 1);" // re-acquire + << endl + << "if (vd->state == ~0UL)" << 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 () && !c.context ().count ("comp-number")) + continue; // Empty compositor. + + if (!p.context ().count ("prefix")) + break; + + UnsignedLong state (p.context ().get ("state")); + + if (first) + first = false; + else + os << "else "; + + os << "if ("; + + particle_test_.dispatch (p); + + os << ")" << endl + << "s = " << state << "UL;"; + } + + 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. + // + + os << endl + << "vd = vs.data + vs.size++;" // push + << "vd->func = &" << ename (type_) << "::" << func << n << ";" + << "vd->state = s;" + << "vd->count = 0;" + << endl + << "this->" << func << n << " (vd->state, vd->count, ns, n, t, true);" + << "}"; + + // This element is not our prefix. + // + + os << "else" + << "{"; + + // 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->_expected_element (" << endl; + + particle_name_.dispatch (c); + + os << "," << endl + << "ns, n);"; + } + + // 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, + protected virtual 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, 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, 0, false);" + << endl + << "if (vd.state == ~0UL)" << endl + << "vs.size--;" // pop + << endl; + } + + private: + SemanticGraph::Complex& type_; + }; + + + // + // + struct CompositorPost: Traversal::All, + Traversal::Compositor, + protected virtual 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, 0, true);" + << "}"; + + if (a.context ().get ("effective-min") != 0) + { + os << "else" << endl + << "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. + { + UnsignedLong min (c.context ().get ("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, 0, true);" + << "assert (vd->state == ~0UL);" + << "vd = vs.data + (--vs.size - 1);" // pop + << "}"; + + // 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->_expected_element (" << endl; + + particle_name_.dispatch (c); + + os << ");"; + } + } + + private: + SemanticGraph::Complex& type_; + ParticleName particle_name_; + }; + + + // + // + struct Complex : Traversal::Complex, + protected virtual 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," << endl + << "const " << string_type << "* t)" + << "{" + << "XSD_UNUSED (t);" + << 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. + // States 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)" + << "{" + << "if (this->"; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + + os << "::_start_element_impl (ns, n, t))" << endl + << "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)" + << "{" + << "if (!"; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "::_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 ()" + << "{" + << "this->v_state_stack_.push ();" + << "static_cast< v_state_* > (this->v_state_stack_.top ())->" << + "size = 0;" + << endl; + + { + 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 ()) + { + os << endl + << fq_name (c.inherits ().base ()) << "::_pre_e_validate ();"; + } + } + + os << "}"; + + + // _post_e_validate + // + os << "void " << name << "::" << endl + << "_post_e_validate ()" + << "{"; + + // 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 ()) + { + os << fq_name (c.inherits ().base ()) << "::_post_e_validate ();" + << 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/xsd/cxx/parser/element-validation-source.hxx b/xsd/cxx/parser/element-validation-source.hxx new file mode 100644 index 0000000..493c1ef --- /dev/null +++ b/xsd/cxx/parser/element-validation-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/elements.cxx b/xsd/cxx/parser/elements.cxx new file mode 100644 index 0000000..8a02ffb --- /dev/null +++ b/xsd/cxx/parser/elements.cxx @@ -0,0 +1,262 @@ +// file : xsd/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 + { + // Keep this symbol first to help HP-UX linker (long symbols?). + // + 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; + } + + 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, + ops.value (), + ops.value (), + ops.value (), + ops.value (), + 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_), + cout_inst (cout_inst_), + cerr_inst (cerr_inst_), + parser_map (parser_map_), + std_string_type (std_string_type_), + validation (validation_), + polymorphic (polymorphic_), + hxx_expr (he), + ixx_expr (ie), + hxx_impl_expr (hie), + xml_parser_ (ops.value ()), + validation_ ((ops.value () == "expat" || + ops.value ()) && + !ops.value ()), + polymorphic_ (ops.value ()) + { + if (char_type == L"char") + std_string_type = L"::std::string"; + else if (char_type == L"wchar_t") + std_string_type = L"::std::wstring"; + else + std_string_type = L"::std::basic_string< " + char_type + L" >"; + + String xs_ns (xs_ns_name ()); + + string_type = xs_ns + L"::ro_string"; + simple_base = xs_ns + L"::simple_content"; + complex_base = xs_ns + L"::complex_content"; + list_base = xs_ns + L"::list_base"; + + cout_inst = (char_type == L"char" ? L"std::cout" : L"std::wcout"); + cerr_inst = (char_type == L"char" ? L"std::cerr" : L"std::wcerr"); + + if (polymorphic) + parser_map_ = xs_ns + L"::parser_map"; + } + + Context:: + 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), + cout_inst (c.cout_inst), + cerr_inst (c.cerr_inst), + parser_map (c.parser_map), + std_string_type (c.std_string_type), + validation (c.validation), + polymorphic (c.polymorphic), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + Context:: + 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), + cout_inst (c.cout_inst), + cerr_inst (c.cerr_inst), + parser_map (c.parser_map), + std_string_type (c.std_string_type), + validation (c.validation), + polymorphic (c.polymorphic), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + hxx_impl_expr (c.hxx_impl_expr) + { + } + + Boolean Context:: + anonymous (SemanticGraph::Type& t) + { + return t.context ().count ("anonymous"); + } + + String const& Context:: + ret_type (SemanticGraph::Type& t) + { + return t.context ().get ("ret-type"); + } + + String const& Context:: + arg_type (SemanticGraph::Type& t) + { + return t.context ().get ("arg-type"); + } + + String const& Context:: + post_name (SemanticGraph::Type& t) + { + return t.context ().get ("post"); + } + + String const& Context:: + eparser (SemanticGraph::Member& m) + { + return m.context ().get ("parser"); + } + + String const& Context:: + emember (SemanticGraph::Member& m) + { + return m.context ().get ("member"); + } + + String const& Context:: + emember_cache (SemanticGraph::Member& m) + { + return m.context ().get ("member-cache"); + } + + String const& Context:: + emember_map (SemanticGraph::Member& m) + { + return m.context ().get ("member-map"); + } + + String const& Context:: + eimpl (SemanticGraph::Type& t) + { + return t.context ().get ("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/xsd/cxx/parser/elements.hxx b/xsd/cxx/parser/elements.hxx new file mode 100644 index 0000000..cac1786 --- /dev/null +++ b/xsd/cxx/parser/elements.hxx @@ -0,0 +1,312 @@ +// file : xsd/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); + Context (Context& c, std::wostream& o); + + 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 Content::Value + content (SemanticGraph::Complex&); + + public: + static Boolean + anonymous (SemanticGraph::Type&); + + public: + static String const& + ret_type (SemanticGraph::Type&); + + static String const& + arg_type (SemanticGraph::Type&); + + static String const& + post_name (SemanticGraph::Type&); + + 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&); + + 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& cout_inst; + String& cerr_inst; + String& parser_map; + String& std_string_type; + Boolean& validation; + Boolean& polymorphic; + + 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 cout_inst_; + String cerr_inst_; + String parser_map_; + String std_string_type_; + Boolean validation_; + Boolean polymorphic_; + }; + + // + // + struct RequiredAttributeTest: Traversal::Attribute + { + RequiredAttributeTest (Boolean& result) + : result_ (result) + { + } + + virtual Void + traverse (Type& a) + { + if (!result_ && !a.optional ()) + result_ = true; + } + + private: + Boolean& result_; + }; + + // + // + struct ParserParamDecl : Traversal::Complex, + Traversal::List, + Traversal::Member, + protected virtual Context + { + ParserParamDecl (Context& c, Boolean name_arg) + : Context (c), first_ (true), name_arg_ (name_arg) + { + inherits_ >> *this; + names_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + names (c, names_); + } + + 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 */"; + } + + virtual Void + traverse (SemanticGraph::Member& m) + { + if (skip (m)) return; + + if (!first_) + os << "," << endl; + else + first_ = false; + + os << fq_name (m.type ()) << "&"; + + if (name_arg_) + os << " " << ename (m); + else + os << " /* " << comment (m.name ()) << " */"; + } + + private: + Traversal::Inherits inherits_; + 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 ? "name" : "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/xsd/cxx/parser/generator.cxx b/xsd/cxx/parser/generator.cxx new file mode 100644 index 0000000..342e3f2 --- /dev/null +++ b/xsd/cxx/parser/generator.cxx @@ -0,0 +1,1450 @@ +// file : xsd/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 + +#include "../../../libxsd/xsd/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, an XML Schema to\n" + "// C++ data binding compiler.\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" + "// In addition, as a special exception, Code Synthesis Tools CC gives\n" + "// permission to link this program with the Xerces-C++ library (or with\n" + "// modified versions of Xerces-C++ that use the same license as Xerces-C++),\n" + "// and distribute linked combinations including the two. You must obey\n" + "// the GNU General Public License version 2 in all respects for all of\n" + "// the code used other than Xerces-C++. If you modify this copy of the\n" + "// program, you may extend this exception to your version of the program,\n" + "// but you are not obligated to do so. If you do not wish to do so, delete\n" + "// this exception statement from your version.\n" + "//\n" + "// Furthermore, Code Synthesis Tools CC makes a special exception for\n" + "// the Free/Libre and Open Source Software (FLOSS) which is described\n" + "// in the accompanying FLOSSE file.\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD, an XML Schema\n" + "// to C++ data binding compiler, in the Proprietary License mode.\n" + "// You should have received a proprietary license from Code Synthesis\n" + "// Tools CC prior to generating this code. See the license text for\n" + "// conditions.\n" + "//\n\n"; + + Char const copyright_impl[] = + "// Not copyrighted - public domain.\n" + "//\n" + "// This sample parser implementation was generated by CodeSynthesis XSD,\n" + "// an XML Schema to C++ data binding compiler. You may use it in your\n" + "// programs without any restrictions.\n" + "//\n\n"; + } + + namespace Parser + { + namespace CLI + { + extern Key char_type; + extern Key type_map = "type-map"; + extern Key char_type = "char-type"; + extern Key output_dir = "output-dir"; + extern Key xml_parser = "xml-parser"; + extern Key generate_inline = "generate-inline"; + extern Key generate_validation = "generate-validation"; + extern Key suppress_validation = "suppress-validation"; + extern Key generate_polymorphic = "generate-polymorphic"; + 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 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 export_symbol = "export-symbol"; + extern Key export_maps = "export-maps"; + extern Key import_maps = "import-maps"; + 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 << "--char-type " << endl + << " Use as the base character type. Valid\n" + << " values are 'char' (default) and 'wchar_t'." + << endl; + + e << "--output-dir " << endl + << " Write generated files to instead of current\n" + << " directory." + << endl; + + e << "--xml-parser " << endl + << " Use as the underlying XML parser. Valid\n" + << " values are 'xerces' (default) and 'expat'." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--generate-validation" << endl + << " Generate validation code." + << 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 << "--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 << "--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 << "--export-symbol " << endl + << " Export symbol for Win32 DLL export/import control." + << endl; + + e << "--export-maps" << endl + << " Export polymorphism support maps from Win32 DLL." + << endl; + + e << "--import-maps" << endl + << " Import polymorphism support maps from Win32 DLL." + << endl; + + 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 ("char"); + spec.option ().default_value ("xerces"); + + 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, + 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 () == "expat" || + ops.value ()) && + !ops.value ()); + + // Compute state machine info. + // + if (validation) + { + StateProcessor proc; + proc.process (schema, file_path); + } + + // Read-in type maps. + // + TypeMap::Namespaces type_map; + { + 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-based types. + // + String char_type (ops.value ()); + String string_type; + + 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" >"; + + String xns; + { + Context ctx (std::wcerr, schema, ops, 0, 0, 0); + xns = ctx.xs_ns_name (); + } + + String buffer (L"::std::auto_ptr< " + xns + L"::buffer >"); + TypeMap::Namespace xsd ("http://www\\.w3\\.org/2001/XMLSchema"); + + xsd.types_push_back ("string", string_type); + xsd.types_push_back ("normalizedString", string_type); + xsd.types_push_back ("token", string_type); + xsd.types_push_back ("Name", string_type); + xsd.types_push_back ("NMTOKEN", string_type); + xsd.types_push_back ("NMTOKENS", xns + L"::string_sequence"); + xsd.types_push_back ("NCName", string_type); + + xsd.types_push_back ("ID", string_type); + xsd.types_push_back ("IDREF", string_type); + xsd.types_push_back ("IDREFS", xns + L"::string_sequence"); + + xsd.types_push_back ("language", string_type); + xsd.types_push_back ("anyURI", string_type); + xsd.types_push_back ("QName", xns + L"::qname"); + + 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"); + + // Fundamental C++ types. + // + 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"); + + 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", "long long"); + + xsd.types_push_back ("negativeInteger", "long long", "long long"); + xsd.types_push_back ("nonPositiveInteger", "long long", "long long"); + + xsd.types_push_back ("positiveInteger", + "unsigned long long", + "unsigned long long"); + xsd.types_push_back ("nonNegativeInteger", + "unsigned long long", + "unsigned long long"); + + xsd.types_push_back ("float", "float", "float"); + xsd.types_push_back ("double", "double", "double"); + xsd.types_push_back ("decimal", "double", "double"); + + 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, gen_driver, type_map); + } + + // + // + Boolean inline_ (ops.value () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + // Generate code. + // + 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-driver" + 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 (XSD_INT_VERSION != " << XSD_INT_VERSION << "L)" << endl + << "#error XSD runtime version mismatch" << 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; + + 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/xsd/cxx/parser/generator.hxx b/xsd/cxx/parser/generator.hxx new file mode 100644 index 0000000..aaab3b8 --- /dev/null +++ b/xsd/cxx/parser/generator.hxx @@ -0,0 +1,55 @@ +// file : xsd/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 + +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, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks); + + private: + Generator (); + }; + } +} + +#endif // CXX_PARSER_GENERATOR_HXX diff --git a/xsd/cxx/parser/impl-header.cxx b/xsd/cxx/parser/impl-header.cxx new file mode 100644 index 0000000..8a52254 --- /dev/null +++ b/xsd/cxx/parser/impl-header.cxx @@ -0,0 +1,237 @@ +// file : xsd/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, + protected virtual 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 " << type_exp << name << ": " << + "public virtual " << ename (e) << "," << endl + << " public " << fq_name (base, "impl") + << "{" + << "public:" << endl + << "virtual void" << endl + << "pre ();" + << endl + << "virtual " << ret << endl + << post_name (e) << " ();" + << "};"; + } + }; + + // + // + struct List: Traversal::List, protected virtual 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 " << type_exp << name << ": public 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, protected virtual Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (eimpl (u)); + String const& ret (ret_type (u)); + + os << "class " << type_exp << name << ": public 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 ParserCallback: Traversal::Member, + protected virtual Context + { + ParserCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + String const& arg (arg_type (m.type ())); + + os << "virtual void" << endl + << ename (m); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual Context + { + Complex (Context& c) + : Context (c), + parser_callback_ (c) + { + names_parser_callback_ >> parser_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (eimpl (c)); + String const& ret (ret_type (c)); + + os << "class " << type_exp << name << ": public virtual " << + ename (c); + + if (c.inherits_p ()) + os << "," << endl + << " public " << fq_name (c.inherits ().base (), "impl"); + + os << "{" + << "public:" << endl + << "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)) + { + names (c, names_parser_callback_); + } + + os << "virtual " << ret << endl + << post_name (c) << " ();" + << "};"; + } + + private: + // + // + ParserCallback parser_callback_; + Traversal::Names names_parser_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/xsd/cxx/parser/impl-header.hxx b/xsd/cxx/parser/impl-header.hxx new file mode 100644 index 0000000..d69c65a --- /dev/null +++ b/xsd/cxx/parser/impl-header.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/impl-source.cxx b/xsd/cxx/parser/impl-source.cxx new file mode 100644 index 0000000..00b9456 --- /dev/null +++ b/xsd/cxx/parser/impl-source.cxx @@ -0,0 +1,389 @@ +// file : xsd/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, + protected virtual 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; + + // 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 ()) + { + PrintCall t (*this, e.name (), "v"); + t.dispatch (base); + } + else + os << "// TODO" << endl + << "//" << endl; + } + else + { + if (base_ret == L"void") + os << post_name (base) << " ();"; + else + os << arg_type (base) << " v (" << post_name (base) << " ());" + << endl + << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + } + + os << "}"; + } + }; + + // + // + struct List: Traversal::List, protected virtual 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; + } + + 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, protected virtual 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 ()) + os << cout_inst << " << " << L << 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 ParserCallback: Traversal::Member, + protected virtual Context + { + ParserCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + String const& name (ename (m)); + String const& arg (arg_type (m.type ())); + + os << "void " << + eimpl (dynamic_cast (m.scope ())) << + "::" << endl + << name; + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << " " << name << ")"; + + os << "{"; + + if (arg != L"void") + { + if (options.value ()) + { + PrintCall t (*this, m.name (), name); + t.dispatch (m.type ()); + } + else + os << "// TODO" << endl + << "//" << endl; + } + + os << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual Context + { + Complex (Context& c) + : Context (c), parser_callback_ (c) + { + names_parser_callback_ >> parser_callback_; + } + + virtual Void + traverse (Type& c) + { + String const& name (eimpl (c)); + + Boolean restriction (restriction_p (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{" + << "}"; + + // Parser callbacks. + // + if (!restriction) + names (c, names_parser_callback_); + + // post + // + String const& ret (ret_type (c)); + + os << ret << " " << name << "::" << endl + << post_name (c) << " ()" + << "{"; + + if (c.inherits_p ()) + { + 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 ()) + { + PrintCall t (*this, c.name (), "v"); + t.dispatch (base); + } + else + os << "// TODO" << endl + << "//" << endl; + } + else + { + if (base_ret == L"void") + os << post_name (base) << " ();"; + else + os << arg_type (base) << " v (" << post_name (base) << " ());" + << endl + << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + } + } + else + { + if (ret != L"void") + os << "// TODO" << endl + << "//" << endl + << "// return ... ;" << endl; + } + + os << "}"; + } + + private: + // + // + ParserCallback parser_callback_; + Traversal::Names names_parser_callback_; + }; + } + + Void + generate_impl_source (Context& ctx) + { + if (ctx.options.value ()) + 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/xsd/cxx/parser/impl-source.hxx b/xsd/cxx/parser/impl-source.hxx new file mode 100644 index 0000000..68a5f5e --- /dev/null +++ b/xsd/cxx/parser/impl-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/name-processor.cxx b/xsd/cxx/parser/name-processor.cxx new file mode 100644 index 0000000..b40522b --- /dev/null +++ b/xsd/cxx/parser/name-processor.cxx @@ -0,0 +1,1205 @@ +// file : xsd/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 + { + NameProcessor:: + NameProcessor () + { + // Dummy ctor, helps with long symbols on HP-UX. + } + + 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, + ops.value (), + ops.value (), + ops.value (), + ops.value (), + 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 ()), + skel_suffix (skel_suffix_), + impl_suffix (impl_suffix_), + global_type_names (global_type_names_), + polymorphic (ops.value ()) + { + } + + protected: + Context (Context& c) + : CXX::Context (c), + schema (c.schema), + schema_path (c.schema_path), + impl (c.impl), + skel_suffix (c.skel_suffix), + impl_suffix (c.impl_suffix), + global_type_names (c.global_type_names), + polymorphic (c.polymorphic) + { + } + + public: + String + find_name (String const& n, NameSet& set) + { + String base_name (escape (n)); + 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; + } + + 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; + String const& skel_suffix; + String const& impl_suffix; + + Cult::Containers::Map& global_type_names; + + Boolean polymorphic; + }; + + + // + // + struct PrimaryMember: Traversal::Member, Context + { + PrimaryMember (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (Type& m) + { + if (Parser::Context::skip (m)) + return; + + m.context ().set ("name", find_name (m.name (), set_)); + } + + private: + NameSet& set_; + }; + + struct DerivedMember: Traversal::Member, Context + { + DerivedMember (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (Type& m) + { + if (Parser::Context::skip (m)) + return; + + m.context ().set ("parser", + find_name (m.name () + L"_parser", set_)); + + String const& base (m.context ().get ("name")); + m.context ().set ("member", find_name (base + L"_parser_", set_)); + + if (polymorphic && + m.is_a () && + !m.type ().context ().count ("anonymous")) + { + m.context ().set ( + "member-cache", find_name (base + L"_parser_cache_", set_)); + + m.context ().set ( + "member-map", find_name (base + L"_parser_map_", set_)); + + m.context ().set ( + "member-map-impl", + find_name (base + L"_parser_map_impl_", set_)); + } + } + + private: + NameSet& set_; + }; + + + // + // + struct MemberInRestrictionBase: Traversal::Member + { + protected: + MemberInRestrictionBase (NameSet& set, SemanticGraph::Complex& base) + : set_ (set), base_ (base) + { + } + + struct NotFound {}; + + Type& + find_member (SemanticGraph::Complex& c, Type& m) + { + using SemanticGraph::Complex; + + Complex::NamesIteratorPair r (c.find (m.name ())); + + for (; r.first != r.second; ++r.first) + { + if (r.first->named ().is_a ()) + { + Type& bm (dynamic_cast (r.first->named ())); + + if (typeid (bm) != typeid (m)) + continue; + + if (m.qualified ()) + { + if (bm.qualified () && + m.name () == bm.name () && + m.namespace_ ().name () == bm.namespace_ ().name ()) + return bm; + } + else + { + if (!bm.qualified () && m.name () == bm.name ()) + return bm; + } + } + } + + // If we didn't find anything, try our base. + // + if (c.inherits_p ()) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + if (base.is_a ()) + return find_member (dynamic_cast (base), m); + } + + //std::wcerr << "unable to find member " << m.name () << " in " + // << c.name () << std::endl; + + throw NotFound (); + } + + protected: + NameSet& set_; + SemanticGraph::Complex& base_; + }; + + struct PrimaryMemberInRestriction: MemberInRestrictionBase, Context + { + PrimaryMemberInRestriction (Context& c, + NameSet& set, + SemanticGraph::Complex& base) + : MemberInRestrictionBase (set, base), Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (Parser::Context::skip (m)) + return; + + String name; + + try + { + // Try to find corresponding member in one of our bases. + // This may fail if we use an element that substitutes + // one in our base. + // + Type& bm (find_member (base_, m)); + name = bm.context ().get ("name"); + } + catch (NotFound const&) + { + // Fall back to the standard name assignment. + // + name = find_name (m.name (), set_); + } + + m.context ().set ("name", name); + } + }; + + struct DerivedMemberInRestriction: MemberInRestrictionBase, Context + { + DerivedMemberInRestriction (Context& c, + NameSet& set, + SemanticGraph::Complex& base) + : MemberInRestrictionBase (set, base), Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (Parser::Context::skip (m)) + return; + + Boolean poly (polymorphic && + m.is_a () && + !m.type ().context ().count ("anonymous")); + + String parser, member, member_cache, member_map, member_map_impl; + + try + { + // Try to find corresponding member in one of our bases. + // This may fail if we use an element that substitutes + // one in our base. + // + Type& bm (find_member (base_, m)); + parser = bm.context ().get ("parser"); + member = bm.context ().get ("member"); + + if (poly) + { + member_cache = bm.context ().get ("member-cache"); + member_map = bm.context ().get ("member-map"); + member_map_impl = bm.context ().get ("member-map-impl"); + } + } + catch (NotFound const&) + { + // Fall back to the standard name assignment. + // + String const& base (m.context ().get ("name")); + + parser = find_name (m.name () + L"_parser", set_); + member = find_name (base + L"_parser_", set_); + + if (poly) + { + member_cache = find_name (base + L"_parser_cache_", set_); + member_map = find_name (base + L"_parser_map_", set_); + member_map_impl = find_name (base + L"_parser_map_impl_", set_); + } + } + + m.context ().set ("parser", parser); + m.context ().set ("member", member); + + if (poly) + { + m.context ().set ("member-cache", member_cache); + m.context ().set ("member-map", member_map); + m.context ().set ("member-map-impl", member_map_impl); + } + } + }; + + // + // + 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 ("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 (); + } + } + + if (restriction) + { + // First assign the "primary" names. + // + { + PrimaryMemberInRestriction member ( + *this, + member_set, + dynamic_cast ( + c.inherits ().base ())); + + Traversal::Names names (member); + + Complex::names (c, names); + } + + // Assign "derived" names. + // + { + DerivedMemberInRestriction member ( + *this, + member_set, + dynamic_cast ( + c.inherits ().base ())); + + Traversal::Names names (member); + + Complex::names (c, names); + } + } + else + { + // First assign the "primary" names. + // + { + PrimaryMember member (*this, member_set); + Traversal::Names names (member); + + Complex::names (c, names); + } + + // Assign "derived" names. + // + { + DerivedMember member (*this, member_set); + Traversal::Names names (member); + + 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 ("name", name); + + // Assign the post_* name. + // + c.set ("post", find_post_name (t)); + + // Note that we do not add this name to the set so that it + // does not influence other names. + // + if (impl) + c.set ("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 ("post")) + set.insert (b->context ().get ("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) + { + NameSet& type_set (global_type_names[ns.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) + { + t.context ().set ("name", make_skel_name ("any_type")); + t.context ().set ("impl", make_impl_name ("any_type")); + t.context ().set ("post", String ("post_any_type")); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + t.context ().set ("name", make_skel_name ("any_simple_type")); + t.context ().set ("impl", make_impl_name ("any_simple_type")); + t.context ().set ("post", String ("post_any_simple_type")); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + t.context ().set ("name", make_skel_name ("boolean")); + t.context ().set ("impl", make_impl_name ("boolean")); + t.context ().set ("post", String ("post_boolean")); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + t.context ().set ("name", make_skel_name ("byte")); + t.context ().set ("impl", make_impl_name ("byte")); + t.context ().set ("post", String ("post_byte")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + t.context ().set ("name", make_skel_name ("unsigned_byte")); + t.context ().set ("impl", make_impl_name ("unsigned_byte")); + t.context ().set ("post", String ("post_unsigned_byte")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + t.context ().set ("name", make_skel_name ("short")); + t.context ().set ("impl", make_impl_name ("short")); + t.context ().set ("post", String ("post_short")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + t.context ().set ("name", make_skel_name ("unsigned_short")); + t.context ().set ("impl", make_impl_name ("unsigned_short")); + t.context ().set ("post", String ("post_unsigned_short")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + t.context ().set ("name", make_skel_name ("int")); + t.context ().set ("impl", make_impl_name ("int")); + t.context ().set ("post", String ("post_int")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + t.context ().set ("name", make_skel_name ("unsigned_int")); + t.context ().set ("impl", make_impl_name ("unsigned_int")); + t.context ().set ("post", String ("post_unsigned_int")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + t.context ().set ("name", make_skel_name ("long")); + t.context ().set ("impl", make_impl_name ("long")); + t.context ().set ("post", String ("post_long")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + t.context ().set ("name", make_skel_name ("unsigned_long")); + t.context ().set ("impl", make_impl_name ("unsigned_long")); + t.context ().set ("post", String ("post_unsigned_long")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + t.context ().set ("name", make_skel_name ("integer")); + t.context ().set ("impl", make_impl_name ("integer")); + t.context ().set ("post", String ("post_integer")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + t.context ().set ("name", make_skel_name ("non_positive_integer")); + t.context ().set ("impl", make_impl_name ("non_positive_integer")); + t.context ().set ("post", String ("post_non_positive_integer")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + t.context ().set ("name", make_skel_name ("non_negative_integer")); + t.context ().set ("impl", make_impl_name ("non_negative_integer")); + t.context ().set ("post", String ("post_non_negative_integer")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + t.context ().set ("name", make_skel_name ("positive_integer")); + t.context ().set ("impl", make_impl_name ("positive_integer")); + t.context ().set ("post", String ("post_positive_integer")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + t.context ().set ("name", make_skel_name ("negative_integer")); + t.context ().set ("impl", make_impl_name ("negative_integer")); + t.context ().set ("post", String ("post_negative_integer")); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + t.context ().set ("name", make_skel_name ("float")); + t.context ().set ("impl", make_impl_name ("float")); + t.context ().set ("post", String ("post_float")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + t.context ().set ("name", make_skel_name ("double")); + t.context ().set ("impl", make_impl_name ("double")); + t.context ().set ("post", String ("post_double")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + t.context ().set ("name", make_skel_name ("decimal")); + t.context ().set ("impl", make_impl_name ("decimal")); + t.context ().set ("post", String ("post_decimal")); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + t.context ().set ("name", make_skel_name ("string")); + t.context ().set ("impl", make_impl_name ("string")); + t.context ().set ("post", String ("post_string")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + t.context ().set ("name", make_skel_name ("normalized_string")); + t.context ().set ("impl", make_impl_name ("normalized_string")); + t.context ().set ("post", String ("post_normalized_string")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + t.context ().set ("name", make_skel_name ("token")); + t.context ().set ("impl", make_impl_name ("token")); + t.context ().set ("post", String ("post_token")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + t.context ().set ("name", make_skel_name ("nmtoken")); + t.context ().set ("impl", make_impl_name ("nmtoken")); + t.context ().set ("post", String ("post_nmtoken")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + t.context ().set ("name", make_skel_name ("nmtokens")); + t.context ().set ("impl", make_impl_name ("nmtokens")); + t.context ().set ("post", String ("post_nmtokens")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + t.context ().set ("name", make_skel_name ("name")); + t.context ().set ("impl", make_impl_name ("name")); + t.context ().set ("post", String ("post_name")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + t.context ().set ("name", make_skel_name ("ncname")); + t.context ().set ("impl", make_impl_name ("ncname")); + t.context ().set ("post", String ("post_ncname")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + t.context ().set ("name", make_skel_name ("language")); + t.context ().set ("impl", make_impl_name ("language")); + t.context ().set ("post", String ("post_language")); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + t.context ().set ("name", make_skel_name ("qname")); + t.context ().set ("impl", make_impl_name ("qname")); + t.context ().set ("post", String ("post_qname")); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + t.context ().set ("name", make_skel_name ("id")); + t.context ().set ("impl", make_impl_name ("id")); + t.context ().set ("post", String ("post_id")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + t.context ().set ("name", make_skel_name ("idref")); + t.context ().set ("impl", make_impl_name ("idref")); + t.context ().set ("post", String ("post_idref")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + t.context ().set ("name", make_skel_name ("idrefs")); + t.context ().set ("impl", make_impl_name ("idrefs")); + t.context ().set ("post", String ("post_idrefs")); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + t.context ().set ("name", make_skel_name ("uri")); + t.context ().set ("impl", make_impl_name ("uri")); + t.context ().set ("post", String ("post_uri")); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + t.context ().set ("name", make_skel_name ("base64_binary")); + t.context ().set ("impl", make_impl_name ("base64_binary")); + t.context ().set ("post", String ("post_base64_binary")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + t.context ().set ("name", make_skel_name ("hex_binary")); + t.context ().set ("impl", make_impl_name ("hex_binary")); + t.context ().set ("post", String ("post_hex_binary")); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + t.context ().set ("name", make_skel_name ("date")); + t.context ().set ("impl", make_impl_name ("date")); + t.context ().set ("post", String ("post_date")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + t.context ().set ("name", make_skel_name ("date_time")); + t.context ().set ("impl", make_impl_name ("date_time")); + t.context ().set ("post", String ("post_date_time")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + t.context ().set ("name", make_skel_name ("duration")); + t.context ().set ("impl", make_impl_name ("duration")); + t.context ().set ("post", String ("post_duration")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + t.context ().set ("name", make_skel_name ("gday")); + t.context ().set ("impl", make_impl_name ("gday")); + t.context ().set ("post", String ("post_gday")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + t.context ().set ("name", make_skel_name ("gmonth")); + t.context ().set ("impl", make_impl_name ("gmonth")); + t.context ().set ("post", String ("post_gmonth")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + t.context ().set ("name", make_skel_name ("gmonth_day")); + t.context ().set ("impl", make_impl_name ("gmonth_day")); + t.context ().set ("post", String ("post_gmonth_day")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + t.context ().set ("name", make_skel_name ("gyear")); + t.context ().set ("impl", make_impl_name ("gyear")); + t.context ().set ("post", String ("post_gyear")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + t.context ().set ("name", make_skel_name ("gyear_month")); + t.context ().set ("impl", make_impl_name ("gyear_month")); + t.context ().set ("post", String ("post_gyear_month")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + t.context ().set ("name", make_skel_name ("time")); + t.context ().set ("impl", make_impl_name ("time")); + t.context ().set ("post", String ("post_time")); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + t.context ().set ("name", make_skel_name ("entity")); + t.context ().set ("impl", make_impl_name ("entity")); + t.context ().set ("post", String ("post_entity")); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + t.context ().set ("name", make_skel_name ("entities")); + t.context ().set ("impl", make_impl_name ("entities")); + t.context ().set ("post", String ("post_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); + } + }; + + // 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/xsd/cxx/parser/name-processor.hxx b/xsd/cxx/parser/name-processor.hxx new file mode 100644 index 0000000..f7849c8 --- /dev/null +++ b/xsd/cxx/parser/name-processor.hxx @@ -0,0 +1,34 @@ +// file : xsd/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: + NameProcessor (); // Dummy ctor, helps with long symbols on HP-UX. + + Void + process (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // CXX_PARSER_NAME_PROCESSOR_HXX diff --git a/xsd/cxx/parser/parser-forward.cxx b/xsd/cxx/parser/parser-forward.cxx new file mode 100644 index 0000000..4d97e23 --- /dev/null +++ b/xsd/cxx/parser/parser-forward.cxx @@ -0,0 +1,115 @@ +// file : xsd/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, + protected virtual Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + os << "class " << ename (e) << ";"; + } + }; + + // + // + struct List: Traversal::List, protected virtual Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + os << "class " << ename (l) << ";"; + } + }; + + // + // + struct Union: Traversal::Union, protected virtual Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + os << "class " << ename (u) << ";"; + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual 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/xsd/cxx/parser/parser-forward.hxx b/xsd/cxx/parser/parser-forward.hxx new file mode 100644 index 0000000..a4c23f2 --- /dev/null +++ b/xsd/cxx/parser/parser-forward.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/parser-header.cxx b/xsd/cxx/parser/parser-header.cxx new file mode 100644 index 0000000..f8ca090 --- /dev/null +++ b/xsd/cxx/parser/parser-header.cxx @@ -0,0 +1,1440 @@ +// file : xsd/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, + protected virtual Context + { + Enumeration (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + String const& name (ename (e)); + SemanticGraph::Type& base (e.inherits ().base ()); + + os << "class " << type_exp << name << ": public virtual " << + fq_name (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)); + + Boolean same (ret == ret_type (base)); + + os << "virtual " << ret << endl + << post_name (e) << " ()" << + (same || ret == L"void" ? ";" : " = 0;"); + + if (polymorphic) + { + os << endl + << "public:" << endl + << "static const " << char_type << "*" << endl + << "_static_type ();" + << endl + << "virtual const " << char_type << "*" << endl + << "_dynamic_type () const;"; + } + + os << "};"; + } + }; + + // + // + struct List: Traversal::List, protected virtual 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")); + + os << "class " << type_exp << 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") << " (" << fq_name (t) << "&);" + << endl; + + // parsers + // + os << "void" << endl + << "parsers (" << fq_name (t) << "& /* item */);" + << endl; + + // c-tor + // + os << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + + + if (polymorphic) + { + os << "public:" << endl + << "static const " << char_type << "*" << endl + << "_static_type ();" + << endl + << "virtual const " << char_type << "*" << endl + << "_dynamic_type () const;" + << endl; + } + + // + // + os << "// Implementation." << endl + << "//" << endl + << "protected:" << endl; + + os << "virtual void" << endl + << "_xsd_parse_item (const " << string_type << "&);" + << endl; + + os << "protected:" << endl + << fq_name (t) << "* _xsd_" << item << "_;" + << "};"; + } + }; + + struct Union: Traversal::Union, protected virtual Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename (u)); + + os << "class " << type_exp << 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 (polymorphic) + { + os << endl + << "public:" << endl + << "static const " << char_type << "*" << endl + << "_static_type ();" + << endl + << "virtual const " << char_type << "*" << endl + << "_dynamic_type () const;"; + } + + os << "};"; + } + }; + + + // + // + struct ParserCallback: Traversal::Member, + protected virtual Context + { + ParserCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) return; + + String const& arg (arg_type (m.type ())); + + os << "virtual void" << endl + << ename (m); + + if (arg == L"void") + os << " ();"; + else + os << " (" << arg << ");"; + + os << endl; + } + }; + + + // + // + struct ParserModifier: Traversal::Member, + protected virtual Context + { + ParserModifier (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + os << "void" << endl + << eparser (m) << " (" << fq_name (m.type ()) << "&);" + << endl; + + if (polymorphic && + m.is_a () && + !anonymous (m.type ())) + { + os << "void" << endl + << eparser (m) << " (const " << parser_map << "&);" + << endl; + } + } + }; + + // + // + struct ParserMember: Traversal::Member, + protected virtual Context + { + ParserMember (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + String type (fq_name (m.type ())); + + os << type << "* " << emember (m) << ";"; + + if (polymorphic && + m.is_a () && + !anonymous (m.type ())) + { + os << type << "* " << emember_cache (m) << ";" + << "const " << parser_map << "* " << emember_map (m) << ";" + << endl; + } + } + }; + + // + // + struct Particle: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + protected virtual Context + { + Particle (Context& c) + : Context (c) + { + *this >> contains_particle_ >> *this; + } + + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context().count ("comp-number")) + return; + + UnsignedLong state_count ( + a.context().get ("state-count")); + + os << "void" << endl + << "all_0 (unsigned long& state," << endl + << "unsigned char* count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "* t," << endl + << "bool start);" + << endl + << "unsigned char v_all_first_[" << state_count << "UL];" + << "::xsd::cxx::parser::validating::all_stack v_all_count_;" + << endl; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (!c.context().count ("comp-number")) + return; + + UnsignedLong n (c.context ().get ("comp-number")); + + os << "void" << endl + << "choice_" << n << " (unsigned long& state," << endl + << "unsigned long& count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "* t," << endl + << "bool start);" + << endl; + + Traversal::Choice::traverse (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (!s.context().count ("comp-number")) + return; + + UnsignedLong n (s.context ().get ("comp-number")); + + os << "void" << endl + << "sequence_" << n << " (unsigned long& state," << endl + << "unsigned long& count," << endl + << "const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "* t," << endl + << "bool start);" + << endl; + + Traversal::Sequence::traverse (s); + } + + private: + Traversal::ContainsParticle contains_particle_; + }; + + + // + // + struct AttributeValidationState: Traversal::Attribute, + protected virtual Context + { + AttributeValidationState (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& a) + { + if (!a.optional ()) + { + os << "bool " << ename (a) << ";"; + } + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual Context + { + Complex (Context& c) + : Context (c), + parser_callback_ (c), + parser_member_ (c), + parser_modifier_ (c), + attribute_validation_state_ (c) + { + names_parser_callback_ >> parser_callback_; + names_parser_member_ >> parser_member_; + names_parser_modifier_ >> parser_modifier_; + 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 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 " << type_exp << name << ": public "; + + if (c.inherits_p ()) + os << "virtual " << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "{" + << "public:" << endl + << "// Parser callbacks. Override them in your " << + "implementation." << endl + << "//" << endl; + + os << "// virtual void" << endl + << "// pre ();" << endl + << endl; + + + if (!restriction && (ha || he)) + { + names (c, names_parser_callback_); + } + + String const& ret (ret_type (c)); + + Boolean same (c.inherits_p () && + 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; + + names (c, names_parser_modifier_); + + os << "void" << endl + << "parsers ("; + + { + ParserParamDecl decl (*this, false); + decl.traverse (c); + } + + os << ");" + << endl; + } + + // Default c-tor. + // + if ((!restriction && (he || ha)) || + (validation && (he || hae || hra))) + { + os << "// Constructor." << endl + << "//" << endl + << name << " ();" + << endl; + } + + if (polymorphic) + { + os << "public:" << endl + << "static const " << char_type << "*" << endl + << "_static_type ();" + << endl + << "virtual const " << char_type << "*" << endl + << "_dynamic_type () const;" + << endl; + } + + // Implementation. + // + if (he || ha || (validation && (hae || haa))) + { + os << "// Implementation." << endl + << "//" << endl + << "protected:" << endl; + } + + // element + // + if (he || (validation && hae)) + { + // _start_element_impl + // + os << "virtual bool" << endl + << "_start_element_impl (const " << string_type << "&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "*);" + << endl; + + // end_element + // + os << "virtual bool" << endl + << "_end_element_impl (const " << string_type << "&," << endl + << "const " << string_type << "&);" + << endl; + } + + // attribute + // + if (validation) + { + 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 << "virtual bool" << endl + << "_attribute_impl (const " << string_type << "&," << endl + << "const " << string_type << "&," << endl + << "const " << string_type << "&);" + << endl; + } + } + + // characters + // + if (validation && c.mixed ()) + { + os << "virtual bool" << endl + << "_characters_impl (const " << string_type << "&);" + << endl; + } + + if (!restriction && (he || ha)) + { + os << "protected:" << endl; + names (c, names_parser_member_); + os << endl; + } + + if (validation && (he || hae)) + { + UnsignedLong depth (c.context ().get ("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 + << "const " << string_type << "*," << endl + << "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_;" + << "::xsd::cxx::parser::pod_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_;" + << "::xsd::cxx::parser::pod_stack v_state_attr_stack_;" + << endl; + + os << "virtual void" << endl + << "_pre_a_validate ();" + << endl; + + os << "virtual void" << endl + << "_post_a_validate ();" + << endl; + } + + os << "};"; + } + + private: + // + // + ParserCallback parser_callback_; + Traversal::Names names_parser_callback_; + + // + // + ParserMember parser_member_; + Traversal::Names names_parser_member_; + + // + // + ParserModifier parser_modifier_; + Traversal::Names names_parser_modifier_; + + // + // + 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_ = "::xsd::cxx::parser::"; + impl_ns_ += (validation ? L"validating" : L"non_validating"); + + 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" >"; + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + gen_typedef (t, "void", "any_type_pskel", "any_type_pimpl"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + gen_typedef (t, "void", + "any_simple_type_pskel", "any_simple_type_pimpl"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + gen_typedef (t, "bool", "boolean_pskel", "boolean_pimpl"); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + gen_typedef (t, "signed char", "byte_pskel", "byte_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + gen_typedef (t, "unsigned char", + "unsigned_byte_pskel", "unsigned_byte_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + gen_typedef (t, "short", "short_pskel", "short_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + gen_typedef (t, "unsigned short", + "unsigned_short_pskel", "unsigned_short_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + gen_typedef (t, "int", "int_pskel", "int_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + gen_typedef (t, "unsigned int", + "unsigned_int_pskel", "unsigned_int_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + gen_typedef (t, "long long", "long_pskel", "long_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + gen_typedef (t, "unsigned long long", + "unsigned_long_pskel", "unsigned_long_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + gen_typedef (t, "long long", "integer_pskel", "integer_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + gen_typedef (t, "long long", + "negative_integer_pskel", "negative_integer_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + gen_typedef (t, "long long", + "non_positive_integer_pskel", + "non_positive_integer_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + gen_typedef (t, "unsigned long long", + "positive_integer_pskel", "positive_integer_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + gen_typedef (t, "unsigned long long", + "non_negative_integer_pskel", + "non_negative_integer_pimpl"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + gen_typedef (t, "float", "float_pskel", "float_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + gen_typedef (t, "double", "double_pskel", "double_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + gen_typedef (t, "double", "decimal_pskel", "decimal_pimpl"); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + gen_typedef (t, string_type_, "string_pskel", "string_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + gen_typedef (t, string_type_, + "normalized_string_pskel", "normalized_string_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + gen_typedef (t, string_type_, "token_pskel", "token_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + nmtoken_ = gen_typedef (t, string_type_, + "nmtoken_pskel", "nmtoken_pimpl"); + } + + 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, xs_ns_ + L"::string_sequence", + "nmtokens_pskel", "nmtokens_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + gen_typedef (t, string_type_, "name_pskel", "name_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + gen_typedef (t, string_type_, "ncname_pskel", "ncname_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + gen_typedef (t, string_type_, "language_pskel", "language_pimpl"); + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + gen_typedef (t, xs_ns_ + L"::qname", "qname_pskel", "qname_pimpl"); + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + gen_typedef (t, string_type_, "id_pskel", "id_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + idref_ = gen_typedef (t, string_type_, "idref_pskel", "idref_pimpl"); + } + + 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, xs_ns_ + L"::string_sequence", + "idrefs_pskel", "idrefs_pimpl"); + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + gen_typedef (t, string_type_, "uri_pskel", "uri_pimpl"); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + String buffer (L"::std::auto_ptr< " + xs_ns_ + L"::buffer >"); + gen_typedef (t, buffer, + "base64_binary_pskel", "base64_binary_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + String buffer (L"::std::auto_ptr< " + xs_ns_ + L"::buffer >"); + gen_typedef (t, buffer, "hex_binary_pskel", "hex_binary_pimpl"); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + gen_typedef (t, xs_ns_ + L"::date", "date_pskel", "date_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + gen_typedef (t, xs_ns_ + L"::date_time", + "date_time_pskel", "date_time_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + gen_typedef (t, xs_ns_ + L"::duration", + "duration_pskel", "duration_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + gen_typedef (t, xs_ns_ + L"::gday", "gday_pskel", "gday_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth", + "gmonth_pskel", "gmonth_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + gen_typedef (t, xs_ns_ + L"::gmonth_day", + "gmonth_day_pskel", "gmonth_day_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + gen_typedef (t, xs_ns_ + L"::gyear", "gyear_pskel", "gyear_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + gen_typedef (t, xs_ns_ + L"::gyear_month", + "gyear_month_pskel", "gyear_month_pimpl"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + gen_typedef (t, xs_ns_ + L"::time", "time_pskel", "time_pimpl"); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity&) + { + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities&) + { + } + + private: + Boolean + gen_typedef (SemanticGraph::Type& t, + String const& type, + String const& pskel, + String const& pimpl) + { + if (ret_type (t) == type) + { + os << "typedef " << impl_ns_ << "::" << pskel << "< " << + char_type << " > " << ename (t) << ";"; + + String const& pimpl_name (t.context ().get ("impl")); + + os << "typedef " << impl_ns_ << "::" << pimpl << "< " << + char_type << " > " << pimpl_name << ";" + << endl; + + return true; + } + + return false; + } + + String xs_ns_; + String impl_ns_; + String string_type_; + + Boolean idref_; + Boolean nmtoken_; + }; + + struct FundNamespace : Namespace, + protected virtual Context + { + FundNamespace (Context& c) + : Context (c), Namespace (c) + { + } + + void + traverse (Type& ns) + { + pre (ns); + + String impl ("::xsd::cxx::parser::"); + impl += (validation ? L"validating" : L"non_validating"); + + String const c (char_type); + + os << "// Built-in XML Schema types mapping." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::string_sequence< " << c << + " > string_sequence;" + << "typedef ::xsd::cxx::parser::qname< " << c << " > qname;" + << "typedef ::xsd::cxx::parser::buffer buffer;" + << "typedef ::xsd::cxx::parser::time_zone time_zone;" + << "typedef ::xsd::cxx::parser::gday gday;" + << "typedef ::xsd::cxx::parser::gmonth gmonth;" + << "typedef ::xsd::cxx::parser::gyear gyear;" + << "typedef ::xsd::cxx::parser::gmonth_day gmonth_day;" + << "typedef ::xsd::cxx::parser::gyear_month gyear_month;" + << "typedef ::xsd::cxx::parser::date date;" + << "typedef ::xsd::cxx::parser::time time;" + << "typedef ::xsd::cxx::parser::date_time date_time;" + << "typedef ::xsd::cxx::parser::duration duration;" + << endl; + + os << "// Base parser skeletons." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::parser_base< " << c << + " > parser_base;" + << "typedef " << impl << "::empty_content< " << c << + " > empty_content;" + << "typedef " << impl << "::simple_content< " << c << + " > simple_content;" + << "typedef " << impl << "::complex_content< " << c << + " > complex_content;" + << "typedef " << impl << "::list_base< " << c << " > list_base;" + << endl; + + if (polymorphic) + { + os << "// Parser map interface and default implementation." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::parser_map< " << c << + " > parser_map;" + << "typedef ::xsd::cxx::parser::parser_map_impl< " << c << + " > parser_map_impl;" + << endl; + } + + os << "// Parser skeletons and implementations for the XML Schema" << endl + << "// built-in types." << endl + << "//" << endl; + + names (ns); + + os << "// Exceptions. See libxsd/xsd/cxx/parser/exceptions.hxx " << + "for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::exception< " << + char_type << " > exception;" + << endl + << "// Parsing diagnostics." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::severity severity;" + << "typedef ::xsd::cxx::parser::error< " << c << " > error;" + << "typedef ::xsd::cxx::parser::diagnostics< " << c << + " > diagnostics;" + << "typedef ::xsd::cxx::parser::parsing< " << c << " > parsing;" + << endl; + + os << "// Error handler. See " << + "libxsd/xsd/cxx/xml/error-handler.hxx for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::xml::error_handler< " << c << + " > error_handler;" + << endl; + + os << "// Read-only string." << endl + << "//" << endl + << "typedef ::xsd::cxx::ro_string< " << c << " > ro_string;" + << endl; + + if (xml_parser == L"xerces") + { + os << "// Parsing flags. See " << + "libxsd/xsd/cxx/parser/xerces/elements.hxx" << endl + << "// for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::xerces::flags flags;" + << endl; + + os << "// Parsing properties. See " << + "libxsd/xsd/cxx/parser/xerces/elements.hxx" << endl + << "// for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::xerces::properties< " << c << + " > properties;" + << endl; + + os << "// Document type. See " << + "libxsd/xsd/cxx/parser/xerces/elements.hxx" << endl + << "// for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::xerces::document< " << c << + " > document;" + << endl; + + } + else if (xml_parser == L"expat") + { + os << "// Document type. See " << + "libxsd/xsd/cxx/parser/expat/elements.hxx" << endl + << "// for details." << endl + << "//" << endl + << "typedef ::xsd::cxx::parser::expat::document< " << c << + " > document;" + << endl; + } + + post (ns); + } + }; + } + + Void + generate_parser_header (Context& ctx, Boolean generate_xml_schema) + { + String c (ctx.char_type); + + // + // + if (c == L"char") + { + ctx.os << "#ifndef XSD_USE_CHAR" << endl + << "#define XSD_USE_CHAR" << endl + << "#endif" << endl + << endl; + + ctx.os << "#ifndef XSD_CXX_PARSER_USE_CHAR" << endl + << "#define XSD_CXX_PARSER_USE_CHAR" << endl + << "#endif" << endl + << endl; + } + else if (c == L"wchar_t") + { + ctx.os << "#ifndef XSD_USE_WCHAR" << endl + << "#define XSD_USE_WCHAR" << endl + << "#endif" << endl + << endl; + + ctx.os << "#ifndef XSD_CXX_PARSER_USE_WCHAR" << endl + << "#define XSD_CXX_PARSER_USE_WCHAR" << endl + << "#endif" << endl + << endl; + } + + // + // + 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 ("includes")) + { + typedef Cult::Containers::Set Includes; + + Includes const& is ( + ctx.schema_root.context ().get ("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 + << "#include " << endl + << "#include " << endl; + + if (ctx.polymorphic) + ctx.os << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl; + else + ctx.os << "#include " << endl + << "#include " << endl + << "#include " << endl; + + ctx.os << "#include " << endl + << endl; + + // Generate includes that came from the type map. + // + if (ctx.schema_root.context ().count ("includes")) + { + typedef Cult::Containers::Set Includes; + + Includes const& is ( + ctx.schema_root.context ().get ("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/xsd/cxx/parser/parser-header.hxx b/xsd/cxx/parser/parser-header.hxx new file mode 100644 index 0000000..348acdf --- /dev/null +++ b/xsd/cxx/parser/parser-header.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/parser-inline.cxx b/xsd/cxx/parser/parser-inline.cxx new file mode 100644 index 0000000..f2d3bd8 --- /dev/null +++ b/xsd/cxx/parser/parser-inline.cxx @@ -0,0 +1,407 @@ +// file : xsd/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 List: Traversal::List, protected virtual 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")); + + os << "// " << name << endl + << "//" << endl + << endl; + + // item_parser + // + os << inl + << "void " << name << "::" << endl + << unclash (name, "item_parser") << " (" << + fq_name (t) << "& " << item << ")" + << "{" + << "this->_xsd_" << item << "_ = &" << item << ";" + << "}"; + + // parsers + // + os << inl + << "void " << name << "::" << endl + << "parsers (" << fq_name (t) << "& " << item << ")" + << "{" + << "this->_xsd_" << item << "_ = &" << item << ";" + << "}"; + + // c-tor + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": _xsd_" << item << "_ (0)" + << "{" + << "}"; + } + }; + + + // + // + struct ParserModifier: Traversal::Member, + protected virtual Context + { + ParserModifier (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + String const& scope (ename (m.scope ())); + String const& parser (eparser (m)); + + Boolean poly (polymorphic && + m.is_a () && + !anonymous (m.type ())); + + os << inl + << "void " << scope << "::" << endl + << parser << " (" << fq_name (m.type ()) << "& p)" + << "{" + << "this->" << emember (m) << " = &p;" + << "}"; + + if (poly) + { + os << inl + << "void " << scope << "::" << endl + << parser << " (const " << parser_map << "& m)" + << "{" + << "this->" << emember_map (m) << " = &m;" + << "}"; + } + } + }; + + + // + // + struct ParserMemberSet: Traversal::Member, + protected virtual Context + { + ParserMemberSet (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) return; + + String const& name (ename (m)); + + os << "this->" << emember (m) << " = &" << name << ";"; + } + }; + + + // + // + struct ParserMemberInit: Traversal::Member, + protected virtual Context + { + ParserMemberInit (Context& c) + : Context (c), first_ (true) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) return; + + if (first_) + first_ = false; + else + os << "," << endl << " "; + + os << emember (m) << " (0)"; + + if (polymorphic && + m.is_a () && + !anonymous (m.type ())) + { + os << "," << endl + << " " << emember_map (m) << " (0)"; + } + } + + Boolean + comma () const + { + return !first_; + } + + private: + Boolean first_; + }; + + struct ParserBaseSet: Traversal::Complex, + Traversal::List, + protected virtual Context + { + ParserBaseSet (Context& c) + : Context (c), member_ (c) + { + inherits_ >> *this; + names_ >> member_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + + if (!restriction_p (c)) + names (c, names_); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + String const& name (ename (l)); + String item (unclash (name, "item")); + + os << "this->_xsd_" << item << "_ = &" << name << "_item;"; + } + + private: + Traversal::Inherits inherits_; + + ParserMemberSet member_; + Traversal::Names names_; + }; + + struct Particle: Traversal::All, + protected virtual Context + { + Particle (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + if (!a.context().count ("comp-number")) + return; + + UnsignedLong state_count ( + a.context().get ("state-count")); + + os << "," << endl + << " v_all_count_ (" << state_count << "UL, v_all_first_)"; + } + }; + + // + // + struct Complex: Traversal::Complex, + protected virtual Context + { + Complex (Context& c) + : Context (c), + parser_modifier_ (c), + parser_base_set_ (c), + parser_member_set_ (c), + particle_ (c) + { + names_parser_modifier_ >> parser_modifier_; + inherits_parser_base_set_ >> parser_base_set_; + names_parser_member_set_ >> parser_member_set_; + } + + virtual Void + traverse (Type& 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); + } + + Boolean restriction (restriction_p (c)); + + if (!((!restriction && (he || ha)) || + (validation && (he || hae || hra)))) + return; + + String const& name (ename (c)); + + os << "// " << name << endl + << "//" << endl + << endl; + + if (!restriction && (he || ha)) + { + // _parser () + // + names (c, names_parser_modifier_); + + + // parsers () + // + + os << inl + << "void " << name << "::" << endl + << "parsers ("; + + { + ParserParamDecl decl (*this, true); + decl.traverse (c); + } + + os << ")" + << "{"; + + inherits (c, inherits_parser_base_set_); + names (c, names_parser_member_set_); + + os << "}"; + } + + // Default c-tor. + // + os << inl + << name << "::" << endl + << name << " ()" << endl + << ": "; + + Boolean comma (false); + + if (!restriction && (he || ha)) + { + ParserMemberInit member_init (*this); + Traversal::Names names_member_init (member_init); + + names (c, names_member_init); + + comma = member_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: + // + // + ParserModifier parser_modifier_; + Traversal::Names names_parser_modifier_; + + // + // + ParserBaseSet parser_base_set_; + Traversal::Inherits inherits_parser_base_set_; + + // + // + ParserMemberSet parser_member_set_; + Traversal::Names names_parser_member_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; + + List list (ctx); + Complex complex (ctx); + + names >> list; + names >> complex; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsd/cxx/parser/parser-inline.hxx b/xsd/cxx/parser/parser-inline.hxx new file mode 100644 index 0000000..2016828 --- /dev/null +++ b/xsd/cxx/parser/parser-inline.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/parser-source.cxx b/xsd/cxx/parser/parser-source.cxx new file mode 100644 index 0000000..be6c8df --- /dev/null +++ b/xsd/cxx/parser/parser-source.cxx @@ -0,0 +1,924 @@ +// file : xsd/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, + protected virtual 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 ()); + + Boolean same (ret == ret_type (base)); + + if (same || ret == L"void" || polymorphic) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (same || ret == L"void") + { + os << ret << " " << name << "::" << endl + << post_name (e) << " ()" + << "{"; + + if (same) + { + if (ret == L"void") + os << post_name (base) << " ();"; + else + os << "return " << post_name (base) << " ();"; + } + + os << "}"; + } + + if (polymorphic) + { + String id (e.name ()); + + if (String ns = xml_ns_name (e)) + { + id += L' '; + id += ns; + } + + os << "const " << char_type << "* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << L << strlit (id) << ";" + << "}"; + + os << "const " << char_type << "* " << 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 ::xsd::cxx::parser::validating::inheritance_map_entry< " << + char_type << " >" << endl + << "_xsd_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + } + }; + + // + // + struct List: Traversal::List, protected virtual 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")); + + 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 << ")"; + + os << "{" + << "}"; + + // post + // + if (ret_type (l) == L"void") + os << "void " << name << "::" << endl + << post_name (l) << " ()" + << "{" + << "}"; + + // parse_item + // + String inst (L"_xsd_" + item + L"_"); + String const& post (post_name (t)); + + os << "void " << name << "::" << endl + << "_xsd_parse_item (const " << string_type << "& v)" + << "{" + << "if (this->" << inst << ")" + << "{" + << "this->" << inst << "->pre ();" + << "this->" << inst << "->_pre_impl ();" + << "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 (polymorphic) + { + String id (l.name ()); + + if (String ns = xml_ns_name (l)) + { + id += L' '; + id += ns; + } + + os << "const " << char_type << "* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << L << strlit (id) << ";" + << "}"; + + os << "const " << char_type << "* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + // + // + struct Union: Traversal::Union, protected virtual 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" || polymorphic) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (ret == L"void") + { + os << "void " << name << "::" << endl + << post_name (u) << " ()" + << "{" + << "}"; + } + + if (polymorphic) + { + String id (u.name ()); + + if (String ns = xml_ns_name (u)) + { + id += L' '; + id += ns; + } + + os << "const " << char_type << "* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << L << strlit (id) << ";" + << "}"; + + os << "const " << char_type << "* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + }; + + // + // + struct StartElement : Traversal::Element, + protected virtual Context + { + StartElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (skip (e)) + return; + + Boolean poly (polymorphic && !anonymous (e.type ())); + + String const& inst (poly ? emember_cache (e) : emember (e)); + + os << "if ("; + + if (poly && e.global ()) + os << "("; + + if (e.qualified () && e.namespace_ ().name ()) + { + os << "n == " << L << strlit (e.name ()) << " && " << + "ns == " << L << strlit (e.namespace_ ().name ()); + } + else + { + os << "n == " << L << strlit (e.name ()) << " && ns.empty ()"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + os << ") ||" << endl + << "::xsd::cxx::parser::substitution_map_instance< " << + char_type << " > ().check (" << endl + << "ns, n, " << L << strlit (e.namespace_ ().name ()) << + ", " << L << strlit (e.name ()) << ", t)"; + } + + os << ")" + << "{"; + + if (poly) + { + SemanticGraph::Type& t (e.type ()); + + // For pre-computing length. + // + String type_id (t.name ()); + + if (String type_ns = xml_ns_name (t)) + { + type_id += L' '; + type_id += type_ns; + } + + String fq_type (fq_name (t)); + 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" + << "{" + << string_type << " ts (" << fq_type << + "::_static_type (), " << type_id.size () << "UL);" + << endl + << "if (t == 0)" << endl + << "t = &ts;" + << endl + << "if (this->" << member << " != 0 && *t == ts)" << endl + << "this->" << inst << " = this->" << member << ";" + << "else if (this->" << member_map << " != 0)" << endl + << "this->" << inst << " = dynamic_cast< " << fq_type << + "* > (" << endl + << "this->" << member_map << "->find (*t));" + << "else" << endl + << "this->" << inst << " = 0;" + << "}"; + } + + os << "this->" << complex_base << "::context_.top ().parser_ = " << + "this->" << inst << ";" + << endl + << "if (this->" << inst << ")" << endl + << "this->" << inst << "->pre ();" // _start_element calls _pre + << endl + << "return true;" + << "}"; + } + }; + + + // + // + struct EndElement : Traversal::Element, + protected virtual Context + { + EndElement (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + if (skip (e)) + return; + + Boolean poly (polymorphic && !anonymous (e.type ())); + + String const& name (ename (e)); + String const& inst (poly ? emember_cache (e) : emember (e)); + + os << "if ("; + + if (poly && e.global ()) + os << "("; + + if (e.qualified () && e.namespace_ ().name ()) + { + os << "n == " << L << strlit (e.name ()) << " && " << + "ns == " << L << strlit (e.namespace_ ().name ()); + } + else + { + os << "n == " << L << strlit (e.name ()) << " && ns.empty ()"; + } + + // Only a globally-defined element can be a subst-group root. + // + if (poly && e.global ()) + { + os << ") ||" << endl + << "::xsd::cxx::parser::substitution_map_instance< " << + char_type << " > ().check (" << endl + << "ns, n, " << L << strlit (e.namespace_ ().name ()) << + ", " << L << strlit (e.name ()) << ")"; + } + + os << ")" + << "{"; + + // _end_element calls post + // + + SemanticGraph::Type& type (e.type ()); + String const& post (post_name (type)); + + os << "if (this->" << inst << ")"; + + if (ret_type (type) == L"void") + os << "{" + << "this->" << inst << "->" << post << " ();" + << "this->" << name << " ();" + << "}"; + else + os << endl + << "this->" << name << " (this->" << inst << "->" << + post << " ());" + << endl; + + os << "return true;" + << "}"; + } + }; + + // + // + struct Attribute : Traversal::Attribute, + protected virtual 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 ()) << " && " << + "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 << ")" + << "{" + << "this->" << inst << "->pre ();" + << "this->" << inst << "->_pre_impl ();" + << "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 << " ());"; + + os << "}" + << "return true;" + << "}"; + } + }; + + // + // + struct ParserCallback: Traversal::Member, + protected virtual Context + { + ParserCallback (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& m) + { + if (skip (m)) + return; + + String const& arg (arg_type (m.type ())); + + os << "void " << ename (m.scope ()) << "::" << endl + << ename (m); + + if (arg == L"void") + os << " ()"; + else + os << " (" << arg << ")"; + + os << "{" + << "}"; + } + }; + + // + // + struct Complex : Traversal::Complex, + protected virtual Context + { + Complex (Context& c) + : Context (c), + parser_callback_ (c), + start_element_ (c), + end_element_ (c), + attribute_ (c) + { + names_parser_callback_ >> parser_callback_; + names_start_element_ >> start_element_; + names_end_element_ >> end_element_; + names_attribute_ >> attribute_; + } + + virtual Void + traverse (Type& c) + { + Boolean he (has (c)); + Boolean ha (has (c)); + + String const& ret (ret_type (c)); + Boolean same (c.inherits_p () && + ret == ret_type (c.inherits ().base ())); + + String const& name (ename (c)); + + if ((he || ha || same || ret == L"void") || polymorphic) + { + os << "// " << name << endl + << "//" << endl + << endl; + } + + if (polymorphic) + { + String id (c.name ()); + + if (String ns = xml_ns_name (c)) + { + id += L' '; + id += ns; + } + + os << "const " << char_type << "* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << L << strlit (id) << ";" + << "}"; + + os << "const " << char_type << "* " << name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + + if (c.inherits_p () && 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 ::xsd::cxx::parser::validating::inheritance_map_entry< " << + char_type << " >" << endl + << "_xsd_" << name << "_inheritance_map_entry_ (" << endl + << name << "::_static_type ()," << endl + << fq_name (base) << "::_static_type ());" + << endl; + } + } + } + + if (!(he || ha || same || ret == L"void")) + return; + + // Parser callbacks. + // + if (!restriction_p (c)) + names (c, names_parser_callback_); + + if (same || ret == L"void") + { + os << ret << " " << name << "::" << endl + << post_name (c) << " ()" + << "{"; + + if (same) + { + SemanticGraph::Type& base (c.inherits ().base ()); + + if (ret == L"void") + os << post_name (base) << " ();"; + else + os << "return " << post_name (base) << " ();"; + } + + os << "}"; + } + + // The rest is parsing/validation code which is generated in + // *-validation-source.cxx. + // + if (validation) + 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 ()); + + // _start_element_impl & _end_element_impl + // + if (he) + { + os << "bool " << name << "::" << endl + << "_start_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n," << endl + << "const " << string_type << "* t)" + << "{" + << "XSD_UNUSED (t);" + << endl; + + if (!restriction) + { + os << "if (this->"; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "::_start_element_impl (ns, n, t))" << endl + << "return true;" + << endl; + } + + names (c, names_start_element_); + + os << "return false;" + << "}"; + + + // _end_element_impl + // + os << "bool " << name << "::" << endl + << "_end_element_impl (const " << string_type << "& ns," << endl + << "const " << string_type << "& n)" + << "{"; + + if (!restriction) + { + os << "if (this->"; + + if (c.inherits_p () && !restriction) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "::_end_element_impl (ns, n))" << endl + << "return true;" + << endl; + } + + names (c, names_end_element_); + + 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) + { + os << "if (this->"; + + if (c.inherits_p ()) + os << fq_name (c.inherits ().base ()); + else + os << complex_base; + + os << "::_attribute_impl (ns, n, v))" << endl + << "return true;" + << endl; + } + + names (c, names_attribute_); + + os << "return false;" + << "}"; + } + } + + private: + // + // + ParserCallback parser_callback_; + Traversal::Names names_parser_callback_; + + // + // + StartElement start_element_; + Traversal::Names names_start_element_; + + // + // + EndElement end_element_; + Traversal::Names names_end_element_; + + // + // + Attribute attribute_; + Traversal::Names names_attribute_; + }; + + + // Generate substitution group map entries. + // + struct GlobalElement: Traversal::Element, + protected virtual 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 ()); + + os << "// Substitution map entry for " << comment (e.name ()) << "." << endl + << "//" << endl + << "static" << endl + << "const ::xsd::cxx::parser::substitution_map_entry< " << + char_type << " >" << endl + << "_xsd_" << name << "_substitution_map_entry_ (" << endl + << L << strlit (e.namespace_ ().name ()) << "," << endl + << L << strlit (e.name ()) << "," << endl + << L << strlit (r.namespace_ ().name ()) << "," << endl + << L << strlit (r.name ()) << "," << endl + << fq_name (type) << "::_static_type ());" + << endl; + } + } + }; + } + + Void + generate_parser_source (Context& ctx) + { + if (ctx.polymorphic) + { + ctx.os << "#include " << endl; + + if (ctx.validation) + ctx.os << "#include " << endl + << endl; + else + ctx.os << endl; + + Boolean import_maps (ctx.options.value ()); + Boolean export_maps (ctx.options.value ()); + + if (import_maps || export_maps) + { + ctx.os << "#ifdef _MSC_VER" << endl + << endl + << "namespace xsd" + << "{" + << "namespace cxx" + << "{" + << "namespace parser" + << "{"; + + if (export_maps) + ctx.os << "template struct __declspec (dllexport) " << + "substitution_map_init< " << ctx.char_type << " >;"; + + if (import_maps) + ctx.os << "template struct __declspec (dllimport) " << + "substitution_map_init< " << ctx.char_type << " >;"; + + if (ctx.validation && export_maps) + ctx.os << "template struct __declspec (dllexport) " << + "inheritance_map_init< " << ctx.char_type << " >;"; + + if (ctx.validation && import_maps) + ctx.os << "template struct __declspec (dllimport) " << + "inheritance_map_init< " << ctx.char_type << " >;"; + + ctx.os << "}" // parser + << "}" // cxx + << "}" // xsd + << "#endif // _MSC_VER" << endl + << endl; + } + + ctx.os << "static" << endl + << "const ::xsd::cxx::parser::substitution_map_init< " << + ctx.char_type << " >" << endl + << "_xsd_substitution_map_init_;" + << endl; + + if (ctx.validation) + { + ctx.os << "static" << endl + << "const ::xsd::cxx::parser::validating::inheritance_map_init< " << + ctx.char_type << " >" << endl + << "_xsd_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.polymorphic) + names >> global_element; + + schema.dispatch (ctx.schema_root); + } + } +} diff --git a/xsd/cxx/parser/parser-source.hxx b/xsd/cxx/parser/parser-source.hxx new file mode 100644 index 0000000..2281c24 --- /dev/null +++ b/xsd/cxx/parser/parser-source.hxx @@ -0,0 +1,22 @@ +// file : xsd/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/xsd/cxx/parser/print-impl-common.hxx b/xsd/cxx/parser/print-impl-common.hxx new file mode 100644 index 0000000..9e501ac --- /dev/null +++ b/xsd/cxx/parser/print-impl-common.hxx @@ -0,0 +1,643 @@ +// file : xsd/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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << + " << static_cast (" << arg_ << ") << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + if (default_type (t, "short")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + if (default_type (t, "unsigned short")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + if (default_type (t, "int")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + if (default_type (t, "unsigned int")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + if (default_type (t, "long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + if (default_type (t, "unsigned long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + if (default_type (t, "long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + if (default_type (t, "long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + if (default_type (t, "long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + if (default_type (t, "unsigned long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + if (default_type (t, "unsigned long long")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + if (default_type (t, "float")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + if (default_type (t, "double")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " << + arg_ << " << std::endl;"; + } + else + gen_user_type (); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + if (default_type (t, "double")) + { + os << cout_inst << " << " << L << 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 (default_type (t, xs_ns_name () + L"::qname")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << ";" + << endl + << "if (" << arg_ << ".prefix ().empty ())" << endl + << cout_inst << " << " << arg_ << ".name ();" + << "else" << endl + << cout_inst << " << " << arg_ << ".prefix () << " << L << + "':' << " << arg_ << ".name ();" + << endl + << cout_inst << " << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << ";" + << endl + << "if (" << arg_ << ".negative ())" << endl + << cout_inst << " << '-';" + << endl + << cout_inst << " << 'P'" << endl + << " << " << arg_ << ".years () << 'Y'" << endl + << " << " << arg_ << ".months () << 'M'" << endl + << " << " << arg_ << ".days () << " << L << "\"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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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")) + { + os << cout_inst << " << " << L << 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 ((char_type == L"char" && default_type (t, "::std::string")) || + (char_type == L"wchar_t" && default_type (t, "::std::wstring"))) + { + os << cout_inst << " << " << L << 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)) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << ";" + << endl; + + os << "for (" << type << "::const_iterator i (" << arg_ << + ".begin ()), e (" << arg_ << ".end ());" << endl + << "i != e;)" + << "{" + << cout_inst << " << *i++;" + << "if (i != e)" << endl + << cout_inst << " << ' ';" + << "}" + << cout_inst << " << std::endl;"; + } + else + gen_user_type (); + } + + void + gen_buffer (SemanticGraph::Type& t) + { + String type (L"::std::auto_ptr< " + xs_ns_name () + L"::buffer >"); + + if (default_type (t, type)) + { + os << cout_inst << " << " << L << strlit (tag_ + L": ") << " << " + << arg_ << "->size () << " << L << "\" bytes\" << std::endl;"; + } + else + gen_user_type (); + } + + void + gen_time_zone () + { + os << endl + << "if (" << arg_ << ".zone_present ())" + << "{" + << "if (" << arg_ << ".zone_hours () < 0)" << endl + << cout_inst << " << " << arg_ << ".zone_hours () << ':' << -" << + arg_ << ".zone_minutes ();" + << "else" << endl + << cout_inst << " << '+' << " << arg_ << ".zone_hours () << " << + "':' << " << arg_ << ".zone_minutes ();"; + + os << "}" + << cout_inst << " << std::endl;"; + } + + private: + String tag_; + String arg_; + }; + } +} + +#endif // CXX_PARSER_PRINT_IMPL_COMMON_HXX diff --git a/xsd/cxx/parser/state-processor.cxx b/xsd/cxx/parser/state-processor.cxx new file mode 100644 index 0000000..141ab05 --- /dev/null +++ b/xsd/cxx/parser/state-processor.cxx @@ -0,0 +1,318 @@ +// file : xsd/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 ("prefix", true); + p.context ().set ("state", state++); + } + + if (!prefixes_.empty ()) + { + a.context ().set ("comp-number", choice_++); + a.context ().set ("prefixes", prefixes_); + a.context ().set ("state-count", UnsignedLong (prefixes_.size ())); + + // effective-min = min * actual-min + // + if (min == 1) + min = a.min (); + + a.context ().set ("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 ("effective-min") == 0) + min = 0; + } + + p.context ().set ("prefix", true); + p.context ().set ("state", state++); + } + + if (!prefixes_.empty ()) + { + c.context ().set ("comp-number", choice_++); + c.context ().set ("prefixes", prefixes_); + + // effective-min = min * actual-min + // + if (min == 1) + min = c.min (); + + c.context ().set ("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 ("effective-min") != 0) + min = 1; + } + } + + p.context ().set ("state", state++); + + if (prefix) + p.context ().set ("prefix", true); + + if (prefix && min != 0) + prefix = false; + } + + if (!prefixes_.empty ()) + { + s.context ().set ("comp-number", sequence_++); + s.context ().set ("prefixes", prefixes_); + + // effective-min = min * actual-min + // + if (min == 1) + min = s.min (); + + s.context ().set ("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 ("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/xsd/cxx/parser/state-processor.hxx b/xsd/cxx/parser/state-processor.hxx new file mode 100644 index 0000000..681959c --- /dev/null +++ b/xsd/cxx/parser/state-processor.hxx @@ -0,0 +1,28 @@ +// file : xsd/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/xsd/cxx/parser/type-processor.cxx b/xsd/cxx/parser/type-processor.cxx new file mode 100644 index 0000000..3d24208 --- /dev/null +++ b/xsd/cxx/parser/type-processor.cxx @@ -0,0 +1,352 @@ +// file : xsd/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 + { + TypeProcessor:: + TypeProcessor () + { + // Dummy ctor, helps with long symbols on HP-UX. + } + + 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 ("ret-type")) + { + SemanticGraph::Schema* s ( + tc.get ("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. + // + 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 ("ret-type", ret_type); + tc.set ("arg-type", arg_type); + } + + tc.set ("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; + + if (!schema_.context ().count ("includes")) + schema_.context ().set ("includes", Includes ()); + + Includes& is ( + schema_.context ().get ("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 GlobalType: Traversal::Type, + Traversal::List, + Traversal::Complex, + Traversal::Enumeration + { + GlobalType (SemanticGraph::Schema& schema, + TypeMap::Namespaces& type_map, + Boolean add_includes) + : type_ (schema, type_map, add_includes) + { + inherits_ >> type_; + names_ >> instance_ >> belongs_ >> type_; + argumented_ >> 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::names (c, names_); + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + type_.traverse (e); + Complex::inherits (e, inherits_); + } + + private: + Parser::Type type_; + Traversal::Names names_; + Traversal::Instance instance_; + Traversal::Inherits inherits_; + Traversal::Belongs belongs_; + Traversal::Argumented argumented_; + }; + + Void + process_impl (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& tu, + Boolean gen_driver, + TypeMap::Namespaces& type_map) + { + 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); + + 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 ()); + + // + // + 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; + GlobalType global_type (tu, type_map, true); + + schema >> schema_names >> ns >> ns_names >> 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); + + xs_schema >> xs_schema_names >> xs_ns >> xs_ns_names >> + xs_global_type; + + schema.dispatch (tu); + + // If we are generating the test driver, make sure the root + // element type is processed. + // + if (gen_driver && options.value ()) + { + // 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 root_element (options, root); + + schema >> schema_names >> ns >> ns_names >> root_element; + + schema.dispatch (tu); + } + + global_type.dispatch (root->type ()); + } + } + } + } + + Void TypeProcessor:: + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema& s, + Boolean gen_driver, + TypeMap::Namespaces& tm) + { + process_impl (options, s, gen_driver, tm); + } + } +} diff --git a/xsd/cxx/parser/type-processor.hxx b/xsd/cxx/parser/type-processor.hxx new file mode 100644 index 0000000..045b331 --- /dev/null +++ b/xsd/cxx/parser/type-processor.hxx @@ -0,0 +1,37 @@ +// file : xsd/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: + TypeProcessor (); // Dummy ctor, helps with long symbols on HP-UX. + + Void + process (CLI::Options const& options, + XSDFrontend::SemanticGraph::Schema&, + Boolean gen_driver, + TypeMap::Namespaces&); + }; + } +} + +#endif // CXX_PARSER_TYPE_PROCESSOR_HXX diff --git a/xsd/cxx/parser/validator.cxx b/xsd/cxx/parser/validator.cxx new file mode 100644 index 0000000..8d6b968 --- /dev/null +++ b/xsd/cxx/parser/validator.cxx @@ -0,0 +1,714 @@ +// file : xsd/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, protected virtual ValidationContext + { + Any (ValidationContext& c) + : ValidationContext (c) + { + } + + struct Element: Traversal::Element, + protected virtual ValidationContext + { + Element (ValidationContext& c, SemanticGraph::Any& any) + : ValidationContext (c), + any_ (any), + ns_ (any.definition_namespace ().name ()) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (skip (e)) return; + + 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::Names names; + Element element (*this, a); + + complex >> names >> element; + + complex.dispatch (type); + } + }; + + + // + // + struct Traverser : Traversal::Schema, + Traversal::Complex, + Traversal::Type, + Traversal::Element, + protected virtual 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 AnonymousType : Traversal::Schema, + Traversal::Complex, + Traversal::Element, + Traversal::Attribute, + protected virtual ValidationContext + { + AnonymousType (ValidationContext& c) + : ValidationContext (c), + anonymous_error_issued_ (false) + { + *this >> sources_ >> *this; + *this >> schema_names_ >> ns_ >> names_ >> *this; + *this >> names_; + } + + Boolean + traverse_common (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + if (!t.named () + && !t.is_a () + && !t.is_a ()) + { + if (!anonymous_error_issued_) + { + valid = false; + anonymous_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; + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (skip (e)) return; + + 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); + } + + virtual Void + traverse (SemanticGraph::Attribute& 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); + } + + private: + Boolean anonymous_error_issued_; + + Containers::Set types_; + + Traversal::Sources sources_; + + Traversal::Names schema_names_; + Traversal::Namespace ns_; + + Traversal::Names names_; + }; + + 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_; + }; + + } + + Validator:: + Validator () + { + // Dummy ctor, helps with long symbols on HP-UX. + } + + 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 () != "char" && + options.value () != "wchar_t" && + !ctx.is_disabled ("P003")) + { + wcerr << "warning P003: unknown base character type '" << + options.value ().c_str () << "'" << endl; + } + + // + // + if (options.value () != "xerces" && + options.value () != "expat" && + !ctx.is_disabled ("P004")) + { + wcerr << "warning P004: unknown underlying XML parser '" << + options.value ().c_str () << "'" << endl; + } + + // + // + if (options.value () == "expat" && + options.value () == "wchar_t") + { + wcerr << "error: using expat with wchar_t is not yet supported" + << endl; + + return false; + } + + // + // + if (options.value () && + options.value ()) + { + wcerr << "error: mutually exclusive options specified: " + << "--generate-validation and --suppress-validation" + << endl; + + return false; + } + + // + // + 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; + } + } + + // + // + Boolean import_maps (options.value ()); + Boolean export_maps (options.value ()); + + if (import_maps && export_maps) + { + wcerr << "error: --import-maps and --export-maps are " + << "mutually exclusive" << endl; + + return false; + } + + if (import_maps && !ctx.polymorphic) + { + wcerr << "error: --import-maps can only be specified together with " + << "--generate-polymorphic" << endl; + + return false; + } + + if (export_maps && !ctx.polymorphic) + { + wcerr << "error: --export-maps can only be specified together with " + << "--generate-polymorphic" << 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/xsd/cxx/parser/validator.hxx b/xsd/cxx/parser/validator.hxx new file mode 100644 index 0000000..3f10073 --- /dev/null +++ b/xsd/cxx/parser/validator.hxx @@ -0,0 +1,35 @@ +// file : xsd/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 + +namespace CXX +{ + namespace Parser + { + using namespace Cult::Types; + + class Validator + { + public: + Validator (); // Dummy ctor, helps with long symbols on HP-UX. + + Boolean + validate (CLI::Options const& options, + SemanticGraph::Schema&, + SemanticGraph::Path const& tu, + Boolean gen_driver, + const WarningSet& disabled_warnings); + }; + } +} + +#endif // CXX_PARSER_VALIDATOR_HXX diff --git a/xsd/cxx/tree/cli.hxx b/xsd/cxx/tree/cli.hxx new file mode 100644 index 0000000..9ccf405 --- /dev/null +++ b/xsd/cxx/tree/cli.hxx @@ -0,0 +1,220 @@ +// file : xsd/cxx/tree/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_TREE_CLI_HXX +#define CXX_TREE_CLI_HXX + +#include + +#include + +#include +#include + +namespace CXX +{ + namespace Tree + { + namespace CLI + { + using namespace Cult::Types; + + typedef Char const Key[]; + + extern Key char_type; + extern Key output_dir; + extern Key generate_polymorphic; + extern Key generate_serialization; + extern Key generate_inline; + extern Key generate_ostream; + extern Key generate_doxygen; + extern Key generate_comparison; + extern Key generate_default_ctor; + extern Key generate_from_base_ctor; + extern Key generate_wildcard; + extern Key generate_insertion; + extern Key generate_extraction; + extern Key generate_forward; + extern Key generate_xml_schema; + extern Key extern_xml_schema; + extern Key suppress_parsing; + extern Key generate_element_type; + extern Key generate_element_map; + extern Key generate_intellisense; + extern Key omit_default_attributes; + extern Key namespace_map; + extern Key namespace_regex; + extern Key namespace_regex_trace; + extern Key reserved_name; + extern Key type_naming; + extern Key function_naming; + extern Key type_regex; + extern Key accessor_regex; + extern Key one_accessor_regex; + extern Key opt_accessor_regex; + extern Key seq_accessor_regex; + extern Key modifier_regex; + extern Key one_modifier_regex; + extern Key opt_modifier_regex; + extern Key seq_modifier_regex; + extern Key parser_regex; + extern Key serializer_regex; + extern Key enumerator_regex; + extern Key element_type_regex; + extern Key name_regex_trace; + extern Key include_with_brackets; + extern Key include_prefix; + extern Key include_regex; + extern Key include_regex_trace; + extern Key guard_prefix; + 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 custom_type; + extern Key custom_type_regex; + 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 parts; + extern Key parts_suffix; + extern Key export_symbol; + extern Key export_xml_schema; + extern Key export_maps; + extern Key import_maps; + extern Key show_anonymous; + extern Key show_sloc; + extern Key proprietary_license; + extern Key disable_multi_import; // Undocumented. + + + typedef Cult::CLI::Options< + + char_type, NarrowString, + output_dir, NarrowString, + generate_polymorphic, Boolean, + generate_serialization, Boolean, + generate_inline, Boolean, + generate_ostream, Boolean, + generate_doxygen, Boolean, + generate_comparison, Boolean, + generate_default_ctor, Boolean, + generate_from_base_ctor, Boolean, + generate_wildcard, Boolean, + generate_insertion, Cult::Containers::Vector, + generate_extraction, Cult::Containers::Vector, + generate_forward, Boolean, + generate_xml_schema, Boolean, + extern_xml_schema, NarrowString, + suppress_parsing, Boolean, + generate_element_type, Boolean, + generate_element_map, Boolean, + generate_intellisense, Boolean, + omit_default_attributes, Boolean, + namespace_map, Cult::Containers::Vector, + namespace_regex, Cult::Containers::Vector, + namespace_regex_trace, Boolean, + reserved_name, Cult::Containers::Vector, + type_naming, NarrowString, + function_naming, NarrowString, + type_regex, Cult::Containers::Vector, + accessor_regex, Cult::Containers::Vector, + one_accessor_regex, Cult::Containers::Vector, + opt_accessor_regex, Cult::Containers::Vector, + seq_accessor_regex, Cult::Containers::Vector, + modifier_regex, Cult::Containers::Vector, + one_modifier_regex, Cult::Containers::Vector, + opt_modifier_regex, Cult::Containers::Vector, + seq_modifier_regex, Cult::Containers::Vector, + parser_regex, Cult::Containers::Vector, + serializer_regex, Cult::Containers::Vector, + enumerator_regex, Cult::Containers::Vector, + element_type_regex, Cult::Containers::Vector, + name_regex_trace, Boolean, + include_with_brackets, Boolean, + include_prefix, NarrowString, + include_regex, Cult::Containers::Vector, + include_regex_trace, Boolean, + guard_prefix, NarrowString, + root_element_first, Boolean, + root_element_last, Boolean, + root_element_all, Boolean, + root_element_none, Boolean, + root_element, Cult::Containers::Vector, + custom_type, Cult::Containers::Vector, + custom_type_regex, Cult::Containers::Vector, + hxx_suffix, NarrowString, + ixx_suffix, NarrowString, + cxx_suffix, NarrowString, + fwd_suffix, NarrowString, + hxx_regex, NarrowString, + ixx_regex, NarrowString, + cxx_regex, NarrowString, + 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, NarrowString, + ixx_prologue_file, NarrowString, + cxx_prologue_file, NarrowString, + fwd_prologue_file, NarrowString, + prologue_file, NarrowString, + hxx_epilogue_file, NarrowString, + ixx_epilogue_file, NarrowString, + cxx_epilogue_file, NarrowString, + fwd_epilogue_file, NarrowString, + epilogue_file, NarrowString, + parts, UnsignedLong, + parts_suffix, NarrowString, + export_symbol, NarrowString, + export_xml_schema, Boolean, + export_maps, Boolean, + import_maps, Boolean, + show_anonymous, Boolean, + show_sloc, Boolean, + proprietary_license, Boolean, + disable_multi_import, Boolean + + > Options; + + struct OptionsSpec: Cult::CLI::OptionsSpec {}; + } + } +} + +#endif // CXX_TREE_CLI_HXX diff --git a/xsd/cxx/tree/counter.cxx b/xsd/cxx/tree/counter.cxx new file mode 100644 index 0000000..d8223bb --- /dev/null +++ b/xsd/cxx/tree/counter.cxx @@ -0,0 +1,265 @@ +// file : xsd/cxx/tree/counter.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include + +namespace CXX +{ + namespace Tree + { + namespace + { + struct Member: Traversal::Member + { + Member (UnsignedLong& complexity) + : complexity_ (complexity) + { + } + + virtual Void + traverse (Type&) + { + complexity_++; + } + + UnsignedLong& complexity_; + }; + + struct Any: Traversal::Any, Traversal::AnyAttribute + { + Any (UnsignedLong& complexity) + : complexity_ (complexity) + { + } + + virtual Void + traverse (SemanticGraph::Any&) + { + complexity_++; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute&) + { + complexity_++; + } + + UnsignedLong& complexity_; + }; + + struct TypeBase: Traversal::List, + Traversal::Union, + Traversal::Enumeration, + Traversal::Complex, + Context + { + TypeBase (Context& c, UnsignedLong& complexity) + : Context (c), complexity_ (complexity) + { + } + + virtual Void + traverse (SemanticGraph::List&) + { + complexity_++; + } + + virtual Void + traverse (SemanticGraph::Union&) + { + complexity_++; + } + + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + Boolean string_based (false); + { + IsStringBasedType t (string_based); + t.dispatch (e); + } + + complexity_ += (string_based ? 1 : 2); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + complexity_++; // One for the type itself. + + // Plus some for each member. + // + Any any (complexity_); + Member member (complexity_); + Traversal::Names names; + + names >> member; + + if (options.value ()) + names >> any; + + Complex::names (c, names); + } + + private: + UnsignedLong& complexity_; + }; + + + // + // + struct GlobalType: Traversal::Type, Context + + { + GlobalType (Context& c, Counts& counts) + : Context (c), counts_ (counts) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + counts_.global_types++; + + UnsignedLong complexity (0); + TypeBase type (*this, complexity); + type.dispatch (t); + + counts_.complexity_total += complexity; + counts_.complexity.push_back (complexity); + } + + private: + Counts& counts_; + }; + + // + // + struct GlobalElement: Traversal::Element, + GlobalElementBase, + Context + { + GlobalElement (Context& c, Counts& counts) + : GlobalElementBase (c), + Context (c), + counts_ (counts), + last_ (0) + { + } + + ~GlobalElement () + { + if (last_ != 0) + { + last_->context ().set ("last", true); + count_last (); + } + } + + virtual Void + traverse (Type& e) + { + // Check if the previous element we saw needs to be generated. + // + if (last_ != 0) + count_last (); + + last_ = &e; + + if (counts_.global_elements == 0) + e.context ().set ("first", true); + + counts_.global_elements++; + } + + private: + Void + count_last () + { + if (generate_p (*last_)) + { + counts_.generated_global_elements++; + + UnsignedLong complexity (0); + + if (doc_root_p (*last_)) + { + if (options.value ()) + { + complexity += 1; // For c-tors and d-tor. + + if (!options.value ()) + complexity += 1; + + if (options.value ()) + complexity += 1; + } + else + { + if (!options.value ()) + complexity += 6; // 13 parsing functions. + + if (options.value ()) + complexity += 4; // 8 serialization functions. + } + } + + if (complexity == 0) + { + // This element must be a substitution group members. For + // such elements we are only generating an entry in a map. + // We will assign it a complexity of 1 so that we don't + // end up with the total complexity that is less than the + // number of elements and types. + // + complexity = 1; + } + + counts_.complexity_total += complexity; + counts_.complexity.push_back (complexity); + } + } + + private: + Counts& counts_; + SemanticGraph::Element* last_; + }; + } + + Counter:: + Counter () + { + } + + Counts Counter:: + count (CLI::Options const& options, SemanticGraph::Schema& tu) + { + Counts counts; + Context ctx (std::wcerr, tu, options, counts, false, 0, 0, 0); + + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalType global_type (ctx, counts); + GlobalElement global_element (ctx, counts); + + schema >> schema_names >> ns >> ns_names; + + ns_names >> global_element; + ns_names >> global_type; + + schema.dispatch (tu); + + return counts; + } + } +} diff --git a/xsd/cxx/tree/counter.hxx b/xsd/cxx/tree/counter.hxx new file mode 100644 index 0000000..f4186ba --- /dev/null +++ b/xsd/cxx/tree/counter.hxx @@ -0,0 +1,28 @@ +// file : xsd/cxx/tree/counter.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_TREE_COUNTER_HXX +#define CXX_TREE_COUNTER_HXX + +#include +#include + +namespace CXX +{ + namespace Tree + { + class Counter + { + public: + Counter (); // Dummy ctor, helps with long symbols on HP-UX. + + Counts + count (CLI::Options const& options, + SemanticGraph::Schema&); + }; + } +} + +#endif // CXX_TREE_COUNTER_HXX diff --git a/xsd/cxx/tree/elements.cxx b/xsd/cxx/tree/elements.cxx new file mode 100644 index 0000000..5e85087 --- /dev/null +++ b/xsd/cxx/tree/elements.cxx @@ -0,0 +1,1327 @@ +// file : xsd/cxx/tree/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 Tree + { + // Context + // + Void Context:: + update_ns_scope () // Keeping this function first helps HP-UX + { // (long symbols). + ns_scope.clear (); + + Boolean first (true); + + for (NamespaceStack::Iterator i (ns_scope_stack.begin ()); + i != ns_scope_stack.end (); + ++i) + { + // We only qualify names until the namespace level. + // + if (first) + first = false; + else + ns_scope += L"::"; + + ns_scope += *i; + } + } + + Context:: + Context (std::wostream& o, + SemanticGraph::Schema& root, + CLI::Options const& ops, + Counts const& counts_, + Boolean generate_xml_schema__, + Regex const* fe, + Regex const* he, + Regex const* ie) + : CXX::Context (o, + root, + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value (), + ops.value ()), + options (ops), + counts (counts_), + any_type (any_type_), + any_simple_type (any_simple_type_), + element_type (element_type_), + container (container_), + flags_type (flags_type_), + qname_type (qname_type_), + xs_string_type (xs_string_type_), + properties_type (properties_type_), + error_handler_type (error_handler_type_), + list_stream_type (list_stream_type_), + namespace_infomap_type (namespace_infomap_type_), + parser_type (parser_type_), + std_ostream_type (std_ostream_type_), + ostream_type (ostream_type_), + istream_type (istream_type_), + xerces_ns (xerces_ns_), + dom_auto_ptr (dom_auto_ptr_), + dom_node_key (dom_node_key_), + as_double_type (as_double_type_), + as_decimal_type (as_decimal_type_), + generate_xml_schema (generate_xml_schema_), + doxygen (doxygen_), + polymorphic (ops.value ()), + fwd_expr (fe), + hxx_expr (he), + ixx_expr (ie), + ns_scope (ns_scope_), + regex_custom_type_map (regex_custom_type_map_), + direct_custom_type_map (direct_custom_type_map_), + qname_type_ (L"::xsd::cxx::xml::qualified_name< " + char_type + L" >"), + parser_type_ (L"::xsd::cxx::xml::dom::parser< " + char_type + L" >"), + generate_xml_schema_ (generate_xml_schema__), + doxygen_ (ops.value ()), + ns_scope_stack (ns_scope_stack_), + cxx_uq_id_expr_ (L"^[a-zA-Z_]\\w*$"), + cxx_uq_id_expr (cxx_uq_id_expr_) + { + SemanticGraph::Namespace& xs (xs_ns ()); + SemanticGraph::Context& xsc (xs.context ()); + + // Cache some often-used names from the XML Schema namespace + // if names have already been processed. + // + if (xsc.count ("container")) + { + String xs_name (ns_name (xs)); + + any_type = fq_name (xs.find ("anyType").first->named ()); + any_simple_type = fq_name (xs.find ("anySimpleType").first->named ()); + xs_string_type = fq_name (xs.find ("string").first->named ()); + + container = xs_name + L"::" + xsc.get ("container"); + flags_type = xs_name + L"::" + xsc.get ("flags"); + + if (ops.value ()) + element_type = xs_name + L"::" + xsc.get ("element-type"); + + properties_type = xs_name + L"::" + xsc.get ("properties"); + + if (!ops.value () || + ops.value ()) + { + error_handler_type = xs_name + L"::" + + xsc.get ("error-handler"); + } + + dom_auto_ptr_ = xs_name + L"::dom::auto_ptr"; + dom_node_key_ = xs_name + L"::dom::" + + xsc.get ("tree-node-key"); + + if (ops.value ()) + { + as_double_type_ = xs_name + L"::" + + xsc.get ("as-double"); + + as_decimal_type_ = xs_name + L"::" + + xsc.get ("as-decimal"); + + list_stream_type = xs_name + L"::" + + xsc.get ("list-stream"); + + namespace_infomap_type = xs_name + L"::" + + xsc.get ("namespace-infomap"); + } + + // istream and ostream are templates and for now use the same + // names regardless of the naming convention. + // + if (!ops.value ().empty ()) + istream_type = xs_name + L"::istream"; + + if (!ops.value ().empty ()) + ostream_type = xs_name + L"::ostream"; + } + + // Xerces-C++ namespace. IntelliSense for some reason does not like + // it fully-qualified (maybe because it's a namespace alias). + // + if (ops.value ()) + xerces_ns = "xercesc"; + else + xerces_ns = "::xercesc"; + + // + // + if (char_type == L"char") + std_ostream_type_ = L"::std::ostream"; + else if (char_type == L"wchar_t") + std_ostream_type_ = L"::std::wostream"; + else + std_ostream_type_ = L"::std::basic_ostream< " + char_type + L" >"; + + // Custom type mapping. + // + typedef Containers::Vector Vector; + + // Direct custom type mapping. + // + { + Vector const& v (ops.value ()); + + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); i != e; ++i) + { + String s (*i); + + if (s.empty ()) + throw InvalidCustomTypeMapping (s, "mapping string is empty"); + + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); + + // If no delimiter found then both type and base are empty. + // + if (pos == String::npos) + { + direct_custom_type_map[s].type.clear (); + direct_custom_type_map[s].base.clear (); + continue; + } + + String name (s, 0, pos); + String rest (s, pos + 1); + + // See if we've got the base part after '/'. + // + pos = rest.rfind ('/'); + + String type, base; + + if (pos != String::npos) + { + type.assign (rest, 0, pos); + base.assign (rest, pos + 1, String::npos); + } + else + type = rest; + + // type can be a potentially-qualified template-id. base is + // an unqualified C++ name. + // + + if (!base.empty () && !cxx_uq_id_expr.match (base)) + throw InvalidCustomTypeMapping (s, "invalid C++ identifier"); + + direct_custom_type_map[name].type = type; + direct_custom_type_map[name].base = base; + } + } + + // Regex custom type mapping. + // + { + Vector const& v (ops.value ()); + + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); i != e; ++i) + { + String s (*i); + + if (s.empty ()) + throw InvalidCustomTypeMapping (s, "mapping string is empty"); + + WideChar delimiter (s[0]); + + // First get pattern. + // + Size pos (s.find (delimiter, 1)); + + if (pos == String::npos) + throw InvalidCustomTypeMapping ( + s, "missing pattern-substitution separator"); + + String pat (s, 1, pos - 1); + String rest (s, pos + 1); + + String type, base; + + // See if we've got type and base. + // + if (!rest.empty ()) + { + pos = rest.find (delimiter); + + if (pos == String::npos) + throw InvalidCustomTypeMapping ( + s, "missing pattern-substitution separator"); + + type.assign (rest, 0, pos); + rest = String (rest, pos + 1); + + if (!rest.empty ()) + { + pos = rest.find (delimiter); + + if (pos == String::npos) + throw InvalidCustomTypeMapping ( + s, "missing pattern-substitution separator"); + + base.assign (rest, 0, pos); + rest = String (rest, pos + 1); + + if (!rest.empty ()) + throw InvalidCustomTypeMapping (s, "invalid format"); + } + } + + regex_custom_type_map.push_back ( + RegexCustomTypeMapInfo (pat, type, base)); + } + } + } + + Context:: + Context (Context& c) + : CXX::Context (c), + options (c.options), + counts (c.counts), + any_type (c.any_type), + any_simple_type (c.any_simple_type), + element_type (c.element_type), + container (c.container), + flags_type (c.flags_type), + qname_type (c.qname_type), + xs_string_type (c.xs_string_type), + properties_type (c.properties_type), + error_handler_type (c.error_handler_type), + list_stream_type (c.list_stream_type), + namespace_infomap_type (c.namespace_infomap_type), + parser_type (c.parser_type), + std_ostream_type (c.std_ostream_type), + ostream_type (c.ostream_type), + istream_type (c.istream_type), + xerces_ns (c.xerces_ns), + dom_auto_ptr (c.dom_auto_ptr), + dom_node_key (c.dom_node_key), + as_double_type (c.as_double_type), + as_decimal_type (c.as_decimal_type), + generate_xml_schema (c.generate_xml_schema), + doxygen (c.doxygen), + polymorphic (c.polymorphic), + fwd_expr (c.fwd_expr), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + ns_scope (c.ns_scope), + regex_custom_type_map (c.regex_custom_type_map), + direct_custom_type_map (c.direct_custom_type_map), + ns_scope_stack (c.ns_scope_stack), + cxx_uq_id_expr (c.cxx_uq_id_expr) + { + } + + Context:: + Context (Context& c, std::wostream& o) + : CXX::Context (c, o), + options (c.options), + counts (c.counts), + any_type (c.any_type), + any_simple_type (c.any_simple_type), + element_type (c.element_type), + container (c.container), + flags_type (c.flags_type), + qname_type (c.qname_type), + xs_string_type (c.xs_string_type), + properties_type (c.properties_type), + error_handler_type (c.error_handler_type), + list_stream_type (c.list_stream_type), + namespace_infomap_type (c.namespace_infomap_type), + parser_type (c.parser_type), + std_ostream_type (c.std_ostream_type), + ostream_type (c.ostream_type), + istream_type (c.istream_type), + xerces_ns (c.xerces_ns), + dom_auto_ptr (c.dom_auto_ptr), + dom_node_key (c.dom_node_key), + as_double_type (c.as_double_type), + as_decimal_type (c.as_decimal_type), + generate_xml_schema (c.generate_xml_schema), + doxygen (c.doxygen), + polymorphic (c.polymorphic), + fwd_expr (c.fwd_expr), + hxx_expr (c.hxx_expr), + ixx_expr (c.ixx_expr), + ns_scope (c.ns_scope), + regex_custom_type_map (c.regex_custom_type_map), + direct_custom_type_map (c.direct_custom_type_map), + ns_scope_stack (c.ns_scope_stack), + cxx_uq_id_expr (c.cxx_uq_id_expr) + { + } + + Boolean Context:: + custom_type (SemanticGraph::Type const& t, String& r) const + { + String const& name (t.name ()); + + // First search the direct mapping. + // + { + DirectCustomTypeMap::ConstIterator i ( + direct_custom_type_map.find (name)); + + if (i != direct_custom_type_map.end ()) + { + r = i->second.type; + return true; + } + } + + + // Second search the regex mapping. + // + for (RegexCustomTypeMap::ConstIterator + i (regex_custom_type_map.begin ()), + e (regex_custom_type_map.end ()); + i != e; ++i) + { + if (i->pat.match (name)) + { + // Empty type sub tells us to use the original name. + // + if (i->type_sub.empty ()) + { + r.clear (); + return true; + } + + r = i->pat.merge (name, i->type_sub); + return true; + } + } + + return false; + } + + String Context:: + custom_type (SemanticGraph::Type const& t) const + { + String r; + if (custom_type (t, r)) + { + // Empty type name tells us to use the original name. + // + if (r.empty ()) + r = ename (t); + } + + return r; + } + + Boolean Context:: + renamed_type (SemanticGraph::Type const& t, String& r) const + { + String const& name (t.name ()); + + // First search the direct mapping. + // + { + DirectCustomTypeMap::ConstIterator i ( + direct_custom_type_map.find (name)); + + if (i != direct_custom_type_map.end ()) + { + r = i->second.base; + return true; + } + } + + + // Second search the regex mapping. + // + for (RegexCustomTypeMap::ConstIterator + i (regex_custom_type_map.begin ()), + e (regex_custom_type_map.end ()); + i != e; ++i) + { + if (i->pat.match (name)) + { + if (!i->base_sub.empty ()) + { + r = i->pat.merge (name, i->base_sub); + } + else + r.clear (); + + return true; + } + } + + return false; + } + + Boolean Context:: + is_qname (SemanticGraph::Type& t) + { + using SemanticGraph::Complex; + using SemanticGraph::Fundamental::QName; + + if (t.is_a ()) + return true; + + if (Complex* c = dynamic_cast (&t)) + { + if (c->inherits_p () && ultimate_base (*c).is_a ()) + return true; + } + + return false; + } + + + Void Context:: + write_annotation (SemanticGraph::Annotation& a) + { + String const& doc (a.documentation ()); + WideChar const* s (doc.c_str ()); + Size size (doc.size ()); + + // Remove leading and trailing whitespaces. + // + while (*s == WideChar (0x20) || *s == WideChar (0x0A) || + *s == WideChar (0x0D) || *s == WideChar (0x09)) + { + s++; + size--; + } + + if (size != 0) + { + WideChar const* e (s + size - 1); + + while (e > s && + (*e == WideChar (0x20) || *e == WideChar (0x0A) || + *e == WideChar (0x0D) || *e == WideChar (0x09))) + --e; + + size = s <= e ? e - s + 1 : 0; + } + + if (size != 0) + { + os << " * "; + + // Go over the data, forcing newline after 80 chars and adding + // ' * ' after each new line. + // + WideChar const* last_space (0); + WideChar const* b (s); + WideChar const* e (s); + Boolean after_newline (false); + Boolean rogue (false); + + for (; e < s + size; ++e) + { + UnsignedLong u (unicode_char (e)); // May advance e. + + // We are going to treat \v and \f as rogue here even though + // they can be present in C++ source code. + // + if (u > 127 || (u < 32 && u != '\t' && u != '\n')) + rogue = true; + + if (u == ' ' || u == '\t') + { + if (after_newline) + { + if (e == b) + b++; // Skip leading spaces after newline. + + continue; + } + else + last_space = e; + } + else if (after_newline) + { + os << " * "; + after_newline = false; + } + + if (u == '\n') + { + write_rogue_text (b, e - b + 1, rogue); + + b = e + 1; + last_space = 0; + after_newline = true; + rogue = false; + continue; + } + + if (e - b >= 70 && last_space != 0) + { + write_rogue_text (b, last_space - b, rogue); + os << endl; + + b = last_space + 1; + last_space = 0; + after_newline = true; + // Cannot reset rogue since we don't output the whole string. + } + } + + if (e != b) + write_rogue_text (b, e - b, rogue); + + if (!after_newline) + os << endl; + } + } + + Void Context:: + write_rogue_text (WideChar const* s, Size size, Boolean rogue) + { + if (!rogue) + os.write (s, size); + else + { + for (WideChar const* p (s); p < s + size; ++p) + { + UnsignedLong u (unicode_char (p)); // May advance p. + + // We are going to treat \v and \f as rogue here even though + // they can be present in C++ source code. + // + if (u > 127 || (u < 32 && u != '\t' && u != '\n')) + os.put ('?'); + else + os.put (static_cast (u)); + } + } + } + + // GenerateDefautCtor + // + GenerateDefaultCtor:: + GenerateDefaultCtor (Context& c, Boolean& generate, Boolean no_base) + : Context (c), generate_ (generate), no_base_ (no_base) + { + *this >> inherits_ >> *this; + *this >> names_ >> *this; + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Complex& c) + { + // Make sure we figure out if we have any required members before + // we base our decision on the base type. + // + Complex::names (c, names_); + + if (!generate_) + Complex::inherits (c, inherits_); + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Type&) + { + if (!no_base_) + generate_ = true; + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Enumeration&) + { + if (!no_base_) + generate_ = true; + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Element& e) + { + if (!skip (e) && min (e) == 1 && max (e) == 1) + generate_ = true; + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Attribute& a) + { + if (min (a) == 1 && !(a.fixed () && !is_qname (a.type ()))) + generate_ = true; + } + + Void GenerateDefaultCtor:: + traverse (SemanticGraph::Any& a) + { + if (options.value () && + min (a) == 1 && max (a) == 1) + generate_ = true; + } + + + // GenerateFromBaseCtor + // + GenerateFromBaseCtor:: + GenerateFromBaseCtor (Context& c, Boolean& generate) + : traverser_ (c, generate) + { + inherits_ >> traverser_; + } + + Void GenerateFromBaseCtor:: + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + } + + GenerateFromBaseCtor::Traverser:: + Traverser (Context& c, Boolean& generate) + : Context (c), generate_ (generate) + { + *this >> inherits_ >> *this; + *this >> names_ >> *this; + } + + Void GenerateFromBaseCtor::Traverser:: + traverse (SemanticGraph::Complex& c) + { + names (c, names_); + + if (!generate_) + inherits (c, inherits_); + } + + Void GenerateFromBaseCtor::Traverser:: + traverse (SemanticGraph::Element& e) + { + if (!skip (e) && min (e) == 1 && max (e) == 1) + generate_ = true; + } + + Void GenerateFromBaseCtor::Traverser:: + traverse (SemanticGraph::Attribute& a) + { + if (min (a) == 1 && !(a.fixed () && !is_qname (a.type ()))) + generate_ = true; + } + + Void GenerateFromBaseCtor::Traverser:: + traverse (SemanticGraph::Any& a) + { + if (options.value () && + min (a) == 1 && max (a) == 1) + generate_ = true; + } + + // HasComplexNonOptArgs + // + HasComplexNonFundNonOptArgs:: + HasComplexNonFundNonOptArgs (Context& c, + Boolean base, + Boolean& complex, + Boolean& non_fund, + Boolean& clash) + : Context (c), + complex_ (complex), + non_fund_ (non_fund), + clash_ (clash) + { + if (base) + *this >> inherits_ >> *this; + + *this >> names_ >> *this; + } + + Void HasComplexNonFundNonOptArgs:: + traverse (SemanticGraph::Complex& c) + { + // No optimizations: need to check every arg for clashes. + // + inherits (c, inherits_); + names (c, names_); + } + + Void HasComplexNonFundNonOptArgs:: + traverse (SemanticGraph::Element& e) + { + if (!skip (e) && min (e) == 1 && max (e) == 1) + { + Boolean fund (false); + IsFundamentalType t (fund); + t.dispatch (e.type ()); + + if (!fund) + { + non_fund_ = true; + + Boolean simple (true); + IsSimpleType t (simple); + t.dispatch (e.type ()); + + if (!simple) + complex_ = true; + else + clash_ = false; + } + } + } + + // FromBaseCtorArg + // + FromBaseCtorArg:: + FromBaseCtorArg (Context& c, ArgType at, Boolean arg) + : Context (c), arg_type_ (at), arg_ (arg) + { + } + + Void FromBaseCtorArg:: + traverse (SemanticGraph::Any& a) + { + if (!options.value ()) + return; + + if (min (a) == 1 && max (a) == 1) + { + String const& name (ename (a)); + + os << "," << endl + << "const " << xerces_ns << "::DOMElement&"; + + if (arg_) + os << " " << name; + } + } + + Void FromBaseCtorArg:: + traverse (SemanticGraph::Element& e) + { + if (skip (e)) + return; + + if (min (e) == 1 && max (e) == 1) + { + String const& name (ename (e)); + + os << "," << endl; + + Boolean auto_ptr (false); + + switch (arg_type_) + { + case arg_complex_auto_ptr: + { + Boolean simple (true); + IsSimpleType t (simple); + t.dispatch (e.type ()); + auto_ptr = !simple; + break; + } + case arg_non_fund_auto_ptr: + { + Boolean fund (false); + IsFundamentalType t (fund); + t.dispatch (e.type ()); + auto_ptr = !fund; + break; + } + case arg_type: + break; + } + + if (auto_ptr) + os << "::std::auto_ptr< " << etype (e) << " >&"; + else + os << "const " << etype (e) << "&"; + + if (arg_) + os << " " << name; + } + } + + Void FromBaseCtorArg:: + traverse (SemanticGraph::Attribute& a) + { + // Note that we are not going to include attributes with + // default or required fixed values here. Instead we are + // going to default-initialize them. + // + if (min (a) == 1 && !(a.fixed () && !is_qname (a.type ()))) + { + String const& name (ename (a)); + + os << "," << endl + << "const " << etype (a) << "&"; + + if (arg_) + os << " " << name; + } + } + + // CtorArgs + // + CtorArgs:: + CtorArgs (Context& c, ArgType at) + : Context (c), + arg_type_ (at), + base_arg_ (0), + first_ (true), + member_name_ (c) + { + *this >> inherits_ >> *this; + *this >> names_ >> *this; + } + + CtorArgs:: + CtorArgs (Context& c, ArgType at, String& base_arg) + : Context (c), + arg_type_ (at), + base_arg_ (&base_arg), + first_ (true), + member_name_ (c) + { + *this >> inherits_ >> *this; + *this >> names_ >> *this; + } + + Void CtorArgs:: + traverse (SemanticGraph::Type& t) + { + os << comma () << "const "; + + member_name_.dispatch (t); + + os << "&"; + + if (base_arg_ != 0) + { + *base_arg_ = L"_xsd_" + ename (t) + L"_base"; + + os << " " << *base_arg_; + } + } + + Void CtorArgs:: + traverse (SemanticGraph::Enumeration& e) + { + os << comma () << "const "; + + member_name_.traverse (e); + + os << "&"; + + if (base_arg_ != 0) + { + *base_arg_ = L"_xsd_" + ename (e) + L"_base"; + + os << " " << *base_arg_; + } + } + + Void CtorArgs:: + traverse (SemanticGraph::Any& a) + { + if (!options.value ()) + return; + + if (min (a) == 1 && max (a) == 1) + { + os << comma () << "const " << xerces_ns << "::DOMElement&"; + + if (base_arg_ != 0) + os << " " << ename (a); + } + } + + Void CtorArgs:: + traverse (SemanticGraph::Element& e) + { + if (skip (e)) + return; + + if (min (e) == 1 && max (e) == 1) + { + Boolean auto_ptr (false); + + switch (arg_type_) + { + case arg_complex_auto_ptr: + { + Boolean simple (true); + IsSimpleType t (simple); + t.dispatch (e.type ()); + auto_ptr = !simple; + break; + } + case arg_non_fund_auto_ptr: + { + Boolean fund (false); + IsFundamentalType t (fund); + t.dispatch (e.type ()); + auto_ptr = !fund; + break; + } + case arg_type: + break; + } + + if (auto_ptr) + os << comma () << "::std::auto_ptr< " << etype (e) << " >&"; + else + os << comma () << "const " << etype (e) << "&"; + + if (base_arg_ != 0) + os << " " << ename (e); + } + } + + Void CtorArgs:: + traverse (SemanticGraph::Attribute& a) + { + // Note that we are not going to include attributes with + // default or required fixed values here. Instead we are + // going to default-initialize them. + // + if (min (a) == 1 && !(a.fixed () && !is_qname (a.type ()))) + { + os << comma () << "const " << etype (a) << "&"; + + if (base_arg_ != 0) + os << " " << ename (a); + } + } + + String CtorArgs:: + comma () + { + Boolean tmp (first_); + first_ = false; + return tmp ? "" : ",\n"; + } + + + // CtorArgsWithoutBase + // + CtorArgsWithoutBase:: + CtorArgsWithoutBase (Context& c, ArgType at, Boolean arg, Boolean first) + : Context (c), arg_type_ (at), arg_ (arg), first_ (first) + { + *this >> inherits_ >> *this; + *this >> names_ >> *this; + } + + Void CtorArgsWithoutBase:: + traverse (SemanticGraph::Any& a) + { + if (!options.value ()) + return; + + if (min (a) == 1 && max (a) == 1) + { + os << comma () << "const " << xerces_ns << "::DOMElement&"; + + if (arg_) + os << " " << ename (a); + } + } + + Void CtorArgsWithoutBase:: + traverse (SemanticGraph::Element& e) + { + if (skip (e)) + return; + + if (min (e) == 1 && max (e) == 1) + { + Boolean auto_ptr (false); + + switch (arg_type_) + { + case arg_complex_auto_ptr: + { + Boolean simple (true); + IsSimpleType t (simple); + t.dispatch (e.type ()); + auto_ptr = !simple; + break; + } + case arg_non_fund_auto_ptr: + { + Boolean fund (false); + IsFundamentalType t (fund); + t.dispatch (e.type ()); + auto_ptr = !fund; + break; + } + case arg_type: + break; + } + + if (auto_ptr) + os << comma () << "::std::auto_ptr< " << etype (e) << " >&"; + else + os << comma () << "const " << etype (e) << "&"; + + if (arg_) + os << " " << ename (e); + } + } + + Void CtorArgsWithoutBase:: + traverse (SemanticGraph::Attribute& a) + { + // Note that we are not going to include attributes with + // default or required fixed values here. Instead we are + // going to default-initialize them. + // + if (min (a) == 1 && !(a.fixed () && !is_qname (a.type ()))) + { + os << comma () << "const " << etype (a) << "&"; + + if (arg_) + os << " " << ename (a); + } + } + + String CtorArgsWithoutBase:: + comma () + { + Boolean tmp (first_); + first_ = false; + return tmp ? "" : ",\n"; + } + + // GlobalElementBase + // + Boolean GlobalElementBase:: + generate_p (SemanticGraph::Element& e) + { + if (e.substitutes_p () && ctx_.polymorphic) + return true; + + if (!doc_root_p (e)) + return false; + + // If we are not generating element types nor parsing/serialization + // code then we won't generate anything from it. + // + if (!ctx_.options.value () && + ctx_.options.value () && + !ctx_.options.value ()) + return false; + + return true; + } + + Boolean GlobalElementBase:: + doc_root_p (SemanticGraph::Element& e) + { + if (!ctx_.options.value () && + !ctx_.options.value () && + !ctx_.options.value () && + !ctx_.options.value () && + ctx_.options.value ().empty ()) + return true; // By default treat them all. + + if (ctx_.options.value ()) + return false; + + if (ctx_.options.value ()) + return true; + + if (ctx_.options.value () && + e.context ().count ("first") != 0) + return true; + + if (ctx_.options.value () && + e.context ().count ("last") != 0) + return true; + + typedef Cult::Containers::Vector Names; + Names const& names (ctx_.options.value ()); + + // Hopefully nobody will specify more than a handful of names ;-). + // + for (Names::ConstIterator i (names.begin ()); i != names.end (); ++i) + { + String name (*i); + + if (e.name () == name) + return true; + } + + return false; + } + + // Namespace + // + Namespace:: + Namespace (Context& c, + UnsignedLong first, + UnsignedLong last) + : CXX::Namespace (c, *this), + GlobalElementBase (c), + ctx_ (c), + first_ (first), + last_ (last), + count_ (0) + { + } + + Void Namespace:: + traverse (Type& ns) + { + using SemanticGraph::Element; + + if (first_ > last_) + CXX::Namespace::traverse (ns); + else + { + Boolean opened (false); + + for (Type::NamesIterator i (ns.names_begin ()); + i != ns.names_end (); ++i) + { + SemanticGraph::Nameable& n (i->named ()); + + if (n.is_a () || + (n.is_a () && generate_p (dynamic_cast (n)))) + { + if (count_ >= first_ && count_ <= last_) + { + if (!opened) + { + opened = true; + pre (ns); + } + + edge_traverser ().dispatch (*i); + } + + ++count_; + } + } + + if (opened) + post (ns); + } + } + + Void Namespace:: + enter (Type&, String const& name, Boolean) + { + ctx_.enter_ns_scope (name); + } + + Void Namespace:: + leave () + { + ctx_.leave_ns_scope (); + } + + // Includes + // + Void TypeForward:: + traverse (SemanticGraph::Type& t) + { + String const& name (ename (t)); + + if (String custom = custom_type (t)) + { + String new_name; + renamed_type (t, new_name); + + if (new_name) + os << "class " << new_name << ";"; + + if (custom == name) + os << "class " << name << ";"; + else + os << "typedef " << custom << " " << name << ";"; + } + else + os << "class " << name << ";"; + } + + 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) + { + // Generate forward declarations. + // + 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 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/xsd/cxx/tree/elements.hxx b/xsd/cxx/tree/elements.hxx new file mode 100644 index 0000000..3d70aab --- /dev/null +++ b/xsd/cxx/tree/elements.hxx @@ -0,0 +1,2030 @@ +// file : xsd/cxx/tree/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_TREE_ELEMENTS_HXX +#define CXX_TREE_ELEMENTS_HXX + +#include + +#include +#include +#include + +#include + +#include + +#include + + +namespace CXX +{ + namespace Tree + { + struct Counts + { + Counts () + : global_types (0), + global_elements (0), + generated_global_elements (0), + complexity_total (0) + { + } + + UnsignedLong global_types; + UnsignedLong global_elements; + UnsignedLong generated_global_elements; + + // Complexity value for each global type and generated global + // element, in order. + // + Cult::Containers::Vector complexity; + UnsignedLong complexity_total; + }; + + struct InvalidCustomTypeMapping + { + InvalidCustomTypeMapping (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 CXX::Context + { + public: + typedef BackendElements::Regex::Expression Regex; + typedef BackendElements::Regex::Pattern WideRegexPat; + + struct DirectCustomTypeMapInfo + { + DirectCustomTypeMapInfo (String const& t = L"", + String const& b = L"") + : type (t), base (b) + { + } + + String type; + String base; + }; + + struct RegexCustomTypeMapInfo + { + RegexCustomTypeMapInfo (WideRegexPat const& p, + String const& t, + String const& b) + : pat (p), type_sub (t), base_sub (b) + { + } + + WideRegexPat pat; + String type_sub; + String base_sub; + }; + + typedef + Cult::Containers::Vector + RegexCustomTypeMap; + + typedef + Cult::Containers::Map + DirectCustomTypeMap; + + public: + Context (std::wostream& o, + SemanticGraph::Schema& root, + CLI::Options const& ops, + Counts const& counts_, + Boolean generate_xml_schema, + Regex const* fwd_expr, + Regex const* hxx_expr, + Regex const* ixx_expr); + + protected: + Context (Context& c); + Context (Context& c, std::wostream& o); + + // Custom type mapping. + // + public: + // Returns empty string if custom mapping is not required. + // + String + custom_type (SemanticGraph::Type const&) const; + + // Returns true if custom mapping is required. name is + // populated with the custom type name or empty if the + // original name should be used. + // + Boolean + custom_type (SemanticGraph::Type const&, String& name) const; + + // Returns true if this type has been renamed as part of the + // customization process. If the function returns true, the + // name string is populated with the new name or empty if + // the type should not be generated at all. + // + Boolean + renamed_type (SemanticGraph::Type const&, String& name) const; + + public: + // Return true if this type is-a QName. + // + Boolean + is_qname (SemanticGraph::Type&); + + public: + // Performs a number of processing steps, including forcing a new + // line after 80 characters as well as "commentizing" the text by + // adding '* ' after each newline. + // + Void + write_annotation (SemanticGraph::Annotation&); + + // Escaped names. + // + public: + // Accessor name. + // + static String const& + eaname (SemanticGraph::Member const& m) + { + return m.context ().get ("aname"); + } + + static String const& + eaname (SemanticGraph::Any const& a) + { + return a.context ().get ("aname"); + } + + static String const& + eaname (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("aname"); + } + + // Modifier name. + // + static String const& + emname (SemanticGraph::Member const& m) + { + return m.context ().get ("mname"); + } + + static String const& + emname (SemanticGraph::Any const& a) + { + return a.context ().get ("mname"); + } + + static String const& + emname (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("mname"); + } + + // + // + static String const& + etype (SemanticGraph::Member const& m) + { + return m.context ().get ("type"); + } + + static String const& + etraits (SemanticGraph::Member const& m) + { + return m.context ().get ("traits"); + } + + static String const& + econtainer (SemanticGraph::Member const& m) + { + return m.context ().get ("container"); + } + + static String const& + econtainer (SemanticGraph::Any const& a) + { + return a.context ().get ("container"); + } + + static String const& + econtainer (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("container"); + } + + static String const& + eiterator (SemanticGraph::Member const& m) + { + return m.context ().get ("iterator"); + } + + static String const& + eiterator (SemanticGraph::Any const& a) + { + return a.context ().get ("iterator"); + } + + static String const& + eiterator (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("iterator"); + } + + static String const& + econst_iterator (SemanticGraph::Member const& m) + { + return m.context ().get ("const-iterator"); + } + + static String const& + econst_iterator (SemanticGraph::Any const& a) + { + return a.context ().get ("const-iterator"); + } + + static String const& + econst_iterator (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("const-iterator"); + } + + static String const& + emember (SemanticGraph::Member const& m) + { + return m.context ().get ("member"); + } + + static String const& + emember (SemanticGraph::Any const& a) + { + return a.context ().get ("member"); + } + + static String const& + emember (SemanticGraph::AnyAttribute const& a) + { + return a.context ().get ("member"); + } + + static String const& + edefault_value (SemanticGraph::Member const& m) + { + return m.context ().get ("default-value"); + } + + static String const& + edefault_value_member (SemanticGraph::Member const& m) + { + return m.context ().get ("default-value-member"); + } + + // Underlying enum value type. + // + static String const& + evalue (SemanticGraph::Enumeration const& e) + { + return e.context ().get ("value"); + } + + // dom_document + // + static Boolean + edom_document_p (SemanticGraph::Complex const& c) + { + return c.context ().count ("dom-document"); + } + + static String const& + edom_document (SemanticGraph::Complex const& c) + { + return c.context ().get ("dom-document"); + } + + static Boolean + edom_document_member_p (SemanticGraph::Complex const& c) + { + return c.context ().count ("dom-document-member"); + } + + static String const& + edom_document_member (SemanticGraph::Complex const& c) + { + return c.context ().get ("dom-document-member"); + } + + // Parsing and serialization function names. + // + static String const& + eparser (SemanticGraph::Element const& e) + { + return e.context ().get ("parser"); + } + + static String const& + eserializer (SemanticGraph::Element const& e) + { + return e.context ().get ("serializer"); + } + + public: + Void + enter_ns_scope (String const& name) + { + ns_scope_stack.push_back (name); + update_ns_scope (); + } + + Void + leave_ns_scope () + { + ns_scope_stack.pop_back (); + update_ns_scope (); + } + + private: + Void + update_ns_scope (); + + private: + // Write text that may contain characters that we will have + // to escape (indicated by the rogue flag). + // + Void + write_rogue_text (WideChar const* s, Size size, Boolean rogue); + + public: + CLI::Options const& options; + Counts const& counts; + String& any_type; + String& any_simple_type; + String& element_type; + String& container; + String& flags_type; + String& qname_type; + String& xs_string_type; + String& properties_type; + String& error_handler_type; + String& list_stream_type; + String& namespace_infomap_type; + String& parser_type; + String& std_ostream_type; + String& ostream_type; + String& istream_type; + String& xerces_ns; + String& dom_auto_ptr; + String& dom_node_key; + String& as_double_type; + String& as_decimal_type; + + Boolean& generate_xml_schema; + Boolean& doxygen; + Boolean polymorphic; + + Regex const* fwd_expr; + Regex const* hxx_expr; + Regex const* ixx_expr; + + String& ns_scope; + + RegexCustomTypeMap& regex_custom_type_map; + DirectCustomTypeMap& direct_custom_type_map; + + private: + String any_type_; + String any_simple_type_; + String element_type_; + String container_; + String flags_type_; + String qname_type_; + String xs_string_type_; + String properties_type_; + String error_handler_type_; + String list_stream_type_; + String namespace_infomap_type_; + String parser_type_; + String std_ostream_type_; + String ostream_type_; + String istream_type_; + String xerces_ns_; + String dom_auto_ptr_; + String dom_node_key_; + String as_double_type_; + String as_decimal_type_; + + Boolean generate_xml_schema_; + Boolean doxygen_; + + typedef + Cult::Containers::Deque + NamespaceStack; + + typedef + Cult::Containers::Deque + ScopeStack; + + String ns_scope_; + + NamespaceStack& ns_scope_stack; + NamespaceStack ns_scope_stack_; + + RegexCustomTypeMap regex_custom_type_map_; + DirectCustomTypeMap direct_custom_type_map_; + + private: + WideRegexPat const cxx_uq_id_expr_; + WideRegexPat const& cxx_uq_id_expr; + }; + + // Check whether this Schema type maps to a fundamental C++ type. + // + struct IsFundamentalType : 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 + + { + IsFundamentalType (Boolean& r) + : r_ (r) + { + } + + // 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_; + }; + + // Check whether this is a string-based type. + // + struct IsStringBasedType : Traversal::Complex, + Traversal::Union, + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language + { + IsStringBasedType (Boolean& r) + : r_ (r) + { + *this >> inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + } + + virtual Void + traverse (SemanticGraph::Union&) + { + // Current mapping of union is string-based. + // + r_ = true; + } + + // Strings. + // + 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; + } + + private: + Boolean& r_; + Traversal::Inherits inherits_; + }; + + + // Check whether this is a enumeration-based type. + // + struct IsEnumBasedType : Traversal::Complex + { + IsEnumBasedType (SemanticGraph::Enumeration*& e) + : enum_ (e) + { + *this >> inherits_; + + inherits_ >> *this; + inherits_ >> enum_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + } + + private: + struct Enumeration: Traversal::Enumeration + { + Enumeration (SemanticGraph::Enumeration*& e) + : e_ (e) + { + } + + virtual Void + traverse (Type& e) + { + if (e_ == 0) + e_ = &e; + } + + private: + SemanticGraph::Enumeration*& e_; + }; + + + private: + Enumeration enum_; + Traversal::Inherits inherits_; + }; + + + // + // + struct MemberTypeName : protected Context, + Traversal::Type, + 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::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 + + { + MemberTypeName (Context& c) + : Context (c) + { + } + + MemberTypeName (Context& c, std::wostream& o) + : Context (c, o) + { + } + + virtual Void + traverse (SemanticGraph::Type&) + { + abort (); + } + + virtual Void + traverse (SemanticGraph::List& l) + { + os << fq_name (l); + } + + virtual Void + traverse (SemanticGraph::Union& u) + { + os << fq_name (u); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + os << fq_name (c); + } + + // anyType & anySimpleType. + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + os << fq_name (t); + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + os << fq_name (t); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + os << fq_name (t); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + os << fq_name (t); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + os << fq_name (t); + } + + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + os << fq_name (t); + } + + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + if (t.named ()) + { + // IDREF + // + os << fq_name (t); + } + else + { + SemanticGraph::Nameable& ncname ( + xs_ns ().find ("NCName").first->named ()); + + os << "::xsd::cxx::tree::idref< " << + type_name (t.argumented ().type ()) << ", " << + char_type << ", " << fq_name (ncname) << " >"; + } + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + if (t.named ()) + { + // IDREFS + // + os << fq_name (t); + } + else + { + SemanticGraph::Nameable& ncname ( + xs_ns ().find ("NCName").first->named ()); + + os << "::xsd::cxx::tree::idrefs< " << char_type << ", " << + any_simple_type << ", ::xsd::cxx::tree::idref< " << + type_name (t.argumented ().type ()) << ", " << char_type << + ", " << fq_name (ncname) << " > >"; + } + } + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + os << fq_name (t); + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + os << fq_name (t); + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + os << fq_name (t); + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + os << fq_name (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + os << fq_name (t); + } + + private: + // For idref/idrefs + // + String + type_name (SemanticGraph::Type& t) + { + // This type is always named. + // + std::wostringstream o; + + MemberTypeName type (*this, o); + type.dispatch (t); + + return o.str (); + } + }; + + + // + // + struct BaseTypeName : MemberTypeName + { + BaseTypeName (Context& c) + : MemberTypeName (c) + { + } + + BaseTypeName (Context& c, std::wostream& o) + : MemberTypeName (c, o) + { + } + + virtual Void + fundamental_base (SemanticGraph::Type& t) + { + os << "::xsd::cxx::tree::fundamental_base< " << + fq_name (t) << ", " << char_type << ", " << + any_simple_type << " >"; + } + + // Integrals. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + fundamental_base (t); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + fundamental_base (t); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + fundamental_base (t); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + os << "::xsd::cxx::tree::fundamental_base< " << + fq_name (t) << ", " << char_type << ", " << + any_simple_type << ", " << + "::xsd::cxx::tree::schema_type::double_ >"; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + os << "::xsd::cxx::tree::fundamental_base< " << + fq_name (t) << ", " << char_type << ", " << + any_simple_type << ", " << + "::xsd::cxx::tree::schema_type::decimal >"; + } + }; + + // Initial value should be true. + // + struct IsSimpleType : Traversal::Complex, + Traversal::Member, + Traversal::Any, + Traversal::AnyAttribute + { + IsSimpleType (Boolean& v) + : v_ (v) + { + *this >> names_ >> *this; + *this >> inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + names (c, names_); + + if (v_) + inherits (c, inherits_); + } + + virtual Void + traverse (SemanticGraph::Member&) + { + v_ = false; + } + + virtual Void + traverse (SemanticGraph::Any&) + { + v_ = false; + } + + virtual Void + traverse (SemanticGraph::AnyAttribute&) + { + v_ = false; + } + + private: + Boolean& v_; + Traversal::Names names_; + Traversal::Inherits inherits_; + }; + + // Test whether we need to generate default c-tor. Note that we are not + // interested in anyAttribute since it is always mapped to a sequence. + // + struct GenerateDefaultCtor: Traversal::Complex, + Traversal::Enumeration, + Traversal::Type, + Traversal::Element, + Traversal::Attribute, + Traversal::Any, + protected virtual Context + { + // generate should initially be false. + // + GenerateDefaultCtor (Context&, Boolean& generate, Boolean no_base); + + virtual Void + traverse (SemanticGraph::Complex&); + + virtual Void + traverse (SemanticGraph::Type&); + + virtual Void + traverse (SemanticGraph::Enumeration&); + + virtual Void + traverse (SemanticGraph::Element&); + + virtual Void + traverse (SemanticGraph::Attribute&); + + virtual Void + traverse (SemanticGraph::Any&); + + private: + Boolean& generate_; + Boolean no_base_; + + private: + Traversal::Inherits inherits_; + Traversal::Names names_; + }; + + // Test whether we need to generate from-base c-tor. + // + struct GenerateFromBaseCtor: Traversal::Complex + { + // generate should initially be false. + // + GenerateFromBaseCtor (Context& c, Boolean& generate); + + virtual Void + traverse (SemanticGraph::Complex& c); + + private: + // Note that we are not interested in anyAttribute since it is always + // mapped to a sequence. + // + struct Traverser: Traversal::Complex, + Traversal::Element, + Traversal::Attribute, + Traversal::Any, + protected virtual Context + { + Traverser (Context& c, Boolean& generate); + + virtual Void + traverse (SemanticGraph::Complex&); + + virtual Void + traverse (SemanticGraph::Attribute&); + + virtual Void + traverse (SemanticGraph::Element&); + + virtual Void + traverse (SemanticGraph::Any&); + + private: + Boolean& generate_; + + private: + Traversal::Inherits inherits_; + Traversal::Names names_; + } traverser_; + + Traversal::Inherits inherits_; + }; + + // Test whether the type has any non-optional element of complex + // (has attributes/elements) and non-fundamental types. + // + struct HasComplexNonFundNonOptArgs: Traversal::Complex, + Traversal::Element, + protected virtual Context + { + // complex and non_fund should initially be false. clash + // should initially be true. + // + HasComplexNonFundNonOptArgs (Context& c, + Boolean including_base, + Boolean& complex, + Boolean& non_fund, + Boolean& clash); + + virtual Void + traverse (SemanticGraph::Complex&); + + virtual Void + traverse (SemanticGraph::Element&); + + private: + Boolean& complex_; + Boolean& non_fund_; + Boolean& clash_; + + Traversal::Inherits inherits_; + Traversal::Names names_; + }; + + // Immediate non-optional member. Note that AnyAttribute is always + // mapped to a sequence. + // + struct FromBaseCtorArg : Traversal::Any, + Traversal::Element, + Traversal::Attribute, + protected virtual Context + { + enum ArgType + { + arg_type, + arg_complex_auto_ptr, + arg_non_fund_auto_ptr + }; + + FromBaseCtorArg (Context& c, ArgType, Boolean arg); + + virtual Void + traverse (SemanticGraph::Any&); + + virtual Void + traverse (SemanticGraph::Attribute&); + + virtual Void + traverse (SemanticGraph::Element&); + + private: + ArgType arg_type_; + Boolean arg_; + }; + + // List of all non-optional members and a simple base. Note that + // AnyAttribute is always mapped to a sequence. + // + struct CtorArgs : Traversal::Complex, + Traversal::Enumeration, + Traversal::Type, + Traversal::Any, + Traversal::Element, + Traversal::Attribute, + protected virtual Context + { + enum ArgType + { + arg_type, + arg_complex_auto_ptr, + arg_non_fund_auto_ptr + }; + + // The second version outputs the argument name and stores + // in in the base_arg string. + // + CtorArgs (Context&, ArgType); + CtorArgs (Context&, ArgType, String& base_arg); + + virtual Void + traverse (SemanticGraph::Type&); + + virtual Void + traverse (SemanticGraph::Enumeration&); + + virtual Void + traverse (SemanticGraph::Any&); + + virtual Void + traverse (SemanticGraph::Attribute&); + + virtual Void + traverse (SemanticGraph::Element&); + + private: + String + comma (); + + private: + ArgType arg_type_; + String base_; + String* base_arg_; + Boolean first_; + + private: + Traversal::Inherits inherits_; + Traversal::Names names_; + + MemberTypeName member_name_; + }; + + + // Check whether we need to generate c-tor without the base argument. + // + struct GenerateWithoutBaseCtor: Traversal::List, + Traversal::Union, + Traversal::Complex, + Traversal::Enumeration, + + Traversal::AnyType, + Traversal::AnySimpleType, + + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + + Traversal::Fundamental::NameTokens, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::Base64Binary, + Traversal::Fundamental::HexBinary + { + // generate should initially be false. + // + GenerateWithoutBaseCtor (Boolean& generate) + : generate_ (generate) + { + *this >> inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::List&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Union&) + { + // No default initialization. + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + Complex::inherits (c); + } + + virtual Void + traverse (SemanticGraph::Enumeration&) + { + // No default initialization. + } + + virtual Void + traverse (SemanticGraph::AnyType&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::AnySimpleType&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary&) + { + generate_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary&) + { + generate_ = true; + } + + private: + Boolean& generate_; + Traversal::Inherits inherits_; + }; + + + // List of all non-optional members sans simple base. Note that + // AnyAttribute is always mapped to a sequence. + // + struct CtorArgsWithoutBase: Traversal::Complex, + Traversal::Any, + Traversal::Element, + Traversal::Attribute, + protected virtual Context + { + enum ArgType + { + arg_type, + arg_complex_auto_ptr, + arg_non_fund_auto_ptr + }; + + CtorArgsWithoutBase (Context& c, ArgType, Boolean arg, Boolean first); + + virtual Void + traverse (SemanticGraph::Any&); + + virtual Void + traverse (SemanticGraph::Element&); + + virtual Void + traverse (SemanticGraph::Attribute&); + + private: + String + comma (); + + private: + ArgType arg_type_; + Boolean arg_; + Boolean first_; + + private: + Traversal::Inherits inherits_; + Traversal::Names names_; + }; + + // + // + struct GlobalElementBase + { + GlobalElementBase (Context& c) + : ctx_ (c) + { + } + + Boolean + generate_p (SemanticGraph::Element&); + + Boolean + doc_root_p (SemanticGraph::Element&); + + private: + Context& ctx_; + }; + + + // + // + struct Namespace: CXX::Namespace, + GlobalElementBase, + CXX::Namespace::ScopeTracker + { + Namespace (Context&, + UnsignedLong first = 1, + UnsignedLong last = 0); + + virtual Void + traverse (Type&); + + protected: + virtual Void + enter (Type&, String const& name, Boolean last); + + virtual Void + leave (); + + protected: + Context& ctx_; + + private: + UnsignedLong first_; + UnsignedLong last_; + UnsignedLong count_; + }; + + // + // + struct DocumentedNamespace: Namespace + { + DocumentedNamespace (Context& c) + : Namespace (c) + { + } + + virtual Void + enter (Type& ns, String const& name, Boolean last) + { + Namespace::enter (ns, name, last); + + // Only add documentation to the innermost namespace. + // + if (ctx_.doxygen && name && last) + { + ctx_.os << "/**" << endl + << " * @brief C++ namespace for the %" << + ctx_.comment (ns.name ()) << endl + << " * schema namespace." << endl + << " */" << endl; + } + } + }; + + // + // + 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, + 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_; + }; + + // + // + struct FundIncludes : 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, + Context + + { + FundIncludes (Context& c, String const& prefix) + : Context (c), prefix_ (prefix), + long_ (false), unsigned_long_ (false) + { + } + + // Integral types. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + gen_include (t, "byte.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + gen_include (t, "unsigned-byte.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + gen_include (t, "short.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + gen_include (t, "unsigned-short.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + gen_include (t, "int.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + gen_include (t, "unsigned-int.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + if (!long_) + long_ = gen_include (t, "long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedLong& t) + { + if (!unsigned_long_) + unsigned_long_ = gen_include (t, "unsigned-long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Integer& t) + { + if (!long_) + long_ = gen_include (t, "long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonPositiveInteger& t) + { + if (!long_) + long_ = gen_include (t, "long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NonNegativeInteger& t) + { + if (!unsigned_long_) + unsigned_long_ = gen_include (t, "unsigned-long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::PositiveInteger& t) + { + if (!unsigned_long_) + unsigned_long_ = gen_include (t, "unsigned-long.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NegativeInteger& t) + { + if (!long_) + long_ = gen_include (t, "long.hxx"); + } + + // Boolean. + // + virtual Void + traverse (SemanticGraph::Fundamental::Boolean& t) + { + gen_include (t, "boolean.hxx"); + } + + // Floats. + // + virtual Void + traverse (SemanticGraph::Fundamental::Float& t) + { + gen_include (t, "float.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Double& t) + { + gen_include (t, "double.hxx"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Decimal& t) + { + gen_include (t, "decimal.hxx"); + } + + private: + Boolean + gen_include (SemanticGraph::Type& t, String const& file) + { + String custom; + + // XML Schema built-in type customization is only possible when + // we are generating separate header. + // + if (generate_xml_schema && custom_type (t, custom)) + { + String new_name; + renamed_type (t, new_name); + + if (!new_name) + return false; + } + + os << "#include " + << endl; + + return true; + } + + private: + String prefix_; + Boolean long_; + Boolean unsigned_long_; + }; + } +} + +#endif // CXX_TREE_ELEMENTS_HXX diff --git a/xsd/cxx/tree/fundamental-header.hxx b/xsd/cxx/tree/fundamental-header.hxx new file mode 100644 index 0000000..5ea3596 --- /dev/null +++ b/xsd/cxx/tree/fundamental-header.hxx @@ -0,0 +1,1186 @@ +// file : xsd/cxx/tree/fundamental-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_TREE_FUNDAMENTAL_HEADER_HXX +#define CXX_TREE_FUNDAMENTAL_HEADER_HXX + +#include +#include + +#include + +namespace CXX +{ + namespace Tree + { + struct FundamentalNamespace : DocumentedNamespace, + + 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::Id, + Traversal::Fundamental::IdRef, + Traversal::Fundamental::IdRefs, + + Traversal::Fundamental::AnyURI, + + Traversal::Fundamental::QName, + + 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, + protected virtual Context + { + FundamentalNamespace (Context& c) + : Context (c), + DocumentedNamespace (c), + export_ (c.options.value () && type_exp) + { + *this >> names_ >> *this; + } + + Void + gen_typedef (String const& type, String const& name) + { + os << "typedef " << type << " " << name << ";"; + + if (export_ && type.find (L'<') != String::npos) + os << "template class " << type_exp << type << ";"; + } + + String + built_in_type (SemanticGraph::Type& t, String const& type) + { + String custom; + + String name (ename (t)); + + // XML Schema built-in type customization is only possible when + // we are generating separate header. + // + if (generate_xml_schema && custom_type (t, custom)) + { + if (custom.empty ()) + custom = name; + + String new_name; + renamed_type (t, new_name); + + if (new_name) + { + gen_typedef (type, new_name); + + if (doxygen) + os << endl; + } + + if (doxygen) + os << "/**" << endl + << " * @brief C++ type corresponding to the " << + comment (t.name ()) << " XML Schema" << endl + << " * built-in type." << endl + << " */" << endl; + + if (custom == name) + os << "class " << name << ";"; + else + os << "typedef " << custom << " " << name << ";"; + + if (doxygen) + os << endl; + } + else + { + // Otherwise generate simple typedef. + // + + if (doxygen) + os << "/**" << endl + << " * @brief C++ type corresponding to the " << + comment (t.name ()) << " XML Schema" << endl + << " * built-in type." << endl + << " */" << endl; + + gen_typedef (type, name); + + if (doxygen) + os << endl; + } + + return name; + } + + // anyType and anySimpleType + // + virtual Void + traverse (SemanticGraph::AnyType& t) + { + os << "// anyType and anySimpleType." << endl + << "//" << endl; + + if (doxygen) + os << endl; + + type_ = built_in_type (t, "::xsd::cxx::tree::type"); + } + + virtual Void + traverse (SemanticGraph::AnySimpleType& t) + { + simple_type_ = built_in_type ( + t, L"::xsd::cxx::tree::simple_type< " + type_ + L" >"); + + if (doxygen) + os << "/**" << endl + << " * @brief Alias for the anyType type." << endl + << " */" << endl; + + gen_typedef ("::xsd::cxx::tree::type", + xs_ns ().context().get ("container")); + + os << endl; + + if (doxygen) + os << endl; + } + + // Integrals. + // + virtual Void + traverse (SemanticGraph::Fundamental::Byte& t) + { + os << "// 8-bit" << endl + << "//" << endl; + + if (doxygen) + os << endl; + + built_in_type (t, "signed char"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedByte& t) + { + built_in_type (t, "unsigned char"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Short& t) + { + os << "// 16-bit" << endl + << "//" << endl; + + if (doxygen) + os << endl; + + built_in_type (t, "short"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedShort& t) + { + built_in_type (t, "unsigned short"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Int& t) + { + os << "// 32-bit" << endl + << "//" << endl; + + if (doxygen) + os << endl; + + built_in_type (t, "int"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::UnsignedInt& t) + { + built_in_type (t, "unsigned int"); + os << endl; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Long& t) + { + os << "// 64-bit" << endl + << "//" <"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString& t) + { + norm_string_ = built_in_type ( + t, + L"::xsd::cxx::tree::normalized_string< " + char_type + + L", " + string_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token& t) + { + token_ = built_in_type ( + t, + L"::xsd::cxx::tree::token< " + char_type + L", " + + norm_string_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken& t) + { + nmtoken_ = built_in_type ( + t, + L"::xsd::cxx::tree::nmtoken< " + char_type + L", " + + token_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameTokens& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::nmtokens< " + char_type + + L", " + simple_type_ + L", " + nmtoken_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name& t) + { + name_ = built_in_type ( + t, + L"::xsd::cxx::tree::name< " + char_type + L", " + token_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName& t) + { + ncname_ = built_in_type ( + t, + L"::xsd::cxx::tree::ncname< " + char_type + L", " + name_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::language< " + char_type + L", " + + token_ + L" >"); + + os << endl; + } + + // ID/IDREF. + // + virtual Void + traverse (SemanticGraph::Fundamental::Id& t) + { + os << "// ID/IDREF." << endl + << "//" << endl; + + if (doxygen) + os << endl; + + built_in_type ( + t, + L"::xsd::cxx::tree::id< " + char_type + L", " + ncname_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRef& t) + { + idref_ = built_in_type ( + t, + L"::xsd::cxx::tree::idref< " + type_ + L", " + char_type + L", " + + ncname_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::IdRefs& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::idrefs< " + char_type + + L", " + simple_type_ + L", " + idref_ + L" >"); + + os << endl; + } + + + // URI. + // + virtual Void + traverse (SemanticGraph::Fundamental::AnyURI& t) + { + os << "// URI." << endl + << "//" << endl; + + if (doxygen) + os << endl; + + uri_ = built_in_type ( + t, + L"::xsd::cxx::tree::uri< " + char_type + L", " + + simple_type_ + L" >"); + + os << endl; + } + + // Qualified name. + // + virtual Void + traverse (SemanticGraph::Fundamental::QName& t) + { + os << "// Qualified name." << endl + << "//" << endl; + + if (doxygen) + os << endl; + + built_in_type ( + t, + L"::xsd::cxx::tree::qname< " + char_type + + L", " + simple_type_ + L", " + uri_ + L", " + ncname_ + L" >"); + + os << endl; + } + + // Binary. + // + virtual Void + traverse (SemanticGraph::Fundamental::Base64Binary& t) + { + os << "// Binary." << endl + << "//" << endl; + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Binary buffer type." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::buffer< " + char_type + L" >", + xs_ns ().context().get ("buffer")); + + if (doxygen) + os << endl; + + built_in_type ( + t, + L"::xsd::cxx::tree::base64_binary< " + char_type + + L", " + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::HexBinary& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::hex_binary< " + char_type + + L", " + simple_type_ + L" >"); + + os << endl; + } + + + // Date/time. + // + virtual Void + traverse (SemanticGraph::Fundamental::Date& t) + { + os << "// Date/time." << endl + << "//" << endl; + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Time zone type." << endl + << " */" << endl; + + gen_typedef ("::xsd::cxx::tree::time_zone", + xs_ns ().context().get ("time-zone")); + + if (doxygen) + os << endl; + + built_in_type ( + t, + L"::xsd::cxx::tree::date< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::DateTime& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::date_time< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Duration& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::duration< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Day& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::gday< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Month& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::gmonth< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::MonthDay& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::gmonth_day< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Year& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::gyear< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::YearMonth& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::gyear_month< " + char_type + L", " + + simple_type_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Time& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::time< " + char_type + L", " + + simple_type_ + L" >"); + + os << endl; + } + + // Entity. + // + virtual Void + traverse (SemanticGraph::Fundamental::Entity& t) + { + os << "// Entity." << endl + << "//" << endl; + + if (doxygen) + os << endl; + + entity_ = built_in_type ( + t, + L"::xsd::cxx::tree::entity< " + char_type + L", " + + ncname_ + L" >"); + } + + virtual Void + traverse (SemanticGraph::Fundamental::Entities& t) + { + built_in_type ( + t, + L"::xsd::cxx::tree::entities< " + char_type + + L", " + simple_type_ + L", " + entity_ + L" >"); + + os << endl; + } + + virtual Void + post (SemanticGraph::Namespace& n) + { + SemanticGraph::Context& c (xs_ns ().context()); + + Boolean parsing (!options.value ()); + Boolean serialization (options.value ()); + Boolean element_map (options.value ()); + + if (options.value ()) + { + if (doxygen) + os << "/**" << endl + << " * @brief Base class for element types." << endl + << " */" << endl; + else + os << "// Base class for element types." << endl + << "//" << endl; + + gen_typedef (L"::xsd::cxx::tree::element_type < " + + char_type + L", " + type_ + L" >", + c.get ("element-type")); + os << endl; + } + + if (element_map) + { + if (doxygen) + os << "/**" << endl + << " * @brief Root element map." << endl + << " */" << endl; + else + os << "// Root element map." << endl + << "//" << endl; + + gen_typedef (L"::xsd::cxx::tree::element_map < " + + char_type + L", " + type_ + L" >", + c.get ("element-map")); + os << endl; + } + + if (serialization) + { + os << "// Namespace information and list stream. Used in" << endl + << "// serialization functions." << endl + << "//" << endl; + + if (doxygen) + os << "/**" << endl + << " * @brief Namespace serialization information." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::xml::dom::namespace_info < " + char_type + L" >", + c.get ("namespace-info")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Namespace serialization information map." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::xml::dom::namespace_infomap < " + + char_type + L" >", + c.get ("namespace-infomap")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief List serialization stream." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::list_stream < " + char_type + L" >", + c.get ("list-stream")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Serialization wrapper for the %double type." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::as_double < " + double_ + L" >", + c.get ("as-double")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Serialization wrapper for the %decimal type." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::as_decimal < " + decimal_ + L" >", + c.get ("as-decimal")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Simple type facet." << endl + << " */" << endl; + + gen_typedef ("::xsd::cxx::tree::facet", c.get ("facet")); + + os << endl; + } + + //@@ Can't change names of ostream/istream since they are + // templates. + // + if (!options.value ().empty ()) + { + if (doxygen) + os << "/**" << endl + << " * @brief Data representation output stream template." << endl + << " */" << endl; + else + os << "// Data representation output stream template." << endl + << "//" << endl; + + os << "using ::xsd::cxx::tree::ostream;" + << endl; + } + + if (!options.value ().empty ()) + { + if (doxygen) + os << "/**" << endl + << " * @brief Data representation input stream template." << endl + << " */" << endl; + else + os << "// Data representation input stream template." << endl + << "//" << endl; + + os << "using ::xsd::cxx::tree::istream;" + << endl; + } + + os << "// Flags and properties." << endl + << "//" << endl; + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Parsing and serialization flags." << endl + << " */" << endl; + + gen_typedef ("::xsd::cxx::tree::flags", c.get ("flags")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Parsing properties." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::properties< " + char_type + L" >", + c.get ("properties")); + os << endl; + + + // + // + os << "// Exceptions." << endl + << "//" << endl; + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Root of the C++/Tree %exception hierarchy." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::exception< " + char_type + L" >", + c.get ("exception")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that the size argument exceeds" << + endl + << " * the capacity argument." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::bounds< " + char_type + L" >", + c.get ("bounds")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that a duplicate ID value" << + endl + << " * was encountered in the object model." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::duplicate_id< " + char_type + L" >", + c.get ("duplicate-id")); + + if (parsing) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating a parsing failure." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::parsing< " + char_type + L" >", + c.get ("parsing")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that an expected element" << + endl + << " * was not encountered." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::expected_element< " + char_type + L" >", + c.get ("expected-element")); + } + + if (parsing || serialization) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that an unexpected " << + "element" << endl + << " * was encountered." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::unexpected_element< " + char_type + L" >", + c.get ("unexpected-element")); + } + + if (parsing) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that an expected " << + "attribute" << endl + << " * was not encountered." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::expected_attribute< " + char_type + L" >", + c.get ("expected-attribute")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that an unexpected " << + "enumerator" << endl + << " * was encountered." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::unexpected_enumerator< " + char_type + L" >", + c.get ("unexpected-enumerator")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that the text content " << + "was" << endl + << " * expected for an element." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::expected_text_content< " + char_type + L" >", + c.get ("expected-text-content")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that a prefix-namespace" << + endl + << " * mapping was not provided." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::no_prefix_mapping< " + char_type + L" >", + c.get ("no-prefix-mapping")); + } + + if (options.value ()) + { + if (parsing || serialization) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that the type " << + "information" << endl + << " * is not available for a type." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::no_type_info< " + char_type + L" >", + c.get ("no-type-info")); + } + + if (parsing) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that the types are not" << + endl + << " * related by inheritance." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::not_derived< " + char_type + L" >", + c.get ("not-derived")); + } + } + + if (element_map) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating that parsing or " << + "serialization" << endl + << " * information is not available for an element." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::no_element_info< " + char_type + L" >", + c.get ("no-element-info")); + } + + if (serialization) + { + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Exception indicating a serialization " << + "failure." << endl + << " */" << endl; + + gen_typedef ( + L"::xsd::cxx::tree::serialization< " + char_type + L" >", + c.get ("serialization")); + } + + os << endl; + + // + // + if (parsing || serialization) + { + os << "// Parsing/serialization diagnostics." << endl + << "//" << endl; + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Error severity." << endl + << " */" << endl; + + gen_typedef ("::xsd::cxx::tree::severity", + c.get ("severity")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief Error condition." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::error< " + char_type + L" >", + c.get ("error")); + + if (doxygen) + os << endl + << "/**" << endl + << " * @brief List of %error conditions." << endl + << " */" << endl; + + gen_typedef (L"::xsd::cxx::tree::diagnostics< " + char_type + L" >", + c.get ("diagnostics")); + os << endl; + } + + if (parsing || serialization) + { + if (doxygen) + os << "/**" << endl + << " * @brief Error handler callback interface." << endl + << " */" << endl; + else + os << "// Error handler callback interface." << endl + << "//" << endl; + + gen_typedef ( + L"::xsd::cxx::xml::error_handler< " + char_type + L" >", + c.get ("error-handler")); + + os << endl; + } + + if (parsing || serialization) + { + if (doxygen) + os << "/**" << endl + << " * @brief DOM interaction." << endl + << " */" << endl; + else + os << "// DOM interaction." << endl + << "//" << endl; + + os << "namespace dom" + << "{"; + + // @@ Disregarding current naming convention by using the + // fixed name (no template typedef). + // + if (doxygen) + os << "/**" << endl + << " * @brief Automatic pointer for DOMDocument." << endl + << " */" << endl; + else + os << "// Automatic pointer for DOMDocument." << endl + << "//" << endl; + + os << "using ::xsd::cxx::xml::dom::auto_ptr;" + << endl; + + if (parsing) + { + if (!generate_xml_schema) + { + String g (L"XSD_CXX_TREE_TREE_NODE_KEY" + ns_name (n)); + + std::transform (g.begin (), g.end(), g.begin (), upcase); + g = escape (g); // Make it a C++ id. + + os << "#ifndef " << g << endl + << "#define " << g << endl; + } + + if (doxygen) + os << "/**" << endl + << " * @brief DOM user data key for back pointers to " << + "tree nodes." << endl + << " */" << endl; + else + os << "// DOM user data key for back pointers to tree nodes." << endl + << "//" << endl; + + os << "const XMLCh* const " << c.get ("tree-node-key") << + " = ::xsd::cxx::tree::user_data_keys::node;"; + + if (!generate_xml_schema) + os << "#endif" << endl; + } + + os << "}"; // namespace dom + } + + if (element_map) + { + if (doxygen) + os << "//@cond" << endl + << endl; + + if (!generate_xml_schema) + { + String g (L"XSD_CXX_TREE_ELEMENT_MAP_INIT" + ns_name (n)); + + std::transform (g.begin (), g.end(), g.begin (), upcase); + g = escape (g); // Make it a C++ id. + + os << "#ifndef " << g << endl + << "#define " << g << endl; + } + + os << "static" << endl + << "const ::xsd::cxx::tree::element_map_init < " << + char_type << ", " << type_ << " >" << endl + << "_xsd_element_map_init;"; + + if (!generate_xml_schema) + os << "#endif" << endl; + + if (doxygen) + os << endl + << "//@endcond" << endl; + } + + Namespace::post (n); + } + + private: + Boolean export_; + + Traversal::Names names_; + + String type_; + String simple_type_; + String string_; + String norm_string_; + String token_; + String nmtoken_; + String name_; + String ncname_; + String idref_; + String uri_; + String entity_; + + String double_; + String decimal_; + }; + } +} + +#endif // CXX_TREE_FUNDAMENTAL_HEADER_HXX diff --git a/xsd/cxx/tree/generator.cxx b/xsd/cxx/tree/generator.cxx new file mode 100644 index 0000000..f9b055e --- /dev/null +++ b/xsd/cxx/tree/generator.cxx @@ -0,0 +1,1689 @@ +// file : xsd/cxx/tree/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 "../../../libxsd/xsd/cxx/version.hxx" + +using std::endl; +using std::wcerr; + +using namespace XSDFrontend::SemanticGraph; + +// +// +typedef +boost::filesystem::wifstream +WideInputFileStream; + +typedef +boost::filesystem::wofstream +WideOutputFileStream; + +namespace CXX +{ + namespace + { + Char const copyright_gpl[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD, an XML Schema to\n" + "// C++ data binding compiler.\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" + "// In addition, as a special exception, Code Synthesis Tools CC gives\n" + "// permission to link this program with the Xerces-C++ library (or with\n" + "// modified versions of Xerces-C++ that use the same license as Xerces-C++),\n" + "// and distribute linked combinations including the two. You must obey\n" + "// the GNU General Public License version 2 in all respects for all of\n" + "// the code used other than Xerces-C++. If you modify this copy of the\n" + "// program, you may extend this exception to your version of the program,\n" + "// but you are not obligated to do so. If you do not wish to do so, delete\n" + "// this exception statement from your version.\n" + "//\n" + "// Furthermore, Code Synthesis Tools CC makes a special exception for\n" + "// the Free/Libre and Open Source Software (FLOSS) which is described\n" + "// in the accompanying FLOSSE file.\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD, an XML Schema\n" + "// to C++ data binding compiler, in the Proprietary License mode.\n" + "// You should have received a proprietary license from Code Synthesis\n" + "// Tools CC prior to generating this code. See the license text for\n" + "// conditions.\n" + "//\n\n"; + } + + namespace Tree + { + namespace CLI + { + extern Key char_type = "char-type"; + extern Key output_dir = "output-dir"; + extern Key generate_polymorphic = "generate-polymorphic"; + extern Key generate_serialization = "generate-serialization"; + extern Key generate_inline = "generate-inline"; + extern Key generate_ostream = "generate-ostream"; + extern Key generate_doxygen = "generate-doxygen"; + extern Key generate_comparison = "generate-comparison"; + extern Key generate_default_ctor = "generate-default-ctor"; + extern Key generate_from_base_ctor = "generate-from-base-ctor"; + extern Key generate_wildcard = "generate-wildcard"; + extern Key generate_insertion = "generate-insertion"; + extern Key generate_extraction = "generate-extraction"; + 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_parsing = "suppress-parsing"; + extern Key generate_element_type = "generate-element-type"; + extern Key generate_element_map = "generate-element-map"; + extern Key generate_intellisense = "generate-intellisense"; + extern Key omit_default_attributes = "omit-default-attributes"; + 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 type_naming = "type-naming"; + extern Key function_naming = "function-naming"; + extern Key type_regex = "type-regex"; + extern Key accessor_regex = "accessor-regex"; + extern Key one_accessor_regex = "one-accessor-regex"; + extern Key opt_accessor_regex = "opt-accessor-regex"; + extern Key seq_accessor_regex = "seq-accessor-regex"; + extern Key modifier_regex = "modifier-regex"; + extern Key one_modifier_regex = "one-modifier-regex"; + extern Key opt_modifier_regex = "opt-modifier-regex"; + extern Key seq_modifier_regex = "seq-modifier-regex"; + extern Key parser_regex = "parser-regex"; + extern Key serializer_regex = "serializer-regex"; + extern Key enumerator_regex = "enumerator-regex"; + extern Key element_type_regex = "element-type-regex"; + extern Key name_regex_trace = "name-regex-trace"; + 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 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 custom_type = "custom-type"; + extern Key custom_type_regex = "custom-type-regex"; + 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 parts = "parts"; + extern Key parts_suffix = "parts-suffix"; + extern Key export_symbol = "export-symbol"; + extern Key export_xml_schema = "export-xml-schema"; + extern Key export_maps = "export-maps"; + extern Key import_maps = "import-maps"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + extern Key disable_multi_import = "disable-multi-import"; + } + } + + Void Tree::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--char-type " << endl + << " Use as the base character type. Valid\n" + << " values are 'char' (default) and 'wchar_t'." + << endl; + + e << "--output-dir " << endl + << " Write generated files to instead of current\n" + << " directory." + << endl; + + + e << "--generate-polymorphic" << endl + << " Generate polymorphism-aware code. Specify this\n" + << " option if you use substitution groups or xsi:type." + << endl; + + e << "--generate-serialization" << endl + << " Generate serialization functions. They convert an\n" + << " in-memory representation back to XML." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--generate-ostream" << endl + << " Generate ostream insertion operators." + << endl; + + e << "--generate-doxygen" << endl + << " Generate documentation comments in the Doxygen\n" + << " format." + << endl; + + e << "--generate-comparison" << endl + << " Generate comparison operators." + << endl; + + e << "--generate-default-ctor" << endl + << " Generate default constructors even for types that\n" + << " have required members." + << endl; + + e << "--generate-from-base-ctor" << endl + << " Generate from-base constructors." + << endl; + + e << "--generate-wildcard" << endl + << " Generate accessors/modifiers as well as parsing\n" + << " and serialization code for XML Schema wildcards." + << endl; + + e << "--generate-insertion " << endl + << " Generate data representation stream insertion\n" + << " operators for the output stream type." + << endl; + + e << "--generate-extraction " << endl + << " Generate data representation stream extraction\n" + << " constructors for the input stream type." + << endl; + + e << "--generate-forward" << endl + << " Generate forward declaration file." + << 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 << "--suppress-parsing" << endl + << " Suppress the generation of parsing functions." + << endl; + + e << "--generate-element-type" << endl + << " Generate types instead of parsing/serialization\n" + << " functions for root elements." + << endl; + + e << "--generate-element-map" << endl + << " Generate a root element map that allows uniform\n" + << " parsing/serialization of multiple root elements.\n" + << endl; + + e << "--generate-intellisense" << endl + << " Generate workarounds for IntelliSense bugs in\n" + << " Visual Studio 2005 (8.0)." + << endl; + + e << "--omit-default-attributes" << endl + << " Omit attributes with default and fixed values\n" + << " from serialized XML documents." + << 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 << "--type-naming