Synopsis - Cross-Reference

File: src/Synopsis/SymbolFactory.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/SymbolFactory.hh>
  8#include <Synopsis/PTree/Display.hh>
  9#include <Synopsis/PTree/Writer.hh>
 10#include <Synopsis/SymbolLookup/Scopes.hh>
 11#include <Synopsis/TypeAnalysis/ConstEvaluator.hh>
 12#include <Synopsis/Trace.hh>
 13#include <cassert>
 14#include <vector>
 15
 16using namespace Synopsis;
 17using namespace PTree;
 18using namespace SymbolLookup;
 19using namespace TypeAnalysis;
 20
 21namespace
 22{
 23PTree::Node const *strip_cv_from_integral_type(PTree::Node const *integral)
 24{
 25  if(integral == 0) return 0;
 26
 27  if(!integral->is_atom())
 28  {
 29    if(PTree::is_a(integral->car(), Token::CONST, Token::VOLATILE))
 30      return PTree::second(integral);
 31    else if(PTree::is_a(PTree::second(integral), Token::CONST, Token::VOLATILE))
 32      return integral->car();
 33  }
 34  return integral;
 35}
 36
 37PTree::ClassSpec const *get_class_template_spec(PTree::Node const *body)
 38{
 39  if(*PTree::third(body) == ';') // template declaration
 40  {
 41    PTree::Node const *spec = strip_cv_from_integral_type(PTree::second(body));
 42    return dynamic_cast<PTree::ClassSpec const *>(spec);
 43  }
 44  return 0;
 45}
 46
 47//. Look up the scope corresponding to a base-specifier.
 48//. FIXME: The lookup may require a template instantiation, or
 49//.        fail because it involves a dependent name. This requires
 50//.        more design.
 51class BaseClassScopeFinder : private PTree::Visitor
 52{
 53public:
 54  BaseClassScopeFinder(Scope const *scope) : my_scope(scope), my_result(0) {}
 55  Class *lookup(PTree::Node const *node)
 56  {
 57    const_cast<PTree::Node *>(node)->accept(this);
 58    return my_result;
 59  }
 60private:
 61  virtual void visit(Identifier *node)
 62  {
 63    Encoding name = Encoding::simple_name(node);
 64    SymbolSet symbols = my_scope->lookup(name, Scope::ELABORATE);
 65    if (symbols.empty()) throw Undefined(name, node);
 66    else
 67    {
 68      ClassName const *class_ = dynamic_cast<ClassName const *>(*symbols.begin());
 69      if (!class_) throw InternalError("Base specifier not a class.");
 70      my_result = class_->as_scope();
 71    }
 72  }
 73  virtual void visit(Name *node)
 74  {
 75    Encoding name = node->encoded_name();
 76    // FIXME: This will fail if the name is a template or a dependent name.
 77    SymbolSet symbols = my_scope->lookup(name, Scope::ELABORATE);
 78    if (symbols.empty()) throw Undefined(name, node);
 79    else
 80    {
 81      ClassName const *class_ = dynamic_cast<ClassName const *>(*symbols.begin());
 82      if (!class_) throw InternalError("Base specifier not a class.");
 83      my_result = class_->as_scope();
 84    }
 85  }
 86
 87  Scope const *my_scope;
 88  Class *      my_result;
 89};
 90
 91}
 92
 93
 94SymbolFactory::SymbolFactory(Language l)
 95  : my_language(l),
 96    my_prototype(0),
 97    my_template_parameters(0)
 98{
 99  // define the global scope
100  my_scopes.push(new Namespace(0, 0));
101}
102
103void SymbolFactory::enter_scope(PTree::NamespaceSpec const *spec)
104{
105  Trace trace("SymbolFactory::enter_scope(NamespaceSpec)", Trace::SYMBOLLOOKUP);
106  if (my_language == NONE) return;
107
108  // Namespaces are only valid within namespaces.
109  Namespace *scope = dynamic_cast<Namespace *>(my_scopes.top());
110  assert(scope);
111
112  Namespace *namespace_ = 0;
113  // If the namespace was already opened before, we add a reference
114  // to it under the current NamespaceSpec, too.
115  if ((namespace_ = scope->find_namespace(spec)))
116  {
117    scope->declare_scope(spec, namespace_);
118  }
119  else
120  {
121    // This is a new namespace. Declare it.
122    namespace_ = new Namespace(spec, scope);
123    scope->declare_scope(spec, namespace_);
124  }
125  my_scopes.push(namespace_);
126}
127
128void SymbolFactory::enter_scope(PTree::ClassSpec const *spec)
129{
130  Trace trace("SymbolFactory::enter_scope(ClassSpec)", Trace::SYMBOLLOOKUP);
131  if (my_language == NONE) return;
132
133  BaseClassScopeFinder base_finder(my_scopes.top());
134  Class::Bases bases;
135  for (PTree::Node const *base_clause = spec->base_clause();
136       base_clause;
137       base_clause = PTree::rest(PTree::rest(base_clause)))
138  {
139    // The last node is the name, the others access specs or 'virtual'
140    PTree::Node const *parent = PTree::last(PTree::second(base_clause))->car();
141    Class *class_ = base_finder.lookup(parent);
142    if (class_) bases.push_back(class_);
143    else ; // FIXME
144  }
145  Scope *scope = my_scopes.top();
146  Class *class_ = new Class(spec, scope, bases, my_template_parameters);
147  scope->declare_scope(spec, class_);
148  my_scopes.push(class_);
149  my_template_parameters = 0;
150}
151
152void SymbolFactory::enter_scope(PTree::Node const *decl)
153{
154  Trace trace("SymbolFactory::enter_scope(Node)", Trace::SYMBOLLOOKUP);
155  if (my_language == NONE) return;
156  Scope *scope = my_scopes.top();
157  // Create a PrototypeScope. If this is part of a function definition, we will
158  // later convert it into a FunctionScope.
159  my_prototype = new PrototypeScope(decl, scope, my_template_parameters);
160  scope->declare_scope(decl, my_prototype);
161  my_scopes.push(my_prototype);
162  my_template_parameters = 0;
163}
164
165void SymbolFactory::enter_scope(PTree::FunctionDefinition const *decl)
166{
167  Trace trace("SymbolFactory::enter_scope(FunctionDefinition)", Trace::SYMBOLLOOKUP);
168  if (my_language == NONE) return;
169
170  Scope *scope = my_scopes.top();
171
172  assert(my_prototype);
173  my_prototype->ref();
174  scope->remove_scope(my_prototype->declaration());
175
176  // look at the declarator's encoded name
177  Encoding name = PTree::third(decl)->encoded_name();
178  if (name.is_qualified())
179    scope = lookup_scope_of_qname(name, PTree::third(decl));
180
181  // Transfer all symbols from the previously seen function declaration
182  // into the newly created FunctionScope, and remove the PrototypeScope.
183  FunctionScope *func = new FunctionScope(decl, my_prototype, scope);
184  scope->declare_scope(decl, func);
185  my_prototype = 0;
186  my_scopes.push(func);
187}
188
189void SymbolFactory::enter_scope(PTree::TemplateDecl const *params)
190{
191  Trace trace("SymbolFactory::enter_scope(TemplateDecl)", Trace::SYMBOLLOOKUP);
192  if (my_language == NONE) return;
193
194  Scope *scope = my_scopes.top();
195  TemplateParameterScope *templ = new TemplateParameterScope(params, scope);
196  scope->declare_scope(params, templ);
197  my_scopes.push(templ);
198}
199
200void SymbolFactory::enter_scope(PTree::Block const *block)
201{
202  Trace trace("SymbolFactory::enter_scope(Block)", Trace::SYMBOLLOOKUP);
203  if (my_language == NONE) return;
204
205  Scope *scope = my_scopes.top();
206  LocalScope *local = new LocalScope(block, scope);
207  scope->declare_scope(block, local);
208  my_scopes.push(local);
209}
210
211void SymbolFactory::leave_scope()
212{
213  Trace trace("SymbolFactory::leave_scope", Trace::SYMBOLLOOKUP);
214  if (my_language == NONE) return;
215
216  Scope *scope = my_scopes.top();
217  my_scopes.pop();
218  // If this was a function prototype, keep it in case we see
219  // the function body and want to transform it into a function
220  // scope.
221  if (PrototypeScope *ps = dynamic_cast<PrototypeScope *>(scope))
222    my_prototype = ps;
223  else if (TemplateParameterScope *ts = dynamic_cast<TemplateParameterScope *>(scope))
224    my_template_parameters = ts;
225  else
226    scope->unref();
227}
228
229void SymbolFactory::declare(PTree::Declaration const *d)
230{
231  Trace trace("SymbolFactory::declare(Declaration *)", Trace::SYMBOLLOOKUP);
232  if (my_language == NONE) return;
233
234  PTree::Node const *decls = PTree::third(d);
235  if(PTree::is_a(decls, Token::ntDeclarator))
236  {
237    // function definition,
238    // declare it only once (but allow overloading)
239
240    PTree::Encoding name = decls->encoded_name();
241    PTree::Encoding type = decls->encoded_type();
242
243    // If the name is qualified, it has to be
244    // declared already. If it hasn't, raise an error.
245    Scope *scope = my_scopes.top();
246    if (name.is_qualified())
247    {
248      scope = lookup_scope_of_qname(name, decls);
249      SymbolSet symbols = scope->find(name, Scope::DECLARATION);
250      // FIXME: We need type analysis / overload resolution
251      //        here to take the right symbol.
252      Symbol const *symbol = *symbols.begin();
253      // TODO: check whether this is the definition of a previously
254      //       declared function, according to 3.1/2 [basic.def]
255      scope->remove(symbol);
256    }
257    scope->declare(name, new FunctionName(type, d, true, scope));
258  }
259  else
260  {
261    // Function or variable declaration.
262//     PTree::Node const *storage_spec = PTree::first(d);
263//     PTree::Node const *type_spec = PTree::second(d);
264    if (decls->is_atom()) ; // it is a ';'
265    else
266    {
267      for (; decls; decls = decls->cdr())
268      {
269	PTree::Node const *decl = decls->car();
270	if (PTree::is_a(decl, Token::ntDeclarator))
271	{
272	  PTree::Encoding name = decl->encoded_name();
273	  PTree::Encoding const &type = decl->encoded_type();
274
275	  Scope *scope = my_scopes.top();
276	  if (name.is_qualified())
277	  {
278	    SymbolSet symbols = scope->lookup(name, Scope::DECLARATION);
279	    if (symbols.empty()) throw Undefined(name, decl);
280	    // FIXME: We need type analysis / overload resolution
281	    //        here to take the right symbol.
282	    Symbol const *symbol = *symbols.begin();
283	    while (name.is_qualified()) name = name.get_symbol();
284	    scope = symbol->scope();
285	    // TODO: check whether this is the definition of a previously
286	    //       declared variable, according to 3.1/2 [basic.def]
287	    scope->remove(symbol);
288	  }
289
290	  if (type.is_function()) // It's a function declaration.
291	    scope->declare(name, new FunctionName(type, decl, false, scope));
292	  else                    // It's a variable definition.
293	    scope->declare(name, new VariableName(type, decl, true, scope));
294	}
295      }
296    }
297  }
298}
299
300void SymbolFactory::declare(Typedef const *td)
301{
302  Trace trace("SymbolFactory::declare(Typedef *)", Trace::SYMBOLLOOKUP);
303  if (my_language == NONE) return;
304  PTree::Node const *declarations = third(td);
305  while(declarations)
306  {
307    PTree::Node const *d = declarations->car();
308    if(type_of(d) == Token::ntDeclarator)
309    {
310      Encoding const &name = d->encoded_name();
311      Encoding const &type = d->encoded_type();
312      Scope *scope = my_scopes.top();
313      scope->declare(name, new TypedefName(type, d, scope));
314    }
315    declarations = tail(declarations, 2);
316  }
317}
318
319void SymbolFactory::declare(EnumSpec const *spec)
320{
321  Trace trace("SymbolFactory::declare(EnumSpec *)", Trace::SYMBOLLOOKUP);
322  if (my_language == NONE) return;
323  PTree::Node const *tag = second(spec);
324  Encoding const &name = spec->encoded_name();
325  Encoding const &type = spec->encoded_type();
326  Scope *scope = my_scopes.top();
327  if(tag && tag->is_atom()) 
328    scope->declare(name, new EnumName(type, spec, my_scopes.top()));
329  // else it's an anonymous enum
330
331  PTree::Node const *body = third(spec);
332  // The numeric value of an enumerator is either specified
333  // by an explicit initializer or it is determined by incrementing
334  // by one the value of the previous enumerator.
335  // The default value for the first enumerator is 0
336  long value = -1;
337  for (PTree::Node const *e = second(body); e; e = rest(rest(e)))
338  {
339    PTree::Node const *enumerator = e->car();
340    bool defined = true;
341    if (enumerator->is_atom()) ++value;
342    else  // [identifier = initializer]
343    {
344      PTree::Node const *initializer = third(enumerator);
345      
346      defined = evaluate_const(current_scope(), initializer, value);
347      enumerator = enumerator->car();
348#ifndef NDEBUG
349      if (!defined)
350      {
351	std::cerr << "Error in evaluating enum initializer:\n"
352		  << "Expression doesn't evaluate to a constant integral value:\n"
353		  << reify(initializer) << std::endl;
354      }
355#endif
356    }
357    assert(enumerator->is_atom());
358    PTree::Encoding name(enumerator->position(), enumerator->length());
359    if (defined)
360      scope->declare(name, new ConstName(type, value, enumerator, true, scope));
361    else
362      scope->declare(name, new ConstName(type, enumerator, true, scope));
363  }
364}
365
366void SymbolFactory::declare(NamespaceSpec const *spec)
367{
368  Trace trace("SymbolFactory::declare(NamespaceSpec *)", Trace::SYMBOLLOOKUP);
369  if (my_language == NONE) return;
370  // Beware anonymous namespaces !
371  Encoding name;
372  if (second(spec)) name.simple_name(second(spec));
373  else name.append_with_length("<anonymous>");
374  Scope *scope = my_scopes.top();
375  // Namespaces can be reopened, so only declare it if it isn't already known.
376  SymbolSet symbols = scope->find(name, Scope::SCOPE);
377  if (symbols.empty())
378  {
379    scope->declare(name, new NamespaceName(spec->encoded_type(), spec, true, scope));
380  }
381  // FIXME: assert that the found symbol really refers to a namespace !
382}
383
384void SymbolFactory::declare(ClassSpec const *spec)
385{
386  Trace trace("SymbolFactory::declare(ClassSpec *)", Trace::SYMBOLLOOKUP);
387  if (my_language == NONE) return;
388  Encoding const &name = spec->encoded_name();
389  // If class spec contains a class body, it's a definition.
390  PTree::ClassBody const *body = const_cast<ClassSpec *>(spec)->body();
391
392  Scope *scope = my_scopes.top();
393
394  SymbolSet symbols = scope->find(name, Scope::DEFAULT);
395  for (SymbolSet::iterator i = symbols.begin(); i != symbols.end(); ++i)
396  {
397    // If the symbol was defined as a different type, the program is ill-formed.
398    // Else if the symbol corresponds to a forward-declared class, replace it.
399    if (ClassName const *class_ = dynamic_cast<ClassName const *>(*i))
400    {
401      if (class_->is_definition())
402      {
403	if (body)
404	  throw MultiplyDefined(name, spec, class_->ptree()); // ODR
405	else return; // Ignore forward declaration if symbol is already defined.
406      }
407      else if (body) scope->remove(*i); // Remove forward declaration.
408      else return;                      // Don't issue another forward declaration.
409    }
410    else if (TypeName const *type = dynamic_cast<TypeName const *>(*i))
411      // Symbol already defined as different type.
412      throw MultiplyDefined(name, spec, type->ptree());
413  }
414  if (body)
415    scope->declare(name, new ClassName(spec->encoded_type(), spec, true, scope));
416  else
417    scope->declare(name, new ClassName(spec->encoded_type(), spec, false, scope));
418}
419
420void SymbolFactory::declare(TemplateDecl const *tdecl)
421{
422  Trace trace("SymbolFactory::declare(TemplateDecl *)", Trace::SYMBOLLOOKUP);
423  if (my_language == NONE) return;
424  PTree::Node const *body = PTree::nth(tdecl, 4);
425  PTree::ClassSpec const *class_spec = get_class_template_spec(body);
426  Scope *scope = my_scopes.top();
427  if (class_spec)
428  {
429    Encoding const &name = class_spec->encoded_name();
430    scope->declare(name, new ClassTemplateName(Encoding(), tdecl, true, scope));
431  }
432  else
433  {
434    PTree::Node const *decl = PTree::third(body);
435    PTree::Encoding const &name = decl->encoded_name();
436    scope->declare(name, new FunctionTemplateName(Encoding(), decl, scope));
437  }
438}
439
440void SymbolFactory::declare(PTree::TypeParameter const *tparam)
441{
442  Trace trace("SymbolFactory::declare(TypeParameter *)", Trace::SYMBOLLOOKUP);
443  Scope *scope = my_scopes.top();
444
445  PTree::Node const *first = PTree::first(tparam);
446  if (dynamic_cast<PTree::Kwd::Typename const *>(first) ||
447      dynamic_cast<PTree::Kwd::Class const *>(first))
448  {
449    PTree::Node const *second = PTree::second(tparam);
450    PTree::Encoding name;
451    name.simple_name(second);
452    scope->declare(name, new TypeName(Encoding(), tparam, true, scope));
453  }
454  else if (PTree::TemplateDecl const *tdecl = 
455	   dynamic_cast<PTree::TemplateDecl const *>(first))
456  {
457    // tdecl has 4 or 5 members:
458    // [template < parameter-list > class id]
459    // [template < parameter-list > class]
460    Encoding name;
461    PTree::Node const *pname = PTree::nth(tdecl, 5);
462    if (pname) name.simple_name(pname);
463    scope->declare(name, new ClassTemplateName(Encoding(), tdecl, true, scope));
464  }
465}
466
467void SymbolFactory::declare(PTree::UsingDirective const *usingdir)
468{
469  Trace trace("SymbolFactory::declare(UsingDirective *)", Trace::SYMBOLLOOKUP);
470  if (my_language == NONE) return;
471  my_scopes.top()->use(usingdir);
472}
473
474void SymbolFactory::declare(PTree::ParameterDeclaration const *pdecl)
475{
476  Trace trace("SymbolFactory::declare(ParameterDeclaration *)", Trace::SYMBOLLOOKUP);
477  if (my_language == NONE) return;
478  PTree::Node const *decl = PTree::third(pdecl);
479  PTree::Encoding const &name = decl->encoded_name();
480  PTree::Encoding const &type = decl->encoded_type();
481  if (!name.empty())
482  {
483    Scope *scope = my_scopes.top();
484    scope->declare(name, new VariableName(type, decl, true, scope));
485  }
486}
487
488void SymbolFactory::declare(PTree::UsingDeclaration const *)
489{
490  Trace trace("SymbolFactory::declare(UsingDeclaration *)", Trace::SYMBOLLOOKUP);
491  trace << "TBD !";
492  if (my_language == NONE) return;
493}
494
495Scope *SymbolFactory::lookup_scope_of_qname(PTree::Encoding &name,
496					    PTree::Node const *decl)
497{
498  Trace trace("SymbolFactory::lookup_scope_of_qname", Trace::SYMBOLLOOKUP);
499
500  Scope *scope = my_scopes.top();
501  SymbolSet symbols = scope->lookup(name, Scope::DECLARATION);
502  if (symbols.empty()) throw Undefined(name, decl);
503  Symbol const *symbol = *symbols.begin();
504  while (name.is_qualified()) name = name.get_symbol();
505  scope = symbol->scope();
506  return scope;
507}