1. binet
  2. cylon

Commits

Sebastien Binet  committed 0dc9f3a

first import of a messy clang plugin

  • Participants
  • Parent commits 88243d0
  • Branches default

Comments (0)

Files changed (4)

File ext/clang/genjson/Makefile

View file
  • Ignore whitespace
+CXX=g++
+#CXX=clang++
+LLVMHOME=/usr
+LLVMCONFIG=$(LLVMHOME)/bin/llvm-config
+CXXFLAGS=-I$(LLVMHOME)/include/clang \
+		 `$(LLVMCONFIG) --cxxflags` -shared -fPIC
+
+LDFLAGS= `$(LLVMCONFIG) --ldflags` -shared -fPIC
+
+#LLVM_LIBS=`$(LLVM_CONFIG) --libs`
+LLVM_LIBS=-L/usr/lib/llvm -lLLVM-2.7
+
+# CLANG_LIBS= \
+# 	-lclangCodeGen -lclangAnalysis -lclangRewrite -lclangSema \
+# 	-lclangDriver  -lclangAST      -lclangParse   -lclangLex  \
+# 	-lclangBasic   -lclangFrontend -lclangIndex   -lclangIndex \
+# 	-lclangLex
+CLANG_LIBS= \
+	-lclangCodeGen  -lclangRewrite  -lclangLex    -lclangBasic \
+    -lclangIndex    -lclangFrontend -lclangDriver -lclangSema \
+	-lclangAnalysis -lclangAST      -lclangParse  -lclangLex  \
+	-lclangBasic
+
+LIBS= $(LLVM_LIBS) $(CLANG_LIBS)
+
+all: clean libclang_genjson.so test
+
+clean:
+	rm -rf libclang_genjson.so
+
+libclang_genjson.so: clang_genjson.cpp
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) -o libclang_genjson.so clang_genjson.cpp $(LIBS)
+
+.PHONY: test clean
+
+test: libclang_genjson.so
+	/bin/rm -f utest_ast.py
+	./run.py utest.cxx

File ext/clang/genjson/clang_genjson.cpp

View file
  • Ignore whitespace
