1226586Sdim//=== ClangASTNodesEmitter.cpp - Generate Clang AST node tables -*- C++ -*-===//
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim//
10226586Sdim// These tablegen backends emit Clang AST node tables
11226586Sdim//
12226586Sdim//===----------------------------------------------------------------------===//
13226586Sdim
14245431Sdim#include "llvm/TableGen/Record.h"
15245431Sdim#include "llvm/TableGen/TableGenBackend.h"
16245431Sdim#include <cctype>
17245431Sdim#include <map>
18226586Sdim#include <set>
19245431Sdim#include <string>
20226586Sdimusing namespace llvm;
21226586Sdim
22245431Sdim/// ClangASTNodesEmitter - The top-level class emits .inc files containing
23245431Sdim///  declarations of Clang statements.
24245431Sdim///
25245431Sdimnamespace {
26245431Sdimclass ClangASTNodesEmitter {
27245431Sdim  // A map from a node to each of its derived nodes.
28245431Sdim  typedef std::multimap<Record*, Record*> ChildMap;
29245431Sdim  typedef ChildMap::const_iterator ChildIterator;
30245431Sdim
31245431Sdim  RecordKeeper &Records;
32245431Sdim  Record Root;
33245431Sdim  const std::string &BaseSuffix;
34245431Sdim
35245431Sdim  // Create a macro-ized version of a name
36245431Sdim  static std::string macroName(std::string S) {
37245431Sdim    for (unsigned i = 0; i < S.size(); ++i)
38245431Sdim      S[i] = std::toupper(S[i]);
39245431Sdim
40245431Sdim    return S;
41245431Sdim  }
42245431Sdim
43245431Sdim  // Return the name to be printed in the base field. Normally this is
44245431Sdim  // the record's name plus the base suffix, but if it is the root node and
45245431Sdim  // the suffix is non-empty, it's just the suffix.
46245431Sdim  std::string baseName(Record &R) {
47245431Sdim    if (&R == &Root && !BaseSuffix.empty())
48245431Sdim      return BaseSuffix;
49245431Sdim
50245431Sdim    return R.getName() + BaseSuffix;
51245431Sdim  }
52245431Sdim
53245431Sdim  std::pair<Record *, Record *> EmitNode (const ChildMap &Tree, raw_ostream& OS,
54245431Sdim                                          Record *Base);
55245431Sdimpublic:
56245431Sdim  explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N,
57245431Sdim                                const std::string &S)
58245431Sdim    : Records(R), Root(N, SMLoc(), R), BaseSuffix(S)
59245431Sdim    {}
60245431Sdim
61245431Sdim  // run - Output the .inc file contents
62245431Sdim  void run(raw_ostream &OS);
63245431Sdim};
64245431Sdim} // end anonymous namespace
65245431Sdim
66226586Sdim//===----------------------------------------------------------------------===//
67226586Sdim// Statement Node Tables (.inc file) generation.
68226586Sdim//===----------------------------------------------------------------------===//
69226586Sdim
70226586Sdim// Returns the first and last non-abstract subrecords
71226586Sdim// Called recursively to ensure that nodes remain contiguous
72226586Sdimstd::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode(
73226586Sdim                                                           const ChildMap &Tree,
74226586Sdim                                                           raw_ostream &OS,
75226586Sdim                                                           Record *Base) {
76226586Sdim  std::string BaseName = macroName(Base->getName());
77226586Sdim
78226586Sdim  ChildIterator i = Tree.lower_bound(Base), e = Tree.upper_bound(Base);
79226586Sdim
80226586Sdim  Record *First = 0, *Last = 0;
81226586Sdim  // This might be the pseudo-node for Stmt; don't assume it has an Abstract
82226586Sdim  // bit
83226586Sdim  if (Base->getValue("Abstract") && !Base->getValueAsBit("Abstract"))
84226586Sdim    First = Last = Base;
85226586Sdim
86226586Sdim  for (; i != e; ++i) {
87226586Sdim    Record *R = i->second;
88226586Sdim    bool Abstract = R->getValueAsBit("Abstract");
89226586Sdim    std::string NodeName = macroName(R->getName());
90226586Sdim
91226586Sdim    OS << "#ifndef " << NodeName << "\n";
92226586Sdim    OS << "#  define " << NodeName << "(Type, Base) "
93226586Sdim        << BaseName << "(Type, Base)\n";
94226586Sdim    OS << "#endif\n";
95226586Sdim
96226586Sdim    if (Abstract)
97226586Sdim      OS << "ABSTRACT_" << macroName(Root.getName()) << "(" << NodeName << "("
98226586Sdim          << R->getName() << ", " << baseName(*Base) << "))\n";
99226586Sdim    else
100226586Sdim      OS << NodeName << "(" << R->getName() << ", "
101226586Sdim          << baseName(*Base) << ")\n";
102226586Sdim
103226586Sdim    if (Tree.find(R) != Tree.end()) {
104226586Sdim      const std::pair<Record *, Record *> &Result
105226586Sdim        = EmitNode(Tree, OS, R);
106226586Sdim      if (!First && Result.first)
107226586Sdim        First = Result.first;
108226586Sdim      if (Result.second)
109226586Sdim        Last = Result.second;
110226586Sdim    } else {
111226586Sdim      if (!Abstract) {
112226586Sdim        Last = R;
113226586Sdim
114226586Sdim        if (!First)
115226586Sdim          First = R;
116226586Sdim      }
117226586Sdim    }
118226586Sdim
119226586Sdim    OS << "#undef " << NodeName << "\n\n";
120226586Sdim  }
121226586Sdim
122226586Sdim  if (First) {
123226586Sdim    assert (Last && "Got a first node but not a last node for a range!");
124226586Sdim    if (Base == &Root)
125226586Sdim      OS << "LAST_" << macroName(Root.getName()) << "_RANGE(";
126226586Sdim    else
127226586Sdim      OS << macroName(Root.getName()) << "_RANGE(";
128226586Sdim    OS << Base->getName() << ", " << First->getName() << ", "
129226586Sdim       << Last->getName() << ")\n\n";
130226586Sdim  }
131226586Sdim
132226586Sdim  return std::make_pair(First, Last);
133226586Sdim}
134226586Sdim
135226586Sdimvoid ClangASTNodesEmitter::run(raw_ostream &OS) {
136252723Sdim  emitSourceFileHeader("List of AST nodes of a particular kind", OS);
137252723Sdim
138226586Sdim  // Write the preamble
139226586Sdim  OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n";
140226586Sdim  OS << "#  define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n";
141226586Sdim  OS << "#endif\n";
142226586Sdim
143226586Sdim  OS << "#ifndef " << macroName(Root.getName()) << "_RANGE\n";
144226586Sdim  OS << "#  define "
145226586Sdim     << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
146226586Sdim  OS << "#endif\n\n";
147226586Sdim
148226586Sdim  OS << "#ifndef LAST_" << macroName(Root.getName()) << "_RANGE\n";
149226586Sdim  OS << "#  define LAST_"
150226586Sdim     << macroName(Root.getName()) << "_RANGE(Base, First, Last) "
151226586Sdim     << macroName(Root.getName()) << "_RANGE(Base, First, Last)\n";
152226586Sdim  OS << "#endif\n\n";
153226586Sdim
154226586Sdim  // Emit statements
155226586Sdim  const std::vector<Record*> Stmts
156226586Sdim    = Records.getAllDerivedDefinitions(Root.getName());
157226586Sdim
158226586Sdim  ChildMap Tree;
159226586Sdim
160226586Sdim  for (unsigned i = 0, e = Stmts.size(); i != e; ++i) {
161226586Sdim    Record *R = Stmts[i];
162226586Sdim
163226586Sdim    if (R->getValue("Base"))
164226586Sdim      Tree.insert(std::make_pair(R->getValueAsDef("Base"), R));
165226586Sdim    else
166226586Sdim      Tree.insert(std::make_pair(&Root, R));
167226586Sdim  }
168226586Sdim
169226586Sdim  EmitNode(Tree, OS, &Root);
170226586Sdim
171226586Sdim  OS << "#undef " << macroName(Root.getName()) << "\n";
172226586Sdim  OS << "#undef " << macroName(Root.getName()) << "_RANGE\n";
173226586Sdim  OS << "#undef LAST_" << macroName(Root.getName()) << "_RANGE\n";
174226586Sdim  OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n";
175226586Sdim}
176226586Sdim
177245431Sdimnamespace clang {
178245431Sdimvoid EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
179245431Sdim                       const std::string &N, const std::string &S) {
180245431Sdim  ClangASTNodesEmitter(RK, N, S).run(OS);
181245431Sdim}
182245431Sdim
183245431Sdim// Emits and addendum to a .inc file to enumerate the clang declaration
184245431Sdim// contexts.
185245431Sdimvoid EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
186226586Sdim  // FIXME: Find a .td file format to allow for this to be represented better.
187226586Sdim
188252723Sdim  emitSourceFileHeader("List of AST Decl nodes", OS);
189252723Sdim
190226586Sdim  OS << "#ifndef DECL_CONTEXT\n";
191226586Sdim  OS << "#  define DECL_CONTEXT(DECL)\n";
192226586Sdim  OS << "#endif\n";
193226586Sdim
194226586Sdim  OS << "#ifndef DECL_CONTEXT_BASE\n";
195226586Sdim  OS << "#  define DECL_CONTEXT_BASE(DECL) DECL_CONTEXT(DECL)\n";
196226586Sdim  OS << "#endif\n";
197226586Sdim
198226586Sdim  typedef std::set<Record*> RecordSet;
199226586Sdim  typedef std::vector<Record*> RecordVector;
200226586Sdim
201226586Sdim  RecordVector DeclContextsVector
202226586Sdim    = Records.getAllDerivedDefinitions("DeclContext");
203226586Sdim  RecordVector Decls = Records.getAllDerivedDefinitions("Decl");
204226586Sdim  RecordSet DeclContexts (DeclContextsVector.begin(), DeclContextsVector.end());
205226586Sdim
206226586Sdim  for (RecordVector::iterator i = Decls.begin(), e = Decls.end(); i != e; ++i) {
207226586Sdim    Record *R = *i;
208226586Sdim
209226586Sdim    if (R->getValue("Base")) {
210226586Sdim      Record *B = R->getValueAsDef("Base");
211226586Sdim      if (DeclContexts.find(B) != DeclContexts.end()) {
212226586Sdim        OS << "DECL_CONTEXT_BASE(" << B->getName() << ")\n";
213226586Sdim        DeclContexts.erase(B);
214226586Sdim      }
215226586Sdim    }
216226586Sdim  }
217226586Sdim
218226586Sdim  // To keep identical order, RecordVector may be used
219226586Sdim  // instead of RecordSet.
220226586Sdim  for (RecordVector::iterator
221226586Sdim         i = DeclContextsVector.begin(), e = DeclContextsVector.end();
222226586Sdim       i != e; ++i)
223226586Sdim    if (DeclContexts.find(*i) != DeclContexts.end())
224226586Sdim      OS << "DECL_CONTEXT(" << (*i)->getName() << ")\n";
225226586Sdim
226226586Sdim  OS << "#undef DECL_CONTEXT\n";
227226586Sdim  OS << "#undef DECL_CONTEXT_BASE\n";
228226586Sdim}
229245431Sdim} // end namespace clang
230