1 // Code to maintain and search namespaces
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
18 void NameSpace::lookup_imports()
20 for (list<StrListRef>::iterator i = import_strs.begin();
21 i != import_strs.end(); ++i)
24 Symbol *sym = lookup_sym(toplevel, strl, this);
25 NameSpace *ns = dynamic_cast<NameSpace *>(sym);
28 const String *str = strl->back();
29 yyerrorfl(str->file, str->line, "\"%s\" is not a namespace.",
30 sym->get_fq_name()->flatten()->c_str());
34 imports.push_back(ns);
37 for (const_iterator i = begin(); i != end(); ++i) {
38 Symbol *sym = (*i).second;
39 sym->lookup_imports();
44 // Find the namespace in which "name" is declared.
45 // The rules for namespace precedence are in doc/idl/namespace-precedence.
47 NameSpace *NameSpace::search(const String *name, Symbol *exclude)
49 // Rule #1: Check current namespace first.
50 Symbol *sym = lookup_noex(name, true);
51 if (sym && sym != exclude)
54 // Rule #2: Check imported symbols
57 for (list<NameSpaceRef>::iterator i = imports.begin();
58 i != imports.end(); ++i)
61 Symbol *newfound = ns->lookup_noex(name, true);
64 if (newfound == exclude)
67 if (found && found != newfound) {
68 yyerrorfl(name->file, name->line,
69 "\"%s\" is ambiguous. Two possibilities "
70 "(there may be more) are:",
73 yyerrorfl(found->name->file, found->name->line, " \"%s\"",
74 found->get_fq_name()->flatten()->c_str());
75 yyerrorfl(newfound->name->file, newfound->name->line, " \"%s\"",
76 newfound->get_fq_name()->flatten()->c_str());
86 return found->get_ns();
91 static NameSpace *search_for_namespace(const String *name, NameSpace *ctx,
95 NameSpace *ret = ctx->search(name, exclude);
103 yyerrorfl(name->file, name->line,
104 "Unknown symbol \"%s\" in namespace search path.",
110 Symbol *lookup_sym(NameSpace *ns, StrList *name, NameSpace *ctx,
116 assert(current_pass != 1);
117 assert(name->size() != 0);
120 StrList::iterator i = name->begin();
122 if (name->front()->length() != 0) {
123 ns = search_for_namespace(name->front(), ctx, exclude);
131 assert(i != name->end());
134 while (i != name->end()) {
136 sym = ns->lookup(*i, first)->get_concrete_sym();
139 catch (SymbolNotFound) {
140 yyerrorfl((*i)->file, (*i)->line,
141 "Unknown symbol \"%s\" in \"%s\".",
142 (*i)->c_str(), ns->get_fq_name()->flatten()->c_str());
150 ns = dynamic_cast<NameSpace *>(sym);
152 if (!ns && i != name->end()) {
153 yyerrorfl((*i)->file, (*i)->line,
154 "\"%s\" is not a namespace.",
155 sym->get_fq_name()->flatten()->c_str());
165 // Returns the namespace (new or otherwise) on success, or NULL on failure.
166 NameSpace *add_nspace(StrList *name, bool push)
168 StrList::iterator i = name->begin();
169 NameSpace *ns = cur_nspace;
172 if ((*i)->length() == 0) {
173 yyerrorfl((*i)->file, (*i)->line,
174 "Namespaces cannot be declared with an absolute path.");
178 for (; i != name->end(); i++) {
179 if ((*i)->token == '*') {
180 yyerrorfl((*i)->file, (*i)->line,
181 "'*' is only allowed with \"using\".");
185 sym = ns->lookup_noex(*i, true);
187 UserNameSpace *new_ns;
190 // Cannot throw DuplicateSymbol, but it can throw
191 // InvalidArgument due to user error (such as trying
192 // to implicitly declare a namespace inside of a
193 // struct/class/whatever.
195 new_ns = new UserNameSpace(*i);
196 ns->add_user(new_ns);
199 catch (InvalidArgument) {
200 yyerrorfl((*i)->file, (*i)->line,
201 "Cannot create namespace \"%s\" inside of a "
202 "non-namespace type or import namespace.",
209 // Don't let the user declare things in non-user namespaces.
210 // Besides the headache of verifying that it's something
211 // that belongs, and of determining order for situations
212 // where it matters, it's just icky.
215 ns = dynamic_cast<UserNameSpace *>(sym);
217 yyerrorfl((*i)->file, (*i)->line,
218 "\"%s\" is not a namespace.",
219 sym->get_fq_name()->flatten()->c_str());
227 nspace_stack.push_front(cur_nspace);
235 if (nspace_stack.empty())
238 cur_nspace = nspace_stack.front();
239 nspace_stack.pop_front();
242 void NameSpace::add_user(Symbol *sym)
248 catch (DuplicateSymbol) {
249 yyerrorfl(sym->name->file, sym->name->line,
250 "\"%s\" already exists in this %s.",
251 sym->name->c_str(), description());
256 void NameSpace::add_import(Symbol *sym, const char *filename)
262 catch (DuplicateSymbol) {
263 yyerrorf("\"%s\" already exists in %s.",
264 sym->name->c_str(), get_fq_name()->flatten()->c_str());
268 catch (InvalidArgument) {
269 yyerrorf("\"%s\" caused an InvalidArgument upon add.", filename);
276 if (ns && !ns->dying) {
281 catch (SymbolNotFound) {
282 fprintf(stderr, "SymbolNotFound in Symbol::~Symbol(), cannot propagate\n");
287 StrList *Symbol::get_fq_name(const char *append, bool not_last) const
290 const String *s = NULL;
293 if (append && not_last &&
294 !dynamic_cast<const UserNameSpace *>(this))
296 String *mut_s = new String(name);
297 mut_s->append(append);
302 } else if (!ns && !dynamic_cast<const UserNameSpace *>(this)) {
303 s = new String("<temporary>");
305 s = new String("<toplevel>");
307 s = new String("<anonymous>");
310 if (!ns || !ns->name) {
313 ret = ns->get_fq_name(append, true);
320 Symbol *Symbol::find_toplevel_type()
322 Symbol *cur = this, *prev;
327 } while (!dynamic_cast<UserNameSpace *>(cur));
332 // FIXME: Use double-dot for initial delimit, but only if
333 // generating IDLC-style names. More generally, it should
334 // allow an arbitrary alternate global scope prefix.
336 String *StrList::flatten(const char *delimit)
338 String *ret = new String();
340 for (const_iterator i = begin(); i != end();) {
341 const String *str = *i;
345 ret->append(delimit);
348 const String *str = back();
349 ret->file = str->file;
350 ret->line = str->line;