#include "debug.hpp"
#include "CgStr.hpp"
#include <cstring>
#include <iostream>
using namespace synth;
static char const kTokenKindChrs[] = "pkilc";
void synth::writeLoc(std::ostream& out, CXSourceLocation loc, CXFile f)
{
CXFile locF;
unsigned lineno, col, off;
clang_getFileLocation(loc, &locF, &lineno, &col, &off);
if (!f || !clang_File_isEqual(f, locF))
out << CgStr(clang_getFileName(locF)) << ':';
out << lineno << ':' << col << '@' << off;
}
static void writeExtentWithLoc(
std::ostream& out, CXSourceRange rng, CXSourceLocation loc, CXFile f)
{
CXSourceLocation beg = clang_getRangeStart(rng);
CXFile begF;
unsigned begLn, begOff;
clang_getFileLocation(beg, &begF, &begLn, nullptr, &begOff);
writeLoc(out, beg, f);
CXFile locF;
unsigned locLn, locOff;
clang_getFileLocation(loc, &locF, &locLn, nullptr, &locOff);
if (!clang_File_isEqual(begF, locF) || begOff != locOff) {
out << '!';
if (!clang_File_isEqual(begF, locF) || begLn != locLn)
writeLoc(out, loc, begF);
else
out << locOff - begOff;
}
CXSourceLocation end = clang_getRangeEnd(rng);
CXFile endF;
unsigned endLn, endOff;
clang_getFileLocation(end, &endF, &endLn, nullptr, &endOff);
if (!clang_File_isEqual(locF, endF) || locLn != endLn) {
out << '-';
writeLoc(out, end, locF);
} else {
out << '+' << endOff - locOff;
}
}
void synth::writeExtent(std::ostream& out, CXSourceRange rng, CXFile f)
{
writeExtentWithLoc(out, rng, clang_getRangeStart(rng), f);
}
void synth::writeToken(std::ostream& out, CXToken tok, CXTranslationUnit tu, CXFile f)
{
out << kTokenKindChrs[clang_getTokenKind(tok)] << ' ';
out << '"' << CgStr(clang_getTokenSpelling(tu, tok)) << "\" ";
CXSourceRange tokExt = clang_getTokenExtent(tu, tok);
writeExtentWithLoc(std::clog, tokExt, clang_getTokenLocation(tu, tok), f);
}
std::ostream& synth::operator<< (std::ostream& out, CXSourceRange rng)
{
writeExtent(out, rng);
return out;
}
static void writeCursor(std::ostream& out, CXCursor c, CXFile f)
{
CXCursorKind k = clang_getCursorKind(c);
if (k == 0)
out << "<bad kind> ";
else
out << CgStr(clang_getCursorKindSpelling(k)) << ' ';
writeExtentWithLoc(
out, clang_getCursorExtent(c), clang_getCursorLocation(c), f);
CgStr dn(clang_getCursorDisplayName(c));
if (!dn.empty())
out << " D:" << dn;
CgStr sp(clang_getCursorSpelling(c));
if (!sp.empty()) {
if (!dn.empty() && !std::strcmp(dn.get(), sp.get()))
out << " S=D";
else
out << " S:" << sp;
}
}
std::ostream& synth::operator<< (std::ostream& out, CXCursor c)
{
writeCursor(out, c, nullptr);
return out;
}
void synth::writeIndent(int ind)
{
for (int i = 0; i < ind; ++i)
std::clog.put(' ');
}
void synth::dumpSingleCursor(CXCursor c, int ind, CXFile f)
{
writeIndent(ind);
writeCursor(std::clog, c, f);
CXCursor refd = clang_getCursorReferenced(c);
if (!clang_Cursor_isNull(refd)) {
if (clang_equalCursors(c, refd)) {
std::clog << " (<-)";
} else {
std::clog << '\n';
writeIndent(ind + 4);
std::clog << "-> ";
writeCursor(std::clog, refd, f);
}
}
std::clog << '\n';
}
static CXChildVisitResult dumpAst(CXCursor c, CXCursor, CXClientData ud)
{
int ind = ud ? *static_cast<int*>(ud) : 0;
dumpSingleCursor(c, ind);
ind += 2;
clang_visitChildren(c, &dumpAst, &ind);
return CXChildVisit_Continue;
}
void synth::dumpAst(CXCursor c, int ind)
{
dumpSingleCursor(c, ind);
ind += 2;
clang_visitChildren(c, &::dumpAst, &ind);
}