summaryrefslogtreecommitdiff
path: root/odb/odb/semantics
diff options
context:
space:
mode:
Diffstat (limited to 'odb/odb/semantics')
-rw-r--r--odb/odb/semantics/class-template.cxx54
-rw-r--r--odb/odb/semantics/class-template.hxx68
-rw-r--r--odb/odb/semantics/class.cxx175
-rw-r--r--odb/odb/semantics/class.hxx142
-rw-r--r--odb/odb/semantics/derived.cxx254
-rw-r--r--odb/odb/semantics/derived.hxx440
-rw-r--r--odb/odb/semantics/elements.cxx619
-rw-r--r--odb/odb/semantics/elements.hxx841
-rw-r--r--odb/odb/semantics/elements.ixx13
-rw-r--r--odb/odb/semantics/enum.cxx85
-rw-r--r--odb/odb/semantics/enum.hxx228
-rw-r--r--odb/odb/semantics/fundamental.cxx222
-rw-r--r--odb/odb/semantics/fundamental.hxx150
-rw-r--r--odb/odb/semantics/namespace.cxx107
-rw-r--r--odb/odb/semantics/namespace.hxx71
-rw-r--r--odb/odb/semantics/relational.hxx18
-rw-r--r--odb/odb/semantics/relational/changelog.cxx187
-rw-r--r--odb/odb/semantics/relational/changelog.hxx164
-rw-r--r--odb/odb/semantics/relational/changeset.cxx56
-rw-r--r--odb/odb/semantics/relational/changeset.hxx93
-rw-r--r--odb/odb/semantics/relational/column.cxx201
-rw-r--r--odb/odb/semantics/relational/column.hxx205
-rw-r--r--odb/odb/semantics/relational/deferrable.cxx55
-rw-r--r--odb/odb/semantics/relational/deferrable.hxx41
-rw-r--r--odb/odb/semantics/relational/elements.cxx179
-rw-r--r--odb/odb/semantics/relational/elements.hxx462
-rw-r--r--odb/odb/semantics/relational/elements.txx215
-rw-r--r--odb/odb/semantics/relational/foreign-key.cxx218
-rw-r--r--odb/odb/semantics/relational/foreign-key.hxx152
-rw-r--r--odb/odb/semantics/relational/index.cxx145
-rw-r--r--odb/odb/semantics/relational/index.hxx100
-rw-r--r--odb/odb/semantics/relational/key.cxx97
-rw-r--r--odb/odb/semantics/relational/key.hxx104
-rw-r--r--odb/odb/semantics/relational/model.cxx54
-rw-r--r--odb/odb/semantics/relational/model.hxx49
-rw-r--r--odb/odb/semantics/relational/name.cxx89
-rw-r--r--odb/odb/semantics/relational/name.hxx159
-rw-r--r--odb/odb/semantics/relational/primary-key.cxx80
-rw-r--r--odb/odb/semantics/relational/primary-key.hxx62
-rw-r--r--odb/odb/semantics/relational/table.cxx183
-rw-r--r--odb/odb/semantics/relational/table.hxx115
-rw-r--r--odb/odb/semantics/template.cxx88
-rw-r--r--odb/odb/semantics/template.hxx146
-rw-r--r--odb/odb/semantics/union-template.cxx54
-rw-r--r--odb/odb/semantics/union-template.hxx33
-rw-r--r--odb/odb/semantics/union.cxx36
-rw-r--r--odb/odb/semantics/union.hxx27
-rw-r--r--odb/odb/semantics/unit.cxx42
-rw-r--r--odb/odb/semantics/unit.hxx183
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