summaryrefslogtreecommitdiff
path: root/odb/lookup.cxx
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/lookup.cxx
parented52acc5e65dd9ea2fb2d9c851c2faa61d5cb2d9 (diff)
Add support for virtual data members
New test: common/virtual.
Diffstat (limited to 'odb/lookup.cxx')
-rw-r--r--odb/lookup.cxx249
1 files changed, 242 insertions, 7 deletions
diff --git a/odb/lookup.cxx b/odb/lookup.cxx
index b3e0551..2190301 100644
--- a/odb/lookup.cxx
+++ b/odb/lookup.cxx
@@ -3,12 +3,120 @@
// license : GNU GPL v3; see accompanying LICENSE file
#include <odb/lookup.hxx>
+#include <odb/semantics.hxx>
using namespace std;
namespace lookup
{
- std::string
+ // Return canonical fundamental type name (<length> <sign> <type>, e.g.,
+ // short unsigned int) or empty string if it is not a fundamental type.
+ // Note that the type can still be invalid (e.g., unsigned float) so it
+ // needs to be resolved.
+ //
+ static string
+ parse_fundamental (cxx_lexer& l,
+ cpp_ttype& tt,
+ string& tl,
+ tree& tn,
+ cpp_ttype& ptt,
+ string& name)
+ {
+ bool
+ si (false), // signed
+ un (false), // unsigned
+ sh (false), // short
+ lo (false), // long
+ ll (false); // long long
+
+ string type;
+
+ for (; tt == CPP_KEYWORD; ptt = tt, tt = l.next (tl, &tn))
+ {
+ if (!name.empty ())
+ name += ' ';
+ name += tl;
+
+ if (tl == "signed")
+ {
+ if (si || un)
+ throw invalid_name ();
+
+ si = true;
+ }
+ else if (tl == "unsigned")
+ {
+ if (si || un)
+ throw invalid_name ();
+
+ un = true;
+ }
+ else if (tl == "short")
+ {
+ if (sh || lo || ll)
+ throw invalid_name ();
+
+ sh = true;
+ }
+ else if (tl == "long")
+ {
+ if (sh || ll)
+ throw invalid_name ();
+
+ if (lo)
+ {
+ lo = false;
+ ll = true;
+ }
+ else
+ lo = true;
+ }
+ else if (tl == "bool" ||
+ tl == "char" ||
+ tl == "wchar_t" ||
+ tl == "char16_t" || // C++11
+ tl == "char32_t" || // C++11
+ tl == "int" ||
+ tl == "float" ||
+ tl == "double")
+ {
+ if (!type.empty ())
+ throw invalid_name ();
+
+ type = tl;
+ }
+ else
+ break;
+ }
+
+ if (type.empty () && (si || un || sh || lo || ll))
+ type = "int"; // If type not specified, it defaults to int.
+
+ if (type.empty ())
+ return type;
+
+ string r;
+
+ if (sh)
+ r += "short ";
+
+ if (lo)
+ r += "long ";
+
+ if (ll)
+ r += "long long ";
+
+ if (si && type == "char")
+ r += "signed ";
+
+ if (un)
+ r += "unsigned ";
+
+ r += type;
+ return r;
+ }
+
+ string
parse_scoped_name (cxx_lexer& l, cpp_ttype& tt, string& tl, tree& tn)
{
string name;
@@ -18,12 +126,18 @@ namespace lookup
name += "::";
tt = l.next (tl, &tn);
}
+ else if (tt == CPP_KEYWORD)
+ {
+ cpp_ttype ptt; // Not used.
+ string t (parse_fundamental (l, tt, tl, tn, ptt, name));
+
+ if (!t.empty ())
+ return name;
+ }
while (true)
{
- // @@ We still need to handle fundamental types, e.g., unsigned int.
- //
- if (tt != CPP_NAME && tt != CPP_KEYWORD)
+ if (tt != CPP_NAME)
throw invalid_name ();
name += tl;
@@ -63,15 +177,32 @@ namespace lookup
ptt = tt;
tt = l.next (tl, &tn);
}
+ else if (tt == CPP_KEYWORD)
+ {
+ string t (parse_fundamental (l, tt, tl, tn, ptt, name));
+
+ if (!t.empty ())
+ {
+ tree decl (
+ lookup_qualified_name (
+ global_namespace, get_identifier (t.c_str ()), true, false));
+
+ if (decl == error_mark_node)
+ throw unable_to_resolve (name, true);
+
+ if (end_scope != 0)
+ *end_scope = global_namespace;
+
+ return decl;
+ }
+ }
while (true)
{
if (end_scope != 0)
*end_scope = scope;
- // @@ We still need to handle fundamental types, e.g., unsigned int.
- //
- if (tt != CPP_NAME && tt != CPP_KEYWORD)
+ if (tt != CPP_NAME)
throw invalid_name ();
name += tl;
@@ -137,4 +268,108 @@ namespace lookup
return scope;
}
+
+ semantics::node&
+ resolve_scoped_name (cxx_lexer& l,
+ cpp_ttype& tt,
+ string& tl,
+ tree& tn,
+ cpp_ttype& ptt,
+ semantics::scope& start_scope,
+ string& name,
+ semantics::type_id const& tid,
+ bool trailing_scope,
+ semantics::scope** end_scope)
+ {
+ bool first (true);
+ semantics::scope* scope (&start_scope);
+
+ if (tt == CPP_SCOPE)
+ {
+ name += "::";
+ for (; !scope->global_scope (); scope = &scope->scope_ ()) ;
+ first = false;
+
+ ptt = tt;
+ tt = l.next (tl, &tn);
+ }
+ else if (tt == CPP_KEYWORD)
+ {
+ string t (parse_fundamental (l, tt, tl, tn, ptt, name));
+
+ if (!t.empty ())
+ {
+ for (; !scope->global_scope (); scope = &scope->scope_ ()) ;
+
+ if (end_scope != 0)
+ *end_scope = scope;
+
+ return scope->lookup<semantics::fund_type> (t);
+ }
+ }
+
+ semantics::names* r;
+
+ for (;;)
+ {
+ if (end_scope != 0)
+ *end_scope = scope;
+
+ if (tt != CPP_NAME)
+ throw invalid_name ();
+
+ name += tl;
+ string n (tl);
+ ptt = tt;
+ tt = l.next (tl, &tn);
+
+ bool last (true);
+ if (tt == CPP_SCOPE)
+ {
+ // If trailing scope names are allowed, then we also need to
+ // check what's after the scope.
+ //
+ if (trailing_scope)
+ {
+ ptt = tt;
+ tt = l.next (tl, &tn);
+
+ if (tt == CPP_NAME)
+ last = false;
+ }
+ else
+ last = false;
+ }
+
+ // If this is the first component in the name, then also search the
+ // outer scopes.
+ //
+ bool hidden (false);
+ r = scope->lookup (
+ n,
+ (last ? tid : typeid (semantics::scope)),
+ (first ? 0 : semantics::scope::exclude_outer) |
+ (last ? semantics::scope::include_hidden : 0),
+ (last ? &hidden : 0));
+
+ if (r == 0)
+ throw semantics::unresolved (name, hidden);
+
+ if (last)
+ break;
+
+ scope = &dynamic_cast<semantics::scope&> (r->named ());
+ first = false;
+
+ name += "::";
+
+ if (!trailing_scope)
+ {
+ ptt = tt;
+ tt = l.next (tl, &tn);
+ }
+ }
+
+ return r->named ();
+ }
}