#include "ASTTableGen.h"
#include "TableGenBackends.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <set>
#include <string>
#include <vector>
using namespace llvm;
using namespace clang;
using namespace clang::tblgen;
#define TypeMacroName "TYPE"
#define AbstractTypeMacroName "ABSTRACT_TYPE"
#define DependentTypeMacroName "DEPENDENT_TYPE"
#define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE"
#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE"
#define TypeMacroArgs "(Class, Base)"
#define LastTypeMacroName "LAST_TYPE"
#define LeafTypeMacroName "LEAF_TYPE"
#define TypeClassName "Type"
namespace {
class TypeNodeEmitter {
RecordKeeper &Records;
raw_ostream &Out;
const std::vector<Record*> Types;
std::vector<StringRef> MacrosToUndef;
public:
TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
: Records(records), Out(out),
Types(Records.getAllDerivedDefinitions(TypeNodeClassName)) {
}
void emit();
private:
void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
StringRef args);
void emitNodeInvocations();
void emitLastNodeInvocation(TypeNode lastType);
void emitLeafNodeInvocations();
void addMacroToUndef(StringRef macroName);
void emitUndefs();
};
}
void TypeNodeEmitter::emit() {
if (Types.empty())
PrintFatalError("no Type records in input!");
emitSourceFileHeader("An x-macro database of Clang type nodes", Out);
addMacroToUndef(TypeMacroName);
addMacroToUndef(AbstractTypeMacroName);
emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs);
emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs);
emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs);
emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName,
TypeMacroArgs);
emitNodeInvocations();
emitLeafNodeInvocations();
emitUndefs();
}
void TypeNodeEmitter::emitFallbackDefine(StringRef macroName,
StringRef fallbackMacroName,
StringRef args) {
Out << "#ifndef " << macroName << "\n";
Out << "# define " << macroName << args
<< " " << fallbackMacroName << args << "\n";
Out << "#endif\n";
addMacroToUndef(macroName);
}
void TypeNodeEmitter::emitNodeInvocations() {
TypeNode lastType;
visitASTNodeHierarchy<TypeNode>(Records, [&](TypeNode type, TypeNode base) {
if (!base) return;
StringRef macroName;
auto setMacroName = [&](StringRef newName) {
if (!macroName.empty())
PrintFatalError(type.getLoc(),
Twine("conflict when computing macro name for "
"Type node: trying to use both \"")
+ macroName + "\" and \"" + newName + "\"");
macroName = newName;
};
if (type.isSubClassOf(AlwaysDependentClassName))
setMacroName(DependentTypeMacroName);
if (type.isSubClassOf(NeverCanonicalClassName))
setMacroName(NonCanonicalTypeMacroName);
if (type.isSubClassOf(NeverCanonicalUnlessDependentClassName))
setMacroName(NonCanonicalUnlessDependentTypeMacroName);
if (type.isAbstract())
setMacroName(AbstractTypeMacroName);
if (macroName.empty())
macroName = TypeMacroName;
Out << macroName << "(" << type.getId() << ", "
<< base.getClassName() << ")\n";
lastType = type;
});
emitLastNodeInvocation(lastType);
}
void TypeNodeEmitter::emitLastNodeInvocation(TypeNode type) {
Out << "#ifdef " LastTypeMacroName "\n"
LastTypeMacroName "(" << type.getId() << ")\n"
"#undef " LastTypeMacroName "\n"
"#endif\n";
}
void TypeNodeEmitter::emitLeafNodeInvocations() {
Out << "#ifdef " LeafTypeMacroName "\n";
for (TypeNode type : Types) {
if (!type.isSubClassOf(LeafTypeClassName)) continue;
Out << LeafTypeMacroName "(" << type.getId() << ")\n";
}
Out << "#undef " LeafTypeMacroName "\n"
"#endif\n";
}
void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
MacrosToUndef.push_back(macroName);
}
void TypeNodeEmitter::emitUndefs() {
for (auto ¯oName : MacrosToUndef) {
Out << "#undef " << macroName << "\n";
}
}
void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
TypeNodeEmitter(records, out).emit();
}