diff options
Diffstat (limited to 'odb/odb/semantics')
49 files changed, 7561 insertions, 0 deletions
diff --git a/odb/odb/semantics/class-template.cxx b/odb/odb/semantics/class-template.cxx new file mode 100644 index 0000000..f8bbca4 --- /dev/null +++ b/odb/odb/semantics/class-template.cxx @@ -0,0 +1,54 @@ +// file : odb/semantics/class-template.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/class-template.hxx> + +namespace semantics +{ + class_template:: + class_template (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + class_instantiation:: + class_instantiation (path const& file, + size_t line, + size_t column, + tree tn) + : node (file, line, column, tn) + { + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // class_template + // + { + type_info ti (typeid (class_template)); + ti.add_base (typeid (type_template)); + ti.add_base (typeid (scope)); + insert (ti); + } + + // class_instantiation + // + { + type_info ti (typeid (class_instantiation)); + ti.add_base (typeid (class_)); + ti.add_base (typeid (type_instantiation)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/class-template.hxx b/odb/odb/semantics/class-template.hxx new file mode 100644 index 0000000..bffb3f2 --- /dev/null +++ b/odb/odb/semantics/class-template.hxx @@ -0,0 +1,68 @@ +// file : odb/semantics/class-template.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_CLASS_TEMPLATE_HXX +#define ODB_SEMANTICS_CLASS_TEMPLATE_HXX + +#include <odb/semantics/elements.hxx> +#include <odb/semantics/class.hxx> +#include <odb/semantics/template.hxx> + +namespace semantics +{ + class class_template: public type_template, public scope + { + private: + typedef std::vector<inherits*> inherits_list; + + public: + typedef pointer_iterator<inherits_list::const_iterator> inherits_iterator; + + inherits_iterator + inherits_begin () const + { + return inherits_.begin (); + } + + inherits_iterator + inherits_end () const + { + return inherits_.end (); + } + + public: + class_template (path const&, size_t line, size_t column, tree); + + void + add_edge_left (inherits& e) + { + inherits_.push_back (&e); + } + + void + add_edge_right (inherits&) + { + } + + using scope::add_edge_left; + using scope::add_edge_right; + + // Resolve conflict between scope::scope and nameable::scope. + // + using nameable::scope; + + private: + inherits_list inherits_; + }; + + class class_instantiation: public class_, public type_instantiation + { + public: + class_instantiation (path const&, size_t line, size_t column, tree); + + using class_::add_edge_left; + using type_instantiation::add_edge_left; + }; +} + +#endif // ODB_SEMANTICS_CLASS_TEMPLATE_HXX diff --git a/odb/odb/semantics/class.cxx b/odb/odb/semantics/class.cxx new file mode 100644 index 0000000..97cf088 --- /dev/null +++ b/odb/odb/semantics/class.cxx @@ -0,0 +1,175 @@ +// file : odb/semantics/class.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/gcc.hxx> // TYPE_HAS_DEFAULT_CONSTRUCTOR + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/class.hxx> + +namespace semantics +{ + inherits:: + inherits (access_type access, bool virt) + : virt_ (virt), access_ (access) + { + } + + class_:: + class_ (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + bool class_:: + default_ctor () const + { + tree t (tree_node ()); + + // TYPE_HAS_DEFAULT_CONSTRUCTOR() returns true if we have a deleted + // default ctor. locate_ctor(), on the other hand, returns NULL_TREE in + // this case. + // + if (TYPE_HAS_DEFAULT_CONSTRUCTOR (t)) + { +#if BUILDING_GCC_MAJOR >= 8 + + // Work around GCC bug 86441. Essentially, we should not trigger an + // instantiation or completion of the default ctor. As a result, we will + // assume that if we have a lazy default ctor, it is not implicitly + // deleted. + // + if (CLASSTYPE_LAZY_DEFAULT_CTOR (t)) + return true; + + for (ovl_iterator i (CLASSTYPE_CONSTRUCTORS (t)); i; ++i) + { + tree f (*i); + + if (TREE_CODE (f) == FUNCTION_DECL && DECL_DELETED_FN (f)) + continue; + + if (default_ctor_p (f)) + return true; + } +#else + return locate_ctor (t) != NULL_TREE; +#endif + + } + + return false; + } + + bool class_:: + complete () const + { + return COMPLETE_TYPE_P (tree_node ()); + } + + bool class_:: + abstract () const + { + return CLASSTYPE_PURE_VIRTUALS (tree_node ()); + } + + names* class_:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* ph) const + { + bool h (false); + bool& rh (ph != 0 ? *ph : h); + + names* r (scope::lookup (name, ti, flags | exclude_outer, &rh)); + + if (r != 0) + return r; + + // If we found a name but the types didn't match, then bail out + // unless we want hidden names. + // + if (rh && (flags & include_hidden) == 0) + return 0; + + // Look in the base classes unless requested not to. For the name + // lookup purposes, bases can be viewed as a parallel set of outer + // scopes that are searched after the class scope and before any + // real outer scope. Interestingly, outer scopes of bases are not + // considered during this lookup, only their bases. + // + if ((flags & exclude_base) == 0) + { + // Being hidden in one base doesn't mean it is also hidden in the + // other. Normally that would be an ambiguous lookup, but we use + // relaxed rules. + // + bool any_h (false); // Indicates whether any base hides the name. + + for (inherits_iterator i (inherits_begin ()); i != inherits_end (); ++i) + { + bool h (false); // Indicates whether this base hides the name. + names* br (i->base ().lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (br != 0) + { + if (r != 0) + throw ambiguous (*r, *br); + + r = br; + + if (h) + rh = true; + } + } + + if (r != 0) + return r; + + if (any_h) + { + rh = true; + if ((flags & include_hidden) == 0) + return 0; + } + } + + // Look in the outer scope unless requested not to. + // + if ((flags & exclude_outer) == 0) + return scope ().lookup (name, ti, flags, &rh); + + return 0; + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // inherits + // + { + type_info ti (typeid (inherits)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // class_ + // + { + type_info ti (typeid (class_)); + ti.add_base (typeid (type)); + ti.add_base (typeid (scope)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/class.hxx b/odb/odb/semantics/class.hxx new file mode 100644 index 0000000..e02337a --- /dev/null +++ b/odb/odb/semantics/class.hxx @@ -0,0 +1,142 @@ +// file : odb/semantics/class.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_CLASS_HXX +#define ODB_SEMANTICS_CLASS_HXX + +#include <vector> +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + class class_; + + class inherits: public edge + { + public: + typedef semantics::access access_type; + + class_& + base () const + { + return *base_; + } + + class_& + derived () const + { + return *derived_; + } + + bool + virtual_ () const + { + return virt_; + } + + access_type + access () const + { + return access_; + } + + public: + inherits (access_type, bool virt); + + void + set_left_node (class_& n) + { + derived_ = &n; + } + + void + set_right_node (class_& n) + { + base_ = &n; + } + + protected: + bool virt_; + access_type access_; + + class_* base_; + class_* derived_; + }; + + // + // + class class_: public virtual type, public scope + { + private: + typedef std::vector<inherits*> inherits_list; + + public: + typedef pointer_iterator<inherits_list::const_iterator> inherits_iterator; + + inherits_iterator + inherits_begin () const + { + return inherits_.begin (); + } + + inherits_iterator + inherits_end () const + { + return inherits_.end (); + } + + public: + bool + default_ctor () const; + + bool + complete () const; + + bool + abstract () const; + + public: + // When doing lookup in class scope, take into account bases. + // + static unsigned int const exclude_base = 0x04; // Exclude base classes. + + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + using scope::lookup; + + public: + class_ (path const&, size_t line, size_t column, tree); + + void + add_edge_left (inherits& e) + { + inherits_.push_back (&e); + } + + void + add_edge_right (inherits&) + { + } + + using scope::add_edge_left; + using type::add_edge_right; + + // Resolve conflict between scope::scope and nameable::scope. + // + using nameable::scope; + + protected: + class_ () + { + } + + private: + inherits_list inherits_; + }; +} + +#endif // ODB_SEMANTICS_CLASS_HXX diff --git a/odb/odb/semantics/derived.cxx b/odb/odb/semantics/derived.cxx new file mode 100644 index 0000000..771ad21 --- /dev/null +++ b/odb/odb/semantics/derived.cxx @@ -0,0 +1,254 @@ +// file : odb/semantics/derived.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <sstream> + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/derived.hxx> + +using namespace std; + +namespace semantics +{ + qualifies:: + qualifies () + : hint_ (0) + { + } + + qualifier:: + qualifier (path const& file, + size_t line, + size_t column, + tree tn, + bool c, + bool v, + bool r) + : node (file, line, column, tn), c_ (c), v_ (v), r_ (r) + { + } + + string qualifier:: + fq_name (names* hint) const + { + if (hint != 0 || defined_ != 0) + return nameable::fq_name (hint); + + // GCC type_as_string() for some reason cannot correctly print names + // like 'const std::string'. Instead it prints 'const string'. + // + type& bt (base_type ()); + + // Use the trailing qualifier syntax so that we don't get bogged down + // in stuff like 'const const foo*'. We also have to handle arrays in + // a special way since char[16] const is not a legal syntax. + // + string q; + if (c_) + q += " const"; + + if (v_) + q += " volatile"; + + if (r_) + q += " __restrict"; + + hint = qualifies ().hint (); + + if (array* a = dynamic_cast<array*> (&bt)) + return a->fq_name (hint, q); + else + return bt.fq_name (hint) + q; + } + + points:: + points () + : hint_ (0) + { + } + + pointer:: + pointer (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + string pointer:: + fq_name (names* hint) const + { + if (hint != 0 || defined_ != 0) + return nameable::fq_name (hint); + + // GCC type_as_string() for some reason cannot correctly print names + // like 'const std::string*'. Instead it prints 'const string*'. + // + string r (base_type ().fq_name (points ().hint ())); + r += '*'; + return r; + } + + references:: + references () + : hint_ (0) + { + } + + reference:: + reference (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + string reference:: + fq_name (names* hint) const + { + if (hint != 0 || defined_ != 0) + return nameable::fq_name (hint); + + // GCC type_as_string() for some reason cannot correctly print names + // like 'const std::string&'. Instead it prints 'const string&'. + // + string r (base_type ().fq_name (points ().hint ())); + r += '&'; + return r; + } + + contains:: + contains () + : hint_ (0) + { + } + + array:: + array (path const& file, + size_t line, + size_t column, + tree tn, + unsigned long long size) + : node (file, line, column, tn), size_ (size) + { + } + + string array:: + fq_name (names* hint) const + { + // GCC type_as_string() for some reason cannot correctly print names + // like 'const std::string[123]'. Instead it prints 'const string[123]'. + // + string t; + return fq_name (hint, t); + } + + string array:: + fq_name (names* hint, string& t) const + { + if (hint != 0 || defined_ != 0) + return nameable::fq_name (hint) + t; + + t += '['; + ostringstream ostr; + ostr << size (); + t += ostr.str (); + + if (size () > 0xFFFFFFFF) + t += "ULL"; + else if (size () > 2147483647) + t += "U"; + + t += ']'; + + type& bt (base_type ()); + hint = contains ().hint (); + array* a; + + if (hint != 0 || (a = dynamic_cast<array*> (&bt)) == 0) + return bt.fq_name (hint) + t; + else + return a->fq_name (0, t); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // derived_type + // + { + type_info ti (typeid (derived_type)); + ti.add_base (typeid (type)); + insert (ti); + } + + // qualifies + // + { + type_info ti (typeid (qualifies)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // qualifier + // + { + type_info ti (typeid (qualifier)); + ti.add_base (typeid (derived_type)); + insert (ti); + } + + // points + // + { + type_info ti (typeid (points)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // pointer + // + { + type_info ti (typeid (pointer)); + ti.add_base (typeid (derived_type)); + insert (ti); + } + + // references + // + { + type_info ti (typeid (references)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // reference + // + { + type_info ti (typeid (reference)); + ti.add_base (typeid (derived_type)); + insert (ti); + } + + // contains + // + { + type_info ti (typeid (contains)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // array + // + { + type_info ti (typeid (array)); + ti.add_base (typeid (derived_type)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/derived.hxx b/odb/odb/semantics/derived.hxx new file mode 100644 index 0000000..e58ec9f --- /dev/null +++ b/odb/odb/semantics/derived.hxx @@ -0,0 +1,440 @@ +// file : odb/semantics/derived.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_DERIVED_HXX +#define ODB_SEMANTICS_DERIVED_HXX + +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + // + // Derived types (cvr-qualifiers, pointer, reference, and array). + // + + class derived_type: public type + { + public: + virtual type& + base_type () const = 0; + }; + + // + // + class qualifier; + + class qualifies: public edge + { + public: + typedef semantics::type type_type; + typedef semantics::qualifier qualifier_type; + + type_type& + type () const + { + return *type_; + } + + qualifier_type& + qualifier () const + { + return *qualifier_; + } + + // Name hint of the base type. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + qualifies (); + + void + set_left_node (qualifier_type& n) + { + qualifier_ = &n; + } + + void + set_right_node (type_type& n) + { + type_ = &n; + } + + protected: + type_type* type_; + qualifier_type* qualifier_; + names* hint_; + }; + + class qualifier: public derived_type + { + public: + typedef semantics::qualifies qualifies_type; + + bool + const_ () const + { + return c_; + } + + bool + volatile_ () const + { + return v_; + } + + bool + restrict_ () const + { + return r_; + } + + virtual type& + base_type () const + { + return qualifies_->type (); + } + + qualifies_type& + qualifies () const + { + return *qualifies_; + } + + public: + virtual string + fq_name (names*) const; + + public: + qualifier (path const&, + size_t line, + size_t column, + tree, + bool c, + bool v, + bool r); + + void + add_edge_left (qualifies_type& e) + { + qualifies_ = &e; + } + + private: + bool c_, v_, r_; + qualifies_type* qualifies_; + }; + + // + // + class pointer; + + class points: public edge + { + public: + typedef semantics::type type_type; + typedef semantics::pointer pointer_type; + + type_type& + type () const + { + return *type_; + } + + pointer_type& + pointer () const + { + return *pointer_; + } + + // Name hint of the base type. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + points (); + + void + set_left_node (pointer_type& n) + { + pointer_ = &n; + } + + void + set_right_node (type_type& n) + { + type_ = &n; + } + + protected: + type_type* type_; + pointer_type* pointer_; + names* hint_; + }; + + class pointer: public derived_type + { + public: + typedef semantics::points points_type; + + virtual type& + base_type () const + { + return points_->type (); + } + + points_type& + points () const + { + return *points_; + } + + public: + virtual string + fq_name (names*) const; + + public: + pointer (path const&, size_t line, size_t column, tree); + + void + add_edge_left (points_type& e) + { + points_ = &e; + } + + private: + points_type* points_; + }; + + + // + // + class reference; + + class references: public edge + { + public: + typedef semantics::type type_type; + typedef semantics::reference reference_type; + + type_type& + type () const + { + return *type_; + } + + reference_type& + reference () const + { + return *reference_; + } + + // Name hint of the base type. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + references (); + + void + set_left_node (reference_type& n) + { + reference_ = &n; + } + + void + set_right_node (type_type& n) + { + type_ = &n; + } + + protected: + type_type* type_; + reference_type* reference_; + names* hint_; + }; + + class reference: public derived_type + { + public: + typedef semantics::references references_type; + + virtual type& + base_type () const + { + return references_->type (); + } + + references_type& + references () const + { + return *references_; + } + + public: + virtual string + fq_name (names*) const; + + public: + reference (path const&, size_t line, size_t column, tree); + + void + add_edge_left (references_type& e) + { + references_ = &e; + } + + private: + references_type* references_; + }; + + + // + // + class array; + + class contains: public edge + { + public: + typedef semantics::type type_type; + typedef semantics::array array_type; + + type_type& + type () const + { + return *type_; + } + + array_type& + array () const + { + return *array_; + } + + // Name hint of the base type. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + contains (); + + void + set_left_node (array_type& n) + { + array_ = &n; + } + + void + set_right_node (type_type& n) + { + type_ = &n; + } + + protected: + type_type* type_; + array_type* array_; + names* hint_; + }; + + class array: public derived_type + { + public: + typedef semantics::contains contains_type; + + // Return the number of elements in the array or 0 if it is not + // specified (e.g., int[]). + // + unsigned long long + size () const + { + return size_; + } + + virtual type& + base_type () const + { + return contains_->type (); + } + + contains_type& + contains () const + { + return *contains_; + } + + public: + virtual string + fq_name (names*) const; + + private: + friend class qualifier; + + string + fq_name (names*, string& trailer) const; + + using derived_type::fq_name; // Unhide. + + public: + array (path const&, + size_t line, + size_t column, + tree, + unsigned long long size); + + void + add_edge_left (contains_type& e) + { + contains_ = &e; + } + + private: + contains_type* contains_; + unsigned long long size_; + }; +} + +#endif // ODB_SEMANTICS_DERIVED_HXX diff --git a/odb/odb/semantics/elements.cxx b/odb/odb/semantics/elements.cxx new file mode 100644 index 0000000..b5793d0 --- /dev/null +++ b/odb/odb/semantics/elements.cxx @@ -0,0 +1,619 @@ +// file : odb/semantics/elements.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/gcc.hxx> + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/cxx-lexer.hxx> + +#include <odb/semantics/elements.hxx> +#include <odb/semantics/namespace.hxx> +#include <odb/semantics/unit.hxx> + +using namespace std; + +namespace semantics +{ + // access + // + static char const* access_str[] = {"public", "protected", "private"}; + + char const* access:: + string () const + { + return access_str[value_]; + } + + // + // + node:: + node (path const& file, size_t line, size_t column, tree tn) + : tree_node_ (tn), loc_ (file, line, column) + { + } + + node:: + node () + : loc_ (0) + { + // GCC plugin machinery #define's abort as a macro. + // + // std::abort (); + abort (); + } + + // nameable + // + + bool nameable:: + in_scope (scope_type& s) + { + for (scope_type* p (&scope ());; p = &p->scope_ ()) + { + //@@ Need to handle namespace extensions. + // + if (p == &s) + return true; + + if (!p->named_p () || p->global_scope ()) + break; + } + + return false; + } + + bool nameable:: + anonymous_ () const + { + tree n (tree_node ()); + + if (TYPE_P (n)) + { + tree name (0); + + if (tree decl = TYPE_NAME (n)) + name = DECL_NAME (decl); + + return name != 0 && IDENTIFIER_ANON_P (name); + } + + return true; + } + + bool nameable:: + fq_anonymous_ (scope_entry const* prev) const + { + scope_entry scope (this, prev); + + // Nameable is fq-anonymous if all the paths to the global scope + // have at least one anonymous link. + // + if (defined_ != 0 || !named_.empty ()) + { + if (named ().global_scope ()) + return false; + + if (defined_ != 0) + { + nameable const& s (defined_->scope ()); + + if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) + return false; + } + + for (names_list::const_iterator i (named_.begin ()), e (named_.end ()); + i != e; ++i) + { + nameable const& s ((*i)->scope ()); + + if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) + return false; + } + } + + // If we can get a literal name for this type node, then it is not + // anonymous as long as its scope is not anonymous. + // + tree type (tree_node ()); + + if (TYPE_P (type)) + { + tree name (0); + + if (tree decl = TYPE_NAME (type)) + { + name = DECL_NAME (decl); + if (name != 0 && IDENTIFIER_ANON_P (name)) + return true; + + tree s (CP_DECL_CONTEXT (decl)); + + gcc_tree_code_type tc (TREE_CODE (s)); + + if (tc == TYPE_DECL) + s = TREE_TYPE (s); + else if (tc == NAMESPACE_DECL) + { + // "Unwind" any inline namespaces since they are not in + // semantic grapth. + // + while (s != global_namespace) + { + tree prev (CP_DECL_CONTEXT (s)); + +#if BUILDING_GCC_MAJOR >= 8 + if (!is_nested_namespace (prev, s, true)) +#else + if (!is_associated_namespace (prev, s)) +#endif + break; + + s = prev; + } + } + + if (nameable* n = dynamic_cast<nameable*> (unit ().find (s))) + return scope.find (n) || n->fq_anonymous_ (&scope); + } + else + return false; // Assume this is a derived type (e.g., pointer). + } + + return true; + } + + bool nameable:: + fq_anonymous (names* hint) const + { + if (hint != 0 || defined_ != 0) + { + names& n (hint ? *hint : *defined_); + + if (n.global_scope ()) + return false; + + return n.scope ().fq_anonymous (); + } + else + return fq_anonymous (); + } + + static string + qualify_names (string const& n, bool qualify_first) + { + // @@ Creating a lexer for each call is a bad idea. Need + // to cache it somewhere. + // + cxx_string_lexer l; + l.start (n); + + string r, t; + bool punc (false); + bool scoped (false); + + // Names returned by GCC's type_as_string() (on which this function + // is called) include inline namespaces (e.g., std::__cxx11::string). + // So, besides fully-qualifying names, this function also needs to get + // rid of those. The idea is to resolve names as we lex them, skipping + // inline namespaces and stopping once we reach something other than a + // namespace. + // + tree ns (global_namespace); + tree id; + + for (cpp_ttype tt = l.next (t, &id); tt != CPP_EOF; tt = l.next (t, &id)) + { + if (punc && tt > CPP_LAST_PUNCTUATOR) + r += ' '; + + punc = false; + tree new_ns (global_namespace); // By default, revert to global. + + switch (static_cast<unsigned> (tt)) + { + case CPP_LESS: + { + r += "< "; + break; + } + case CPP_GREATER: + { + r += " >"; + break; + } + case CPP_COMMA: + { + r += ", "; + break; + } + case CPP_NAME: + { + // Check if this is a namespace and, if so, whether it is + // inline. + // + if (ns != 0) + { + new_ns = lookup_qualified_name (ns, id, false, false); + + if (new_ns == error_mark_node || + TREE_CODE (new_ns) != NAMESPACE_DECL) + new_ns = 0; // Not a namespace, stop resolving. + else + { + // Check if this is an inline namespace and skip it if so. + // +#if BUILDING_GCC_MAJOR >= 8 + if (is_nested_namespace (ns, new_ns, true)) +#else + if (is_associated_namespace (ns, new_ns)) +#endif + { + // Skip also the following scope operator. Strictly speaking + // there could be none (i.e., this is a name of an inline + // namespace) but we only use this function to print names + // of anonymous types. + // + assert (l.next (t) == CPP_SCOPE); + continue; + } + } + } + else + new_ns = 0; // Keep it disabled until we hit a new name. + + // If the name was not preceeded with '::', qualify it. + // + if (!scoped) + { + if (!qualify_first) + qualify_first = true; + else + r += "::"; + } + + r += t; + punc = true; + break; + } + case CPP_KEYWORD: + case CPP_NUMBER: + { + r += t; + punc = true; + break; + } + case CPP_SCOPE: + { + new_ns = ns; // Don't change the namespace. + } + // Fall through. + default: + { + r += t; + break; + } + } + + scoped = (tt == CPP_SCOPE); + ns = new_ns; + } + + return r; + } + + string nameable:: + name_ () const + { + tree n (tree_node ()); + + if (!TYPE_P (n)) + return "<anonymous>"; + + // @@ Doing this once and caching the result is probably a + // good idea. + // + return qualify_names ( + type_as_string (n, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME), false); + } + + string nameable:: + fq_name () const + { + return fq_name_ (0); + } + + string nameable:: + fq_name_ (scope_entry const* prev) const + { + // @@ Doing this once and caching the result is probably a + // good idea. + // + scope_entry scope (this, prev); + + if (named_p () && named ().global_scope ()) + return ""; + + if (defined_ != 0) + { + nameable const& s (defined_->scope ()); + + if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) + return s.fq_name_ (&scope) + "::" + name (); + } + + for (names_list::const_iterator i (named_.begin ()), e (named_.end ()); + i != e; ++i) + { + nameable const& s ((*i)->scope ()); + + if (!scope.find (&s) && !s.fq_anonymous_ (&scope)) + return s.fq_name_ (&scope) + "::" + name (); + } + + tree n (tree_node ()); + + if (!TYPE_P (n)) + return "<anonymous>"; + + return qualify_names (type_as_string (n, TFF_PLAIN_IDENTIFIER), true); + } + + string nameable:: + fq_name (names* hint) const + { + if (hint != 0 || defined_ != 0) + { + names& n (hint ? *hint : *defined_); + + if (n.global_scope ()) + return ""; + + return n.scope ().fq_name () + "::" + n.name (); + } + else + { + // Since there was no hint, prefer the literal name over the names + // edges. + // + tree n (tree_node ()); + + if (TYPE_P (n)) + return qualify_names (type_as_string (n, TFF_PLAIN_IDENTIFIER), true); + + // Last resort is to call the other version of fq_name which will + // check the names edges. + // + return fq_name (); + } + } + + // scope + // + + scope::names_iterator_pair scope:: + find (string const& name) const + { + names_map::const_iterator i (names_map_.find (name)); + + if (i == names_map_.end ()) + return names_iterator_pair (names_.end (), names_.end ()); + else + return names_iterator_pair (i->second.begin (), i->second.end ()); + } + + scope::names_iterator scope:: + find (names& e) + { + list_iterator_map::iterator i (iterator_map_.find (&e)); + return i != iterator_map_.end () ? i->second : names_.end (); + } + + static bool + is_base (type_id const& b, compiler::type_info const& d) + { + using compiler::type_info; + + for (type_info::base_iterator i (d.begin_base ()); + i != d.end_base (); ++i) + { + type_info const& ti (i->type_info ()); + + if (b == ti.type_id () || is_base (b, ti)) + return true; + } + + return false; + } + + names* scope:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* hidden) const + { + names_iterator_pair p (find (name)); + names* r (0); + + for (names_const_iterator i (p.first); i != p.second; ++i) + { + type_id const& xti (typeid (i->named ())); + + // If types are equal, then we found a match. Also check if ti is + // a base type of xti. + // + if (xti == ti || is_base (ti, compiler::lookup (xti))) + { + if (r != 0) + { + // If both are namespaces, then the one is just an extension + // of the other. + // + if (!(r->named ().is_a<namespace_> () && + i->named ().is_a<namespace_> ())) + throw ambiguous (*r, *i); + } + else + r = &*i; + } + } + + if (r != 0) + return r; + + // If we found a name but the types didn't match, then bail out + // unless we want hidden names. + // + if (p.first != p.second) + { + if (hidden != 0) + *hidden = true; + + if ((flags & include_hidden) == 0) + return 0; + } + + // Look in the outer scope unless requested not to or if this is + // the global scope. + // + if ((flags & exclude_outer) == 0 && named_p () && !global_scope ()) + return scope ().lookup (name, ti, flags, hidden); + + return 0; + } + + void scope:: + add_edge_left (names& e) + { + names_list::iterator i (names_.insert (names_.end (), &e)); + iterator_map_[&e] = i; + names_map_[e.name ()].push_back (&e); + } + + void scope:: + add_edge_left (names& e, names_iterator after) + { + names_list::iterator i; + + if (after.base () == names_.end ()) + i = names_.insert (names_.begin (), &e); + else + { + names_list::iterator j (after.base ()); + i = names_.insert (++j, &e); + } + + iterator_map_[&e] = i; + names_map_[e.name ()].push_back (&e); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // node + // + insert (type_info (typeid (node))); + + // edge + // + insert (type_info (typeid (edge))); + + // names + // + { + type_info ti (typeid (names)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // declares + // + { + type_info ti (typeid (declares)); + ti.add_base (typeid (names)); + insert (ti); + } + + // defines + // + { + type_info ti (typeid (defines)); + ti.add_base (typeid (declares)); + insert (ti); + } + + // typedefs + // + { + type_info ti (typeid (typedefs)); + ti.add_base (typeid (declares)); + insert (ti); + } + + // nameable + // + { + type_info ti (typeid (nameable)); + ti.add_base (typeid (node)); + insert (ti); + } + + // scope + // + { + type_info ti (typeid (scope)); + ti.add_base (typeid (nameable)); + insert (ti); + } + + // type + // + { + type_info ti (typeid (type)); + ti.add_base (typeid (nameable)); + insert (ti); + } + + // belongs + // + { + type_info ti (typeid (belongs)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // instance + // + { + type_info ti (typeid (instance)); + ti.add_base (typeid (node)); + insert (ti); + } + + // data_member + // + { + type_info ti (typeid (data_member)); + ti.add_base (typeid (nameable)); + ti.add_base (typeid (instance)); + insert (ti); + } + + // unsupported_type + // + { + type_info ti (typeid (unsupported_type)); + ti.add_base (typeid (type)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/elements.hxx b/odb/odb/semantics/elements.hxx new file mode 100644 index 0000000..699a1be --- /dev/null +++ b/odb/odb/semantics/elements.hxx @@ -0,0 +1,841 @@ +// file : odb/semantics/elements.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_ELEMENTS_HXX +#define ODB_SEMANTICS_ELEMENTS_HXX + +#include <map> +#include <list> +#include <vector> +#include <string> +#include <cstdlib> // std::abort +#include <cstddef> // std::size_t +#include <utility> // std::pair +#include <cassert> + +#include <libcutl/fs/path.hxx> +#include <libcutl/container/graph.hxx> +#include <libcutl/container/pointer-iterator.hxx> +#include <libcutl/compiler/type-id.hxx> +#include <libcutl/compiler/context.hxx> + +#include <odb/gcc-fwd.hxx> +#include <odb/location.hxx> + +namespace semantics +{ + using namespace cutl; + + using std::size_t; + using std::string; + + using container::graph; + using container::pointer_iterator; + + using compiler::type_id; + using compiler::context; + + // + // + using fs::path; + using fs::invalid_path; + + // + // + class access + { + public: + enum value { public_, protected_, private_ }; + + access (value v) + : value_ (v) + { + } + + operator value () const + { + return value_; + } + + char const* string () const; + + private: + value value_; + }; + + // + // + class node; + class edge; + class unit; + + // Support for inserting edges at specified positions. + // + template <typename N, typename I> + struct node_position + { + node_position (N& node, I pos) + : node_ (node), pos_ (pos) + { + } + + operator N& () const + { + return node_; + } + + template <typename E> + void + add_edge_left (E& e) + { + node_.add_edge_left (e, pos_); + } + + template <typename E> + void + add_edge_right (E& e) + { + node_.add_edge_right (e, pos_); + } + + private: + N& node_; + I pos_; + }; + + // + // + class edge: public context + { + public: + virtual + ~edge () {} + + public: + template <typename X> + X* + is_a () {return dynamic_cast<X*> (this);} + + template <typename X> + const X* + is_a () const {return dynamic_cast<const X*> (this);} + }; + + // + // + class node: public context + { + public: + virtual + ~node () {} + + public: + tree + tree_node () const + { + return tree_node_; + } + + public: + typedef ::location location_type; + + path const& + file () const + { + return loc_.file; + } + + size_t + line () const + { + return loc_.line; + } + + size_t + column () const + { + return loc_.column; + } + + location_type const& + location () const + { + return loc_; + } + + public: + template <typename X> + X* + is_a () {return dynamic_cast<X*> (this);} + + template <typename X> + const X* + is_a () const {return dynamic_cast<const X*> (this);} + + public: + node (path const& file, size_t line, size_t column, tree); + + // Sink functions that allow extensions in the form of one-way + // edges. + // + void + add_edge_left (edge&) {} + + void + add_edge_right (edge&) {} + + protected: + // For virtual inheritance. Should never be actually called. + // + node (); + + protected: + typedef semantics::unit unit_type; + + unit_type const& + unit () const + { + return *unit_; + } + + unit_type& + unit () + { + return *unit_; + } + + private: + friend class semantics::unit; + + void + unit (unit_type& u) + { + unit_ = &u; + } + + private: + tree tree_node_; + unit_type* unit_; + + location_type loc_; + }; + + // + // + class scope; + class nameable; + + + // + // + class names: public edge + { + public: + typedef semantics::scope scope_type; + typedef semantics::access access_type; + + string const& + name () const + { + return name_; + } + + scope_type& + scope () const + { + return *scope_; + } + + // Return true if the entity that this edge names is a global scope. + // In this case calling scope() is undefined behavior. + // + bool + global_scope () const + { + return scope_ == 0; + } + + nameable& + named () const + { + return *named_; + } + + access_type + access () const + { + return access_; + } + + // Names edge in terms of which this edge was defined. Can be NULL. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + names (string const& name, access_type access = access_type::public_) + : name_ (name), access_ (access), hint_ (0) + { + } + + void + set_left_node (scope_type& n) + { + scope_ = &n; + } + + void + set_right_node (nameable& n) + { + named_ = &n; + } + + protected: + scope_type* scope_; + nameable* named_; + string name_; + access_type access_; + names* hint_; + }; + + // + // Declarations and definitions. + // + + class declares: public names + { + public: + declares (string const& name, access_type access = access_type::public_) + : names (name, access) + { + } + }; + + class defines: public declares + { + public: + defines (string const& name, access_type access = access_type::public_) + : declares (name, access) + { + } + }; + + class type; + class typedefs: public declares + { + public: + typedef semantics::type type_type; + + type_type& + type () const; + + public: + typedefs (string const& name, access_type access = access_type::public_) + : declares (name, access) + { + } + }; + + // + // + class nameable: public virtual node + { + typedef std::vector<names*> names_list; + + public: + typedef semantics::scope scope_type; + + // Return true if this type is unnamed and no literal name, such as + // template-id or derived type declarator, can be used instead. + // + bool + anonymous () const + { + if (defined_ != 0 || !named_.empty ()) + return false; + + return anonymous_ (); + } + + // Return true if the node itself or any of the scopes up to the + // global scope is anonymous. For a named class nested in an unnamed + // class, anonymous() will return false and fq_anonymous() will + // return true. + // + bool + fq_anonymous () const + { + return fq_anonymous_ (0); + } + + // As above but use the hint to select the first outer scope. If + // hint is 0, use the defines edge. + // + bool + fq_anonymous (names* hint) const; + + // Return the node's unqualifed name. If the node has a name, then + // return it, preferring the defines edge. Otherwise, return a + // literal name, e.g., template-id or a derived type declarator. + // Finally, if the type is anonymous, return <anonymous> string. + // + string + name () const + { + if (defined_ != 0) + return defined_->name (); + + if (!named_.empty ()) + return named_[0]->name (); + + return name_ (); + } + + // Return the node's fully-qualifed name. + // + virtual string + fq_name () const; + + // As above but use the hint to select the first outer scope. If hint + // is 0, use the defines edge. + // + virtual string + fq_name (names* hint) const; + + // Return true if the type is named. + // + bool + named_p () const + { + return defined_ != 0 || !named_.empty (); + } + + scope_type& + scope () const + { + return named ().scope (); + } + + names& + named () const + { + return defined_ != 0 ? *defined_ : *named_[0]; + } + + bool + in_scope (scope_type&); + + public: + nameable () + : defined_ (0) + { + } + + void + add_edge_right (defines& e) + { + assert (defined_ == 0); + defined_ = &e; + } + + void + add_edge_right (names& e) + { + named_.push_back (&e); + } + + using node::add_edge_right; + + protected: + // We need to keep the scope we have seen in the fq_* function + // family in order to detect names that are inside the node + // and which would otherwise lead to infinite recursion. Here + // is the canonical example: + // + // template <typename X> + // class c + // { + // typedef c this_type; + // }; + // + struct scope_entry + { + scope_entry (nameable const* e, scope_entry const* p) + : entry_ (e), prev_ (p) + { + } + + bool + find (nameable const* n) const + { + for (scope_entry const* i (this); i != 0; i = i->prev_) + if (i->entry_ == n) + return true; + + return false; + } + + private: + nameable const* entry_; + scope_entry const* prev_; + }; + + bool + anonymous_ () const; + + bool + fq_anonymous_ (scope_entry const*) const; + + string + name_ () const; + + string + fq_name_ (scope_entry const*) const; + + protected: + defines* defined_; + names_list named_; + }; + + + // Ambiguous name lookup exception. + // + struct ambiguous + { + ambiguous (names& f, names& s): first (f), second (s) {} + names& first; + names& second; + }; + + // Unresolved name lookup exception. + // + struct unresolved + { + unresolved (string const& n, bool tm): name (n), type_mismatch (tm) {} + string name; + bool type_mismatch; // True if the name resolved but types didn't match. + }; + + // + // + class scope: public virtual nameable + { + protected: + typedef std::list<names*> names_list; + typedef std::map<names*, names_list::iterator> list_iterator_map; + typedef std::map<string, names_list> names_map; + + public: + typedef pointer_iterator<names_list::iterator> names_iterator; + typedef pointer_iterator<names_list::const_iterator> names_const_iterator; + + typedef + std::pair<names_const_iterator, names_const_iterator> + names_iterator_pair; + + public: + bool + global_scope () const + { + return named ().global_scope (); + } + + scope& + scope_ () const + { + return nameable::scope (); + } + + names_iterator + names_begin () + { + return names_.begin (); + } + + names_iterator + names_end () + { + return names_.end (); + } + + names_const_iterator + names_begin () const + { + return names_.begin (); + } + + names_const_iterator + names_end () const + { + return names_.end (); + } + + // Find a name in this scope. + // + public: + virtual names_iterator_pair + find (string const& name) const; + + names_iterator + find (names&); + + // Lookup a name of the specified type in this scope and, if not + // found, in outer scopes. + // + public: + static unsigned int const exclude_outer = 0x01; // Exclude outer scopes. + static unsigned int const include_hidden = 0x02; // Include hidden names. + + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + template <typename T> + T& + lookup (string const& name, unsigned int flags = 0) const + { + bool hidden (false); + + if (names* n = lookup (name, typeid (T), flags, &hidden)) + return dynamic_cast<T&> (n->named ()); + + throw unresolved (name, hidden); + } + + public: + scope (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + void + add_edge_left (names&); + + void + add_edge_left (names&, names_iterator after); + + using nameable::add_edge_right; + + protected: + scope () + { + } + + private: + names_list names_; + list_iterator_map iterator_map_; + names_map names_map_; + }; + + // + // + class points; + + class belongs; + class qualifies; + + class type: public virtual nameable + { + typedef std::vector<qualifies*> qualified; + + public: + typedef pointer_iterator<qualified::const_iterator> qualified_iterator; + + qualified_iterator + qualified_begin () const + { + return qualified_.begin (); + } + + qualified_iterator + qualified_end () const + { + return qualified_.end (); + } + + public: + bool + pointed_p () const {return pointed_ != 0;} + + points& + pointed () const {return *pointed_;} + + public: + type (): pointed_ (0) {} + + void + add_edge_right (belongs&) + { + } + + void + add_edge_right (qualifies& e) + { + qualified_.push_back (&e); + } + + void + add_edge_right (points& e) + { + pointed_ = &e; + } + + using nameable::add_edge_right; + + private: + qualified qualified_; + points* pointed_; + }; + + // + // + class instance; + + class belongs: public edge + { + public: + typedef semantics::type type_type; + typedef semantics::instance instance_type; + + type_type& + type () const + { + return *type_; + } + + instance_type& + instance () const + { + return *instance_; + } + + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + belongs () + : hint_ (0) + { + } + + void + set_left_node (instance_type& n) + { + instance_ = &n; + } + + void + set_right_node (type_type& n) + { + type_ = &n; + } + + private: + type_type* type_; + instance_type* instance_; + names* hint_; + }; + + // + // + class instance: public virtual node + { + public: + typedef semantics::type type_type; + typedef semantics::belongs belongs_type; + + type_type& + type () const + { + return belongs_->type (); + } + + belongs_type& + belongs () const + { + return *belongs_; + } + + public: + void + add_edge_left (belongs_type& e) + { + belongs_ = &e; + } + + protected: + instance () + { + } + + private: + belongs_type* belongs_; + }; + + // Data member for class and union types. + // + class data_member: public nameable, public instance + { + public: + data_member (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + protected: + data_member () + { + } + }; + + // Unsupported type. + // + class unsupported_type: public type + { + public: + string const& + type_name () const + { + return type_name_; + } + + public: + unsupported_type (path const& file, + size_t line, + size_t column, + tree tn, + string const& type_name) + : node (file, line, column, tn), type_name_ (type_name) + { + } + + private: + string const type_name_; + }; +} + +#include <odb/semantics/elements.ixx> + +#endif // ODB_SEMANTICS_ELEMENTS_HXX diff --git a/odb/odb/semantics/elements.ixx b/odb/odb/semantics/elements.ixx new file mode 100644 index 0000000..32f9ced --- /dev/null +++ b/odb/odb/semantics/elements.ixx @@ -0,0 +1,13 @@ +// file : odb/semantics/elements.ixx +// license : GNU GPL v3; see accompanying LICENSE file + +namespace semantics +{ + // typedefs + // + inline typedefs::type_type& typedefs:: + type () const + { + return dynamic_cast<type_type&> (named ()); + } +} diff --git a/odb/odb/semantics/enum.cxx b/odb/odb/semantics/enum.cxx new file mode 100644 index 0000000..6432986 --- /dev/null +++ b/odb/odb/semantics/enum.cxx @@ -0,0 +1,85 @@ +// file : odb/semantics/enum.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/enum.hxx> + +namespace semantics +{ + enumerates:: + enumerates () + { + } + + enumerator:: + enumerator (path const& file, + size_t line, + size_t column, + tree tn, + unsigned long long value) + : node (file, line, column, tn), value_ (value) + { + } + + underlies:: + underlies () + : type_ (0), enum__ (0), hint_ (0) + { + } + + enum_:: + enum_ (path const& file, + size_t line, + size_t column, + tree tn) + : node (file, line, column, tn) + { + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // enumerates + // + { + type_info ti (typeid (enumerates)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // enumerator + // + { + type_info ti (typeid (enumerator)); + ti.add_base (typeid (nameable)); + ti.add_base (typeid (instance)); + insert (ti); + } + + // underlies + // + { + type_info ti (typeid (underlies)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // enum_ + // + { + type_info ti (typeid (enum_)); + ti.add_base (typeid (type)); + ti.add_base (typeid (scope)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/enum.hxx b/odb/odb/semantics/enum.hxx new file mode 100644 index 0000000..bfcce53 --- /dev/null +++ b/odb/odb/semantics/enum.hxx @@ -0,0 +1,228 @@ +// file : odb/semantics/enum.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_ENUM_HXX +#define ODB_SEMANTICS_ENUM_HXX + +#include <vector> +#include <odb/semantics/elements.hxx> +#include <odb/semantics/fundamental.hxx> + +namespace semantics +{ + class enum_; + class enumerator; + + class enumerates: public edge + { + public: + typedef semantics::enum_ enum_type; + typedef semantics::enumerator enumerator_type; + + enum_type& + enum_ () const + { + return *enum__; + } + + enumerator_type& + enumerator () const + { + return *enumerator_; + } + + public: + enumerates (); + + void + set_left_node (enum_type& n) + { + enum__ = &n; + } + + void + set_right_node (enumerator_type& n) + { + enumerator_ = &n; + } + + protected: + enum_type* enum__; + enumerator_type* enumerator_; + }; + + // + // + class enumerator: public nameable, public instance + { + public: + typedef semantics::enum_ enum_type; + + enum_type& + enum_ () const + { + return enumerated_->enum_ (); + } + + enumerates& + enumerated () const + { + return *enumerated_; + } + + // If the enumeration is signed, then this value should be re- + // interpreted as signed. + // + unsigned long long + value () const + { + return value_; + } + + public: + enumerator (path const&, + size_t line, + size_t column, + tree, + unsigned long long value); + + void + add_edge_right (enumerates& e) + { + enumerated_ = &e; + } + + using nameable::add_edge_right; + + private: + unsigned long long value_; + enumerates* enumerated_; + }; + + // + // + class underlies: public edge + { + public: + typedef semantics::enum_ enum_type; + + integral_type& + type () const + { + return *type_; + } + + enum_type& + enum_ () const + { + return *enum__; + } + + // Names edge in terms of which this edge was defined. Can be NULL. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + underlies (); + + void + set_left_node (integral_type& n) + { + type_ = &n; + } + + void + set_right_node (enum_type& n) + { + enum__ = &n; + } + + protected: + integral_type* type_; + enum_type* enum__; + names* hint_; + }; + + // + // + class enum_: public type, public scope + { + private: + typedef std::vector<enumerates*> enumerates_list; + + public: + typedef + pointer_iterator<enumerates_list::const_iterator> + enumerates_iterator; + + enumerates_iterator + enumerates_begin () const + { + return enumerates_.begin (); + } + + enumerates_iterator + enumerates_end () const + { + return enumerates_.end (); + } + + underlies& + underlied () const + { + return *underlied_; + } + + integral_type& + underlying_type () const + { + return underlied_->type (); + } + + names* + underlying_type_hint () const + { + return underlied_->hint (); + } + + bool + unsigned_ () const + { + return underlying_type ().unsigned_ (); + } + + public: + enum_ (path const&, size_t line, size_t column, tree); + + void + add_edge_right (underlies& e) + { + underlied_ = &e; + } + + void + add_edge_left (enumerates& e) + { + enumerates_.push_back (&e); + } + + using scope::add_edge_left; + + private: + enumerates_list enumerates_; + underlies* underlied_; + }; +} + +#endif // ODB_SEMANTICS_ENUM_HXX diff --git a/odb/odb/semantics/fundamental.cxx b/odb/odb/semantics/fundamental.cxx new file mode 100644 index 0000000..ed4a67f --- /dev/null +++ b/odb/odb/semantics/fundamental.cxx @@ -0,0 +1,222 @@ +// file : odb/semantics/fundamental.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/gcc.hxx> + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/fundamental.hxx> + +namespace semantics +{ + string fund_type:: + fq_name () const + { + return name (); + } + + string fund_type:: + fq_name (names* hint) const + { + if (hint == 0) + return name (); + + return type::fq_name (hint); + } + + // char + // + bool fund_char:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + + // wchar_t + // + bool fund_wchar:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // fund_type + // + { + type_info ti (typeid (fund_type)); + ti.add_base (typeid (type)); + insert (ti); + } + + // fund_void + // + { + type_info ti (typeid (fund_void)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + + // integral_type + // + { + type_info ti (typeid (integral_type)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + + // fund_bool + // + { + type_info ti (typeid (fund_bool)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char + // + { + type_info ti (typeid (fund_char)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_wchar + // + { + type_info ti (typeid (fund_wchar)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char16 + // + { + type_info ti (typeid (fund_char16)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char32 + // + { + type_info ti (typeid (fund_char32)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_signed_char + // + { + type_info ti (typeid (fund_signed_char)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_unsigned_char + // + { + type_info ti (typeid (fund_unsigned_char)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_short + // + { + type_info ti (typeid (fund_short)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_unsigned_short + // + { + type_info ti (typeid (fund_unsigned_short)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_int + // + { + type_info ti (typeid (fund_int)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_unsigned_int + // + { + type_info ti (typeid (fund_unsigned_int)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_long + // + { + type_info ti (typeid (fund_long)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_unsigned_long + // + { + type_info ti (typeid (fund_unsigned_long)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_long_long + // + { + type_info ti (typeid (fund_long_long)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_unsigned_long_long + // + { + type_info ti (typeid (fund_unsigned_long_long)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_float + // + { + type_info ti (typeid (fund_float)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + + // fund_double + // + { + type_info ti (typeid (fund_double)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + + // fund_long_double + // + { + type_info ti (typeid (fund_long_double)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/fundamental.hxx b/odb/odb/semantics/fundamental.hxx new file mode 100644 index 0000000..15b5cbb --- /dev/null +++ b/odb/odb/semantics/fundamental.hxx @@ -0,0 +1,150 @@ +// file : odb/semantics/fundamental.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_FUNDAMENTAL_HXX +#define ODB_SEMANTICS_FUNDAMENTAL_HXX + +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + // + // Fundamental C++ types. + // + + struct fund_type: type + { + virtual string + fq_name () const; + + virtual string + fq_name (names*) const; + }; + + struct fund_void: fund_type + { + fund_void (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + }; + + // + // Integral. + // + + struct integral_type: fund_type + { + virtual bool + unsigned_ () const = 0; + }; + + struct fund_bool: integral_type + { + fund_bool (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_char: integral_type + { + fund_char (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const; + }; + + struct fund_wchar: integral_type + { + fund_wchar (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const; + }; + + struct fund_char16: integral_type + { + fund_char16 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_char32: integral_type + { + fund_char32 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_signed_char: integral_type + { + fund_signed_char (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} + }; + + struct fund_unsigned_char: integral_type + { + fund_unsigned_char (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_short: integral_type + { + fund_short (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} + }; + + struct fund_unsigned_short: integral_type + { + fund_unsigned_short (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_int: integral_type + { + fund_int (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} + }; + + struct fund_unsigned_int: integral_type + { + fund_unsigned_int (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_long: integral_type + { + fund_long (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} + }; + + struct fund_unsigned_long: integral_type + { + fund_unsigned_long (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_long_long: integral_type + { + fund_long_long (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} + }; + + struct fund_unsigned_long_long: integral_type + { + fund_unsigned_long_long (tree tn) + : node (path ("<fundamental>"), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + // + // Real. + // + + struct fund_float: fund_type + { + fund_float (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + }; + + struct fund_double: fund_type + { + fund_double (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + }; + + struct fund_long_double: fund_type + { + fund_long_double (tree tn): node (path ("<fundamental>"), 0, 0, tn) {} + }; +} + +#endif // ODB_SEMANTICS_FUNDAMENTAL_HXX diff --git a/odb/odb/semantics/namespace.cxx b/odb/odb/semantics/namespace.cxx new file mode 100644 index 0000000..d9be903 --- /dev/null +++ b/odb/odb/semantics/namespace.cxx @@ -0,0 +1,107 @@ +// file : odb/semantics/namespace.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/namespace.hxx> + +namespace semantics +{ + namespace_:: + namespace_ (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn), original_ (0) + { + } + + namespace_:: + namespace_ () + : original_ (0) + { + } + + names* namespace_:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* hidden) const + { + if (original_ != 0) + return original_->lookup (name, ti, flags, hidden); + + // Being hidden in one namespace doesn't mean it is also hidden in + // the other. Normally that would be an ambiguous lookup, but we use + // relaxed rules. + // + bool h (false); // Indicates whether this namespace hides the name. + bool any_h (false); // Indicates whether any namespace hides the name. + + names* r (scope::lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (r != 0 && h && hidden != 0) + *hidden = true; + + for (extensions_iterator i (extensions_begin ()); + i != extensions_end (); + ++i) + { + h = false; + names* er ((*i)->scope::lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (er != 0) + { + if (r != 0) + { + // If both are namespaces, then the one is just an extension + // of the other. + // + if (!(r->named ().is_a<namespace_> () && + er->named ().is_a<namespace_> ())) + throw ambiguous (*r, *er); + } + else + r = er; + + if (h && hidden != 0) + *hidden = true; + } + } + + if (r != 0) + return r; + + if (any_h) + { + if (hidden != 0) + *hidden = true; + + if ((flags & include_hidden) == 0) + return 0; + } + + // Look in the outer scope unless requested not to or if this is + // the global scope. + // + if ((flags & exclude_outer) == 0 && !global_scope ()) + return scope ().lookup (name, ti, flags, hidden); + + return 0; + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + type_info ti (typeid (namespace_)); + ti.add_base (typeid (scope)); + insert (ti); + } + } init_; + } +} diff --git a/odb/odb/semantics/namespace.hxx b/odb/odb/semantics/namespace.hxx new file mode 100644 index 0000000..b025c2e --- /dev/null +++ b/odb/odb/semantics/namespace.hxx @@ -0,0 +1,71 @@ +// file : odb/semantics/namespace.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_NAMESPACE_HXX +#define ODB_SEMANTICS_NAMESPACE_HXX + +#include <vector> + +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + class namespace_: public scope + { + typedef std::vector<namespace_*> extensions_type; + + public: + bool + extension () const + { + return original_ != 0; + } + + namespace_& + original () + { + return *original_; + } + + void + original (namespace_& ns) + { + original_ = &ns; + ns.extensions_.push_back (this); + } + + public: + typedef extensions_type::const_iterator extensions_iterator; + + extensions_iterator + extensions_begin () const {return extensions_.begin ();} + + extensions_iterator + extensions_end () const {return extensions_.end ();} + + public: + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + using scope::lookup; + + public: + namespace_ (path const&, size_t line, size_t column, tree); + + // Resolve conflict between scope::scope and nameable::scope. + // + using nameable::scope; + + protected: + namespace_ (); + + private: + namespace_* original_; + extensions_type extensions_; + }; +} + +#endif // ODB_SEMANTICS_NAMESPACE_HXX diff --git a/odb/odb/semantics/relational.hxx b/odb/odb/semantics/relational.hxx new file mode 100644 index 0000000..db08a61 --- /dev/null +++ b/odb/odb/semantics/relational.hxx @@ -0,0 +1,18 @@ +// file : odb/semantics/relational.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_HXX +#define ODB_SEMANTICS_RELATIONAL_HXX + +#include <odb/semantics/relational/changelog.hxx> +#include <odb/semantics/relational/changeset.hxx> +#include <odb/semantics/relational/column.hxx> +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/foreign-key.hxx> +#include <odb/semantics/relational/index.hxx> +#include <odb/semantics/relational/key.hxx> +#include <odb/semantics/relational/model.hxx> +#include <odb/semantics/relational/primary-key.hxx> +#include <odb/semantics/relational/table.hxx> + +#endif // ODB_SEMANTICS_RELATIONAL_HXX diff --git a/odb/odb/semantics/relational/changelog.cxx b/odb/odb/semantics/relational/changelog.cxx new file mode 100644 index 0000000..353497f --- /dev/null +++ b/odb/odb/semantics/relational/changelog.cxx @@ -0,0 +1,187 @@ +// file : odb/semantics/relational/changelog.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <vector> +#include <sstream> + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/changelog.hxx> +#include <odb/semantics/relational/model.hxx> +#include <odb/semantics/relational/changeset.hxx> + +using namespace std; + +namespace semantics +{ + namespace relational + { + changelog:: + changelog (xml::parser& p) + : contains_model_ (0) + { + using namespace xml; + + p.next_expect (parser::start_element, xmlns, "changelog"); + p.content (content::complex); + + if (p.attribute<unsigned int> ("version") != 1) + throw parsing (p, "unsupported changelog format version"); + + database_ = p.attribute ("database"); + schema_name_ = p.attribute ("schema-name", ""); + + // Because things are stored in the reverse order, first save the + // changesets as XML chunks and then re-parse them in the reverse + // order. We have to do it this way so that we can do lookups along + // the alters edges. + // + typedef vector<string> changesets; + changesets cs; + + for (parser::event_type e (p.peek ()); + e == parser::start_element; + e = p.peek ()) + { + if (p.qname () != xml::qname (xmlns, "changeset")) + break; // Not our elements. + + ostringstream os; + os.exceptions (ios_base::badbit | ios_base::failbit); + serializer s (os, "changeset", 0); // No pretty-printing. + size_t depth (0); + + do + { + switch (p.next ()) + { + case parser::start_element: + { + s.start_element (p.qname ()); + + if (depth == 0) + s.namespace_decl (xmlns, ""); + + typedef parser::attribute_map_type attr_map; + attr_map const& am (p.attribute_map ()); + + for (attr_map::const_iterator i (am.begin ()); + i != am.end (); ++i) + s.attribute (i->first, i->second.value); + + depth++; + break; + } + case parser::end_element: + { + depth--; + s.end_element (); + break; + } + case parser::characters: + { + s.characters (p.value ()); + break; + } + default: + { + depth = 0; + break; + } + } + } while (depth != 0); + + cs.push_back (os.str ()); + } + + // Get the model. + // + p.next_expect (parser::start_element, xmlns, "model"); + model_type& m (new_node<model_type> (p, *this)); + new_edge<contains_model_type> (*this, m); + p.next_expect (parser::end_element); + + // Re-parse the changesets in reverse order. + // + qscope* base (&m); + for (changesets::reverse_iterator i (cs.rbegin ()); i != cs.rend (); ++i) + { + istringstream is (*i); + is.exceptions (ios_base::badbit | ios_base::failbit); + parser ip (is, p.input_name ()); + + ip.next_expect (parser::start_element, xmlns, "changeset"); + + changeset& c (new_node<changeset> (ip, *base, *this)); + new_edge<contains_changeset> (*this, c); + base = &c; + + ip.next_expect (parser::end_element); + } + + p.next_expect (parser::end_element); + } + + void changelog:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "changelog"); + s.namespace_decl (xmlns, ""); + s.attribute ("database", database_); + if (!schema_name_.empty ()) + s.attribute ("schema-name", schema_name_); + s.attribute ("version", 1); // Format version. + + // For better readability serialize things in reverse order so that + // the most recent changeset appears first. + // + for (contains_changeset_list::const_reverse_iterator i ( + contains_changeset_.rbegin ()); + i != contains_changeset_.rend (); ++i) + { + (*i)->changeset ().serialize (s); + s.characters ("\n"); + } + + model ().serialize (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // contains_model + // + { + type_info ti (typeid (contains_model)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // contains_changeset + // + { + type_info ti (typeid (contains_changeset)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // changelog + // + { + type_info ti (typeid (changelog)); + ti.add_base (typeid (node)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/changelog.hxx b/odb/odb/semantics/relational/changelog.hxx new file mode 100644 index 0000000..2398cf6 --- /dev/null +++ b/odb/odb/semantics/relational/changelog.hxx @@ -0,0 +1,164 @@ +// file : odb/semantics/relational/changelog.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX +#define ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX + +#include <odb/semantics/relational/elements.hxx> + +namespace semantics +{ + namespace relational + { + class model; + class changeset; + class changelog; + + class contains_model: public edge + { + public: + typedef relational::changelog changelog_type; + typedef relational::model model_type; + + changelog_type& + changelog () const {return *changelog_;} + + model_type& + model () const {return *model_;} + + public: + void + set_left_node (changelog_type& n) {changelog_ = &n;} + + void + set_right_node (model_type& n) {model_ = &n;} + + protected: + changelog_type* changelog_; + model_type* model_; + }; + + class contains_changeset: public edge + { + public: + typedef relational::changelog changelog_type; + typedef relational::changeset changeset_type; + + changelog_type& + changelog () const {return *changelog_;} + + changeset_type& + changeset () const {return *changeset_;} + + public: + void + set_left_node (changelog_type& n) {changelog_ = &n;} + + void + set_right_node (changeset_type& n) {changeset_ = &n;} + + protected: + changelog_type* changelog_; + changeset_type* changeset_; + }; + + class changelog: public graph, public node + { + typedef std::vector<contains_changeset*> contains_changeset_list; + + public: + typedef relational::model model_type; + typedef relational::contains_model contains_model_type; + + model_type& + model () const {return contains_model_->model ();} + + contains_model_type& + contains_model () const {return *contains_model_;} + + public: + typedef + pointer_iterator<contains_changeset_list::const_iterator> + contains_changeset_iterator; + + contains_changeset const& + contains_changeset_back () const + { + return *contains_changeset_.back (); + } + + contains_changeset const& + contains_changeset_at (contains_changeset_list::size_type i) const + { + return *contains_changeset_[i]; + } + + contains_changeset_iterator + contains_changeset_begin () const + { + return contains_changeset_.begin (); + } + + contains_changeset_iterator + contains_changeset_end () const + { + return contains_changeset_.end (); + } + + contains_changeset_list::size_type + contains_changeset_size () const + { + return contains_changeset_.size (); + } + + bool + contains_changeset_empty () const + { + return contains_changeset_.empty (); + } + + public: + string const& + database () const {return database_;} + + string const& + schema_name () const {return schema_name_;} + + public: + changelog (string const& db, string const& sn) + : database_ (db), schema_name_ (sn), contains_model_ (0) {} + changelog (xml::parser&); + + void + add_edge_left (contains_model_type& e) + { + assert (contains_model_ == 0); + contains_model_ = &e; + } + + void + add_edge_left (contains_changeset& e) + { + contains_changeset_.push_back (&e); + } + + virtual string + kind () const {return "changelog";} + + virtual void + serialize (xml::serializer&) const; + + private: + changelog (changelog const&); + changelog& operator= (changelog const&); + + protected: + string database_; + string schema_name_; + contains_model_type* contains_model_; + contains_changeset_list contains_changeset_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_CHANGELOG_HXX diff --git a/odb/odb/semantics/relational/changeset.cxx b/odb/odb/semantics/relational/changeset.cxx new file mode 100644 index 0000000..b044a0c --- /dev/null +++ b/odb/odb/semantics/relational/changeset.cxx @@ -0,0 +1,56 @@ +// file : odb/semantics/relational/changeset.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/changeset.hxx> + +namespace semantics +{ + namespace relational + { + changeset:: + changeset (changeset const& c, qscope& b, graph& g) + : qscope (c, &b, g), + version_ (c.version_), + alters_model_ (0) + { + } + + changeset:: + changeset (xml::parser& p, qscope& b, graph& g) + : qscope (p, &b, g), + version_ (p.attribute<version_type> ("version")), + alters_model_ (0) + { + } + + void changeset:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "changeset"); + s.attribute ("version", version_); + qscope::serialize_content (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + { + type_info ti (typeid (changeset)); + ti.add_base (typeid (qscope)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/changeset.hxx b/odb/odb/semantics/relational/changeset.hxx new file mode 100644 index 0000000..efe2c61 --- /dev/null +++ b/odb/odb/semantics/relational/changeset.hxx @@ -0,0 +1,93 @@ +// file : odb/semantics/relational/changeset.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX +#define ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX + +#include <odb/semantics/relational/elements.hxx> + +namespace semantics +{ + namespace relational + { + class model; + class changeset; + + class alters_model: public edge + { + public: + typedef relational::model model_type; + typedef relational::changeset changeset_type; + + model_type& + model () const {return *model_;} + + changeset_type& + changeset () const {return *changeset_;} + + public: + alters_model () : model_ (0), changeset_ (0) {} + + void + set_left_node (changeset_type& c) + { + assert (changeset_ == 0); + changeset_ = &c; + } + + void + set_right_node (model_type& m) + { + assert (model_ == 0); + model_ = &m; + } + + protected: + model_type* model_; + changeset_type* changeset_; + }; + + class changeset: public qscope + { + public: + typedef relational::version version_type; + + version_type + version () const {return version_;} + + // Returns model to which this changeset applies (as opposed to the + // ultimate base model). Note that it may not be set. + // + model& + base_model () const {return alters_model_->model ();} + + public: + changeset (version_type v): version_ (v), alters_model_ (0) {} + changeset (changeset const&, qscope& base, graph&); + changeset (xml::parser&, qscope& base, graph&); + + virtual string + kind () const {return "changeset";} + + virtual void + serialize (xml::serializer&) const; + + public: + virtual void + add_edge_left (alters_model& am) + { + assert (alters_model_ == 0); + alters_model_ = &am; + } + + using qscope::add_edge_left; + using qscope::add_edge_right; + + private: + version_type version_; + alters_model* alters_model_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_CHANGESET_HXX diff --git a/odb/odb/semantics/relational/column.cxx b/odb/odb/semantics/relational/column.cxx new file mode 100644 index 0000000..9d4d6e5 --- /dev/null +++ b/odb/odb/semantics/relational/column.cxx @@ -0,0 +1,201 @@ +// file : odb/semantics/relational/column.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/column.hxx> + +namespace semantics +{ + namespace relational + { + // column + // + column:: + column (column const& c, uscope&, graph& g) + : unameable (c, g), + type_ (c.type_), + null_ (c.null_), + default__ (c.default__), + options_ (c.options_) + { + } + + column:: + column (xml::parser& p, uscope&, graph& g) + : unameable (p, g), + type_ (p.attribute ("type", string ())), + null_ (p.attribute<bool> ("null")), + default__ (p.attribute ("default", string ())), + options_ (p.attribute ("options", string ())) + { + p.content (xml::content::empty); + } + + column& column:: + clone (uscope& s, graph& g) const + { + return g.new_node<column> (*this, s, g); + } + + void column:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "column"); + serialize_attributes (s); + s.end_element (); + } + + void column:: + serialize_attributes (xml::serializer& s) const + { + unameable::serialize_attributes (s); + + s.attribute ("type", type ()); + s.attribute ("null", null ()); // Output even if false. + + if (!default_ ().empty ()) + s.attribute ("default", default_ ()); + + if (!options ().empty ()) + s.attribute ("options", options ()); + } + + // add_column + // + add_column& add_column:: + clone (uscope& s, graph& g) const + { + return g.new_node<add_column> (*this, s, g); + } + + void add_column:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "add-column"); + column::serialize_attributes (s); + s.end_element (); + } + + // drop_column + // + drop_column:: + drop_column (xml::parser& p, uscope&, graph& g) + : unameable (p, g) + { + p.content (xml::content::empty); + } + + drop_column& drop_column:: + clone (uscope& s, graph& g) const + { + return g.new_node<drop_column> (*this, s, g); + } + + void drop_column:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "drop-column"); + unameable::serialize_attributes (s); + s.end_element (); + } + + // alter_column + // + alter_column:: + alter_column (alter_column const& ac, uscope& s, graph& g) + : column (ac, s, g), + alters_ (0), + null_altered_ (ac.null_altered_) + { + column* b (s.lookup<column, drop_column> (ac.name ())); + assert (b != 0); + g.new_edge<alters> (*this, *b); + } + + alter_column:: + alter_column (xml::parser& p, uscope& s, graph& g) + : column (p, s, g), + alters_ (0), + null_altered_ (p.attribute_present ("null")) + { + name_type n (p.attribute<name_type> ("name")); + column* b (s.lookup<column, drop_column> (n)); + assert (b != 0); + g.new_edge<alters> (*this, *b); + } + + alter_column& alter_column:: + clone (uscope& s, graph& g) const + { + return g.new_node<alter_column> (*this, s, g); + } + + void alter_column:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "alter-column"); + + // Here we override the standard column logic. + // + unameable::serialize_attributes (s); + + if (null_altered_) + s.attribute ("null", null_); + + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + unameable::parser_map& m (unameable::parser_map_); + + m["column"] = &unameable::parser_impl<column>; + m["add-column"] = &unameable::parser_impl<add_column>; + m["drop-column"] = &unameable::parser_impl<drop_column>; + m["alter-column"] = &unameable::parser_impl<alter_column>; + + using compiler::type_info; + + // column + // + { + type_info ti (typeid (column)); + ti.add_base (typeid (unameable)); + insert (ti); + } + + // add_column + // + { + type_info ti (typeid (add_column)); + ti.add_base (typeid (column)); + insert (ti); + } + + // drop_column + // + { + type_info ti (typeid (drop_column)); + ti.add_base (typeid (unameable)); + insert (ti); + } + + // alter_column + // + { + type_info ti (typeid (alter_column)); + ti.add_base (typeid (column)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/column.hxx b/odb/odb/semantics/relational/column.hxx new file mode 100644 index 0000000..b7a2c31 --- /dev/null +++ b/odb/odb/semantics/relational/column.hxx @@ -0,0 +1,205 @@ +// file : odb/semantics/relational/column.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_COLUMN_HXX +#define ODB_SEMANTICS_RELATIONAL_COLUMN_HXX + +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/table.hxx> + +namespace semantics +{ + namespace relational + { + class contains; + + class column: public unameable + { + typedef std::vector<contains*> contained_list; + + public: + virtual string const& + type () const {return type_;} + + virtual bool + null () const {return null_;} + + virtual void + null (bool n) {null_ = n;} + + virtual string const& + default_ () const {return default__;} + + virtual void + default_ (string const& d) {default__ = d;} + + virtual string const& + options () const {return options_;} + + virtual void + options (string const& o) {options_ = o;} + + public: + typedef relational::table table_type; + + table_type& + table () const {return dynamic_cast<table_type&> (scope ());} + + // Key containment. + // + public: + typedef + pointer_iterator<contained_list::const_iterator> + contained_iterator; + + contained_iterator + contained_begin () const {return contained_.begin ();} + + contained_iterator + contained_end () const {return contained_.end ();} + + public: + column (string const& id, string const& type, bool null) + : unameable (id), type_ (type), null_ (null) + { + } + + column (column const&, uscope&, graph&); + column (xml::parser&, uscope&, graph&); + + virtual column& + clone (uscope&, graph&) const; + + void + add_edge_right (contains& e) + { + contained_.push_back (&e); + } + + using unameable::add_edge_right; + + virtual string + kind () const + { + return "column"; + } + + virtual void + serialize (xml::serializer&) const; + + protected: + void + serialize_attributes (xml::serializer&) const; + + protected: + string type_; + bool null_; + string default__; + string options_; + + private: + contained_list contained_; + }; + + class add_column: public column + { + public: + add_column (string const& id, string const& type, bool null) + : column (id, type, null) {} + add_column (column const& c, uscope& s, graph& g): column (c, s, g) {} + add_column (xml::parser& p, uscope& s, graph& g): column (p, s, g) {} + + virtual add_column& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "add column";} + + virtual void + serialize (xml::serializer&) const; + }; + + class drop_column: public unameable + { + public: + drop_column (string const& id): unameable (id) {} + drop_column (drop_column const& c, uscope&, graph& g) + : unameable (c, g) {} + drop_column (xml::parser&, uscope&, graph&); + + public: + typedef relational::table table_type; + + table_type& + table () const {return dynamic_cast<table_type&> (scope ());} + + public: + virtual drop_column& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "drop column";} + + virtual void + serialize (xml::serializer&) const; + }; + + class alter_column: public column + { + public: + virtual string const& + type () const {return base ().type ();} + + bool + null_altered () const {return null_altered_;} + + virtual bool + null () const {return null_altered_ ? null_ : base ().null ();} + + virtual void + null (bool n) {null_ = n; null_altered_ = true;} + + virtual string const& + default_ () const {return base ().default_ ();} + + virtual string const& + options () const {return base ().options ();} + + public: + column& + base () const {return dynamic_cast<column&> (alters_->base ());} + + public: + alter_column (string const& id) + : column (id, "", false), alters_ (0), null_altered_ (false) {} + alter_column (alter_column const&, uscope&, graph&); + alter_column (xml::parser&, uscope&, graph&); + + virtual alter_column& + clone (uscope&, graph&) const; + + virtual string + kind () const + { + return "alter column"; + } + + virtual void + serialize (xml::serializer&) const; + + virtual void + add_edge_left (alters& a) + { + assert (alters_ == 0); + alters_ = &a; + } + + private: + alters* alters_; + + bool null_altered_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_COLUMN_HXX diff --git a/odb/odb/semantics/relational/deferrable.cxx b/odb/odb/semantics/relational/deferrable.cxx new file mode 100644 index 0000000..076ff69 --- /dev/null +++ b/odb/odb/semantics/relational/deferrable.cxx @@ -0,0 +1,55 @@ +// file : odb/semantics/relational/deferrable.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <ostream> +#include <istream> + +#include <odb/semantics/relational/deferrable.hxx> + +using namespace std; + +namespace semantics +{ + namespace relational + { + static const char* deferrable_[] = + { + "NOT DEFERRABLE", + "IMMEDIATE", + "DEFERRED" + }; + + string deferrable:: + string () const + { + return deferrable_[v_]; + } + + ostream& + operator<< (ostream& os, deferrable const& v) + { + return os << v.string (); + } + + istream& + operator>> (istream& is, deferrable& v) + { + string s; + is >> s; + + if (!is.fail ()) + { + if (s == "not_deferrable" || s == "NOT DEFERRABLE") + v = deferrable::not_deferrable; + else if (s == "immediate" || s == "IMMEDIATE") + v = deferrable::immediate; + else if (s == "deferred" || s == "DEFERRED") + v = deferrable::deferred; + else + is.setstate (istream::failbit); + } + + return is; + } + } +} diff --git a/odb/odb/semantics/relational/deferrable.hxx b/odb/odb/semantics/relational/deferrable.hxx new file mode 100644 index 0000000..b2f888d --- /dev/null +++ b/odb/odb/semantics/relational/deferrable.hxx @@ -0,0 +1,41 @@ +// file : odb/semantics/relational/deferrable.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX +#define ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX + +#include <string> +#include <iosfwd> + +namespace semantics +{ + namespace relational + { + struct deferrable + { + enum value + { + not_deferrable, + immediate, + deferred + }; + + deferrable (value v = value (0)) : v_ (v) {} + operator value () const {return v_;} + + std::string + string () const; + + private: + value v_; + }; + + std::ostream& + operator<< (std::ostream&, deferrable const&); + + std::istream& + operator>> (std::istream&, deferrable&); + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_DEFERRABLE_HXX diff --git a/odb/odb/semantics/relational/elements.cxx b/odb/odb/semantics/relational/elements.cxx new file mode 100644 index 0000000..de1878a --- /dev/null +++ b/odb/odb/semantics/relational/elements.cxx @@ -0,0 +1,179 @@ +// file : odb/semantics/relational/elements.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/column.hxx> +#include <odb/semantics/relational/primary-key.hxx> + +namespace semantics +{ + namespace relational + { + string const xmlns = "http://www.codesynthesis.com/xmlns/odb/changelog"; + + // duplicate_name + // + template <> + duplicate_name:: + duplicate_name (uscope& s, unameable& o, unameable& d) + : scope (s), orig (o), dup (d), name (o.name ()) + { + } + + template <> + duplicate_name:: + duplicate_name (qscope& s, qnameable& o, qnameable& d) + : scope (s), orig (o), dup (d), name (o.name ().string ()) + { + } + + // scope<uname> + // + template <> + void scope<uname>:: + add_edge_left (names_type& e) + { + nameable_type& n (e.nameable ()); + name_type const& name (e.name ()); + + typename names_map::iterator i (names_map_.find (name)); + + if (i == names_map_.end ()) + { + typename names_list::iterator i; + + // We want the order to be add/alter columns first, then the + // primary key, then other keys, and finnally drop columns. + // + if (n.is_a<column> () || + n.is_a<add_column> () || + n.is_a<alter_column> ()) + { + i = names_.insert (first_key_, &e); + } + else if (!n.is_a<drop_column> ()) + { + if (n.is_a<primary_key> ()) + first_key_ = i = names_.insert ( + first_key_ != names_.end () ? first_key_ : first_drop_column_, + &e); + else + { + i = names_.insert (first_drop_column_, &e); + + if (first_key_ == names_.end ()) + first_key_ = i; + } + } + else + { + i = names_.insert (names_.end (), &e); + + if (first_drop_column_ == names_.end ()) + first_drop_column_ = i; + } + + names_map_[name] = i; + iterator_map_[&e] = i; + } + else + throw duplicate_name (*this, (*i->second)->nameable (), n); + } + + template <> + void scope<uname>:: + remove_edge_left (names_type& e) + { + typename names_iterator_map::iterator i (iterator_map_.find (&e)); + assert (i != iterator_map_.end ()); + + // If we are removing the first key, then move to the next key (or + // the end which means there are no keys). + // + if (first_key_ == i->second) + first_key_++; + + // The same for the first drop column. + // + if (first_drop_column_ == i->second) + first_drop_column_++; + + names_.erase (i->second); + names_map_.erase (e.name ()); + iterator_map_.erase (i); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // node + // + insert (type_info (typeid (node))); + + // edge + // + insert (type_info (typeid (edge))); + + // alters + // + { + type_info ti (typeid (alters)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // names + // + { + type_info ti (typeid (unames)); + ti.add_base (typeid (edge)); + insert (ti); + } + + { + type_info ti (typeid (qnames)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // nameable + // + { + type_info ti (typeid (unameable)); + ti.add_base (typeid (node)); + insert (ti); + } + + { + type_info ti (typeid (qnameable)); + ti.add_base (typeid (node)); + insert (ti); + } + + // scope + // + { + type_info ti (typeid (uscope)); + ti.add_base (typeid (node)); + insert (ti); + } + + { + type_info ti (typeid (qscope)); + ti.add_base (typeid (node)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/elements.hxx b/odb/odb/semantics/relational/elements.hxx new file mode 100644 index 0000000..4036942 --- /dev/null +++ b/odb/odb/semantics/relational/elements.hxx @@ -0,0 +1,462 @@ +// file : odb/semantics/relational/elements.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX +#define ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX + +#include <map> +#include <list> +#include <vector> +#include <string> +#include <cassert> + +#include <libcutl/container/graph.hxx> +#include <libcutl/container/pointer-iterator.hxx> +#include <libcutl/compiler/context.hxx> + +#include <libstudxml/parser.hxx> +#include <libstudxml/serializer.hxx> + +#include <odb/semantics/relational/name.hxx> + +namespace semantics +{ + namespace relational + { + using namespace cutl; + + using std::string; + + using container::pointer_iterator; + using compiler::context; + + typedef unsigned long long version; + + // + // + extern string const xmlns; + + // + // + class node; + class edge; + + typedef container::graph<node, edge> graph; + + // + // + class edge: public context + { + public: + template <typename X> + bool + is_a () const + { + return dynamic_cast<X const*> (this) != 0; + } + + public: + virtual + ~edge () {} + }; + + // + // + class node: public context + { + // Return name of the node. + // + public: + virtual string + kind () const = 0; + + public: + template <typename X> + bool + is_a () const + { + return dynamic_cast<X const*> (this) != 0; + } + + public: + virtual + ~node () {} + + // XML serialization. + // + virtual void + serialize (xml::serializer&) const = 0; + + // Sink functions that allow extensions in the form of one-way + // edges. + // + void + add_edge_right (edge&) {} + + void + remove_edge_right (edge&) {} + }; + + // + // + class alters: public edge + { + public: + node& + base () const {return *base_;} + + node& + modifier () const {return *modifier_;} + + public: + alters () : base_ (0), modifier_ (0) {} + + void + set_left_node (node& m) + { + assert (modifier_ == 0); + modifier_ = &m; + } + + void + set_right_node (node& b) + { + assert (base_ == 0); + base_ = &b; + } + + void + clear_left_node (node& m) + { + assert (modifier_ == &m); + modifier_ = 0; + } + + void + clear_right_node (node& b) + { + assert (base_ == &b); + base_ = 0; + } + + protected: + node* base_; + node* modifier_; + }; + + // + // + template <typename N> + class scope; + + template <typename N> + class nameable; + + // + // + template <typename N> + class names: public edge + { + public: + typedef N name_type; + typedef relational::scope<N> scope_type; + typedef relational::nameable<N> nameable_type; + + name_type const& + name () const + { + return name_; + } + + scope_type& + scope () const + { + return *scope_; + } + + nameable_type& + nameable () const + { + return *nameable_; + } + + public: + names (name_type const& name): name_ (name) {} + + void + set_left_node (scope_type& n) + { + scope_ = &n; + } + + void + set_right_node (nameable_type& n) + { + nameable_ = &n; + } + + void + clear_left_node (scope_type& n) + { + assert (scope_ == &n); + scope_ = 0; + } + + void + clear_right_node (nameable_type& n) + { + assert (nameable_ == &n); + nameable_ = 0; + } + + protected: + name_type name_; + scope_type* scope_; + nameable_type* nameable_; + }; + + typedef names<uname> unames; + typedef names<qname> qnames; + + // + // + template <typename N> + class nameable: public virtual node + { + public: + typedef N name_type; + typedef relational::names<N> names_type; + typedef relational::scope<N> scope_type; + + name_type const& + name () const {return named_->name ();} + + scope_type& + scope () const {return named ().scope ();} + + names_type& + named () const {return *named_;} + + string const& + id () const {return id_;} + + public: + // Id identifies the C++ node (e.g., a class or a data member) that + // this model node corresponds to. The ids are not necessarily unique + // (e.g., there can be a foreign key and an index with the same id that + // correspond to a container member). However, in any given scope, the + // {id,typeid} must be unique. This becomes important when we try to + // find correspondance between nodes during model diff'ing. + // + nameable (string const& id): id_ (id), named_ (0) {} + + virtual nameable& + clone (scope_type&, graph&) const = 0; + + // Virtual because we call it via nameable interface (e.g., in copy). + // + virtual void + add_edge_right (names_type& e) + { + assert (named_ == 0); + named_ = &e; + } + + virtual void + remove_edge_right (names_type& e) + { + assert (named_ == &e); + named_ = 0; + } + + using node::add_edge_right; + using node::remove_edge_right; + + protected: + nameable (nameable const&, graph& g); + nameable (xml::parser&, graph& g); + + void + serialize_attributes (xml::serializer&) const; + + public: + typedef void (*parser_func) (xml::parser&, scope_type&, graph&); + typedef std::map<std::string, parser_func> parser_map; + static parser_map parser_map_; + + template <typename T> + static void + parser_impl (xml::parser&, scope_type&, graph&); + + private: + string id_; + names_type* named_; + }; + + typedef nameable<uname> unameable; + typedef nameable<qname> qnameable; + + + // + // + struct duplicate_name + { + template <typename N> + duplicate_name (relational::scope<N>&, + relational::nameable<N>& orig, + relational::nameable<N>& dup); + + node& scope; + node& orig; + node& dup; + + string name; + }; + + template <typename N> + class scope: public virtual node + { + protected: + typedef N name_type; + typedef relational::names<N> names_type; + typedef relational::nameable<N> nameable_type; + + typedef std::list<names_type*> names_list; + typedef std::map<name_type, typename names_list::iterator> names_map; + typedef + std::map<names_type const*, typename names_list::iterator> + names_iterator_map; + + public: + typedef pointer_iterator<typename names_list::iterator> names_iterator; + typedef + pointer_iterator<typename names_list::const_iterator> + names_const_iterator; + + public: + // Iteration. + // + names_iterator + names_begin () + { + return names_.begin (); + } + + names_iterator + names_end () + { + return names_.end (); + } + + names_const_iterator + names_begin () const + { + return names_.begin (); + } + + names_const_iterator + names_end () const + { + return names_.end (); + } + + bool + names_empty () const + { + return names_.empty (); + } + + // Find (this scope only). + // + template <typename T> + T* + find (name_type const&); + + names_iterator + find (name_type const&); + + names_const_iterator + find (name_type const&) const; + + names_iterator + find (names_type const&); + + names_const_iterator + find (names_type const&) const; + + // Lookup in this and all altered scopes until we find what we are + // looking for or hit a stop node of type S (e.g., drop_*). + // + template <typename T, typename S> + T* + lookup (name_type const&); + + public: + scope* + base () const + { + return alters_ != 0 ? &dynamic_cast<scope&> (alters_->base ()) : 0; + } + + public: + scope () + : first_key_ (names_.end ()), + first_drop_column_ (names_.end ()), + alters_ (0) {} + + // Virtual because we call it via scope interface (e.g., in copy). + // + virtual void + add_edge_left (alters& a) + { + assert (alters_ == 0); + alters_ = &a; + } + + virtual void + remove_edge_left (alters& a) + { + assert (alters_ == &a); + alters_ = 0; + } + + virtual void + add_edge_left (names_type&); + + virtual void + remove_edge_left (names_type&); + + protected: + scope (scope const&, scope* base, graph&); + scope (xml::parser&, scope* base, graph&); + + void + serialize_content (xml::serializer&) const; + + protected: + names_list names_; + names_map names_map_; + names_iterator_map iterator_map_; + + typename names_list::iterator first_key_; + typename names_list::iterator first_drop_column_; + + alters* alters_; + }; + + template <> + void scope<uname>:: + add_edge_left (names_type&); + + template <> + void scope<uname>:: + remove_edge_left (names_type&); + + typedef scope<uname> uscope; + typedef scope<qname> qscope; + } +} + +#include <odb/semantics/relational/elements.txx> + +#endif // ODB_SEMANTICS_RELATIONAL_ELEMENTS_HXX diff --git a/odb/odb/semantics/relational/elements.txx b/odb/odb/semantics/relational/elements.txx new file mode 100644 index 0000000..2362d48 --- /dev/null +++ b/odb/odb/semantics/relational/elements.txx @@ -0,0 +1,215 @@ +// file : odb/semantics/relational/elements.txx +// license : GNU GPL v3; see accompanying LICENSE file + +namespace semantics +{ + namespace relational + { + // nameable + // + template <typename N> + typename nameable<N>::parser_map nameable<N>::parser_map_; + + template <typename N> + template <typename T> + void nameable<N>:: + parser_impl (xml::parser& p, scope_type& s, graph& g) + { + name_type n (p.attribute ("name", name_type ())); + T& x (g.new_node<T> (p, s, g)); + g.new_edge<names_type> (s, x, n); + } + + template <typename N> + nameable<N>:: + nameable (nameable const& n, graph&) + : id_ (n.id_), named_ (0) + { + } + + template <typename N> + nameable<N>:: + nameable (xml::parser&, graph&) + // : id_ (p.attribute<string> ("id")) + : named_ (0) + { + // The name attribute is handled in parser_impl(). + } + + template <typename N> + void nameable<N>:: + serialize_attributes (xml::serializer& s) const + { + // Omit empty names (e.g., a primary key). + // + name_type const& n (name ()); + if (!n.empty ()) + s.attribute ("name", n); + + //s.attribute ("id", id_); + } + + // scope + // + + template <typename N> + template <typename T, typename S> + T* scope<N>:: + lookup (name_type const& name) + { + if (T* r = find<T> (name)) + return r; + + if (scope* b = base ()) + { + if (find<S> (name) == 0) + return b->lookup<T, S> (name); + } + + return 0; + } + + template <typename N> + template <typename T> + T* scope<N>:: + find (name_type const& name) + { + typename names_map::iterator i (names_map_.find (name)); + return i != names_map_.end () + ? dynamic_cast<T*> (&(*i->second)->nameable ()) + : 0; + } + + template <typename N> + typename scope<N>::names_iterator scope<N>:: + find (name_type const& name) + { + typename names_map::iterator i (names_map_.find (name)); + + if (i == names_map_.end ()) + return names_.end (); + else + return i->second; + } + + template <typename N> + typename scope<N>::names_const_iterator scope<N>:: + find (name_type const& name) const + { + typename names_map::const_iterator i (names_map_.find (name)); + + if (i == names_map_.end ()) + return names_.end (); + else + return names_const_iterator (i->second); + } + + template <typename N> + typename scope<N>::names_iterator scope<N>:: + find (names_type const& e) + { + typename names_iterator_map::iterator i (iterator_map_.find (&e)); + return i != iterator_map_.end () ? i->second : names_.end (); + } + + template <typename N> + typename scope<N>::names_const_iterator scope<N>:: + find (names_type const& e) const + { + typename names_iterator_map::const_iterator i (iterator_map_.find (&e)); + return i != iterator_map_.end () ? i->second : names_.end (); + } + + template <typename N> + scope<N>:: + scope (scope const& s, scope* base, graph& g) + : first_key_ (names_.end ()), + first_drop_column_ (names_.end ()), + alters_ (0) + { + // Set the alters edge for lookup. + // + if (base != 0) + g.new_edge<alters> (*this, *base); + + for (names_const_iterator i (s.names_begin ()); + i != s.names_end (); ++i) + { + nameable_type& n (i->nameable ().clone (*this, g)); + g.new_edge<names_type> (*this, n, i->name ()); + } + } + + template <typename N> + scope<N>:: + scope (xml::parser& p, scope* base, graph& g) + : first_key_ (names_.end ()), + first_drop_column_ (names_.end ()), + alters_ (0) + { + // Set the alters edge for lookup. + // + if (base != 0) + g.new_edge<alters> (*this, *base); + + using namespace xml; + p.content (content::complex); + + for (parser::event_type e (p.peek ()); + e == parser::start_element; + e = p.peek ()) + { + typename nameable_type::parser_map::iterator i ( + nameable_type::parser_map_.find (p.name ())); + + if (p.namespace_ () != xmlns || i == nameable_type::parser_map_.end ()) + break; // Not one of our elements. + + p.next (); + i->second (p, *this, g); + p.next_expect (parser::end_element); + } + } + + template <typename N> + void scope<N>:: + serialize_content (xml::serializer& s) const + { + for (names_const_iterator i (names_begin ()); i != names_end (); ++i) + i->nameable ().serialize (s); + } + + class column; + class primary_key; + + template <typename N> + void scope<N>:: + add_edge_left (names_type& e) + { + name_type const& name (e.name ()); + + typename names_map::iterator i (names_map_.find (name)); + + if (i == names_map_.end ()) + { + typename names_list::iterator i (names_.insert (names_.end (), &e)); + names_map_[name] = i; + iterator_map_[&e] = i; + } + else + throw duplicate_name (*this, (*i->second)->nameable (), e.nameable ()); + } + + template <typename N> + void scope<N>:: + remove_edge_left (names_type& e) + { + typename names_iterator_map::iterator i (iterator_map_.find (&e)); + assert (i != iterator_map_.end ()); + + names_.erase (i->second); + names_map_.erase (e.name ()); + iterator_map_.erase (i); + } + } +} diff --git a/odb/odb/semantics/relational/foreign-key.cxx b/odb/odb/semantics/relational/foreign-key.cxx new file mode 100644 index 0000000..0357d95 --- /dev/null +++ b/odb/odb/semantics/relational/foreign-key.cxx @@ -0,0 +1,218 @@ +// file : odb/semantics/relational/foreign-key.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <ostream> +#include <istream> + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/foreign-key.hxx> + +using namespace std; + +namespace semantics +{ + namespace relational + { + static const char* action_str[] = {"NO ACTION", "CASCADE", "SET NULL"}; + + ostream& + operator<< (ostream& os, foreign_key::action_type v) + { + return os << action_str[v]; + } + + istream& + operator>> (istream& is, foreign_key::action_type& v) + { + string s; + getline (is, s); + + if (!is.eof ()) + is.setstate (istream::failbit); + + if (!is.fail ()) + { + if (s == "NO ACTION") + v = foreign_key::no_action; + else if (s == "CASCADE") + v = foreign_key::cascade; + else if (s == "SET NULL") + v = foreign_key::set_null; + else + is.setstate (istream::failbit); + } + + return is; + } + + foreign_key:: + foreign_key (foreign_key const& k, uscope& s, graph& g) + : key (k, s, g), + referenced_table_ (k.referenced_table_), + referenced_columns_ (k.referenced_columns_), + deferrable_ (k.deferrable_), + on_delete_ (k.on_delete_) + { + } + + foreign_key:: + foreign_key (xml::parser& p, uscope& s, graph& g) + : key (p, s, g), + deferrable_ (p.attribute ("deferrable", deferrable_type ())), + on_delete_ (p.attribute ("on-delete", no_action)) + { + using namespace xml; + + p.next_expect (parser::start_element, xmlns, "references"); + referenced_table_ = p.attribute<qname> ("table"); + p.content (content::complex); + + for (parser::event_type e (p.peek ()); + e == parser::start_element; + e = p.peek ()) + { + if (p.qname () != xml::qname (xmlns, "column")) + break; // Not our elements. + + p.next (); + referenced_columns_.push_back (p.attribute<uname> ("name")); + p.content (content::empty); + p.next_expect (parser::end_element); + } + + p.next_expect (parser::end_element); + } + + foreign_key& foreign_key:: + clone (uscope& s, graph& g) const + { + return g.new_node<foreign_key> (*this, s, g); + } + + void foreign_key:: + serialize_attributes (xml::serializer& s) const + { + key::serialize_attributes (s); + + if (deferrable () != deferrable_type::not_deferrable) + s.attribute ("deferrable", deferrable ()); + + if (on_delete () != no_action) + s.attribute ("on-delete", on_delete ()); + } + + void foreign_key:: + serialize_content (xml::serializer& s) const + { + key::serialize_content (s); + + // Referenced columns. + // + s.start_element (xmlns, "references"); + s.attribute ("table", referenced_table ()); + + for (columns::const_iterator i (referenced_columns_.begin ()); + i != referenced_columns_.end (); ++i) + { + s.start_element (xmlns, "column"); + s.attribute ("name", *i); + s.end_element (); + } + + s.end_element (); // references + } + + void foreign_key:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "foreign-key"); + serialize_attributes (s); + serialize_content (s); + s.end_element (); // foreign-key + } + + // add_foreign_key + // + add_foreign_key& add_foreign_key:: + clone (uscope& s, graph& g) const + { + return g.new_node<add_foreign_key> (*this, s, g); + } + + void add_foreign_key:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "add-foreign-key"); + foreign_key::serialize_attributes (s); + foreign_key::serialize_content (s); + s.end_element (); + } + + // drop_foreign_key + // + drop_foreign_key:: + drop_foreign_key (xml::parser& p, uscope&, graph& g) + : unameable (p, g) + { + p.content (xml::content::empty); + } + + drop_foreign_key& drop_foreign_key:: + clone (uscope& s, graph& g) const + { + return g.new_node<drop_foreign_key> (*this, s, g); + } + + void drop_foreign_key:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "drop-foreign-key"); + unameable::serialize_attributes (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + unameable::parser_map& m (unameable::parser_map_); + + m["foreign-key"] = &unameable::parser_impl<foreign_key>; + m["add-foreign-key"] = &unameable::parser_impl<add_foreign_key>; + m["drop-foreign-key"] = &unameable::parser_impl<drop_foreign_key>; + + using compiler::type_info; + + // foreign_key + // + { + type_info ti (typeid (foreign_key)); + ti.add_base (typeid (key)); + insert (ti); + } + + // add_foreign_key + // + { + type_info ti (typeid (add_foreign_key)); + ti.add_base (typeid (foreign_key)); + insert (ti); + } + + // drop_foreign_key + // + { + type_info ti (typeid (drop_foreign_key)); + ti.add_base (typeid (unameable)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/foreign-key.hxx b/odb/odb/semantics/relational/foreign-key.hxx new file mode 100644 index 0000000..32179fa --- /dev/null +++ b/odb/odb/semantics/relational/foreign-key.hxx @@ -0,0 +1,152 @@ +// file : odb/semantics/relational/foreign-key.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX +#define ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX + +#include <iosfwd> + +#include <odb/semantics/relational/deferrable.hxx> +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/key.hxx> + +namespace semantics +{ + namespace relational + { + class foreign_key: public key + { + public: + qname const& + referenced_table () const + { + return referenced_table_; + } + + typedef std::vector<string> columns; + + columns const& + referenced_columns () const + { + return referenced_columns_; + } + + columns& + referenced_columns () + { + return referenced_columns_; + } + + public: + typedef relational::deferrable deferrable_type; + + deferrable_type + deferrable () const {return deferrable_;} + + bool + not_deferrable () const + { + return deferrable_ == deferrable_type::not_deferrable; + } + + enum action_type + { + no_action, + cascade, + set_null + }; + + action_type + on_delete () const {return on_delete_;} + + public: + foreign_key (string const& id, + qname const& referenced_table, + deferrable_type deferrable, + action_type on_delete = no_action) + : key (id), + referenced_table_ (referenced_table), + deferrable_ (deferrable), + on_delete_ (on_delete) + { + } + + foreign_key (foreign_key const&, uscope&, graph&); + foreign_key (xml::parser&, uscope&, graph&); + + virtual foreign_key& + clone (uscope&, graph&) const; + + virtual string + kind () const + { + return "foreign key"; + } + + virtual void + serialize (xml::serializer&) const; + + protected: + void + serialize_attributes (xml::serializer&) const; + + void + serialize_content (xml::serializer&) const; + + private: + qname referenced_table_; + columns referenced_columns_; + deferrable_type deferrable_; + action_type on_delete_; + }; + + std::ostream& + operator<< (std::ostream&, foreign_key::action_type); + + std::istream& + operator>> (std::istream&, foreign_key::action_type&); + + class add_foreign_key: public foreign_key + { + public: + add_foreign_key (string const& id, + qname const& rt, + deferrable_type d, + action_type od = no_action) + : foreign_key (id, rt, d, od) {} + add_foreign_key (foreign_key const& fk, uscope& s, graph& g) + : foreign_key (fk, s, g) {} + add_foreign_key (xml::parser& p, uscope& s, graph& g) + : foreign_key (p, s, g) {} + + virtual add_foreign_key& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "add foreign key";} + + virtual void + serialize (xml::serializer&) const; + }; + + class drop_foreign_key: public unameable + { + public: + drop_foreign_key (string const& id): unameable (id) {} + drop_foreign_key (drop_foreign_key const& dfk, uscope&, graph& g) + : unameable (dfk, g) {} + drop_foreign_key (xml::parser&, uscope&, graph&); + + virtual drop_foreign_key& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "drop foreign key";} + + virtual void + serialize (xml::serializer&) const; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_FOREIGN_KEY_HXX diff --git a/odb/odb/semantics/relational/index.cxx b/odb/odb/semantics/relational/index.cxx new file mode 100644 index 0000000..2329f3a --- /dev/null +++ b/odb/odb/semantics/relational/index.cxx @@ -0,0 +1,145 @@ +// file : odb/semantics/relational/index.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/index.hxx> + +namespace semantics +{ + namespace relational + { + // index + // + index:: + index (index const& i, uscope& s, graph& g) + : key (i, s, g), + type_ (i.type_), + method_ (i.method_), + options_ (i.options_) + { + } + + index:: + index (xml::parser& p, uscope& s, graph& g) + : key (p, s, g), + type_ (p.attribute ("type", string ())), + method_ (p.attribute ("method", string ())), + options_ (p.attribute ("options", string ())) + { + } + + index& index:: + clone (uscope& s, graph& g) const + { + return g.new_node<index> (*this, s, g); + } + + void index:: + serialize_attributes (xml::serializer& s) const + { + key::serialize_attributes (s); + + if (!type ().empty ()) + s.attribute ("type", type ()); + + if (!method ().empty ()) + s.attribute ("method", method ()); + + if (!options ().empty ()) + s.attribute ("options", options ()); + } + + void index:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "index"); + serialize_attributes (s); + key::serialize_content (s); + s.end_element (); + } + + // add_index + // + add_index& add_index:: + clone (uscope& s, graph& g) const + { + return g.new_node<add_index> (*this, s, g); + } + + void add_index:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "add-index"); + index::serialize_attributes (s); + index::serialize_content (s); + s.end_element (); + } + + // drop_index + // + drop_index:: + drop_index (xml::parser& p, uscope&, graph& g) + : unameable (p, g) + { + p.content (xml::content::empty); + } + + drop_index& drop_index:: + clone (uscope& s, graph& g) const + { + return g.new_node<drop_index> (*this, s, g); + } + + void drop_index:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "drop-index"); + unameable::serialize_attributes (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + unameable::parser_map& m (unameable::parser_map_); + + m["index"] = &unameable::parser_impl<index>; + m["add-index"] = &unameable::parser_impl<add_index>; + m["drop-index"] = &unameable::parser_impl<drop_index>; + + using compiler::type_info; + + // index + // + { + type_info ti (typeid (index)); + ti.add_base (typeid (key)); + insert (ti); + } + + // add_index + // + { + type_info ti (typeid (add_index)); + ti.add_base (typeid (index)); + insert (ti); + } + + // drop_index + // + { + type_info ti (typeid (drop_index)); + ti.add_base (typeid (unameable)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/index.hxx b/odb/odb/semantics/relational/index.hxx new file mode 100644 index 0000000..68648cb --- /dev/null +++ b/odb/odb/semantics/relational/index.hxx @@ -0,0 +1,100 @@ +// file : odb/semantics/relational/index.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_INDEX_HXX +#define ODB_SEMANTICS_RELATIONAL_INDEX_HXX + +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/key.hxx> + +namespace semantics +{ + namespace relational + { + // Note that in our model indexes are defined in the table scope. + // + class index: public key + { + public: + string const& + type () const {return type_;} + + string const& + method () const {return method_;} + + string const& + options () const {return options_;} + + public: + index (string const& id, + string const& t = string (), + string const& m = string (), + string const& o = string ()) + : key (id), type_ (t), method_ (m), options_ (o) {} + index (index const&, uscope&, graph&); + index (xml::parser&, uscope&, graph&); + + virtual index& + clone (uscope&, graph&) const; + + virtual string + kind () const + { + return "index"; + } + + virtual void + serialize (xml::serializer&) const; + + protected: + void + serialize_attributes (xml::serializer&) const; + + private: + string type_; // E.g., "UNIQUE", etc. + string method_; // E.g., "BTREE", etc. + string options_; // Database-specific index options. + }; + + class add_index: public index + { + public: + add_index (string const& id, + string const& t = string (), + string const& m = string (), + string const& o = string ()) + : index (id, t, m, o) {} + add_index (index const& i, uscope& s, graph& g): index (i, s, g) {} + add_index (xml::parser& p, uscope& s, graph& g): index (p, s, g) {} + + virtual add_index& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "add index";} + + virtual void + serialize (xml::serializer&) const; + }; + + class drop_index: public unameable + { + public: + drop_index (string const& id): unameable (id) {} + drop_index (drop_index const& di, uscope&, graph& g) + : unameable (di, g) {} + drop_index (xml::parser&, uscope&, graph&); + + virtual drop_index& + clone (uscope&, graph&) const; + + virtual string + kind () const {return "drop index";} + + virtual void + serialize (xml::serializer&) const; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_INDEX_HXX diff --git a/odb/odb/semantics/relational/key.cxx b/odb/odb/semantics/relational/key.cxx new file mode 100644 index 0000000..3511618 --- /dev/null +++ b/odb/odb/semantics/relational/key.cxx @@ -0,0 +1,97 @@ +// file : odb/semantics/relational/key.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/key.hxx> +#include <odb/semantics/relational/column.hxx> + +namespace semantics +{ + namespace relational + { + key:: + key (key const& k, uscope& s, graph& g) + : unameable (k, g) + { + for (contains_iterator i (k.contains_begin ()); + i != k.contains_end (); ++i) + { + column* c (s.lookup<column, drop_column> (i->column ().name ())); + assert (c != 0); + g.new_edge<contains> (*this, *c, i->options ()); + } + } + + key:: + key (xml::parser& p, uscope& s, graph& g) + : unameable (p, g) + { + using namespace xml; + p.content (content::complex); + + for (parser::event_type e (p.peek ()); + e == parser::start_element; + e = p.peek ()) + { + if (p.qname () != xml::qname (xmlns, "column")) + break; // Not our elements. + + p.next (); + p.content (content::empty); + + uname n (p.attribute<uname> ("name")); + column* c (s.lookup<column, drop_column> (n)); + if (c == 0) + throw parsing (p, "invalid column name in the 'name' attribute"); + + string o (p.attribute ("options", string ())); + g.new_edge<contains> (*this, *c, o); + + p.next_expect (parser::end_element); + } + } + + void key:: + serialize_content (xml::serializer& s) const + { + for (contains_iterator i (contains_begin ()); i != contains_end (); ++i) + { + s.start_element (xmlns, "column"); + s.attribute ("name", i->column ().name ()); + if (!i->options ().empty ()) + s.attribute ("options", i->options ()); + s.end_element (); + } + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // contains + // + { + type_info ti (typeid (contains)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // key + // + { + type_info ti (typeid (key)); + ti.add_base (typeid (node)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/key.hxx b/odb/odb/semantics/relational/key.hxx new file mode 100644 index 0000000..814d2ec --- /dev/null +++ b/odb/odb/semantics/relational/key.hxx @@ -0,0 +1,104 @@ +// file : odb/semantics/relational/key.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_KEY_HXX +#define ODB_SEMANTICS_RELATIONAL_KEY_HXX + +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/table.hxx> + +namespace semantics +{ + namespace relational + { + class key; + class column; + + class contains: public edge + { + public: + typedef relational::key key_type; + typedef relational::column column_type; + + key_type& + key () const {return *key_;} + + column_type& + column () const {return *column_;} + + string const& + options () const {return options_;} + + public: + contains (string const& o = string ()) : options_ (o) {} + + void + set_left_node (key_type& n) + { + key_ = &n; + } + + void + set_right_node (column_type& n) + { + column_ = &n; + } + + protected: + key_type* key_; + column_type* column_; + string options_; + }; + + class key: public unameable + { + typedef std::vector<contains*> contains_list; + + public: + typedef contains_list::size_type contains_size_type; + + typedef + pointer_iterator<contains_list::const_iterator> + contains_iterator; + + contains_iterator + contains_begin () const {return contains_.begin ();} + + contains_iterator + contains_end () const {return contains_.end ();} + + contains_size_type + contains_size () const {return contains_.size ();} + + contains& + contains_at (contains_size_type i) const {return *contains_[i];} + + public: + typedef relational::table table_type; + + table_type& + table () const {return dynamic_cast<table_type&> (scope ());} + + public: + key (std::string const& id): unameable (id) {} + + void + add_edge_left (contains& e) + { + contains_.push_back (&e); + } + + protected: + key (key const&, uscope&, graph&); + key (xml::parser&, uscope&, graph&); + + void + serialize_content (xml::serializer&) const; + + private: + contains_list contains_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_KEY_HXX diff --git a/odb/odb/semantics/relational/model.cxx b/odb/odb/semantics/relational/model.cxx new file mode 100644 index 0000000..8763045 --- /dev/null +++ b/odb/odb/semantics/relational/model.cxx @@ -0,0 +1,54 @@ +// file : odb/semantics/relational/model.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/model.hxx> + +namespace semantics +{ + namespace relational + { + model:: + model (model const& m, graph& g) + : qscope (m, 0, g), + version_ (m.version_) + { + } + + model:: + model (xml::parser& p, graph& g) + : qscope (p, 0, g), + version_ (p.attribute<version_type> ("version")) + { + } + + void model:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "model"); + s.attribute ("version", version_); + qscope::serialize_content (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + { + type_info ti (typeid (model)); + ti.add_base (typeid (qscope)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/model.hxx b/odb/odb/semantics/relational/model.hxx new file mode 100644 index 0000000..02d1863 --- /dev/null +++ b/odb/odb/semantics/relational/model.hxx @@ -0,0 +1,49 @@ +// file : odb/semantics/relational/model.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_MODEL_HXX +#define ODB_SEMANTICS_RELATIONAL_MODEL_HXX + +#include <odb/semantics/relational/elements.hxx> + +namespace semantics +{ + namespace relational + { + class model: public graph, public qscope + { + public: + typedef relational::version version_type; + + version_type + version () const {return version_;} + + void + version (version_type v) {version_ = v;} + + public: + model (version_type v): version_ (v) {} + model (model const&, graph&); + model (xml::parser&, graph&); + + virtual string + kind () const {return "model";} + + virtual void + serialize (xml::serializer&) const; + + public: + using qscope::add_edge_left; + using qscope::add_edge_right; + + private: + model (model const&); + model& operator= (model const&); + + private: + version_type version_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_MODEL_HXX diff --git a/odb/odb/semantics/relational/name.cxx b/odb/odb/semantics/relational/name.cxx new file mode 100644 index 0000000..6eb2e16 --- /dev/null +++ b/odb/odb/semantics/relational/name.cxx @@ -0,0 +1,89 @@ +// file : odb/semantics/relational/name.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <ostream> +#include <istream> + +#include <odb/semantics/relational/name.hxx> + +using namespace std; + +namespace semantics +{ + namespace relational + { + string qname:: + string () const + { + std::string r; + + bool f (true); + for (iterator i (begin ()); i < end (); ++i) + { + if (i->empty ()) + continue; + + if (f) + f = false; + else + r += '.'; + + r += *i; + } + + return r; + } + + qname qname:: + from_string (std::string const& s) + { + using std::string; + + qname n; + + string::size_type p (string::npos); + + for (size_t i (0); i < s.size (); ++i) + { + char c (s[i]); + + if (c == '.') + { + if (p == string::npos) + n.append (string (s, 0, i)); + else + n.append (string (s, p + 1, i - p - 1)); + + p = i; + } + } + + if (p == string::npos) + n.append (s); + else + n.append (string (s, p + 1, string::npos)); + + return n; + } + + ostream& + operator<< (ostream& os, qname const& n) + { + return os << n.string (); + } + + istream& + operator>> (istream& is, qname& n) + { + string s; + is >> s; + + if (!is.fail ()) + n = qname::from_string (s); + else + n.clear (); + + return is; + } + } +} diff --git a/odb/odb/semantics/relational/name.hxx b/odb/odb/semantics/relational/name.hxx new file mode 100644 index 0000000..5268b4a --- /dev/null +++ b/odb/odb/semantics/relational/name.hxx @@ -0,0 +1,159 @@ +// file : odb/semantics/relational/name.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_NAME_HXX +#define ODB_SEMANTICS_RELATIONAL_NAME_HXX + +#include <string> +#include <vector> +#include <iosfwd> + +namespace semantics +{ + namespace relational + { + typedef std::string uname; + + class qname + { + public: + typedef relational::uname uname_type; + + qname () {} + + explicit + qname (uname_type const& n) {append (n);} + + template <typename I> + qname (I begin, I end) + { + for (; begin != end; ++begin) + append (*begin); + } + + qname& + operator= (uname_type const& n) + { + components_.resize (1); + components_[0] = n; + return *this; + } + + void + append (uname_type const& n) {components_.push_back (n);} + + void + append (qname const& n) + { + components_.insert (components_.end (), + n.components_.begin (), + n.components_.end ()); + } + + void + clear () {components_.clear ();} + + // Append a string to the last component. + // + qname& + operator+= (std::string const& s) + { + if (empty ()) + append (s); + else + uname () += s; + + return *this; + } + + friend qname + operator+ (qname const& n, std::string const& s) + { + qname r (n); + + if (r.empty ()) + r.append (s); + else + r.uname () += s; + + return r; + } + + void + swap (qname& n) {components_.swap (n.components_);} + + public: + bool + empty () const {return components_.empty ();} + + bool + qualified () const {return components_.size () > 1;} + + bool + fully_qualified () const + { + return qualified () && components_.front ().empty (); + } + + public: + typedef std::vector<uname_type> components; + typedef components::const_iterator iterator; + + iterator + begin () const {return components_.begin ();} + + iterator + end () const {return components_.end ();} + + uname_type& + uname () {return components_.back ();} + + uname_type const& + uname () const {return components_.back ();} + + qname + qualifier () const + { + return empty () + ? qname () + : qname (components_.begin (), components_.end () - 1); + } + + std::string + string () const; + + static qname + from_string (std::string const&); + + public: + friend bool + operator== (qname const& x, qname const& y) + { + return x.components_ == y.components_; + } + + friend bool + operator!= (qname const& x, qname const& y) + { + return x.components_ != y.components_; + } + + friend bool + operator< (qname const& x, qname const& y) + { + return x.components_ < y.components_; + } + + private: + components components_; + }; + + std::ostream& + operator<< (std::ostream&, qname const&); + + std::istream& + operator>> (std::istream&, qname&); + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_NAME_HXX diff --git a/odb/odb/semantics/relational/primary-key.cxx b/odb/odb/semantics/relational/primary-key.cxx new file mode 100644 index 0000000..235340f --- /dev/null +++ b/odb/odb/semantics/relational/primary-key.cxx @@ -0,0 +1,80 @@ +// file : odb/semantics/relational/primary-key.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/primary-key.hxx> + +namespace semantics +{ + namespace relational + { + primary_key:: + primary_key (primary_key const& k, uscope& s, graph& g) + : key (k, s, g), auto__ (k.auto__), extra_map_ (k.extra_map_) + { + } + + primary_key:: + primary_key (xml::parser& p, uscope& s, graph& g) + : key (p, s, g), + auto__ (p.attribute ("auto", false)) + { + // All unhandled attributes go into the extra map. + // + typedef xml::parser::attribute_map_type attr_map; + attr_map const& am (p.attribute_map ()); + + for (attr_map::const_iterator i (am.begin ()); i != am.end (); ++i) + { + if (!i->second.handled) + extra_map_[i->first.name ()] = i->second.value; + } + } + + primary_key& primary_key:: + clone (uscope& s, graph& g) const + { + return g.new_node<primary_key> (*this, s, g); + } + + void primary_key:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "primary-key"); + key::serialize_attributes (s); + + if (auto_ ()) + s.attribute ("auto", true); + + for (extra_map::const_iterator i (extra_map_.begin ()); + i != extra_map_.end (); ++i) + s.attribute (i->first, i->second); + + key::serialize_content (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + unameable::parser_map_["primary-key"] = + &unameable::parser_impl<primary_key>; + + using compiler::type_info; + + { + type_info ti (typeid (primary_key)); + ti.add_base (typeid (key)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/primary-key.hxx b/odb/odb/semantics/relational/primary-key.hxx new file mode 100644 index 0000000..114f682 --- /dev/null +++ b/odb/odb/semantics/relational/primary-key.hxx @@ -0,0 +1,62 @@ +// file : odb/semantics/relational/primary-key.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX +#define ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX + +#include <map> + +#include <odb/semantics/relational/elements.hxx> +#include <odb/semantics/relational/key.hxx> + +namespace semantics +{ + namespace relational + { + class primary_key: public key + { + public: + bool + auto_ () const {return auto__;} + + // Extra information. + // + public: + typedef std::map<string, string> extra_map; + + extra_map& + extra () {return extra_map_;} + + extra_map const& + extra () const {return extra_map_;} + + public: + primary_key (bool auto_) + : key (""), // Primary key has the implicit empty id. + auto__ (auto_) + { + } + + primary_key (primary_key const&, uscope&, graph&); + primary_key (xml::parser&, uscope&, graph&); + + virtual primary_key& + clone (uscope&, graph&) const; + + virtual string + kind () const + { + return "primary key"; + } + + virtual void + serialize (xml::serializer&) const; + + private: + bool auto__; + extra_map extra_map_; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_PRIMARY_KEY_HXX diff --git a/odb/odb/semantics/relational/table.cxx b/odb/odb/semantics/relational/table.cxx new file mode 100644 index 0000000..3bf763d --- /dev/null +++ b/odb/odb/semantics/relational/table.cxx @@ -0,0 +1,183 @@ +// file : odb/semantics/relational/table.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> + +#include <odb/semantics/relational/table.hxx> + +namespace semantics +{ + namespace relational + { + // table + // + table:: + table (table const& t, qscope& s, graph& g, bool b) + : qnameable (t, g), + uscope (t, (b ? s.lookup<table, drop_table> (t.name ()) : 0), g), + options_ (t.options_), + extra_map_ (t.extra_map_) + { + } + + table:: + table (xml::parser& p, qscope& s, graph& g, bool b) + : qnameable (p, g), + uscope ( + p, + (b ? s.lookup<table, drop_table> ( + p.attribute<qnameable::name_type> ("name")) : 0), + g), + options_ (p.attribute ("options", string ())) + { + // All unhandled attributes go into the extra map. + // + typedef xml::parser::attribute_map_type attr_map; + attr_map const& am (p.attribute_map ()); + + for (attr_map::const_iterator i (am.begin ()); i != am.end (); ++i) + { + if (!i->second.handled) + extra_map_[i->first.name ()] = i->second.value; + } + } + + table& table:: + clone (qscope& s, graph& g) const + { + return g.new_node<table> (*this, s, g); + } + + void table:: + serialize_attributes (xml::serializer& s) const + { + qnameable::serialize_attributes (s); + + if (!options_.empty ()) + s.attribute ("options", options_); + + for (extra_map::const_iterator i (extra_map_.begin ()); + i != extra_map_.end (); ++i) + s.attribute (i->first, i->second); + } + + void table:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "table"); + serialize_attributes (s); + uscope::serialize_content (s); + s.end_element (); + } + + // add_table + // + add_table& add_table:: + clone (qscope& s, graph& g) const + { + return g.new_node<add_table> (*this, s, g); + } + + void add_table:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "add-table"); + table::serialize_attributes (s); + table::serialize_content (s); + s.end_element (); + } + + // drop_table + // + drop_table:: + drop_table (xml::parser& p, qscope&, graph& g) + : qnameable (p, g) + { + p.content (xml::content::empty); + } + + drop_table& drop_table:: + clone (qscope& s, graph& g) const + { + return g.new_node<drop_table> (*this, s, g); + } + + void drop_table:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "drop-table"); + qnameable::serialize_attributes (s); + s.end_element (); + } + + // alter_table + // + alter_table& alter_table:: + clone (qscope& s, graph& g) const + { + return g.new_node<alter_table> (*this, s, g); + } + + void alter_table:: + serialize (xml::serializer& s) const + { + s.start_element (xmlns, "alter-table"); + table::serialize_attributes (s); + table::serialize_content (s); + s.end_element (); + } + + // type info + // + namespace + { + struct init + { + init () + { + qnameable::parser_map& m (qnameable::parser_map_); + + m["table"] = &qnameable::parser_impl<table>; + m["add-table"] = &qnameable::parser_impl<add_table>; + m["drop-table"] = &qnameable::parser_impl<drop_table>; + m["alter-table"] = &qnameable::parser_impl<alter_table>; + + using compiler::type_info; + + // table + // + { + type_info ti (typeid (table)); + ti.add_base (typeid (qnameable)); + ti.add_base (typeid (uscope)); + insert (ti); + } + + // add_table + // + { + type_info ti (typeid (add_table)); + ti.add_base (typeid (table)); + insert (ti); + } + + // drop_table + // + { + type_info ti (typeid (drop_table)); + ti.add_base (typeid (qnameable)); + insert (ti); + } + + // alter_table + // + { + type_info ti (typeid (alter_table)); + ti.add_base (typeid (table)); + insert (ti); + } + } + } init_; + } + } +} diff --git a/odb/odb/semantics/relational/table.hxx b/odb/odb/semantics/relational/table.hxx new file mode 100644 index 0000000..1c4efcf --- /dev/null +++ b/odb/odb/semantics/relational/table.hxx @@ -0,0 +1,115 @@ +// file : odb/semantics/relational/table.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_RELATIONAL_TABLE_HXX +#define ODB_SEMANTICS_RELATIONAL_TABLE_HXX + +#include <odb/semantics/relational/elements.hxx> + +namespace semantics +{ + namespace relational + { + class table: public qnameable, public uscope + { + public: + virtual string const& + options () const {return options_;} + + virtual void + options (string const& o) {options_ = o;} + + // Extra information. + // + public: + typedef std::map<string, string> extra_map; + + extra_map& + extra () {return extra_map_;} + + extra_map const& + extra () const {return extra_map_;} + + public: + table (string const& id): qnameable (id) {} + table (table const&, qscope&, graph&, bool base = false); + table (xml::parser&, qscope&, graph&, bool base = false); + + virtual table& + clone (qscope&, graph&) const; + + virtual string + kind () const {return "table";} + + virtual void + serialize (xml::serializer&) const; + + // Resolve ambiguity. + // + using qnameable::scope; + + protected: + void + serialize_attributes (xml::serializer&) const; + + protected: + string options_; + extra_map extra_map_; + }; + + class add_table: public table + { + public: + add_table (string const& id): table (id) {} + add_table (table const& t, qscope& s, graph& g): table (t, s, g) {} + add_table (xml::parser& p, qscope& s, graph& g): table (p, s, g) {} + + virtual add_table& + clone (qscope&, graph&) const; + + virtual string + kind () const {return "add table";} + + virtual void + serialize (xml::serializer&) const; + }; + + class drop_table: public qnameable + { + public: + drop_table (string const& id): qnameable (id) {} + drop_table (drop_table const& t, qscope&, graph& g): qnameable (t, g) {} + drop_table (xml::parser&, qscope&, graph&); + + virtual drop_table& + clone (qscope&, graph&) const; + + virtual string + kind () const {return "drop table";} + + virtual void + serialize (xml::serializer&) const; + }; + + class alter_table: public table + { + public: + alter_table (string const& id): table (id) {} + alter_table (alter_table const& at, qscope& s, graph& g) + : table (at, s, g, true) {} + alter_table (xml::parser& p, qscope& s, graph& g) + : table (p, s, g, true) {} + + virtual alter_table& + clone (qscope&, graph&) const; + + virtual string + kind () const {return "alter table";} + + virtual void + serialize (xml::serializer&) const; + }; + } +} + +#endif // ODB_SEMANTICS_RELATIONAL_TABLE_HXX diff --git a/odb/odb/semantics/template.cxx b/odb/odb/semantics/template.cxx new file mode 100644 index 0000000..f492be0 --- /dev/null +++ b/odb/odb/semantics/template.cxx @@ -0,0 +1,88 @@ +// file : odb/semantics/template.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/template.hxx> + +namespace semantics +{ + template_:: + template_ () + { + } + + instantiates:: + instantiates () + { + } + + instantiation:: + instantiation () + { + } + + type_template:: + type_template () + { + } + + type_instantiation:: + type_instantiation () + { + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // template_ + // + { + type_info ti (typeid (template_)); + ti.add_base (typeid (nameable)); + insert (ti); + } + + // instantiates + // + { + type_info ti (typeid (instantiates)); + ti.add_base (typeid (edge)); + insert (ti); + } + + // instantiation + // + { + type_info ti (typeid (instantiation)); + ti.add_base (typeid (node)); + insert (ti); + } + + // type_template + // + { + type_info ti (typeid (type_template)); + ti.add_base (typeid (template_)); + insert (ti); + } + + // type_instantiation + // + { + type_info ti (typeid (type_instantiation)); + ti.add_base (typeid (type)); + ti.add_base (typeid (instantiation)); + insert (ti); + } + + } + } init_; + } +} diff --git a/odb/odb/semantics/template.hxx b/odb/odb/semantics/template.hxx new file mode 100644 index 0000000..11fe340 --- /dev/null +++ b/odb/odb/semantics/template.hxx @@ -0,0 +1,146 @@ +// file : odb/semantics/template.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_TEMPLATE_HXX +#define ODB_SEMANTICS_TEMPLATE_HXX + +#include <vector> +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + // + // + class instantiates; + + class template_: public virtual nameable + { + typedef std::vector<instantiates*> instantiated; + + public: + typedef + pointer_iterator<instantiated::const_iterator> + instantiated_iterator; + + instantiated_iterator + instantiated_begin () const + { + return instantiated_.begin (); + } + + instantiated_iterator + instantiated_end () const + { + return instantiated_.end (); + } + + public: + void + add_edge_right (instantiates& e) + { + instantiated_.push_back (&e); + } + + using nameable::add_edge_right; + + protected: + template_ (); + + private: + instantiated instantiated_; + }; + + // + // + class instantiation; + + class instantiates: public edge + { + public: + typedef semantics::template_ template_type; + typedef semantics::instantiation instantiation_type; + + template_type& + template_ () const + { + return *template__; + } + + instantiation_type& + instantiation () const + { + return *instantiation_; + } + + public: + instantiates (); + + void + set_left_node (instantiation_type& n) + { + instantiation_ = &n; + } + + void + set_right_node (template_type& n) + { + template__ = &n; + } + + private: + template_type* template__; + instantiation_type* instantiation_; + }; + + // + // + class instantiation: public virtual node + { + public: + typedef semantics::template_ template_type; + typedef semantics::instantiates instantiates_type; + + template_type& + template_ () const + { + return instantiates_->template_ (); + } + + instantiates_type& + instantiates () const + { + return *instantiates_; + } + + public: + void + add_edge_left (instantiates_type& e) + { + instantiates_ = &e; + } + + protected: + instantiation (); + + private: + instantiates_type* instantiates_; + }; + + // + // Type template and instantiation. + // + + class type_template: public template_ + { + protected: + type_template (); + }; + + class type_instantiation: public virtual type, public instantiation + { + protected: + type_instantiation (); + }; +} + +#endif // ODB_SEMANTICS_TEMPLATE_HXX diff --git a/odb/odb/semantics/union-template.cxx b/odb/odb/semantics/union-template.cxx new file mode 100644 index 0000000..21fc9c0 --- /dev/null +++ b/odb/odb/semantics/union-template.cxx @@ -0,0 +1,54 @@ +// file : odb/semantics/union-template.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/union-template.hxx> + +namespace semantics +{ + union_template:: + union_template (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + union_instantiation:: + union_instantiation (path const& file, + size_t line, + size_t column, + tree tn) + : node (file, line, column, tn) + { + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // union_template + // + { + type_info ti (typeid (union_template)); + ti.add_base (typeid (type_template)); + ti.add_base (typeid (scope)); + insert (ti); + } + + // union_instantiation + // + { + type_info ti (typeid (union_instantiation)); + ti.add_base (typeid (union_)); + ti.add_base (typeid (type_instantiation)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/union-template.hxx b/odb/odb/semantics/union-template.hxx new file mode 100644 index 0000000..3e719b7 --- /dev/null +++ b/odb/odb/semantics/union-template.hxx @@ -0,0 +1,33 @@ +// file : odb/semantics/union-template.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_UNION_TEMPLATE_HXX +#define ODB_SEMANTICS_UNION_TEMPLATE_HXX + +#include <odb/semantics/elements.hxx> +#include <odb/semantics/union.hxx> +#include <odb/semantics/template.hxx> + +namespace semantics +{ + class union_template: public type_template, public scope + { + public: + union_template (path const&, size_t line, size_t column, tree); + + // Resolve conflict between scope::scope and nameable::scope. + // + using nameable::scope; + }; + + class union_instantiation: public union_, public type_instantiation + { + public: + union_instantiation (path const&, size_t line, size_t column, tree); + + using union_::add_edge_left; + using type_instantiation::add_edge_left; + }; +} + +#endif // ODB_SEMANTICS_UNION_TEMPLATE_HXX diff --git a/odb/odb/semantics/union.cxx b/odb/odb/semantics/union.cxx new file mode 100644 index 0000000..007ef57 --- /dev/null +++ b/odb/odb/semantics/union.cxx @@ -0,0 +1,36 @@ +// file : odb/semantics/union.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/union.hxx> + +namespace semantics +{ + union_:: + union_ (path const& file, size_t line, size_t column, tree tn) + : node (file, line, column, tn) + { + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // union_ + // + { + type_info ti (typeid (union_)); + ti.add_base (typeid (type)); + ti.add_base (typeid (scope)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/union.hxx b/odb/odb/semantics/union.hxx new file mode 100644 index 0000000..79adc42 --- /dev/null +++ b/odb/odb/semantics/union.hxx @@ -0,0 +1,27 @@ +// file : odb/semantics/union.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_UNION_HXX +#define ODB_SEMANTICS_UNION_HXX + +#include <odb/semantics/elements.hxx> + +namespace semantics +{ + class union_: public virtual type, public scope + { + public: + union_ (path const&, size_t line, size_t column, tree); + + // Resolve conflict between scope::scope and nameable::scope. + // + using nameable::scope; + + protected: + union_ () + { + } + }; +} + +#endif // ODB_SEMANTICS_UNION_HXX diff --git a/odb/odb/semantics/unit.cxx b/odb/odb/semantics/unit.cxx new file mode 100644 index 0000000..4f92aed --- /dev/null +++ b/odb/odb/semantics/unit.cxx @@ -0,0 +1,42 @@ +// file : odb/semantics/unit.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/gcc.hxx> + +#include <libcutl/compiler/type-info.hxx> +#include <odb/semantics/unit.hxx> + +namespace semantics +{ + unit:: + unit (path const& file) + : node (file, 1, 1, global_namespace), graph_ (*this) + { + // Use a special edge to get this->name() return the global + // namespace name (""). + // + new_edge<global_names> (*this, *this); + node::unit (*this); + } + + // type info + // + namespace + { + struct init + { + init () + { + using compiler::type_info; + + // unit + // + { + type_info ti (typeid (unit)); + ti.add_base (typeid (namespace_)); + insert (ti); + } + } + } init_; + } +} diff --git a/odb/odb/semantics/unit.hxx b/odb/odb/semantics/unit.hxx new file mode 100644 index 0000000..cfccbff --- /dev/null +++ b/odb/odb/semantics/unit.hxx @@ -0,0 +1,183 @@ +// file : odb/semantics/unit.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_SEMANTICS_UNIT_HXX +#define ODB_SEMANTICS_UNIT_HXX + +#include <map> + +#include <odb/semantics/elements.hxx> +#include <odb/semantics/namespace.hxx> + +namespace semantics +{ + class unit: public graph<node, edge>, public namespace_ + { + public: + unit (path const&); + + private: + unit (unit const&); + unit& operator= (unit const&); + + // Mapping from tree nodes to semantic graph nodes. + // + public: + node* + find (tree key) const + { + tree_node_map::const_iterator i (tree_node_map_.find (key)); + return i != tree_node_map_.end () ? i->second : 0; + } + + void + insert (tree key, node& value) + { + tree_node_map_[key] = &value; + } + + using namespace_::find; + + // Mapping from tree nodes to name hints. + // + public: + names* + find_hint (tree key) const + { + name_hint_map::const_iterator i (name_hint_map_.find (key)); + return i != name_hint_map_.end () ? i->second : 0; + } + + void + insert_hint (tree key, names& name) + { + name_hint_map_[key] = &name; + } + + public: + template <class T> + T& + new_node (path const& file, size_t line, size_t column) + { + T& r (graph_.new_node<T> (file, line, column)); + r.unit (*this); + return r; + } + + template <class T, class A0> + T& + new_node (path const& file, size_t line, size_t column, A0 const& a0) + { + T& r (graph_.new_node<T> (file, line, column, a0)); + r.unit (*this); + return r; + } + + template <class T, class A0, class A1> + T& + new_node (path const& file, size_t line, size_t column, + A0 const& a0, A1 const& a1) + { + T& r (graph_.new_node<T> (file, line, column, a0, a1)); + r.unit (*this); + return r; + } + + template <class T, class A0, class A1, class A2> + T& + new_node (path const& file, size_t line, size_t column, + A0 const& a0, A1 const& a1, A2 const& a2) + { + T& r (graph_.new_node<T> (file, line, column, a0, a1, a2)); + r.unit (*this); + return r; + } + + template <class T, class A0, class A1, class A2, class A3> + T& + new_node (path const& file, size_t line, size_t column, + A0 const& a0, A1 const& a1, A2 const& a2, A3 const& a3) + { + T& r (graph_.new_node<T> (file, line, column, a0, a1, a2, a3)); + r.unit (*this); + return r; + } + + template <class T, class A0, class A1, class A2, class A3, class A4> + T& + new_node (path const& file, size_t line, size_t column, + A0 const& a0, A1 const& a1, A2 const& a2, A3 const& a3, + A4 const& a4) + { + T& r (graph_.new_node<T> (file, line, column, a0, a1, a2, a3, a4)); + r.unit (*this); + return r; + } + + // For fundamental types. + // + template <class T> + T& + new_fund_node (tree tn) + { + T& r (graph_.new_node<T> (tn)); + r.unit (*this); + return r; + } + + protected: + // Special names edge for the global namespace. + // + class global_names: public names + { + public: + global_names () + : names ("") + { + scope_ = 0; + } + + void + set_left_node (unit&) + { + } + + void + set_right_node (nameable& n) + { + named_ = &n; + } + + void + clear_left_node (unit&) + { + } + + void + clear_right_node (nameable& n) + { + assert (named_ == &n); + named_ = 0; + } + }; + + public: + void + add_edge_left (global_names&) + { + } + + using namespace_::add_edge_right; + + private: + graph<node, edge>& graph_; + + typedef std::map<tree, node*> tree_node_map; + tree_node_map tree_node_map_; + + typedef std::map<tree, names*> name_hint_map; + name_hint_map name_hint_map_; + }; +} + +#endif // ODB_SEMANTICS_UNIT_HXX |