Synopsis - Cross-Reference

File: src/Synopsis/SymbolLookup/Scopes.cc
  1//
  2// Copyright (C) 2004 Stefan Seefeld
  3// All rights reserved.
  4// Licensed to the public under the terms of the GNU LGPL (>= 2),
  5// see the file COPYING for details.
  6//
  7#include <Synopsis/SymbolLookup/Scopes.hh>
  8#include <Synopsis/PTree/Writer.hh>
  9#include <Synopsis/PTree/Display.hh>
 10#include <Synopsis/Trace.hh>
 11#include <sstream>
 12#include <cassert>
 13
 14using namespace Synopsis;
 15using namespace PTree;
 16using namespace SymbolLookup;
 17
 18SymbolSet 
 19TemplateParameterScope::unqualified_lookup(Encoding const &name,
 20					   LookupContext context) const
 21{
 22  Trace trace("TemplateParameterScope::unqualified_lookup", Trace::SYMBOLLOOKUP);
 23  trace << name;
 24  SymbolSet symbols = find(name, context == SCOPE);
 25  return symbols.size() ? symbols : my_outer->unqualified_lookup(name, context);
 26}
 27
 28SymbolSet 
 29LocalScope::unqualified_lookup(Encoding const &name,
 30			       LookupContext context) const
 31{
 32  Trace trace("LocalScope::unqualified_lookup", Trace::SYMBOLLOOKUP);
 33  trace << name;
 34  SymbolSet symbols = find(name, context == SCOPE);
 35  return symbols.size() ? symbols : my_outer->unqualified_lookup(name, context);
 36}
 37
 38FunctionScope::FunctionScope(PTree::Declaration const *decl, 
 39			     PrototypeScope *proto,
 40			     Scope const *outer)
 41  : my_decl(decl), my_outer(outer->ref()),
 42    my_parameters(proto->parameters())
 43{
 44  for (SymbolTable::iterator i = proto->my_symbols.begin();
 45       i != proto->my_symbols.end();
 46       ++i)
 47  {
 48    Symbol const *symbol = i->second;
 49    my_symbols.insert(std::make_pair(i->first,
 50				     new VariableName(symbol->type(),
 51						      symbol->ptree(),
 52						      true, this)));
 53  }
 54  proto->unref();
 55}
 56
 57void FunctionScope::use(PTree::UsingDirective const *udecl)
 58{
 59  if (*PTree::second(udecl) == "namespace") // using.dir
 60  {
 61    PTree::Encoding name = PTree::third(udecl)->encoded_name();
 62    SymbolSet symbols = lookup(name);
 63    // now get the namespace associated with that symbol:
 64    Symbol const *symbol = *symbols.begin();
 65    // FIXME: may this symbol-to-scope conversion be implemented
 66    //        by the appropriate Symbol subclass(es) ?
 67    Scope const *scope = symbol->scope()->find_scope(name, symbol);
 68    Namespace const *ns = dynamic_cast<Namespace const *>(scope);
 69    if (ns) my_using.insert(ns);
 70  }
 71  else
 72  {
 73    std::cout << "sorry, using declaration not supported yet" << std::endl;
 74  }
 75}
 76
 77SymbolSet 
 78FunctionScope::unqualified_lookup(Encoding const &name,
 79				  LookupContext context) const
 80{
 81  Trace trace("FunctionScope::unqualified_lookup", Trace::SYMBOLLOOKUP);
 82  trace << name;
 83  SymbolSet symbols = find(name, context);
 84  if (my_parameters)
 85  {
 86    SymbolSet more = my_parameters->find(name, context);
 87    symbols.insert(more.begin(), more.end());
 88  }
 89  if (symbols.size()) return symbols;
 90
 91  // see 7.3.4 [namespace.udir]
 92  for (Using::const_iterator i = my_using.begin(); i != my_using.end(); ++i)
 93  {
 94    SymbolSet more = (*i)->unqualified_lookup(name, context | USING);
 95    symbols.insert(more.begin(), more.end());
 96  }
 97  if (symbols.size() || !my_outer)
 98    return symbols;
 99  else
100    return my_outer->unqualified_lookup(name, context);
101}
102
103std::string FunctionScope::name() const
104{
105  std::ostringstream oss;
106  oss << PTree::reify(PTree::third(my_decl));
107  return oss.str();
108}
109
110SymbolSet 
111FunctionScope::qualified_lookup(PTree::Encoding const &name,
112				LookupContext context) const
113{
114  Trace trace("FunctionScope::qualified_lookup", Trace::SYMBOLLOOKUP);
115  trace << name;
116  PTree::Encoding symbol_name = name.get_scope();
117  PTree::Encoding remainder = name.get_symbol();
118
119  if (symbol_name.empty())
120  {
121    symbol_name = name;
122    remainder.clear();
123  }
124
125  // find symbol locally
126  SymbolSet symbols = find(symbol_name, context);
127  // see 7.3.4 [namespace.udir]
128  if (symbols.empty())
129    for (Using::const_iterator i = my_using.begin(); i != my_using.end(); ++i)
130    {
131      SymbolSet more = (*i)->qualified_lookup(name, context);
132      symbols.insert(more.begin(), more.end());
133    }
134  if (symbols.empty()) return symbols; // nothing found
135
136  // If the remainder is empty, just return the found symbol(s).
137  else if (remainder.empty()) return symbols;
138
139  // Having multiple symbols implies they are all overloaded functions.
140  // That's a type error if the reminder is non-empty, as we are looking
141  // for a scope.
142  else if (symbols.size() > 1)
143    throw TypeError(symbol_name, (*symbols.begin())->ptree()->encoded_type());
144
145  // Find the scope the symbol refers to 
146  // and look up the remainder there.
147
148  // move into inner scope and start over the lookup
149  Scope const *nested = find_scope(symbol_name, *symbols.begin());
150  if (!nested) throw InternalError("undeclared scope !");
151
152  return nested->qualified_lookup(remainder, context);
153}
154
155SymbolSet 
156PrototypeScope::unqualified_lookup(PTree::Encoding const &,
157				   LookupContext) const
158{
159  Trace trace("PrototypeScope::unqualified_lookup", Trace::SYMBOLLOOKUP);
160  return SymbolSet();
161}
162
163std::string PrototypeScope::name() const
164{
165  std::ostringstream oss;
166  oss << PTree::reify(my_decl);
167  return oss.str();
168}
169
170SymbolSet 
171Class::unqualified_lookup(Encoding const &name,
172			  LookupContext context) const
173{
174  Trace trace("Class::unqualified_lookup", Trace::SYMBOLLOOKUP);
175  trace << name;
176  SymbolSet symbols = find(name, context);
177  for (Bases::const_iterator i = my_bases.begin(); i != my_bases.end(); ++i)
178  {
179    SymbolSet more = (*i)->find(name, context);
180    symbols.insert(more.begin(), more.end());
181  }
182  if (my_parameters)
183  {
184    SymbolSet more = my_parameters->find(name, context);
185    symbols.insert(more.begin(), more.end());
186  }
187  return symbols.size() ? symbols : my_outer->unqualified_lookup(name, context);
188}
189
190std::string Class::name() const
191{
192  PTree::Node const *name_spec = PTree::second(my_spec);
193  // FIXME: why is name_spec for anonumous classes 'list(0, 0)' ?
194  //        see Parser::class_spec()...
195  if (name_spec && name_spec->is_atom())
196    return std::string(name_spec->position(), name_spec->length());
197  return "";
198}
199
200Namespace *Namespace::find_namespace(PTree::NamespaceSpec const *spec) const
201{
202  std::string name = "<anonymous>";
203  PTree::Node const *ns_name = PTree::second(spec);
204  if (ns_name)
205    name.assign(ns_name->position(), ns_name->length());
206  for (ScopeTable::const_iterator i = my_scopes.begin();
207       i != my_scopes.end();
208       ++i)
209  {
210    Namespace *ns = dynamic_cast<Namespace *>(i->second);
211    if (ns && name == ns->name())
212      return ns;
213  }
214  return 0;
215}
216
217void Namespace::use(PTree::UsingDirective const *udecl)
218{
219  if (*PTree::second(udecl) == "namespace") // using.dir
220  {
221    PTree::Encoding name = PTree::third(udecl)->encoded_name();
222    SymbolSet symbols = lookup(name);
223    // now get the namespace associated with that symbol:
224    Symbol const *symbol = *symbols.begin();
225    // FIXME: may this symbol-to-scope conversion be implemented
226    //        by the appropriate Symbol subclass(es) ?
227    Scope const *scope = symbol->scope()->find_scope(name, symbol);
228    Namespace const *ns = dynamic_cast<Namespace const *>(scope);
229    if (ns) my_using.insert(ns);
230  }
231  else
232  {
233    std::cout << "sorry, using declaration not supported yet" << std::endl;
234  }
235}
236
237SymbolSet 
238Namespace::unqualified_lookup(Encoding const &name,
239			      LookupContext context) const
240{
241  Using searched;
242  return unqualified_lookup(name, context, searched);
243}
244
245SymbolSet 
246Namespace::qualified_lookup(PTree::Encoding const &name,
247			    LookupContext context) const
248{
249  Using searched;
250  return qualified_lookup(name, context, searched);
251}
252
253std::string Namespace::name() const
254{
255  if (!my_spec) return "<global>";
256  PTree::Node const *name_spec = PTree::second(my_spec);
257  if (name_spec)
258    return std::string(name_spec->position(), name_spec->length());
259  else
260    return "<anonymous>";
261}
262
263SymbolSet Namespace::unqualified_lookup(Encoding const &name,
264					LookupContext context,
265					Using &searched) const
266{
267  Trace trace("Namespace::unqualified_lookup", Trace::SYMBOLLOOKUP, this->name());
268  trace << name;
269  searched.insert(this);
270  SymbolSet symbols = find(name, context);
271  if (symbols.size()) return symbols;
272
273  // see 7.3.4 [namespace.udir]
274  for (Using::const_iterator i = my_using.begin(); i != my_using.end(); ++i)
275    if (searched.find(*i) == searched.end())
276    {
277      SymbolSet more = (*i)->unqualified_lookup(name, context | USING, searched);
278      symbols.insert(more.begin(), more.end());
279    }
280  if (symbols.size() ||
281      context & USING ||
282      !my_outer ||
283      searched.find(my_outer) != searched.end())
284    return symbols;
285  else
286    return my_outer->unqualified_lookup(name, context, searched);
287}
288
289SymbolSet Namespace::qualified_lookup(PTree::Encoding const &name,
290				      LookupContext context,
291				      Using &searched) const
292{
293  Trace trace("Namespace::qualified_lookup", Trace::SYMBOLLOOKUP, this->name());
294  trace << name;
295
296  PTree::Encoding symbol_name = name.get_scope();
297  PTree::Encoding remainder = name.get_symbol();
298
299  if (symbol_name.empty())
300  {
301    symbol_name = name;
302    remainder.clear();
303  }
304
305  // find symbol locally
306  SymbolSet symbols = find(symbol_name, context);
307
308  // see 3.4.3.2/2 and 3.4.3.2/6
309  if (!symbols.size() && (context ^ DECLARATION || name.is_qualified()))
310    for (Using::const_iterator i = my_using.begin(); i != my_using.end(); ++i)
311      if (searched.find(*i) == searched.end())
312      {
313	SymbolSet more = (*i)->qualified_lookup(name, context, searched);
314	symbols.insert(more.begin(), more.end());
315      }
316  if (symbols.empty()) return symbols; // nothing found
317
318  // If the remainder is empty, just return the found symbol(s).
319  else if (remainder.empty()) return symbols;
320
321  // Having multiple symbols implies they are all overloaded functions.
322  // That's a type error if the reminder is non-empty, as we are looking
323  // for a scope.
324  else if (symbols.size() > 1)
325    throw TypeError(symbol_name, (*symbols.begin())->ptree()->encoded_type());
326
327  // Find the scope the symbol refers to 
328  // and look up the remainder there.
329
330  // move into inner scope and start over the lookup
331  Scope const *nested = find_scope(symbol_name, *symbols.begin());
332  if (!nested) throw InternalError("undeclared scope !");
333
334  return nested->qualified_lookup(remainder, context);
335}
336