Synopsis - Cross-Reference
File: src/Synopsis/SymbolFactory.cc1// 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}
Generated on Tue May 13 02:39:18 2008 by
synopsis (version 0.10)
synopsis (version 0.10)