Synopsis - Cross-Reference

File: /tests/Cxx/src/SymbolLookup.cc
  1#include <Synopsis/Trace.hh>
  2#include <Synopsis/Buffer.hh>
  3#include <Synopsis/Lexer.hh>
  4#include <Synopsis/Parser.hh>
  5#include <Synopsis/PTree.hh>
  6#include <Synopsis/PTree/Display.hh>
  7#include <Synopsis/PTree/Writer.hh>
  8#include <Synopsis/SymbolLookup.hh>
  9#include <iostream>
 10#include <iomanip>
 11#include <fstream>
 12
 13using namespace Synopsis;
 14using namespace SymbolLookup;
 15
 16class SymbolFinder : private Walker
 17{
 18public:
 19  SymbolFinder(Buffer const &buffer, Scope *scope, std::ostream &os)
 20    : Walker(scope), my_buffer(buffer), my_os(os), my_in_template_decl(false) {}
 21  void find(PTree::Node *node) { node->accept(this);}
 22private:
 23  using Walker::visit;
 24  virtual void visit(PTree::Identifier *iden)
 25  {
 26    Trace trace("SymbolFinder::visit(Identifier)", Trace::SYMBOLLOOKUP);
 27    PTree::Encoding name = PTree::Encoding::simple_name(iden);
 28    my_os << "Identifier : " << name.unmangled() << std::endl;
 29    lookup(name);
 30  }
 31
 32  virtual void visit(PTree::Block *node)
 33  {
 34    Trace trace("SymbolFinder::visit(Block)", Trace::SYMBOLLOOKUP);
 35    Walker::visit(node);
 36  }
 37
 38  virtual void visit(PTree::Typedef *typed)
 39  {
 40    Trace trace("SymbolFinder::visit(Typedef)", Trace::SYMBOLLOOKUP);
 41    // We need to figure out how to reproduce the (encoded) name of
 42    // the type being aliased.
 43    my_os << "Type : " << "<not implemented yet>" << std::endl;
 44//     lookup(name);
 45    PTree::third(typed)->accept(this);
 46  }
 47
 48  virtual void visit(PTree::TemplateDecl *tdecl)
 49  {
 50    Trace trace("SymbolFinder::visit(TemplateDecl)", Trace::SYMBOLLOOKUP);
 51    traverse_parameters(tdecl);
 52    bool saved_in_template_decl = my_in_template_decl;
 53    my_in_template_decl = true;
 54    PTree::Node *fourth = PTree::nth(tdecl, 4);
 55    if (!fourth->is_atom())
 56      fourth->accept(this); // This is a declaration.
 57    else
 58    {
 59      // We are in a template template parameter.
 60      // Visit the identifier and the default type, if present.
 61      PTree::Node *fifth = PTree::nth(tdecl, 5);
 62      if (fifth) fifth->accept(this); // This is an identifier
 63    }
 64    my_in_template_decl = saved_in_template_decl;
 65  }
 66
 67  virtual void visit(PTree::NamespaceSpec *node)
 68  {
 69    Trace trace("SymbolFinder::visit(NamespaceSpec)", Trace::SYMBOLLOOKUP);
 70    PTree::Node const *name = PTree::second(node);
 71    PTree::Encoding ename;
 72    if (name) ename.simple_name(name);
 73    else ename.append_with_length("<anonymous>");
 74    my_os << "Namespace : " << ename.unmangled() << std::endl;
 75    lookup(ename);
 76    traverse_body(node);
 77  }
 78
 79  virtual void visit(PTree::Declaration *node)
 80  {
 81    Trace trace("SymbolFinder::visit(Declaration)", Trace::SYMBOLLOOKUP);
 82    PTree::Node *type_spec = PTree::second(node);
 83    // FIXME: what about compound types ?
 84    if (type_spec && type_spec->is_atom())
 85    {
 86      PTree::Atom const *name = static_cast<PTree::Atom *>(type_spec);
 87      PTree::Encoding type = PTree::Encoding::simple_name(name);
 88      my_os << "Type : " << type.unmangled() << std::endl;
 89      lookup(type, Scope::DEFAULT, true);
 90      PTree::third(node)->accept(this);
 91    }
 92    else
 93      Walker::visit(node);
 94  }
 95
 96  virtual void visit(PTree::UsingDirective *udir)
 97  {
 98    PTree::Node *node = PTree::third(udir);
 99    PTree::Encoding name = node->encoded_name();
100    my_os << "Namespace : " << name.unmangled() << std::endl;
101    lookup(name);
102  }
103  virtual void visit(PTree::UsingDeclaration *udecl)
104  { visit(static_cast<PTree::List *>(udecl));}
105  virtual void visit(PTree::NamespaceAlias *alias)
106  {
107    {
108      PTree::Node *node = PTree::second(alias);
109      PTree::Encoding name = PTree::Encoding::simple_name(static_cast<PTree::Atom *>(node));
110      my_os << "Namespace : " << name.unmangled() << std::endl;
111      lookup(name);
112    }
113    {
114      PTree::Node *node = PTree::nth(alias, 3);
115      PTree::Encoding name = node->encoded_name();
116      my_os << "Namespace : " << name.unmangled() << std::endl;
117      lookup(name);
118    }
119  }
120
121  virtual void visit(PTree::FunctionDefinition *node)
122  {
123    Trace trace("SymbolFinder::visit(FunctionDefinition)", Trace::SYMBOLLOOKUP);
124    PTree::Node *decl = PTree::third(node);
125    visit(static_cast<PTree::Declarator *>(decl)); // visit the declarator
126    try { traverse_body(node);}
127    catch (Undefined const &e) {} // just ignore
128  }
129
130  virtual void visit(PTree::Declarator *decl)
131  {
132    Trace trace("SymbolFinder::visit(Declarator)", Trace::SYMBOLLOOKUP);
133    PTree::Encoding name = decl->encoded_name();
134    // FIXME: The parser currently parses type specifiers that contain a template_id
135    //        such that in contains declarators with empty names.
136    //        Ignore these until the parser is fixed.
137    if (name.empty()) return;
138    PTree::Encoding type = decl->encoded_type();
139    my_os << "Declarator : " << name.unmangled() << std::endl;
140    lookup(name, Scope::DECLARATION);
141    if (type.is_function()) return;
142    if (PTree::Node *initializer = decl->initializer())
143      initializer->accept(this);
144  }
145
146  virtual void visit(PTree::Name *n)
147  {
148    Trace trace("SymbolFinder::visit(Name)", Trace::SYMBOLLOOKUP);
149    PTree::Encoding name = n->encoded_name();
150    my_os << "Name : " << name.unmangled() << std::endl;
151    lookup(name);
152  }
153  
154  virtual void visit(PTree::ClassSpec *node)
155  {
156    Trace trace("SymbolFinder::visit(ClassSpec)", Trace::SYMBOLLOOKUP);
157    PTree::Encoding name = node->encoded_name();
158    my_os << "ClassSpec : " << name.unmangled() << std::endl;
159    // FIXME: A ClassSpec may correspond to a class template, in which case
160    //        we shouldn't do a elaborate lookup. The visit(TemplateDecl)
161    //        method above will thus deal with the lookup itself.
162    if (my_in_template_decl)
163      lookup(name);
164    else
165      lookup(name, Scope::ELABORATE);
166    
167    for (PTree::Node const *base_clause = node->base_clause();
168	 base_clause;
169	 base_clause = PTree::rest(PTree::rest(base_clause)))
170    {
171      PTree::Node const *parent = PTree::last(PTree::second(base_clause))->car();
172      const_cast<PTree::Node *>(parent)->accept(this);
173    }
174    traverse_body(node);
175  }
176
177  virtual void visit(PTree::FuncallExpr *node)
178  {
179    Trace trace("SymbolFinder::visit(FuncallExpr)", Trace::SYMBOLLOOKUP);
180    PTree::Node *function = node->car();
181    PTree::Encoding name;
182    if (function->is_atom()) name.simple_name(function);
183    else name = function->encoded_name(); // function is a 'PTree::Name'
184    my_os << "Function : " << name.unmangled() << std::endl;
185    lookup(name);
186  }
187
188  void lookup(PTree::Encoding const &name,
189	      Scope::LookupContext c = Scope::DEFAULT,
190	      bool type = false)
191  {
192    Trace trace("SymbolFinder::lookup", Trace::SYMBOLLOOKUP);
193    SymbolSet symbols = current_scope()->lookup(name, c);
194    if (!symbols.empty())
195    {
196      if (type) // Expect a single match that is a type-name.
197      {
198	TypeName const *type = dynamic_cast<TypeName const *>(*symbols.begin());
199	if (type)
200	{
201	  std::string filename;
202	  unsigned long line_number = my_buffer.origin(type->ptree()->begin(), filename);
203	  my_os << "declared at line " << line_number << " in " << filename << std::endl;
204	  return;
205	}
206	else my_os << "only non-types found" << std::endl;
207      }
208
209      for (SymbolSet::iterator s = symbols.begin(); s != symbols.end(); ++s)
210      {
211	std::string filename;
212	unsigned long line_number = my_buffer.origin((*s)->ptree()->begin(), filename);
213	my_os << "declared at line " << line_number << " in " << filename << std::endl;
214      }
215    }
216    else
217      my_os << "undeclared ! " << std::endl;
218  }
219
220  Buffer const &my_buffer;
221  std::ostream &my_os;
222  bool          my_in_template_decl;
223};
224
225int main(int argc, char **argv)
226{
227  if (argc < 3)
228  {
229    std::cerr << "Usage: " << argv[0] << " [-d] <output> <input>" << std::endl;
230    exit(-1);
231  }
232  try
233  {
234    std::string output;
235    std::string input;
236    if (argv[1] == std::string("-d"))
237    {
238      Trace::enable(Trace::SYMBOLLOOKUP);
239      output = argv[2];
240      input = argv[3];
241    }
242    else
243    {
244      output = argv[1];
245      input = argv[2];
246    }
247    std::ofstream ofs(output.c_str());
248    std::ifstream ifs(input.c_str());
249    Buffer buffer(ifs.rdbuf(), "<input>");
250    Lexer lexer(&buffer);
251    SymbolFactory symbols;
252    Parser parser(lexer, symbols);
253    PTree::Node *node = parser.parse();
254    const Parser::ErrorList &errors = parser.errors();
255    for (Parser::ErrorList::const_iterator i = errors.begin(); i != errors.end(); ++i)
256      (*i)->write(ofs);
257    if (errors.empty())
258    {
259      SymbolFinder finder(buffer, symbols.current_scope(), ofs);
260      finder.find(node);
261    }
262  }
263  catch (std::exception const &e)
264  {
265    std::cerr << "Caught exception : " << e.what() << std::endl;
266  }
267}