1 /* namespace.cc -- Code to maintain and search namespaces
3 * Written by Scott Wood <scott@buserror.net>
9 void NameSpace::lookup_imports()
11 for (list<StrListRef>::iterator i = import_strs.begin();
12 i != import_strs.end(); ++i)
15 Symbol *sym = lookup_sym(toplevel, strl, this);
16 NameSpace *ns = dynamic_cast<NameSpace *>(sym);
19 const String *str = strl->back();
20 yyerrorfl(str->file, str->line, "\"%s\" is not a namespace.",
21 sym->get_fq_name()->flatten()->c_str());
25 imports.push_back(ns);
28 for (const_iterator i = begin(); i != end(); ++i) {
29 Symbol *sym = (*i).second;
30 sym->lookup_imports();
35 // Find the namespace in which "name" is declared.
36 // The rules for namespace precedence are in doc/idl/namespace-precedence.
38 NameSpace *NameSpace::search(const String *name, Symbol *exclude)
40 // Rule #1: Check current namespace first.
41 Symbol *sym = lookup_noex(name, true);
42 if (sym && sym != exclude)
45 // Rule #2: Check imported symbols
48 for (list<NameSpaceRef>::iterator i = imports.begin();
49 i != imports.end(); ++i)
52 Symbol *newfound = ns->lookup_noex(name, true);
55 if (newfound == exclude)
58 if (found && found != newfound) {
59 yyerrorfl(name->file, name->line,
60 "\"%s\" is ambiguous. Two possibilities "
61 "(there may be more) are:",
64 yyerrorfl(found->name->file, found->name->line, " \"%s\"",
65 found->get_fq_name()->flatten()->c_str());
66 yyerrorfl(newfound->name->file, newfound->name->line, " \"%s\"",
67 newfound->get_fq_name()->flatten()->c_str());
77 return found->get_ns();
82 static NameSpace *search_for_namespace(const String *name, NameSpace *ctx,
86 NameSpace *ret = ctx->search(name, exclude);
94 yyerrorfl(name->file, name->line,
95 "Unknown symbol \"%s\" in namespace search path.",
101 Symbol *lookup_sym(NameSpace *ns, StrList *name, NameSpace *ctx,
107 assert(current_pass != 1);
108 assert(name->size() != 0);
111 StrList::iterator i = name->begin();
113 if (name->front()->length() != 0) {
114 ns = search_for_namespace(name->front(), ctx, exclude);
122 assert(i != name->end());
125 while (i != name->end()) {
127 sym = ns->lookup(*i, first)->get_concrete_sym();
130 catch (SymbolNotFound) {
131 yyerrorfl((*i)->file, (*i)->line,
132 "Unknown symbol \"%s\" in \"%s\".",
133 (*i)->c_str(), ns->get_fq_name()->flatten()->c_str());
141 ns = dynamic_cast<NameSpace *>(sym);
143 if (!ns && i != name->end()) {
144 yyerrorfl((*i)->file, (*i)->line,
145 "\"%s\" is not a namespace.",
146 sym->get_fq_name()->flatten()->c_str());
156 // Returns the namespace (new or otherwise) on success, or NULL on failure.
157 NameSpace *add_nspace(StrList *name, bool push)
159 StrList::iterator i = name->begin();
160 NameSpace *ns = cur_nspace;
163 if ((*i)->length() == 0) {
164 yyerrorfl((*i)->file, (*i)->line,
165 "Namespaces cannot be declared with an absolute path.");
169 for (; i != name->end(); i++) {
170 if ((*i)->token == '*') {
171 yyerrorfl((*i)->file, (*i)->line,
172 "'*' is only allowed with \"using\".");
176 sym = ns->lookup_noex(*i, true);
178 UserNameSpace *new_ns;
181 // Cannot throw DuplicateSymbol, but it can throw
182 // InvalidArgument due to user error (such as trying
183 // to implicitly declare a namespace inside of a
184 // struct/class/whatever.
186 new_ns = new UserNameSpace(*i);
187 ns->add_user(new_ns);
190 catch (InvalidArgument) {
191 yyerrorfl((*i)->file, (*i)->line,
192 "Cannot create namespace \"%s\" inside of a "
193 "non-namespace type or import namespace.",
200 // Don't let the user declare things in non-user namespaces.
201 // Besides the headache of verifying that it's something
202 // that belongs, and of determining order for situations
203 // where it matters, it's just icky.
206 ns = dynamic_cast<UserNameSpace *>(sym);
208 yyerrorfl((*i)->file, (*i)->line,
209 "\"%s\" is not a namespace.",
210 sym->get_fq_name()->flatten()->c_str());
218 nspace_stack.push_front(cur_nspace);
226 if (nspace_stack.empty())
229 cur_nspace = nspace_stack.front();
230 nspace_stack.pop_front();
233 void NameSpace::add_user(Symbol *sym)
239 catch (DuplicateSymbol) {
240 yyerrorfl(sym->name->file, sym->name->line,
241 "\"%s\" already exists in this %s.",
242 sym->name->c_str(), description());
247 void NameSpace::add_import(Symbol *sym, const char *filename)
253 catch (DuplicateSymbol) {
254 yyerrorf("\"%s\" already exists in %s.",
255 sym->name->c_str(), get_fq_name()->flatten()->c_str());
259 catch (InvalidArgument) {
260 yyerrorf("\"%s\" caused an InvalidArgument upon add.", filename);
267 if (ns && !ns->dying) {
272 catch (SymbolNotFound) {
273 fprintf(stderr, "SymbolNotFound in Symbol::~Symbol(), cannot propagate\n");
278 StrList *Symbol::get_fq_name(const char *append, bool not_last) const
281 const String *s = NULL;
284 if (append && not_last &&
285 !dynamic_cast<const UserNameSpace *>(this))
287 String *mut_s = new String(name);
288 mut_s->append(append);
293 } else if (!ns && !dynamic_cast<const UserNameSpace *>(this)) {
294 s = new String("<temporary>");
296 s = new String("<toplevel>");
298 s = new String("<anonymous>");
301 if (!ns || !ns->name) {
304 ret = ns->get_fq_name(append, true);
311 Symbol *Symbol::find_toplevel_type()
313 Symbol *cur = this, *prev;
318 } while (!dynamic_cast<UserNameSpace *>(cur));
323 // FIXME: Use double-dot for initial delimit, but only if
324 // generating IDLC-style names. More generally, it should
325 // allow an arbitrary alternate global scope prefix.
327 String *StrList::flatten(const char *delimit)
329 String *ret = new String();
331 for (const_iterator i = begin(); i != end();) {
332 const String *str = *i;
336 ret->append(delimit);
339 const String *str = back();
340 ret->file = str->file;
341 ret->line = str->line;