summaryrefslogtreecommitdiff
path: root/odb/semantics
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-08-31 10:03:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-08-31 10:03:45 +0200
commitc0957cfe1c73ecb6c96314e45e7d29b4199b20d6 (patch)
tree96a747f7196baa335cf83ff160527bb8333ca9e3 /odb/semantics
parented52acc5e65dd9ea2fb2d9c851c2faa61d5cb2d9 (diff)
Add support for virtual data members
New test: common/virtual.
Diffstat (limited to 'odb/semantics')
-rw-r--r--odb/semantics/class.cxx71
-rw-r--r--odb/semantics/class.hxx13
-rw-r--r--odb/semantics/elements.cxx84
-rw-r--r--odb/semantics/elements.hxx59
-rw-r--r--odb/semantics/fundamental.hxx10
-rw-r--r--odb/semantics/namespace.cxx70
-rw-r--r--odb/semantics/namespace.hxx24
7 files changed, 312 insertions, 19 deletions
diff --git a/odb/semantics/class.cxx b/odb/semantics/class.cxx
index 864a96e..e9e6610 100644
--- a/odb/semantics/class.cxx
+++ b/odb/semantics/class.cxx
@@ -39,6 +39,77 @@ namespace semantics
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
diff --git a/odb/semantics/class.hxx b/odb/semantics/class.hxx
index b9f8f34..dc30da2 100644
--- a/odb/semantics/class.hxx
+++ b/odb/semantics/class.hxx
@@ -97,6 +97,19 @@ namespace semantics
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
diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx
index ddae187..367ccbd 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/semantics/elements.cxx
@@ -9,8 +9,11 @@
#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
@@ -319,6 +322,79 @@ namespace semantics
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 && !global_scope ())
+ return scope ().lookup (name, ti, flags, hidden);
+
+ return 0;
+ }
+
void scope::
add_edge_left (names& e)
{
@@ -443,14 +519,6 @@ namespace semantics
insert (ti);
}
- // virtual_data_member
- //
- {
- type_info ti (typeid (virtual_data_member));
- ti.add_base (typeid (data_member));
- insert (ti);
- }
-
// unsupported_type
//
{
diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx
index c9aa00e..137fbda 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/semantics/elements.hxx
@@ -17,6 +17,7 @@
#include <cutl/fs/path.hxx>
#include <cutl/container/graph.hxx>
#include <cutl/container/pointer-iterator.hxx>
+#include <cutl/compiler/type-id.hxx>
#include <cutl/compiler/context.hxx>
#include <odb/gcc-fwd.hxx>
@@ -32,6 +33,7 @@ namespace semantics
using container::graph;
using container::pointer_iterator;
+ using compiler::type_id;
using compiler::context;
//
@@ -501,6 +503,24 @@ namespace semantics
};
+ // 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
@@ -555,12 +575,40 @@ namespace semantics
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)
@@ -757,17 +805,6 @@ namespace semantics
}
};
- // Virtual data member (extension to the standard C++ model).
- //
- class virtual_data_member: public data_member
- {
- public:
- virtual_data_member (path const& file, size_t line, size_t column)
- : node (file, line, column, 0)
- {
- }
- };
-
// Unsupported type.
//
class unsupported_type: public type
diff --git a/odb/semantics/fundamental.hxx b/odb/semantics/fundamental.hxx
index 291d73c..879837c 100644
--- a/odb/semantics/fundamental.hxx
+++ b/odb/semantics/fundamental.hxx
@@ -46,6 +46,16 @@ namespace semantics
fund_wchar (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
};
+ struct fund_char16: fund_type
+ {
+ fund_char16 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
+ };
+
+ struct fund_char32: fund_type
+ {
+ fund_char32 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
+ };
+
struct fund_signed_char: fund_type
{
fund_signed_char (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
diff --git a/odb/semantics/namespace.cxx b/odb/semantics/namespace.cxx
index 9906219..257385e 100644
--- a/odb/semantics/namespace.cxx
+++ b/odb/semantics/namespace.cxx
@@ -19,6 +19,76 @@ namespace semantics
{
}
+ 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
diff --git a/odb/semantics/namespace.hxx b/odb/semantics/namespace.hxx
index a4ead38..df48e437 100644
--- a/odb/semantics/namespace.hxx
+++ b/odb/semantics/namespace.hxx
@@ -5,12 +5,16 @@
#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
@@ -28,9 +32,28 @@ namespace semantics
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.
@@ -42,6 +65,7 @@ namespace semantics
private:
namespace_* original_;
+ extensions_type extensions_;
};
}