1 // Code to maintain and search namespaces
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
26 void NameSpace::lookup_imports()
28 for (list<StrListRef>::iterator i = import_strs.begin();
29 i != import_strs.end(); ++i)
32 Symbol *sym = lookup_sym(toplevel, strl, this);
33 NameSpace *ns = dynamic_cast<NameSpace *>(sym);
36 const String *str = strl->back();
37 yyerrorfl(str->file, str->line, "\"%s\" is not a namespace.",
38 sym->get_fq_name()->flatten()->c_str());
42 imports.push_back(ns);
45 for (const_iterator i = begin(); i != end(); ++i) {
46 Symbol *sym = (*i).second;
47 sym->lookup_imports();
52 // Find the namespace in which "name" is declared.
53 // The rules for namespace precedence are in doc/idl/namespace-precedence.
55 NameSpace *NameSpace::search(const String *name, Symbol *exclude)
57 // Rule #1: Check current namespace first.
58 Symbol *sym = lookup_noex(name, true);
59 if (sym && sym != exclude)
62 // Rule #2: Check imported symbols
65 for (list<NameSpaceRef>::iterator i = imports.begin();
66 i != imports.end(); ++i)
69 Symbol *newfound = ns->lookup_noex(name, true);
72 if (newfound == exclude)
75 if (found && found != newfound) {
76 yyerrorfl(name->file, name->line,
77 "\"%s\" is ambiguous. Two possibilities "
78 "(there may be more) are:",
81 yyerrorfl(found->name->file, found->name->line, " \"%s\"",
82 found->get_fq_name()->flatten()->c_str());
83 yyerrorfl(newfound->name->file, newfound->name->line, " \"%s\"",
84 newfound->get_fq_name()->flatten()->c_str());
94 return found->get_ns();
99 static NameSpace *search_for_namespace(const String *name, NameSpace *ctx,
103 NameSpace *ret = ctx->search(name, exclude);
111 yyerrorfl(name->file, name->line,
112 "Unknown symbol \"%s\" in namespace search path.",
118 Symbol *lookup_sym(NameSpace *ns, StrList *name, NameSpace *ctx,
124 assert(current_pass != 1);
125 assert(name->size() != 0);
128 StrList::iterator i = name->begin();
130 if (name->front()->length() != 0) {
131 ns = search_for_namespace(name->front(), ctx, exclude);
139 assert(i != name->end());
142 while (i != name->end()) {
144 sym = ns->lookup(*i, first)->get_concrete_sym();
147 catch (SymbolNotFound) {
148 yyerrorfl((*i)->file, (*i)->line,
149 "Unknown symbol \"%s\" in \"%s\".",
150 (*i)->c_str(), ns->get_fq_name()->flatten()->c_str());
158 ns = dynamic_cast<NameSpace *>(sym);
160 if (!ns && i != name->end()) {
161 yyerrorfl((*i)->file, (*i)->line,
162 "\"%s\" is not a namespace.",
163 sym->get_fq_name()->flatten()->c_str());
173 // Returns the namespace (new or otherwise) on success, or NULL on failure.
174 NameSpace *add_nspace(StrList *name, bool push)
176 StrList::iterator i = name->begin();
177 NameSpace *ns = cur_nspace;
180 if ((*i)->length() == 0) {
181 yyerrorfl((*i)->file, (*i)->line,
182 "Namespaces cannot be declared with an absolute path.");
186 for (; i != name->end(); i++) {
187 if ((*i)->token == '*') {
188 yyerrorfl((*i)->file, (*i)->line,
189 "'*' is only allowed with \"using\".");
193 sym = ns->lookup_noex(*i, true);
195 UserNameSpace *new_ns;
198 // Cannot throw DuplicateSymbol, but it can throw
199 // InvalidArgument due to user error (such as trying
200 // to implicitly declare a namespace inside of a
201 // struct/class/whatever.
203 new_ns = new UserNameSpace(*i);
204 ns->add_user(new_ns);
207 catch (InvalidArgument) {
208 yyerrorfl((*i)->file, (*i)->line,
209 "Cannot create namespace \"%s\" inside of a "
210 "non-namespace type or import namespace.",
217 // Don't let the user declare things in non-user namespaces.
218 // Besides the headache of verifying that it's something
219 // that belongs, and of determining order for situations
220 // where it matters, it's just icky.
223 ns = dynamic_cast<UserNameSpace *>(sym);
225 yyerrorfl((*i)->file, (*i)->line,
226 "\"%s\" is not a namespace.",
227 sym->get_fq_name()->flatten()->c_str());
235 nspace_stack.push_front(cur_nspace);
243 if (nspace_stack.empty())
246 cur_nspace = nspace_stack.front();
247 nspace_stack.pop_front();
250 void NameSpace::add_user(Symbol *sym)
256 catch (DuplicateSymbol) {
257 yyerrorfl(sym->name->file, sym->name->line,
258 "\"%s\" already exists in this %s.",
259 sym->name->c_str(), description());
264 void NameSpace::add_import(Symbol *sym, const char *filename)
270 catch (DuplicateSymbol) {
271 yyerrorf("\"%s\" already exists in %s.",
272 sym->name->c_str(), get_fq_name()->flatten()->c_str());
276 catch (InvalidArgument) {
277 yyerrorf("\"%s\" caused an InvalidArgument upon add.", filename);
284 if (ns && !ns->dying) {
289 catch (SymbolNotFound) {
290 fprintf(stderr, "SymbolNotFound in Symbol::~Symbol(), cannot propagate\n");
295 StrList *Symbol::get_fq_name(const char *append, bool not_last) const
298 const String *s = NULL;
301 if (append && not_last &&
302 !dynamic_cast<const UserNameSpace *>(this))
304 String *mut_s = new String(name);
305 mut_s->append(append);
310 } else if (!ns && !dynamic_cast<const UserNameSpace *>(this)) {
311 s = new String("<temporary>");
313 s = new String("<toplevel>");
315 s = new String("<anonymous>");
318 if (!ns || !ns->name) {
321 ret = ns->get_fq_name(append, true);
328 Symbol *Symbol::find_toplevel_type()
330 Symbol *cur = this, *prev;
335 } while (!dynamic_cast<UserNameSpace *>(cur));
340 // FIXME: Use double-dot for initial delimit, but only if
341 // generating IDLC-style names. More generally, it should
342 // allow an arbitrary alternate global scope prefix.
344 String *StrList::flatten(const char *delimit)
346 String *ret = new String();
348 for (const_iterator i = begin(); i != end();) {
349 const String *str = *i;
353 ret->append(delimit);
356 const String *str = back();
357 ret->file = str->file;
358 ret->line = str->line;