+// -*- c++ -*-
+// a CLang plugin inspecting a translation unit and dumping its AST 
+// representation into a python file
+// @author Sebastien Binet
+//
+// ---------------------------------------------
+// TODO: 
+//   - clean-up
+//   - re-factorize a-la PrinterXML or Cursor
+//   - handle the U, UL, ULL integer literals
+//   - extensive unit-tests
+// ---------------------------------------------
+
+#include "llvm/Config/config.h"
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Format.h"
+#include "llvm/System/Path.h"
+
+using namespace clang;
+
+static QualType get_base_type(QualType T) {
+  // FIXME: This should be on the Type class!
+  QualType BaseType = T;
+  while (!BaseType->isSpecifierType()) {
+    if (isa<TypedefType>(BaseType))
+      break;
+    else if (const PointerType* PTy = BaseType->getAs<PointerType>())
+      BaseType = PTy->getPointeeType();
+    else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
+      BaseType = ATy->getElementType();
+    else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
+      BaseType = FTy->getResultType();
+    else if (const VectorType *VTy = BaseType->getAs<VectorType>())
+      BaseType = VTy->getElementType();
+    else
+      assert(0 && "Unknown declarator!");
+  }
+  return BaseType;
+}
+
+static QualType get_decl_type(Decl* D) {
+  if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D))
+    return TDD->getUnderlyingType();
+  if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
+    return VD->getType();
+  return QualType();
+}
+
+namespace {
+
+  class JsonVisitor 
+    : public clang::DeclVisitor< ::JsonVisitor >,
+      public clang::StmtVisitor< ::JsonVisitor >
+  {
+    //std::string m_json_err_info;
+    //llvm::raw_fd_ostream m_js;
+    llvm::raw_ostream &m_js;
+    llvm::raw_ostream &m_out;
+    clang::ASTContext &m_ast_ctx;
+    clang::PrintingPolicy m_policy;
+    unsigned m_indent;
+
+    bool m_dump_fct_body;
+
+    using clang::DeclVisitor< ::JsonVisitor >::Visit;
+    using clang::StmtVisitor< ::JsonVisitor >::Visit;
+
+    void process_access_specifier(AccessSpecifier as)
+    {
+      switch(as) {
+      case AS_none:      assert(0 && "No access specifier!"); break;
+      case AS_public:    
+        m_out << "public"; 
+        m_js << "\"access\": \"public\",\n";
+        break;
+      case AS_protected: 
+        m_out << "protected"; 
+        m_js << "\"access\": \"protected\",\n";
+        break;
+      case AS_private:   
+        m_out << "private"; 
+        m_js << "\"access\": \"private\",\n";
+        break;
+      }
+    }
+
+    llvm::raw_ostream& 
+    indent() 
+    { return this->indent(m_indent); }
+
+    llvm::raw_ostream& 
+    indent(unsigned indentation)
+    {
+      for (unsigned i = 0; i != indentation; ++i) {
+        m_out << "  ";
+      }
+      return m_out;
+    }
+
+    void
+    process_declgrp(llvm::SmallVectorImpl<Decl*>& decls)
+    {
+      this->indent();
+      this->process_grp(decls.data(), decls.size(), m_out, m_policy, m_indent);
+      m_out << ";\n";
+      decls.clear();
+    }  
+
+    void
+    process_grp(Decl **begin, unsigned ndecls,
+                llvm::raw_ostream &out,
+                const PrintingPolicy &policy,
+                unsigned indentation)
+    {
+      if (ndecls == 1) {
+        //(*begin)->print(out, policy, indentation);
+        this->Visit(*begin);
+        return;
+      }
+      m_js << "\"decl-kind\": \"" << (*begin)->getDeclKindName() << "\",\n";
+      Decl** end = begin + ndecls;
+      TagDecl *td = dyn_cast<TagDecl>(*begin);
+      if (td) {
+        ++begin;
+      }
+
+      PrintingPolicy sub_policy = policy;
+      if (td && td->isDefinition()) {
+        td->print(out, policy, indentation);
+        out << " ";
+        sub_policy.SuppressTag = true;
+      }
+
+      bool is_first = true;
+      for ( ; begin != end; ++begin) {
+        if (is_first) {
+          sub_policy.SuppressSpecifiers = false;
+          is_first = false;
+        } else {
+          if (!is_first) out << ", ";
+          sub_policy.SuppressSpecifiers = true;
+        }
+        (*begin)->print(out, sub_policy, indentation);
+      }
+    }
+
+    void
+    process_expr(Expr *e)
+    {
+      if (e) {
+        this->Visit(e);
+      } else {
+        m_out << "<<<NULL EXPR>>>";
+      }
+    }
+    void
+    process_expr(Expr *e, llvm::raw_ostream &out, ASTContext &ctx,
+                 PrinterHelper *helper,
+                 const PrintingPolicy &policy,
+                 unsigned indentation = 0)
+    {
+      //e->printPretty(out, ctx, helper, policy, indentation);
+
+      //m_out << " @expr: [" << e->getStmtClassName() << "] ";
+      this->process_expr(e);
+    }
+
+    void
+    process_stmt(Stmt *s)
+    {
+      this->process_stmt(s, m_policy.Indentation);
+    }
+    void
+    process_stmt(Stmt *s, unsigned indent)
+    {
+      //llvm::errs() << "*********************************\n";
+      m_indent += indent;
+      if (s && isa<Expr>(s)) {
+        // if this is an expr used in a stmt context, indent and newline it
+        this->indent();
+        this->Visit(s);
+        m_out << ";\n";
+      } else if (s) {
+        this->Visit(s);
+      } else {
+        this->indent() << "<<<NULL STATEMENT>>>\n";
+      }
+      m_indent -= indent;
+    }
+
+    void
+    process_stmt(Stmt *s, llvm::raw_ostream &out, ASTContext &ctx,
+                 PrinterHelper *helper,
+                 const PrintingPolicy &policy,
+                 unsigned indentation = 0)
+    {
+      //s->printPretty(out, ctx, helper, policy, indentation);
+      //this->Visit(s);
+      this->process_stmt(s, indentation);
+
+      //this->indent();
+      //m_out << "(" << s->getStmtClassName() << ")";
+    }
+
+    void
+    process_qualifier(QualType* q, 
+                      llvm::raw_ostream &out, 
+                      const PrintingPolicy& policy)
+    {
+      //q->print(out, policy);
+      out << "[[" << q->getAsString() << "]]";
+    }
+
+    void
+    process_qualifier(NestedNameSpecifier *spec,
+                      llvm::raw_ostream &out, 
+                      const PrintingPolicy& policy)
+    {
+      out << "***************************************\n";
+      std::string qual;
+      llvm::raw_string_ostream buf(qual);
+      spec->print(buf, policy);
+      buf.flush();
+      out << qual;
+      m_js << "\"" << qual << "\"";
+    }
+    
+    void
+    dump_expr(Expr *e)
+    {
+      this->dump_stmt(e);
+      m_out << ' ';
+      this->dump_type(e->getType());
+    }
+
+    void
+    dump_stmt(const Stmt *node)
+    {
+      this->indent();
+      m_out << "(" << node->getStmtClassName()
+            << " " << (void*)node;
+    }
+
+    void
+    dump_type(QualType t)
+    {
+      m_out << "*********** dump-type ****************************\n";
+      m_out << "'" << t.getAsString() << "'";
+      
+      if (!t.isNull()) {
+        // If the type is sugared, also dump a (shallow) desugared type.
+        QualType simplified = t.getDesugaredType();
+        if (simplified != t) {
+          m_out << ":'" << simplified.getAsString() << "'";
+        }
+      }
+    }
+
+  public:
+    /*
+    JsonVisitor(llvm::raw_ostream &out,
+                clang::ASTContext &ctx,
+                const clang::PrintingPolicy &policy,
+                unsigned indentation = 0,
+                bool dump_fct_body = false) :
+      m_json_err_info(),
+      m_js("data.json", m_json_err_info, 
+           llvm::raw_fd_ostream::F_Append),
+      m_out(out),
+      m_ast_ctx(ctx),
+      m_policy(policy),
+      m_indent(indentation),
+      m_dump_fct_body(dump_fct_body)
+    {
+      //m_out << "===> json-visitor <===\n";
+      m_js << "# -*- python -*-\n"
+           << "ast = \\\n";
+    }
+    */
+
+    JsonVisitor(llvm::raw_ostream &out,
+                llvm::raw_ostream &js,
+                clang::ASTContext &ctx,
+                const clang::PrintingPolicy &policy,
+                unsigned indentation = 0,
+                bool dump_fct_body = false) :
+      m_js(js),
+      m_out(out),
+      m_ast_ctx(ctx),
+      m_policy(policy),
+      m_indent(indentation),
+      m_dump_fct_body(dump_fct_body)
+    {
+      //m_out << "===> json-visitor <===\n";
+    }
+
+    void do_visit(Decl* D) 
+    { this->Visit(D); }
+
+    // declaration visitors
+    void VisitDeclContext(DeclContext *DC, bool Indent = true);
+
+    void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+    void VisitTypedefDecl(TypedefDecl *D);
+    void VisitEnumDecl(EnumDecl *D);
+    void VisitRecordDecl(RecordDecl *D);
+    void VisitEnumConstantDecl(EnumConstantDecl *D);
+    void VisitFunctionDecl(FunctionDecl *D);
+    void VisitFieldDecl(FieldDecl *D);
+    void VisitVarDecl(VarDecl *D);
+    void VisitParmVarDecl(ParmVarDecl *D);
+    void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+    void VisitNamespaceDecl(NamespaceDecl *D);
+    void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+    void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+    void VisitCXXRecordDecl(CXXRecordDecl *D);
+    void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+    void VisitTemplateDecl(TemplateDecl *D);
+    void VisitObjCMethodDecl(ObjCMethodDecl *D);
+    void VisitObjCClassDecl(ObjCClassDecl *D);
+    void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+    void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+    void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+    void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+    void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+    void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+    void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+    void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+    void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+    void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+    void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+    void VisitUsingDecl(UsingDecl *D);
+    void VisitUsingShadowDecl(UsingShadowDecl *D);
+    
+    // statement visitors
+    //void VisitStmt(Stmt *S);
+    void VisitDeclStmt(DeclStmt *S);
+    void VisitCompoundStmt(CompoundStmt *node);
+    // FIXME: LabelStmt label?
+    // void VisitIfStmt(IfStmt *) {}
+    // void VisitSwitchStmt(SwitchStmt *) {}
+    // void VisitWhileStmt(WhileStmt *) {}
+    // void VisitForStmt(ForStmt *) {}
+    // void VisitExpr(Expr *node)
+    // {
+    //   //m_out << "<<<UNKNOWN EXPR TYPE>>>";
+    //   this->dump_expr(node);
+    // }
+    void VisitDeclRefExpr(DeclRefExpr *node);
+    void VisitCharacterLiteral(CharacterLiteral *node);
+    void VisitIntegerLiteral(IntegerLiteral *node);
+    void VisitFloatingLiteral(FloatingLiteral *node);
+    void VisitImaginaryLiteral(ImaginaryLiteral *node);
+    void VisitStringLiteral(StringLiteral *node);
+    void VisitUnaryOperator(UnaryOperator *node);
+    void VisitImplicitCastExpr(ImplicitCastExpr *node);
+
+  };
+
+  class ASTPrinterJson : public clang::ASTConsumer
+  {
+    llvm::StringRef m_ifname;
+    llvm::raw_ostream &m_out;
+  public:
+
+    ASTPrinterJson(llvm::StringRef ifname,
+                   llvm::raw_ostream *o = NULL) :
+      m_ifname(ifname),
+      m_out(o ? *o : llvm::nulls())
+    {}
+
+    // void Initialize(clang::ASTContext &ctx)
+    // {
+    //   ctx.dump();
+    // }
+
+    virtual
+    void
+    HandleTranslationUnit(clang::ASTContext &ctx)
+    {
+#if 1
+      //clang::PrintingPolicy policy = ctx.PrintingPolicy;
+      clang::TranslationUnitDecl *tu = ctx.getTranslationUnitDecl();
+      assert(tu);
+      //tu->dump();
+      std::string basename = llvm::sys::Path(m_ifname).getBasename().str();
+      const std::string fname = basename + std::string("_ast.py");
+      if (0) {
+        typedef clang::TranslationUnitDecl::decl_iterator decl_iterator;
+        for (decl_iterator 
+               decl_itr = tu->decls_begin(), 
+               decl_end = tu->decls_end();
+             decl_itr != decl_end;
+             ++decl_itr) {
+          m_out << "\n=================[" << decl_itr->getDeclKindName()
+                << "]========\n";
+          //decl_itr->print(m_out);
+          std::string js_error;
+          llvm::raw_fd_ostream js(fname.c_str(), js_error,
+                                  llvm::raw_fd_ostream::F_Append);
+          js << "# -*- python -*-\n"
+             << "ast = \\\n";
+          JsonVisitor v(m_out, js, ctx, ctx.PrintingPolicy);
+          v.do_visit(*decl_itr);
+        }
+      } else {
+          std::string js_error;
+          llvm::raw_fd_ostream js(fname.c_str(), js_error,
+                                  llvm::raw_fd_ostream::F_Append);
+          js << "# -*- python -*-\n"
+             << "ast = \\\n";
+          JsonVisitor v(m_out, js, ctx, ctx.PrintingPolicy);
+          v.do_visit(tu);
+      }
+#endif
+
+#if 0
+      const std::vector<clang::Type*>& types = ctx.getTypes();
+      m_out << "types: " << types.size() << "\n";
+      for (std::size_t i = 0, imax = types.size(); i != imax; ++i) {
+        const clang::Type& t = *types[i];
+        m_out << " ====[" << t.getTypeClassName() << "]====>\n";
+        //t.dump();
+        m_out << " ---\n";
+        clang::QualType qty = t.getCanonicalTypeInternal();
+        m_out << " [" << qty.getAsString() << "]\n";
+        m_out << " <===========\n";
+      }
+#endif
+      //clang::DeclarationNameTable& dnt = ctx.DeclarationNames;
+    }
+    
+  };
+
+  class JsonPrinterAction : public ASTFrontendAction {
+  protected:
+    ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 
+                                   llvm::StringRef input_file) {
+      //llvm::errs() << "===> input_file: [" << input_file << "]\n";
+      return new ASTPrinterJson(input_file);
+    }
+  };
+
+  void
+  JsonVisitor::VisitDeclContext(DeclContext *DC, bool Indent)
+  {
+    this->indent() << "---[decl-ctx]---\n";
+    if (Indent)
+      m_indent += m_policy.Indentation;
+    m_js << "[ # decl-ctx\n";
+
+    bool PrintAccess = isa<CXXRecordDecl>(DC);
+    AccessSpecifier CurAS = AS_none;
+    
+    llvm::SmallVector<Decl*, 2> Decls;
+    for (DeclContext::decl_iterator 
+           D    = DC->decls_begin(), 
+           DEnd = DC->decls_end();
+         D != DEnd;
+         ++D) {
+      if (!m_policy.Dump) {
+        // Skip over implicit declarations in pretty-printing mode.
+        if (D->isImplicit()) continue;
+        // FIXME: Ugly hack so we don't pretty-print the builtin declaration
+        // of __builtin_va_list.  There should be some other way to check that.
+        if (isa<NamedDecl>(*D)) {
+          const std::string nd = cast<NamedDecl>(*D)->getNameAsString();
+          if (nd == "__builtin_va_list" ||
+              nd == "__int128_t" ||
+              nd == "__uint128_t" ||
+              nd == "__va_list_tag") {
+            continue;
+          }
+        }
+      }
+      
+      if (PrintAccess) {
+        AccessSpecifier AS = D->getAccess();
+        
+        if (AS != CurAS) {
+          if (Indent)
+            this->indent(m_indent - m_policy.Indentation);
+          switch(AS) {
+          case AS_none:      assert(0 && "No access specifier!"); break;
+          case AS_public:     m_out << "public";        break;
+          case AS_protected:  m_out << "protected";     break;
+          case AS_private:    m_out << "private";       break;
+          }
+          m_out << ":\n";
+          CurAS = AS;
+        }
+      }
+
+      // The next bits of code handles stuff like "struct {int x;} a,b"; we're
+      // forced to merge the declarations because there's no other way to
+      // refer to the struct in question.  This limited merging is safe without
+      // a bunch of other checks because it only merges declarations directly
+      // referring to the tag, not typedefs.
+      //
+      // Check whether the current declaration should be grouped with a previous
+      // unnamed struct.
+      QualType CurDeclType = get_decl_type(*D);
+      if (!Decls.empty() && !CurDeclType.isNull()) {
+        QualType BaseType = get_base_type(CurDeclType);
+        if (!BaseType.isNull() && isa<TagType>(BaseType) &&
+            cast<TagType>(BaseType)->getDecl() == Decls[0]) {
+          Decls.push_back(*D);
+          continue;
+        }
+      }
+
+      // If we have a merged group waiting to be handled, handle it now.
+      if (!Decls.empty()) {
+        this->process_declgrp(Decls);
+      }
+
+      // If the current declaration is an unnamed tag type, save it
+      // so we can merge it with the subsequent declaration(s) using it.
+      if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) {
+        Decls.push_back(*D);
+        continue;
+      }
+      this->indent();
+      Visit(*D);
+
+      const char *Terminator = 0;
+      if (isa<FunctionDecl>(*D) &&
+          cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) {
+        Terminator = 0;
+      }
+      else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) {
+        Terminator = 0;
+      }
+      else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
+               isa<ObjCImplementationDecl>(*D) ||
+               isa<ObjCInterfaceDecl>(*D) ||
+               isa<ObjCProtocolDecl>(*D) ||
+               isa<ObjCCategoryImplDecl>(*D) ||
+               isa<ObjCCategoryDecl>(*D)) {
+        Terminator = 0;
+      }
+      else if (isa<EnumConstantDecl>(*D)) {
+        DeclContext::decl_iterator Next = D;
+        ++Next;
+        if (Next != DEnd) {
+          Terminator = ",";
+        }
+      } else {
+        Terminator = ";";
+      }
+
+      if (Terminator) {
+        m_out << Terminator;
+      }
+      m_out << "\n";
+
+    } // loop over decl-contexts
+
+    if (!Decls.empty()) {
+      this->process_declgrp(Decls);
+    }
+
+    if (m_indent) {
+      m_indent -= m_policy.Indentation;
+    }
+    m_js << "], # decl-ctx\n";
+  }
+
+  void 
+  JsonVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *d)
+  {
+    this->indent() << "---[tu-decl]---\n";
+    ASTContext& ctx = d->getASTContext();
+    SourceLocation src_loc = d->getLocation();
+    const char* kind_name = ((const Decl*)d)->getDeclKindName();
+    m_js << "{\n"
+         << "\"name\": \"" << ctx.getSourceManager().getBufferName(src_loc)
+         << "\",\n"
+         << "\"decl-kind\": \"" << kind_name << "\",\n"
+         << "\"fields\": ";
+    this->VisitDeclContext(d, false);
+    m_js << "} # translation-unit\n";
+  }
+
+  void 
+  JsonVisitor::VisitTypedefDecl(TypedefDecl *d)
+  {
+    this->indent() << "---[typedef-decl]---\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << d->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n";
+    std::string s = d->getNameAsString();
+    m_js << "\"type\": \"" 
+         << d->getUnderlyingType().getAsString() << "\",\n"
+         << "}, # typedef\n";
+    d->getUnderlyingType().getAsStringInternal(s, m_policy);
+    if (!m_policy.SuppressSpecifiers) {
+      m_out << "typedef ";
+    }
+    m_out << s;
+  }
+
+  void
+  JsonVisitor::VisitEnumDecl(EnumDecl *d) 
+  {
+    this->indent() << "---[enum-decl]---\n";
+    m_out << "enum " << d->getNameAsString() << " {\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"fields\": [\n";
+    this->VisitDeclContext(d);
+    m_js << "],\n";
+    m_js << "},\n";
+    this->indent() << "}";
+  }
+    
+  void
+  JsonVisitor::VisitRecordDecl(RecordDecl *d)
+  {
+    this->indent() << "---[record-decl]---\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"kind\": \"" << d->getKindName() << "\",\n";
+    m_out << d->getKindName();
+    std::string identifier = "None";
+    if (d->getIdentifier()) {
+      m_out << " ";
+      m_out << d->getNameAsString();
+      m_js << "\"identifier\": \"" << d->getNameAsString() << "\",\n";
+    } else {
+      m_js << "\"identifier\": None,n";
+    }
+
+    if (d->isDefinition()) {
+      m_out << " {\n";
+      m_js << "\"fields\": [\n";
+      this->VisitDeclContext(d);
+      m_js << "], # record-fields\n";
+      this->indent() << "}";
+    }
+    m_js << "},\n";
+  }
+
+  void
+  JsonVisitor::VisitEnumConstantDecl(EnumConstantDecl *d)
+  {
+    this->indent() << "---[enum-constant-decl]---\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"type\": \"" << d->getType().getAsString() << "\",\n";
+    m_out << d->getNameAsString();
+    if (Expr *init = d->getInitExpr()) {
+      m_out << " = ";
+      //init->printPretty(m_out, m_ast_ctx, 0, m_policy, m_indent);
+      m_js << "\"init\": ";
+      this->Visit(init);
+      //m_js << ",\n";
+    } else {
+      m_js << "\"init\": None,\n";
+    }
+    m_js << "},\n";
+  }
+    
+  void
+  JsonVisitor::VisitFunctionDecl(FunctionDecl *d)
+  {
+    this->indent() << "---[fct-decl]---\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"type\": \"" << d->getType().getAsString() << "\",\n"
+         << "\"specifiers\": [";
+    if (!m_policy.SuppressSpecifiers) {
+      switch (d->getStorageClass()) {
+      case FunctionDecl::None: break;
+      case FunctionDecl::Extern: 
+        m_out << "extern "; 
+        m_js << "\"extern\", ";
+        break;
+      case FunctionDecl::Static: 
+        m_out << "static "; 
+        m_js << "\"static\", ";
+        break;
+      case FunctionDecl::PrivateExtern: 
+        m_out << "__private_extern__ "; 
+        m_js << "\"__private_extern__\", ";
+        break;
+      }
+
+      if (d->isInlineSpecified()) {
+        m_out << "inline ";
+        m_js << "\"inline\", ";
+      }
+      if (d->isVirtualAsWritten()) {
+        m_out << "virtual ";
+        m_js << "\"virtual\", ";
+      }
+    }
+    m_js << "], # fct-specifiers\n";
+
+    PrintingPolicy sub_policy = m_policy;
+    sub_policy.SuppressSpecifiers = false;
+    std::string proto = d->getNameAsString();
+    // llvm::errs() << "proto=[" << proto << "]\n";
+    if (isa<FunctionType>(d->getType().getTypePtr())) {
+      const FunctionType *aft = d->getType()->getAs<FunctionType>();
+      const FunctionProtoType *ft = 0;
+      if (d->hasWrittenPrototype()) {
+        ft = dyn_cast<FunctionProtoType>(aft);
+      }
+      if (ft) {
+        m_js << "\"is-variadic\": " << (ft->isVariadic() ? "True" : "False")
+             << ",\n";
+      }
+      m_js << "\"args\": [ ";
+      proto += "(";
+      {
+        std::string args_buf;
+        llvm::raw_string_ostream args_str(args_buf);
+        JsonVisitor args_printer(llvm::nulls(), args_str,
+                                 m_ast_ctx, sub_policy, m_indent);
+        llvm::raw_string_ostream pout(proto);
+        JsonVisitor proto_printer
+          (pout, llvm::nulls(),
+           m_ast_ctx, sub_policy, m_indent);
+        if (ft) {
+          for (unsigned i = 0, e = d->getNumParams(); i != e; ++i) {
+            if (i) pout << ", ";
+            proto_printer.VisitParmVarDecl(d->getParamDecl(i));
+            args_printer.VisitParmVarDecl(d->getParamDecl(i));
+            //this->VisitParmVarDecl(d->getParamDecl(i));
+          }
+          
+          if (ft->isVariadic()) {
+            if (d->getNumParams()) pout << ", ";
+            pout << "...";
+          }
+        } else if (d->isThisDeclarationADefinition() && !d->hasPrototype()) {
+          for (unsigned i = 0, e = d->getNumParams(); i != e; ++i) {
+            if (i) pout << ", ";
+            //pout << d->getParamDecl(i)->getNameAsString();
+            proto_printer.VisitParmVarDecl(d->getParamDecl(i));
+            args_printer.VisitParmVarDecl(d->getParamDecl(i));
+           //this->VisitParmVarDecl(d->getParamDecl(i));
+          }
+        }
+        args_str.flush();
+        m_js << args_buf;
+      }
+      m_js << "], # args\n";
+      proto += ")";
+      
+      if (ft && ft->hasExceptionSpec()) {
+        m_js << "\"throws\": ";
+        proto += " throw(";
+        if (ft->hasAnyExceptionSpec()) {
+          proto += "...";
+          m_js << "\"...\"";
+        } else {
+          for (unsigned i =0, n = ft->getNumExceptions(); i != n; ++i) {
+            if (i) proto += ", ";
+            std::string exception_type;
+            ft->getExceptionType(i).getAsStringInternal(exception_type,
+                                                        sub_policy);
+            proto += exception_type;
+            m_js << "\"" << exception_type << "\"";
+          }
+        }
+        proto += ")";
+        m_js << ",\n";
+      } // has-exception-spec
+
+      if (d->hasAttr<NoReturnAttr>()) {
+        proto += " __attribute__((noreturn))";
+        m_js << "\"attribute\": [ \"noreturn\", ],\n";
+      }
+      m_js << "\"prototype\": \"";
+      m_js.write_escaped(proto);
+      m_js << "\",\n";
+
+      AccessSpecifier fct_spec = d->getAccess();
+      if (fct_spec != AS_none) {
+        this->process_access_specifier(fct_spec);
+        m_out << " ";
+      }
+
+      {
+        std::string is_virtual = "None";
+        std::string is_instance = "None";
+        if (CXXMethodDecl *cdecl = dyn_cast<CXXMethodDecl>(d)) {
+          is_instance= (cdecl->isInstance() ? "True" : "False");
+          is_virtual= (cdecl->isVirtual() ? "True": "False");
+        } // is a cxx method
+        m_js << "\"is-virtual\": " << is_virtual << ",\n"
+             << "\"is-instance\": " << is_instance << ",\n";
+      }
+
+      std::string is_ctor = "False";
+      std::string is_dtor = "False";
+      std::string is_cnv  = "False";
+      std::string return_type = "";
+      if (CXXConstructorDecl *cdecl = dyn_cast<CXXConstructorDecl>(d)) {
+        is_ctor = "True";
+      } // is cxx-constructor
+      else if (CXXDestructorDecl *cdecl = dyn_cast<CXXDestructorDecl>(d)) {
+        is_dtor = "True";
+      } // is cxx-dtor
+      else if (CXXConversionDecl *cdecl = dyn_cast<CXXConversionDecl>(d)) {
+        is_cnv = "True";
+      } // is conversion operator
+      else {
+        aft->getResultType().getAsStringInternal(proto, m_policy);
+        aft->getResultType().getAsStringInternal(return_type, m_policy);
+      }
+      m_js << "\"is-dtor\": " << is_dtor << ",\n"
+           << "\"is-ctor\": " << is_ctor << ",\n"
+           << "\"is-cnv\": "  << is_cnv << ",\n"
+           << "\"return-type\": \"" << return_type << "\",\n";
+    } else {
+      d->getType().getAsStringInternal(proto, m_policy);
+      std::string json_type;
+      d->getType().getAsStringInternal(json_type, m_policy);
+      m_js << "\"type\": \"" << json_type << "\",\n";
+    }
+
+    m_out << proto;
+
+    std::string is_pure = "False";
+    std::string is_deleted = "False";
+
+    if (d->isPure()) {
+      m_out << " = 0";
+      is_pure = "True";
+    } else if (d->isDeleted()) {
+      m_out << " = delete";
+      is_deleted = "True";
+    } else if (d->isThisDeclarationADefinition()) {
+      if (!d->hasPrototype() && d->getNumParams()) {
+        // This is a K&R function definition, so we need to print the
+        // parameters.
+        m_out << '\n';
+        //JsonVisitor params_printer(m_out, m_ast_ctx, sub_policy, m_indent);
+        m_indent += m_policy.Indentation;
+        m_js << "\"K&R-fct\": [ ";
+        for (unsigned i = 0, e = d->getNumParams(); i != e; ++i) {
+          this->indent();
+          //params_printer.VisitParmVarDecl(d->getParamDecl(i));
+          this->VisitParmVarDecl(d->getParamDecl(i));
+          m_out << ";\n";
+        }
+        m_indent -= m_policy.Indentation;
+        m_js << "],\n";
+      } else {
+        m_out << ' ';
+      }
+      
+      if (m_dump_fct_body) {
+        m_js << "\"fct-body\": {\n";
+        this->process_stmt(d->getBody(), m_out, m_ast_ctx,
+                           0, sub_policy, m_indent);
+        m_js << "},\n";
+      }
+      m_out << '\n';
+    }
+    // const DeclContext *sema_dc = d->getDeclContext();
+    // const DeclContext *lexical_dc = d->getLexicalDeclContext();
+    // if (sema_dc != lexical_dc) {
+    //   m_out << " [[[filter-out]]]\n";
+    // } else {
+    //   m_out << " [[[keep-it]]]\n";
+    // }
+    m_js << "},\n";
+  }
+
+  void
+  JsonVisitor::VisitFieldDecl(FieldDecl *d)
+  {
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"specifiers\": {\n";
+    if (!m_policy.SuppressSpecifiers) {
+      AccessSpecifier field_spec = d->getAccess();
+      if (field_spec != AS_none) {
+        this->process_access_specifier(field_spec);
+      }
+      m_out << " ";
+
+      m_js << "\"is-mutable\": ";
+      if (d->isMutable()) {
+        m_out << "mutable ";
+        m_js << "True";
+      } else {
+        m_js << "False";
+      }
+      m_js << ",\n";
+    }
+    m_js << "}, # field-specifiers\n";
+
+    std::string name = d->getNameAsString();
+    m_js << "\"name\": \"" << name << "\",\n";
+    m_js << "\"type\": \"" << d->getType().getAsString() << "\",\n";
+    d->getType().getAsStringInternal(name, m_policy);
+    m_out << name;
+
+    if (d->isBitField()) {
+      m_js << "\"is-bitfield\": True,\n"
+           << "\"bit-width\": ";
+      m_out << " : ";
+      this->process_expr(d->getBitWidth(), m_out, m_ast_ctx,
+                         0, m_policy, m_indent);
+    }
+    m_js << "},\n";
+  }
+
+  void
+  JsonVisitor::VisitVarDecl(VarDecl *d)
+  {
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << d->getDeclKindName() << "\",\n"
+         << "\"specifiers\": [\n";
+    if (!m_policy.SuppressSpecifiers) {
+      if (d->getStorageClass() != VarDecl::None) {
+        m_out << VarDecl::getStorageClassSpecifierString(d->getStorageClass()) 
+              << " ";
+        m_js << "\"" 
+             << VarDecl::getStorageClassSpecifierString(d->getStorageClass())
+             << "\", ";
+      }
+
+      if (d->isThreadSpecified()) {
+        m_out << "__thread ";
+        m_js << "\"__thread\", ";
+      }
+    }
+    m_js << "],\n";
+
+    std::string name = d->getNameAsString();
+    m_js << "\"name\": \"" << name << "\",\n";
+    QualType t = d->getType();
+    //std::string deflt_value = "None";
+    if (ParmVarDecl *parm = dyn_cast<ParmVarDecl>(d)) {
+      t = parm->getOriginalType();
+      // Expr * dflt_expr = parm->getDefaultArg();
+      // if (dflt_expr) {
+        
+      // }
+    }
+    m_js << "\"type\": \"" << t.getAsString() << "\",\n";
+    t.getAsStringInternal(name, m_policy);
+    m_out << name;
+    if (d->getInit()) {
+      if (d->hasCXXDirectInitializer()) {
+        m_out << "(";
+      } 
+      else {
+        m_out << " = ";
+      }
+      m_js << "\"default-value\": ";
+      this->process_expr(d->getInit(), m_out, m_ast_ctx,
+                         0, m_policy, m_indent);
+      m_js << ", # default-value\n";
+      if (d->hasCXXDirectInitializer()) {
+        m_out << ")";
+      }
+    }
+    m_js << "}, # var-decl\n";
+  }
+
+  void
+  JsonVisitor::VisitParmVarDecl(ParmVarDecl *d)
+  {
+    this->VisitVarDecl(d);
+  }
+
+  void
+  JsonVisitor::VisitFileScopeAsmDecl(FileScopeAsmDecl *d)
+  {
+    m_out << "__asm (";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"asm-body\": {\n";
+
+    this->process_expr(d->getAsmString(), m_out, m_ast_ctx,
+                       0, m_policy, m_indent);
+    m_out << ")";
+    m_js << "} #asm-body\n"
+         << "},\n";
+  }
+
+  // -----------------------
+  // C++ declarations...
+  void
+  JsonVisitor::VisitNamespaceDecl(NamespaceDecl *d)
+  {
+    m_out << "namespace " << d->getNameAsString() << " {\n";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"fields\": ";
+
+    this->VisitDeclContext(d);
+    this->indent() << "}";
+    m_js << "}, # namespace\n";
+  }
+
+  void
+  JsonVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *d)
+  {
+    m_out << "using namespace ";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"using-namespace\": ";
+      
+    if (d->getQualifier()) {
+      this->process_qualifier(d->getQualifier(), m_out, m_policy);
+      //NestedNameSpecifier * spec = dyn_cast<NestedNameSpecifier>(d->getQualifier());
+      //this->process_nsspecifier(spec, m_out, m_policy);
+    }
+    m_out << d->getNominatedNamespaceAsWritten()->getNameAsString();
+    m_js << "\"nominated-namespace\": \"" 
+         << d->getNominatedNamespaceAsWritten()->getNameAsString()
+         << "\",\n"
+         << "}, # using-namespace\n";
+  }
+
+  void
+  JsonVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *d)
+  {
+    m_out << "namespace " << d->getNameAsString() << " = ";
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n";
+    if (d->getQualifier()) {
+      m_js << "\"alias-namespace\": ";
+      this->process_qualifier(d->getQualifier(), m_out, m_policy);
+      m_js << ",\n";
+    }
+    m_out << d->getAliasedNamespace()->getNameAsString();
+    m_js << "\"aliased-namespace\": \"" 
+         << d->getAliasedNamespace()->getNameAsString()
+         << "\",\n"
+         << "}, # alias-namespace\n";
+  }
+
+  void
+  JsonVisitor::VisitCXXRecordDecl(CXXRecordDecl *d)
+  {
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((DeclContext*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"kind-name\": \"" << d->getKindName() << "\",\n";
+
+    m_out << d->getKindName();
+    if (d->getIdentifier()) {
+      m_out << " ";
+      m_out << d->getNameAsString();
+      m_js << "\"identifier\": \"" << d->getNameAsString() << "\",\n";
+    }
+    m_js << "\"is-dynamic\": " << (d->isDynamicClass() ? "True" : "False")
+         << ",\n"
+         << "\"is-aggregate\": " << (d->isAggregate() ? "True" : "False")
+         << ",\n"
+         << "\"is-pod\": " << (d->isPOD() ? "True" : "False")
+         << ",\n"
+         << "\"is-empty\": " << (d->isEmpty() ? "True" : "False")
+         << ",\n"
+         << "\"is-polymorphic\": " 
+         << (d->isPolymorphic() ? "True" : "False")
+         << ",\n"
+         << "\"is-abstract\": " << (d->isAbstract() ? "True" : "False")
+         << ",\n"
+         << "\"has-trivial-ctor\": "
+         << (d->hasTrivialConstructor() ? "True" : "False")
+         << ",\n"
+         << "\"has-trivial-copyctor\": "
+         << (d->hasTrivialCopyConstructor() ? "True" : "False")
+         << ",\n"
+         << "\"has-trivial-copy-assgn\": "
+         << (d->hasTrivialCopyAssignment() ? "True" : "False")
+         << ",\n"
+         << "\"has-trivial-dtor\": "
+         << (d->hasTrivialDestructor() ? "True" : "False")
+         << ",\n"
+         << "\"is-local-class\": "
+         << (d->isLocalClass() ? "True" : "False")
+         << ",\n";
+
+
+    if (d->isDefinition()) {
+      // print the base classes
+      m_js << "\"bases\": [\n";
+      if (d->getNumBases()) {
+        m_out << " : ";
+        PrintingPolicy base_policy = m_policy;
+        base_policy.SuppressTagKind = true;
+        for (CXXRecordDecl::base_class_iterator 
+               base = d->bases_begin(),
+               bend = d->bases_end();
+             base != bend;
+             ++base) {
+          m_js << "{\n"
+               << "\"name\": \"" 
+               << base->getType().getAsString(base_policy) << "\",\n"
+               << "\"specifiers\": {\n";
+          if (base != d->bases_begin()) {
+            m_out << ", ";
+          }
+          m_js << "\"is-virtual\": ";
+          if (base->isVirtual()) {
+            m_out << "virtual ";
+            m_js << "True";
+          } else {
+            m_js << "False";
+          }
+          m_js << ",\n";
+
+          AccessSpecifier as = base->getAccessSpecifierAsWritten();
+          if (as != AS_none) {
+            this->process_access_specifier(as);
+          }
+          m_js << "}, # specifiers\n";
+          m_out << " " << base->getType().getAsString(m_policy);
+          m_js << "}, # base-class\n";
+        }// loop over bases
+      } // n-bases
+      m_js << "], # bases\n";
+
+      // print the class definition
+      m_out << " {\n";
+      m_js << "\"fields\": ";
+      this->VisitDeclContext(d);
+      this->indent() << "}";
+    } // is-definition
+    m_js << "}, # cxx-record\n";
+  }
+
+  void
+  JsonVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *d)
+  {
+    const char *l = 0;
+    if (d->getLanguage() == LinkageSpecDecl::lang_c) {
+      l = "C";
+    } else {
+      assert(d->getLanguage() == LinkageSpecDecl::lang_cxx &&
+             "unknown language in linkage specification");
+      l = "C++";
+    }
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"linkage\": \"" << l << "\",\n"
+         << "\"fields\": ";
+    m_out << "extern \"" << l << "\" ";
+    if (d->hasBraces()) {
+      m_out << "{\n";
+      this->VisitDeclContext(d);
+      this->indent() << "}";
+    } else {
+      this->Visit(*d->decls_begin());
+    }
+    m_js << "}, # linkage\n";
+  }
+
+  void
+  JsonVisitor::VisitTemplateDecl(TemplateDecl *d)
+  {
+    m_js << "{\n"
+         << "\"decl-kind\": \"" << ((Decl*)d)->getDeclKindName() << "\",\n"
+         << "\"name\": \"" << d->getNameAsString() << "\",\n"
+         << "\"tmpl-params\": [";
+      
+    m_out << "template <";
+    TemplateParameterList *params = d->getTemplateParameters();
+    for (unsigned i = 0, e = params->size(); i != e; ++i) {
+      m_js << "{\n";
+      if (i != 0) m_out << ", ";
+      const Decl *param = params->getParam(i);
+      if (const TemplateTypeParmDecl *ttp =
+          dyn_cast<TemplateTypeParmDecl>(param)) {
+        QualType param_type = 
+          m_ast_ctx.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(ttp));
+
+        m_js << "\"is-tmpl-type\": True,\n"
+             << "\"declared-with\": ";
+        if (ttp->wasDeclaredWithTypename()) {
+          m_out << "typename ";
+          m_js << "\"typename\"";
+        } else {
+          m_out << "class ";
+          m_js << "\"class\"";
+        }
+        m_js << ",\n";
+
+        m_js << "\"is-parameter-pack\": " << (ttp->isParameterPack() ?
+                                              "True" : "False")
+             << ",\n";
+
+        if (ttp->isParameterPack()) {
+          m_out << "... ";
+        }
+
+        m_js << "\"type\": \"" << param_type.getAsString(m_policy) << "\",\n";
+        m_js << "\"default-arg\": ";
+        m_out << param_type.getAsString(m_policy);
+        if (ttp->hasDefaultArgument()) {
+          m_out << " = ";
+          m_out << ttp->getDefaultArgument().getAsString(m_policy);
+          m_js << "\"" << ttp->getDefaultArgument().getAsString(m_policy)
+               << "\"";
+        } else {
+          m_js << "None";
+        }
+        m_js << ",\n";
+
+      } // ttp-decl
+      else if (const NonTypeTemplateParmDecl *nttp =
+               dyn_cast<NonTypeTemplateParmDecl>(param)) {
+        m_out << nttp->getType().getAsString(m_policy);
+        m_js << "\"is-tmpl-type\": False,\n"
+             << "\"type\": \""
+             << nttp->getType().getAsString(m_policy)
+             << "\",\n"
+             << "\"name\": ";
+        if (IdentifierInfo *name = nttp->getIdentifier()) {
+          m_out << " ";
+          m_out << name->getName();
+          m_js << "\"" << name->getName() << "\"";
+        } else {
+          m_js << "None";
+        }
+        m_js << ",\n";
+
+        m_js << "\"default-arg\": ";
+        if (nttp->hasDefaultArgument()) {
+          m_out << " = ";
+          this->process_expr(nttp->getDefaultArgument(),
+                             m_out, m_ast_ctx,
+                             0, m_policy, m_indent);
+        } else {
+          m_js << "None,\n";
+        }
+      } // non-ttp-decl
+      m_js << "}, # tmpl-param\n";
+    } // loop over template parameters
+
+    m_out << "> ";
+    m_js << "], # tmpl-params\n"
+         << "\"tmpl-decl\": \n";
+    this->Visit(d->getTemplatedDecl());
+    m_js << "}, # template-decl\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCMethodDecl(ObjCMethodDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C method declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCClassDecl(ObjCClassDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C class declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C implementation declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C interface declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C fwd protocol declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C protocol declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C category-impl declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C category declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C compatible alias declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C property declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+
+  void
+  JsonVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *d)
+  {
+    llvm::errs() << "sorry, visiting Obj-C property-impl declaration "
+                 << "is not (yet?) implemented.\n";
+  }
+  
+  void
+  JsonVisitor::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *d)
+  {
+    m_out << "using typename ";
+    this->process_qualifier(d->getTargetNestedNameSpecifier(), 
+                            m_out,
+                            m_policy);
+    m_out << d->getDeclName().getAsString();
+  }
+
+  void
+  JsonVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *d)
+  {
+  }
+
+  void
+  JsonVisitor::VisitUsingDecl(UsingDecl *d)
+  {}
+
+  void
+  JsonVisitor::VisitUsingShadowDecl(UsingShadowDecl *d)
+  {}
+
+  // statement visitors
+  // void
+  // JsonVisitor::VisitStmt(Stmt *stmt) 
+  // {
+  //   this->dump_stmt(stmt);
+  //   #if 0
+  //   for (Stmt::child_iterator
+  //          child = stmt->child_begin(),
+  //          end   = stmt->child_end();
+  //        child != end;
+  //        ++child) {
+  //     if (*child) {
+  //       m_out << "--> [" << child->getStmtClassName() << "] <--\n";
+  //       this->Visit(stmt);
+  //     }
+  //   }
+  //   #endif
+  // }
+
+  void
+  JsonVisitor::VisitDeclStmt(DeclStmt *s) 
+  {
+    llvm::SmallVector<Decl*, 2> decls;
+    for (DeclStmt::decl_iterator 
+           d   = s->decl_begin(), 
+           end = s->decl_end();
+         d != end; ++d) {
+      decls.push_back(*d);
+    }
+    this->process_declgrp(decls);
+  }
+
+  void
+  JsonVisitor::VisitCompoundStmt(CompoundStmt *node)
+  {
+    this->indent();
+    for (CompoundStmt::body_iterator 
+           i = node->body_begin(),
+           e = node->body_end();
+         i != e;
+         ++i) {
+      this->process_stmt(*i);
+    }
+    m_out << "\n";
+  }
+
+  void 
+  JsonVisitor::VisitCharacterLiteral(CharacterLiteral *node)
+  {
+    unsigned value = node->getValue();
+    std::string literal;
+    llvm::raw_string_ostream buf(literal);
+    if (node->isWide()) {
+      buf << "L";
+    }
+    switch (value) {
+    case '\\':
+      buf << "'\\\\'";
+      break;
+    case '\'':
+      buf << "'\\''";
+      break;
+    case '\a':
+      // TODO: K&R: the meaning of '\\a' is different in traditional C
+      buf << "'\\a'";
+      break;
+    case '\b':
+      buf << "'\\b'";
+      break;
+      // Nonstandard escape sequence.
+      /*case '\e':
+        buf << "'\\e'";
+        break;*/
+    case '\f':
+      buf << "'\\f'";
+      break;
+    case '\n':
+      buf << "'\\n'";
+      break;
+    case '\r':
+      buf << "'\\r'";
+      break;
+    case '\t':
+      buf << "'\\t'";
+      break;
+    case '\v':
+      buf << "'\\v'";
+      break;
+    default:
+      if (value < 256 && isprint(value)) {
+        buf << "'" << (char)value << "'";
+      } else if (value < 256) {
+        buf << "'\\x" << llvm::format("%x", value) << "'";
+      } else {
+        // FIXME what to really do here?
+        buf << value;
+      }
+    }
+    buf.flush();
+    m_out << literal;
+    m_js << literal;
+  }
+
+  void
+  JsonVisitor::VisitIntegerLiteral(IntegerLiteral *node)
+  {
+    bool isSigned = node->getType()->isSignedIntegerType();
+    std::string literal;
+    {
+      llvm::raw_string_ostream buf(literal);
+      buf << node->getValue().toString(10, isSigned);
+
+      // Emit suffixes.  Integer literals are always a builtin integer type.
+      switch (node->getType()->getAs<BuiltinType>()->getKind()) {
+      default: assert(0 && "Unexpected type for integer literal!");
+      case BuiltinType::Int:       break; // no suffix.
+      case BuiltinType::UInt:      buf << 'U'; break;
+      case BuiltinType::Long:      buf << 'L'; break;
+      case BuiltinType::ULong:     buf << "UL"; break;
+      case BuiltinType::LongLong:  buf << "LL"; break;
+      case BuiltinType::ULongLong: buf << "ULL"; break;
+      }
+      buf.flush();
+    }
+    m_out << literal;
+    #if 0
+    m_js << "{\n"
+         << "\"stmt-kind\": \"integer-literal\",\n"
+         << "\"value\": " << literal << ",\n"
+         << "}, # literal\n";
+    #else
+    m_js << literal; // << ",\n";
+    #endif
+  }
+
+  void
+  JsonVisitor::VisitFloatingLiteral(FloatingLiteral *node)
+  {
+    // FIXME: print value more precisely.
+    m_out << " " << node->getValueAsApproximateDouble();
+    m_js << " " << node->getValueAsApproximateDouble();
+  }
+
+  void
+  JsonVisitor::VisitImaginaryLiteral(ImaginaryLiteral *node)
+  {
+    this->process_expr(node->getSubExpr());
+    m_out << "i";
+    m_js << "j";
+  }
+
+
+  void
+  JsonVisitor::VisitStringLiteral(StringLiteral *node)
+  {
+    std::string literal;
+    llvm::raw_string_ostream buf(literal);
+    if (node->isWide()) buf << 'L';
+    buf << '"';
+
+    // FIXME: this doesn't print wstrings right.
+    for (unsigned i = 0, e = node->getByteLength(); i != e; ++i) {
+      unsigned char Char = node->getStrData()[i];
+
+      switch (Char) {
+      default:
+        if (isprint(Char))
+          buf << (char)Char;
+        else  // Output anything hard as an octal escape.
+          buf << '\\'
+                << (char)('0'+ ((Char >> 6) & 7))
+                << (char)('0'+ ((Char >> 3) & 7))
+                << (char)('0'+ ((Char >> 0) & 7));
+        break;
+        // Handle some common non-printable cases to make dumps prettier.
+      case '\\': buf << "\\\\"; break;
+      case '"': buf << "\\\""; break;
+      case '\n': buf << "\\n"; break;
+      case '\t': buf << "\\t"; break;
+      case '\a': buf << "\\a"; break;
+      case '\b': buf << "\\b"; break;
+      }
+    }
+    buf << '"';
+    buf.flush();
+    m_out << literal;
+    m_js << literal;
+  }
+
+  void
+  JsonVisitor::VisitUnaryOperator(UnaryOperator *node)
+  {
+    m_out << " " << (node->isPostfix() ? "postfix" : "prefix")
+          << " '" << UnaryOperator::getOpcodeStr(node->getOpcode()) << "'";
+  }
+
+  void 
+  JsonVisitor::VisitImplicitCastExpr(ImplicitCastExpr *node) 
+  {
+    // No need to print anything, simply forward to the sub expression.
+    this->process_expr(node->getSubExpr());
+  }
+
+
+  void
+  JsonVisitor::VisitDeclRefExpr(DeclRefExpr *node)
+  {
+    if (NestedNameSpecifier *qual = node->getQualifier()) {
+      this->process_qualifier(qual, m_out, m_policy);
+    }
+    m_out << node->getDecl()->getNameAsString();
+    if (node->hasExplicitTemplateArgumentList()) {
+      m_out << TemplateSpecializationType::PrintTemplateArgumentList
+        (node->getTemplateArgs(),
+         node->getNumTemplateArgs(),
+         m_policy);
+    }
+  }
+
+}
+
+FrontendPluginRegistry::Add<JsonPrinterAction>
+X("print-json", "print json");
+

File ext/clang/genjson/run.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+
+import os
+import sys
+import imp
+import commands as com
+
+try:
+    import json
+except ImportError:
+    import simplejson as json # if that fails...
+    pass
+
+cmd = "clang -cc1 -load libclang_genjson.so -plugin print-json".split()
+fname = sys.argv[-1]
+
+cmd.append(fname)
+sc,out = com.getstatusoutput(' '.join(cmd))
+print out
+if sc == 0:
+    fname = os.path.splitext(fname)[0]
+    ast_name = os.path.basename(fname) + "_ast.py"
+    json_name= os.path.basename(fname) + "_ast.json"
+    mod_name = os.path.splitext(os.path.basename(ast_name))[0]
+    mod = imp.find_module(mod_name)
+    mod = imp.load_module(mod_name, *mod)
+    if os.path.exists(json_name):
+        os.remove(json_name)
+    json.dump({'ast': mod.ast},
+              open(json_name,"w"),
+              indent=2)
+
+    ast_stream = open(ast_name, "w")
+    from pprint import pprint
+    pprint({'ast' : mod.ast},
+           stream=ast_stream,
+           indent=2)
+    
+sys.exit(sc)
+

File ext/clang/genjson/utest.cxx

View file
  • Ignore whitespace
+typedef int MyInt;
+struct Foo {int i; char *c; MyInt mi;};
+
+
+// int main(int argc, char** argv)
+// {
+//   return 0;
+// }
+
+// gcc -print-file-name=plugin
+//#include <vector>
+
+extern "C" {
+  int foo_c(int a, int b)
+  {
+    return a - b;
+  }
+}
+
+enum Colors 
+{
+  Red = 0,
+  Green,
+  Blue
+};
+
+class A
+{
+  int i;
+  float f;
+  double d;
+  int bitfield_1 : 2;
+  int bitfield_2 : 2;
+
+public:
+  void do_public_stuff();
+  ~A();
+  A();
+  operator int()    { return this->i; }
+  operator float()  { return this->f; }
+  operator double() { return this->d; }
+
+  double test_override(double d);
+  float  test_override(float  f);
+  int    test_override(int i);
+
+  A& operator += (const A& rhs);
+
+protected:
+  void do_protected_stuff();
+private:
+  void do_private_stuff();
+  //std::vector<int> vi;
+};
+
+A::~A() {}
+A::A() : i(0), f(0.), d(0.)
+{}
+
+inline
+void
+A::do_public_stuff() {}
+
+void
+A::do_protected_stuff() {}
+
+void
+A::do_private_stuff() {}
+
+class B
+{
+public:
+  double foo(int i = 0, double d=3., float f=4.)
+  { return i+d+f; }
+
+  virtual void doit() const { return; }
+};
+
+double foo_bar(int i, double d=3.)
+{
+  return i+d;
+}
+
+namespace Nirvana
+{
+  class Kurt {};
+
+  class AA : public A, private B 
+  {
+    int ii;
+  public:
+    AA() : A(), B(), ii(0) {}
+  };
+}
+
+namespace Cobain = Nirvana;
+
+static
+void
+fct2() { return; }
+
+namespace {
+  void fct1() { return fct2(); }
+}
+
+class IMom
+{
+public:
+  virtual double px() const = 0;
+};
+
+class INav
+{
+public:
+  virtual void do_nav() const = 0;
+};
+
+class INav4Mom : virtual public INav,
+                 virtual public IMom
+{};
+
+class IPart : virtual public INav4Mom
+{
+public:
+  virtual void do_part() const = 0;
+};
+
+class Mom : virtual public IMom
+{
+public:
+  virtual double px() const { return 0.; }
+};
+
+class Nav : virtual public INav
+{
+public:
+  virtual void do_nav() const {}
+};
+
+class Part: virtual public IPart, public Mom, public Nav
+{
+public:
+  virtual void do_part() const {}
+  void test()
+  {
+    // Part p; p.do_part(); p.do_nav();
+    // (double)p.px();
+    return;
+  }
+};
+
+class Scope
+{
+public:
+  class Nested0 {
+  public:
+    class Nested1 {
+      int i;
+    };
+  };
+};
+
+template<class F, class S>
+struct Pair
+{
+  F first;
+  S second;
+  Pair(const F& f, const S& s) : first(f), second(s) {}
+  ~Pair() {}
+};
+
+template<class F, class S>
+struct Pair<F,S> 
+make_pair(const F& f, const S& s)
+{ return Pair<F,S>(f,s); }
+
+int test_pair()
+{
+  struct Pair<int,float> p = make_pair<int,float>(3, 3.14);
+  int f = p.first;
+  int s = p.second;
+  return f+s;
+}
+
+const char* test_c_string(const char *str = "foo_str");
+const char*
+test_c_string(const char *str)
+{
+  return str;
+}
+
+template<int N, int M = 3>
+struct Matrix
+{
+  int cols[N];
+  int rows[M];
+};
+
+#if 0 // this crashes the json-printer, but not the regular ast-printer...
+#include <vector>
+typedef std::vector<int> MyInts_t;
+#endif