<commit_before>// xml_type_writer.cc            see license.txt for copyright and terms of use

#include "xml_type_writer.h"    // this module
#include "variable.h"           // Variable
#include "cc_flags.h"           // toXml(DeclFlags &out, rostring str)
#include "asthelp.h"            // xmlPrintPointer
#include "xmlhelp.h"            // toXml_int() etc.
#include "strutil.h"            // DelimStr
#include "cc_ast.h"             // AST nodes only for AST sub-traversals
#include "strtokp.h"            // StrtokParse

#define serializeOracle serializeOracle_m

// toXml for enums

char const *toXml(CompoundType::Keyword id) {
  switch(id) {
  default: xfailure("bad enum"); break;
    PRINTENUM(CompoundType::K_STRUCT);
    PRINTENUM(CompoundType::K_CLASS);
    PRINTENUM(CompoundType::K_UNION);
  }
}

string toXml(FunctionFlags id) {
  if (id == FF_NONE) return "FF_NONE";
  DelimStr b('|');
  PRINTFLAG(FF_METHOD);
  PRINTFLAG(FF_VARARGS);
  PRINTFLAG(FF_CONVERSION);
  PRINTFLAG(FF_CTOR);
  PRINTFLAG(FF_DTOR);
  PRINTFLAG(FF_BUILTINOP);
  PRINTFLAG(FF_NO_PARAM_INFO);
  PRINTFLAG(FF_DEFAULT_ALLOC);
  PRINTFLAG(FF_KANDR_DEFN);
  return b.sb;
}

char const *toXml(ScopeKind id) {
  switch(id) {
  default: xfailure("bad enum"); break;
  PRINTENUM(SK_UNKNOWN);
  PRINTENUM(SK_GLOBAL);
  PRINTENUM(SK_PARAMETER);
  PRINTENUM(SK_FUNCTION);
  PRINTENUM(SK_CLASS);
  PRINTENUM(SK_TEMPLATE_PARAMS);
  PRINTENUM(SK_TEMPLATE_ARGS);
  PRINTENUM(SK_NAMESPACE);
  }
}

char const *toXml(STemplateArgument::Kind id) {
  switch(id) {
  default: xfailure("bad enum"); break;
  PRINTENUM(STemplateArgument::STA_NONE);
  PRINTENUM(STemplateArgument::STA_TYPE);
  PRINTENUM(STemplateArgument::STA_INT);
  PRINTENUM(STemplateArgument::STA_ENUMERATOR);
  PRINTENUM(STemplateArgument::STA_REFERENCE);
  PRINTENUM(STemplateArgument::STA_POINTER);
  PRINTENUM(STemplateArgument::STA_MEMBER);
  PRINTENUM(STemplateArgument::STA_DEPEXPR);
  PRINTENUM(STemplateArgument::STA_TEMPLATE);
  PRINTENUM(STemplateArgument::STA_ATOMIC);
  }
}

XmlTypeWriter::XmlTypeWriter (IdentityManager &idmgr0,
                              ASTVisitor *astVisitor0, ostream *out0, int &depth0, bool indent0,
                              XTW_SerializeOracle *serializeOracle0)
  : XmlWriter(idmgr0, out0, depth0, indent0)
  , astVisitor(astVisitor0)
  , serializeOracle(serializeOracle0)
{}

// **** toXml

// This one occurs in the AST, so it has to have its own first-class
// method.  FIX: This should not have such a general API and yet refer
// to such a specific list: PseudoInstantiation::args.
void XmlTypeWriter::toXml(ObjList<STemplateArgument> *list) {
  travObjList_standalone(*list, PseudoInstantiation, args, STemplateArgument);
}

void XmlTypeWriter::toXml(Type *t) {
  // idempotency
  if (idmgr.printed(t)) return;

  switch(t->getTag()) {
  default: xfailure("illegal tag");

  case Type::T_ATOMIC: {
    CVAtomicType *atom = t->asCVAtomicType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("CVAtomicType", atom);
      // **** attributes
      printPtr(atom, atomic);
      printXml(cv, atom->cv);
      tagPrinter.tagEnd();
    }
    // **** subtags
    trav(atom->atomic);
    break;
  }

  case Type::T_POINTER: {
    PointerType *ptr = t->asPointerType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PointerType", ptr);
      // **** attributes
      printXml(cv, ptr->cv);
      printPtr(ptr, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ptr->atType);
    break;
  }

  case Type::T_REFERENCE: {
    ReferenceType *ref = t->asReferenceType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("ReferenceType", ref);
      // **** attributes
      printPtr(ref, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ref->atType);
    break;
  }

  case Type::T_FUNCTION: {
    FunctionType *func = t->asFunctionType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("FunctionType", func);
      // **** attributes
      printXml(flags, func->flags);
      printPtr(func, retType);
      printEmbed(func, params);
      printPtr(func, exnSpec);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(func->retType);
    travObjList_S(func, FunctionType, params, Variable); // Variable
    // exnSpec
    if (func->exnSpec) {
      toXml_FunctionType_ExnSpec(func->exnSpec);
    }
    break;
  }

  case Type::T_ARRAY: {
    ArrayType *arr = t->asArrayType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("ArrayType", arr);
      // **** attributes
      printPtr(arr, eltType);
      printXml_int(size, arr->size);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(arr->eltType);
    break;
  }

  case Type::T_POINTERTOMEMBER: {
    PointerToMemberType *ptm = t->asPointerToMemberType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PointerToMemberType", ptm);
      // **** attributes
      printPtr(ptm, inClassNAT);
      printXml(cv, ptm->cv);
      printPtr(ptm, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ptm->inClassNAT);
    trav(ptm->atType);
    break;
  }

  }
}

void XmlTypeWriter::toXml(AtomicType *atom) {
  // idempotency done in each sub-type as it is not done for
  // CompoundType here.
  switch(atom->getTag()) {
  default: xfailure("illegal tag");

  case AtomicType::T_SIMPLE: {
    // idempotency
    if (idmgr.printed(atom)) return;
    SimpleType *simple = atom->asSimpleType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("SimpleType", simple);
      // **** attributes
      printXml(type, simple->type);
      tagPrinter.tagEnd();
    }
    break;
  }

  case AtomicType::T_COMPOUND: {
    // NO!  Do NOT do this here:
//      // idempotency
//      if (idmgr.printed(atom)) return;
    CompoundType *cpd = atom->asCompoundType();
    toXml(cpd);
    break;
  }

  case AtomicType::T_ENUM: {
    // idempotency
    if (idmgr.printed(atom)) return;
    EnumType *e = atom->asEnumType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("EnumType", e);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(e);
      // * members
      printEmbed(e, valueIndex);
      printXml_int(nextValue, e->nextValue);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(e);
    // * members
    // valueIndex
    if (!idmgr.printed(&e->valueIndex)) {
      XmlTagPrinter tagPrinter2(*this);
      if (writingP()) {
        tagPrinter2.printOpenTag("NameMap_EnumType_valueIndex", &e->valueIndex);
        tagPrinter2.tagEnd();
      }

      if (sortNameMapDomainWhenSerializing) {
        for(StringObjDict<EnumType::Value>::SortedKeyIter iter(e->valueIndex);
            !iter.isDone(); iter.next()) {
          char const *name = iter.key();
          // dsw: do you know how bad it gets if I don't put a
          // const-cast here?
          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());

          XmlTagPrinter tagPrinter3(*this);
          if (writingP()) {
            tagPrinter3.printNameMapItemOpenTag(name, eValue);
          }

          toXml_EnumType_Value(eValue);
        }
      } else {
        for(StringObjDict<EnumType::Value>::Iter iter(e->valueIndex);
            !iter.isDone(); iter.next()) {
          rostring name = iter.key();
          // dsw: do you know how bad it gets if I don't put a
          // const-cast here?
          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());

          XmlTagPrinter tagPrinter3(*this);
          if (writingP()) {
            tagPrinter3.printNameMapItemOpenTag(name.c_str(), eValue);
          }

          toXml_EnumType_Value(eValue);
        }
      }
    }
    break;
  }

  case AtomicType::T_TYPEVAR: {
    // idempotency
    if (idmgr.printed(atom)) return;
    TypeVariable *tvar = atom->asTypeVariable();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("TypeVariable", tvar);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(tvar);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(tvar);
    break;
  }

  case AtomicType::T_PSEUDOINSTANTIATION: {
    // idempotency
    if (idmgr.printed(atom)) return;
    PseudoInstantiation *pseudo = atom->asPseudoInstantiation();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PseudoInstantiation", pseudo);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(pseudo);
      // * members
      printPtr(pseudo, primary);
      printEmbed(pseudo, args);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(pseudo);
    // * members
    trav(pseudo->primary);
    travObjList(pseudo, PseudoInstantiation, args, STemplateArgument);
    break;
  }

  case AtomicType::T_DEPENDENTQTYPE: {
    // idempotency
    if (idmgr.printed(atom)) return;
    DependentQType *dep = atom->asDependentQType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("DependentQType", dep);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(dep);
      // * members
      printPtr(dep, first);
      printPtrAST(dep, rest);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(dep);
    // * members
    trav(dep->first);
    travAST(dep->rest);
    break;
  }

  }
}

void XmlTypeWriter::toXml(CompoundType *cpd) {
  // idempotency
  if (idmgr.printed(cpd)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("CompoundType", cpd);
    // **** attributes
    // * superclasses
    toXml_NamedAtomicType_properties(cpd);
    toXml_Scope_properties(cpd);
    // * members
    printXml_bool(forward, cpd->forward);
    printXml(keyword, cpd->keyword);
    printEmbed(cpd, dataMembers);
    printEmbed(cpd, bases);
    printEmbed(cpd, virtualBases);
    printEmbed(cpd, subobj);
    printEmbed(cpd, conversionOperators);
    printStrRef(instName, cpd->instName);
    printPtrAST(cpd, syntax);
    printPtr(cpd, parameterizingScope);
    printPtr(cpd, selfType);
    tagPrinter.tagEnd();
  }

  // **** subtags
  // * superclasses
  toXml_NamedAtomicType_subtags(cpd);
  toXml_Scope_subtags(cpd);
  // * members
  travObjList_S(cpd, CompoundType, dataMembers, Variable); // Variable
  travObjList(cpd, CompoundType, bases, BaseClass);
  travObjList(cpd, CompoundType, virtualBases, BaseClassSubobj);
  toXml(&cpd->subobj);          // embedded
  travObjList_S(cpd, CompoundType, conversionOperators, Variable); // Variable
  travAST(cpd->syntax);
  trav(cpd->parameterizingScope);
  trav(cpd->selfType);
}

void XmlTypeWriter::toXml_Variable_properties(Variable *var) {
  assert(writingP());
  printXml_SourceLoc(loc, var->loc);
  printStrRef(name, var->name);
  printPtr(var, type);
  printXml(flags, var->flags);
  printPtrAST(var, value);
  printPtr(var, defaultParamType);
  printPtrAST(var, funcDefn);
  printPtr(var, overload);
  printPtr(var, scope);

  // these three fields are an abstraction; here we pretend they are
  // real
  AccessKeyword access = var->getAccess();
  printXml(access, access);
  ScopeKind scopeKind = var->getScopeKind();
  printXml(scopeKind, scopeKind);
  int parameterOrdinal = var->getParameterOrdinal();
  printXml_int(parameterOrdinal, parameterOrdinal);

  printPtr(var, usingAlias_or_parameterizedEntity);
  printPtr(var, templInfo);

  if (var->linkerVisibleName()) {
    newline();
    *out << "fullyQualifiedMangledName=" << xmlAttrQuote(var->fullyQualifiedMangledName0());
  }
}

void XmlTypeWriter::toXml_Variable_subtags(Variable *var) {
  trav(var->type);
  travAST(var->value);
  trav(var->defaultParamType);
  travAST(var->funcDefn);
  trav(var->overload);
  trav(var->scope);
  trav(var->usingAlias_or_parameterizedEntity); // Variable
  trav(var->templInfo);
}

void XmlTypeWriter::toXml(Variable *var) {
#ifdef OINK
  xfailure("this should never be called in Oink");
#endif

  // idempotency
  if (idmgr.printed(var)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("Variable", var);
    // **** attributes
    toXml_Variable_properties(var);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_Variable_subtags(var);
}

void XmlTypeWriter::toXml_FunctionType_ExnSpec(void /*FunctionType::ExnSpec*/ *exnSpec0) {
  FunctionType::ExnSpec *exnSpec = static_cast<FunctionType::ExnSpec *>(exnSpec0);
  // idempotency
  if (idmgr.printed(exnSpec)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("FunctionType_ExnSpec", exnSpec);
    // **** attributes
    printEmbed(exnSpec, types);
    tagPrinter.tagEnd();
  }

  // **** subtags
  travObjList_S(exnSpec, ExnSpec, types, Type);
}

void XmlTypeWriter::toXml_EnumType_Value(void /*EnumType::Value*/ *eValue0) {
  EnumType::Value *eValue = static_cast<EnumType::Value *>(eValue0);
  // idempotency
  if (idmgr.printed(eValue)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("EnumType_Value", eValue);
    // **** attributes
    printStrRef(name, eValue->name);
    printPtr(eValue, type);
    printXml_int(value, eValue->value);
    printPtr(eValue, decl);
    tagPrinter.tagEnd();
  }

  // **** subtags
  trav(eValue->type);
  trav(eValue->decl);           // Variable
}

void XmlTypeWriter::toXml_NamedAtomicType_properties(NamedAtomicType *nat) {
  printStrRef(name, nat->name);
  printPtr(nat, typedefVar);
  printXml(access, nat->access);
}

void XmlTypeWriter::toXml_NamedAtomicType_subtags(NamedAtomicType *nat) {
  trav(nat->typedefVar);        // Variable
}

void XmlTypeWriter::toXml(OverloadSet *oload) {
  // idempotency
  if (idmgr.printed(oload)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("OverloadSet", oload);
    // **** attributes
    printEmbed(oload, set);
    tagPrinter.tagEnd();
  }

  // **** subtags
  travObjList_S(oload, OverloadSet, set, Variable); // Variable
}

void XmlTypeWriter::toXml(BaseClass *bc) {
  // Since BaseClass objects are never manipulated polymorphically,
  // that is, every BaseClass pointer's static type equals its dynamic
  // type, 'bc' cannot actually be a BaseClassSubobj.

  // idempotency
  if (idmgr.printed(bc)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("BaseClass", bc);
    // **** attributes
    toXml_BaseClass_properties(bc);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_BaseClass_subtags(bc);
}

void XmlTypeWriter::toXml_BaseClass_properties(BaseClass *bc) {
  printPtr(bc, ct);
  printXml(access, bc->access);
  printXml_bool(isVirtual, bc->isVirtual);
}

void XmlTypeWriter::toXml_BaseClass_subtags(BaseClass *bc) {
  trav(bc->ct);
}

void XmlTypeWriter::toXml(BaseClassSubobj *bc) {
  // idempotency
  if (idmgr.printed(bc)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("BaseClassSubobj", bc);
    // **** attributes
    // * superclass
    toXml_BaseClass_properties(bc);
    // * members
    printEmbed(bc, parents);
    tagPrinter.tagEnd();
  }

  // **** subtags
  // * superclass
  toXml_BaseClass_subtags(bc);
  // * members
  travObjList_S(bc, BaseClassSubobj, parents, BaseClassSubobj);
}

void XmlTypeWriter::toXml(Scope *scope) {
  // are we really a CompoundType?
  if (CompoundType *cpd = dynamic_cast<CompoundType*>(scope)) {
    toXml(cpd);
    return;
  }
  // idempotency
  if (idmgr.printed(scope)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("Scope", scope);
    // **** attributes
    toXml_Scope_properties(scope);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_Scope_subtags(scope);
}

void XmlTypeWriter::toXml_Scope_properties(Scope *scope) {
  printEmbed(scope, variables);
  printEmbed(scope, typeTags);
  printXml_bool(canAcceptNames, scope->canAcceptNames);
  printPtr(scope, parentScope);
  printXml(scopeKind, scope->scopeKind);
  printPtr(scope, namespaceVar);
  printEmbed(scope, templateParams);
  printPtr(scope, curCompound);
  printXml_SourceLoc(curLoc, scope->curLoc);
}

void XmlTypeWriter::toXml_Scope_subtags(Scope *scope) {
  // FIX: these are like function template "partial specializations"
  // (if such things existed), as the 'Variable' paramter actually
  // also changes the implementation.
  travStringRefMap(scope, Scope, variables, Variable); // Variable
  travStringRefMap(scope, Scope, typeTags, Variable); // Variable
  trav(scope->parentScope);
  trav(scope->namespaceVar);    // Variable
  travObjList_S(scope, Scope, templateParams, Variable); // Variable
  trav(scope->curCompound);
}

void XmlTypeWriter::toXml(STemplateArgument *sta) {
  // idempotency
  if (idmgr.printed(sta)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("STemplateArgument", sta);

    // **** attributes
    printXml(kind, sta->kind);
    newline();

    switch(sta->kind) {
    default: xfailure("illegal STemplateArgument kind"); break;

    case STemplateArgument::STA_TYPE:
      printPtrUnion(sta, value.t, t);
      break;

    case STemplateArgument::STA_INT:
      printXml_int(i, sta->value.i);
      break;

    case STemplateArgument::STA_ENUMERATOR:
    case STemplateArgument::STA_REFERENCE:
    case STemplateArgument::STA_POINTER:
    case STemplateArgument::STA_MEMBER:
      printPtrUnion(sta, value.v, v);
      break;

    case STemplateArgument::STA_DEPEXPR:
      printPtrASTUnion(sta, value.e, e);
      break;

    case STemplateArgument::STA_TEMPLATE:
      xfailure("template template arguments not implemented");
      break;

    case STemplateArgument::STA_ATOMIC:
      printPtrUnion(sta, value.at, at);
      break;
    }
    tagPrinter.tagEnd();
  }

  // **** subtags

  // NOTE: I don't use the trav() macro here because it would be weird
  // to test the member of a union for being NULL; it should have a
  // well-defined value if it is the selected type of the tag.
  switch(sta->kind) {
  default: xfailure("illegal STemplateArgument kind"); break;
  case STemplateArgument::STA_TYPE:
    toXml(sta->value.t);
    break;

  case STemplateArgument::STA_INT:
    // nothing to do
    break;

  case STemplateArgument::STA_ENUMERATOR:
  case STemplateArgument::STA_REFERENCE:
  case STemplateArgument::STA_POINTER:
  case STemplateArgument::STA_MEMBER:
    trav(sta->value.v);         // Variable
    break;

  case STemplateArgument::STA_DEPEXPR:
    // (quarl) TODO: I don't get what's going on here; this looks weird.
    if (astVisitor) {
      sta->value.e->traverse(*astVisitor);
    }
    break;

  case STemplateArgument::STA_TEMPLATE:
    xfailure("template template arguments not implemented");
    break;

  case STemplateArgument::STA_ATOMIC:
    toXml(const_cast<AtomicType*>(sta->value.at));
    break;
  }
}

void XmlTypeWriter::toXml(TemplateInfo *ti) {<commit_msg>*** empty log message ***<commit_after>// xml_type_writer.cc            see license.txt for copyright and terms of use

#include "xml_type_writer.h"    // this module
#include "variable.h"           // Variable
#include "cc_flags.h"           // toXml(DeclFlags &out, rostring str)
#include "asthelp.h"            // xmlPrintPointer
#include "xmlhelp.h"            // toXml_int() etc.
#include "strutil.h"            // DelimStr
#include "cc_ast.h"             // AST nodes only for AST sub-traversals
#include "strtokp.h"            // StrtokParse

#define serializeOracle serializeOracle_m

// toXml for enums

char const *toXml(CompoundType::Keyword id) {
  switch(id) {
  default: xfailure("bad enum"); break;
    PRINTENUM(CompoundType::K_STRUCT);
    PRINTENUM(CompoundType::K_CLASS);
    PRINTENUM(CompoundType::K_UNION);
  }
}

string toXml(FunctionFlags id) {
  if (id == FF_NONE) return "FF_NONE";
  DelimStr b('|');
  PRINTFLAG(FF_METHOD);
  PRINTFLAG(FF_VARARGS);
  PRINTFLAG(FF_CONVERSION);
  PRINTFLAG(FF_CTOR);
  PRINTFLAG(FF_DTOR);
  PRINTFLAG(FF_BUILTINOP);
  PRINTFLAG(FF_NO_PARAM_INFO);
  PRINTFLAG(FF_DEFAULT_ALLOC);
  PRINTFLAG(FF_KANDR_DEFN);
  return b.sb;
}

char const *toXml(ScopeKind id) {
  switch(id) {
  default: xfailure("bad enum"); break;
  PRINTENUM(SK_UNKNOWN);
  PRINTENUM(SK_GLOBAL);
  PRINTENUM(SK_PARAMETER);
  PRINTENUM(SK_FUNCTION);
  PRINTENUM(SK_CLASS);
  PRINTENUM(SK_TEMPLATE_PARAMS);
  PRINTENUM(SK_TEMPLATE_ARGS);
  PRINTENUM(SK_NAMESPACE);
  }
}

char const *toXml(STemplateArgument::Kind id) {
  switch(id) {
  default: xfailure("bad enum"); break;
  PRINTENUM(STemplateArgument::STA_NONE);
  PRINTENUM(STemplateArgument::STA_TYPE);
  PRINTENUM(STemplateArgument::STA_INT);
  PRINTENUM(STemplateArgument::STA_ENUMERATOR);
  PRINTENUM(STemplateArgument::STA_REFERENCE);
  PRINTENUM(STemplateArgument::STA_POINTER);
  PRINTENUM(STemplateArgument::STA_MEMBER);
  PRINTENUM(STemplateArgument::STA_DEPEXPR);
  PRINTENUM(STemplateArgument::STA_TEMPLATE);
  PRINTENUM(STemplateArgument::STA_ATOMIC);
  }
}

XmlTypeWriter::XmlTypeWriter (IdentityManager &idmgr0,
                              ASTVisitor *astVisitor0, ostream *out0, int &depth0, bool indent0,
                              XTW_SerializeOracle *serializeOracle0)
  : XmlWriter(idmgr0, out0, depth0, indent0)
  , astVisitor(astVisitor0)
  , serializeOracle(serializeOracle0)
{}

// **** toXml

// This one occurs in the AST, so it has to have its own first-class
// method.  FIX: This should not have such a general API and yet refer
// to such a specific list: PseudoInstantiation::args.
void XmlTypeWriter::toXml(ObjList<STemplateArgument> *list) {
  travObjList_standalone(*list, PseudoInstantiation, args, STemplateArgument);
}

void XmlTypeWriter::toXml(Type *t) {
  // idempotency
  if (idmgr.printed(t)) return;

  switch(t->getTag()) {
  default: xfailure("illegal tag");

  case Type::T_ATOMIC: {
    CVAtomicType *atom = t->asCVAtomicType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("CVAtomicType", atom);
      // **** attributes
      printPtr(atom, atomic);
      printXml(cv, atom->cv);
      tagPrinter.tagEnd();
    }
    // **** subtags
    trav(atom->atomic);
    break;
  }

  case Type::T_POINTER: {
    PointerType *ptr = t->asPointerType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PointerType", ptr);
      // **** attributes
      printXml(cv, ptr->cv);
      printPtr(ptr, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ptr->atType);
    break;
  }

  case Type::T_REFERENCE: {
    ReferenceType *ref = t->asReferenceType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("ReferenceType", ref);
      // **** attributes
      printPtr(ref, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ref->atType);
    break;
  }

  case Type::T_FUNCTION: {
    FunctionType *func = t->asFunctionType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("FunctionType", func);
      // **** attributes
      printXml(flags, func->flags);
      printPtr(func, retType);
      printEmbed(func, params);
      printPtr(func, exnSpec);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(func->retType);
    travObjList_S(func, FunctionType, params, Variable); // Variable
    // exnSpec
    if (func->exnSpec) {
      toXml_FunctionType_ExnSpec(func->exnSpec);
    }
    break;
  }

  case Type::T_ARRAY: {
    ArrayType *arr = t->asArrayType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("ArrayType", arr);
      // **** attributes
      printPtr(arr, eltType);
      printXml_int(size, arr->size);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(arr->eltType);
    break;
  }

  case Type::T_POINTERTOMEMBER: {
    PointerToMemberType *ptm = t->asPointerToMemberType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PointerToMemberType", ptm);
      // **** attributes
      printPtr(ptm, inClassNAT);
      printXml(cv, ptm->cv);
      printPtr(ptm, atType);
      tagPrinter.tagEnd();
    }

    // **** subtags
    trav(ptm->inClassNAT);
    trav(ptm->atType);
    break;
  }

  }
}

void XmlTypeWriter::toXml(AtomicType *atom) {
  // idempotency done in each sub-type as it is not done for
  // CompoundType here.
  switch(atom->getTag()) {
  default: xfailure("illegal tag");

  case AtomicType::T_SIMPLE: {
    // idempotency
    if (idmgr.printed(atom)) return;
    SimpleType *simple = atom->asSimpleType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("SimpleType", simple);
      // **** attributes
      printXml(type, simple->type);
      tagPrinter.tagEnd();
    }
    break;
  }

  case AtomicType::T_COMPOUND: {
    // NO!  Do NOT do this here:
//      // idempotency
//      if (idmgr.printed(atom)) return;
    CompoundType *cpd = atom->asCompoundType();
    toXml(cpd);
    break;
  }

  case AtomicType::T_ENUM: {
    // idempotency
    if (idmgr.printed(atom)) return;
    EnumType *e = atom->asEnumType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("EnumType", e);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(e);
      // * members
      printEmbed(e, valueIndex);
      printXml_int(nextValue, e->nextValue);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(e);
    // * members
    // valueIndex
    if (!idmgr.printed(&e->valueIndex)) {
      XmlTagPrinter tagPrinter2(*this);
      if (writingP()) {
        tagPrinter2.printOpenTag("NameMap_EnumType_valueIndex", &e->valueIndex);
        tagPrinter2.tagEnd();
      }

      if (sortNameMapDomainWhenSerializing) {
        for(StringObjDict<EnumType::Value>::SortedKeyIter iter(e->valueIndex);
            !iter.isDone(); iter.next()) {
          char const *name = iter.key();
          // dsw: do you know how bad it gets if I don't put a
          // const-cast here?
          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());

          XmlTagPrinter tagPrinter3(*this);
          if (writingP()) {
            tagPrinter3.printNameMapItemOpenTag(name, eValue);
          }

          toXml_EnumType_Value(eValue);
        }
      } else {
        for(StringObjDict<EnumType::Value>::Iter iter(e->valueIndex);
            !iter.isDone(); iter.next()) {
          rostring name = iter.key();
          // dsw: do you know how bad it gets if I don't put a
          // const-cast here?
          EnumType::Value *eValue = const_cast<EnumType::Value*>(iter.value());

          XmlTagPrinter tagPrinter3(*this);
          if (writingP()) {
            tagPrinter3.printNameMapItemOpenTag(name.c_str(), eValue);
          }

          toXml_EnumType_Value(eValue);
        }
      }
    }
    break;
  }

  case AtomicType::T_TYPEVAR: {
    // idempotency
    if (idmgr.printed(atom)) return;
    TypeVariable *tvar = atom->asTypeVariable();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("TypeVariable", tvar);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(tvar);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(tvar);
    break;
  }

  case AtomicType::T_PSEUDOINSTANTIATION: {
    // idempotency
    if (idmgr.printed(atom)) return;
    PseudoInstantiation *pseudo = atom->asPseudoInstantiation();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("PseudoInstantiation", pseudo);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(pseudo);
      // * members
      printPtr(pseudo, primary);
      printEmbed(pseudo, args);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(pseudo);
    // * members
    trav(pseudo->primary);
    travObjList(pseudo, PseudoInstantiation, args, STemplateArgument);
    break;
  }

  case AtomicType::T_DEPENDENTQTYPE: {
    // idempotency
    if (idmgr.printed(atom)) return;
    DependentQType *dep = atom->asDependentQType();
    XmlTagPrinter tagPrinter(*this);
    if (writingP()) {
      tagPrinter.printOpenTag("DependentQType", dep);
      // **** attributes
      // * superclasses
      toXml_NamedAtomicType_properties(dep);
      // * members
      printPtr(dep, first);
      printPtrAST(dep, rest);
      tagPrinter.tagEnd();
    }

    // **** subtags
    // * superclasses
    toXml_NamedAtomicType_subtags(dep);
    // * members
    trav(dep->first);
    travAST(dep->rest);
    break;
  }

  }
}

void XmlTypeWriter::toXml(CompoundType *cpd) {
  // idempotency
  if (idmgr.printed(cpd)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("CompoundType", cpd);
    // **** attributes
    // * superclasses
    toXml_NamedAtomicType_properties(cpd);
    toXml_Scope_properties(cpd);
    // * members
    printXml_bool(forward, cpd->forward);
    printXml(keyword, cpd->keyword);
    printEmbed(cpd, dataMembers);
    printEmbed(cpd, bases);
    printEmbed(cpd, virtualBases);
    printEmbed(cpd, subobj);
    printEmbed(cpd, conversionOperators);
    printStrRef(instName, cpd->instName);
    printPtrAST(cpd, syntax);
    printPtr(cpd, parameterizingScope);
    printPtr(cpd, selfType);
    tagPrinter.tagEnd();
  }

  // **** subtags
  // * superclasses
  toXml_NamedAtomicType_subtags(cpd);
  toXml_Scope_subtags(cpd);
  // * members
  travObjList_S(cpd, CompoundType, dataMembers, Variable); // Variable
  travObjList(cpd, CompoundType, bases, BaseClass);
  travObjList(cpd, CompoundType, virtualBases, BaseClassSubobj);
  toXml(&cpd->subobj);          // embedded
  travObjList_S(cpd, CompoundType, conversionOperators, Variable); // Variable
  travAST(cpd->syntax);
  trav(cpd->parameterizingScope);
  trav(cpd->selfType);
}

void XmlTypeWriter::toXml_Variable_properties(Variable *var) {
  assert(writingP());
  printXml_SourceLoc(loc, var->loc);
  printStrRef(name, var->name);
  printPtr(var, type);
  printXml(flags, var->flags);
  printPtrAST(var, value);
  printPtr(var, defaultParamType);
  printPtrAST(var, funcDefn);
  printPtr(var, overload);
  printPtr(var, scope);

  // these three fields are an abstraction; here we pretend they are
  // real
  AccessKeyword access = var->getAccess();
  printXml(access, access);
  ScopeKind scopeKind = var->getScopeKind();
  printXml(scopeKind, scopeKind);
  int parameterOrdinal = var->getParameterOrdinal();
  printXml_int(parameterOrdinal, parameterOrdinal);

  printPtr(var, usingAlias_or_parameterizedEntity);
  printPtr(var, templInfo);

  if (var->linkerVisibleName()) {
    newline();
    *out << "fullyQualifiedMangledName=" << xmlAttrQuote(var->fullyQualifiedMangledName0());
  }
}

void XmlTypeWriter::toXml_Variable_subtags(Variable *var) {
  trav(var->type);
  travAST(var->value);
  trav(var->defaultParamType);
  travAST(var->funcDefn);
  trav(var->overload);
  trav(var->scope);
  trav(var->usingAlias_or_parameterizedEntity); // Variable
  trav(var->templInfo);
}

void XmlTypeWriter::toXml(Variable *var) {
#ifdef OINK
  xfailure("this should never be called in Oink");
#endif

  // idempotency
  if (idmgr.printed(var)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("Variable", var);
    // **** attributes
    toXml_Variable_properties(var);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_Variable_subtags(var);
}

void XmlTypeWriter::toXml_FunctionType_ExnSpec(void /*FunctionType::ExnSpec*/ *exnSpec0) {
  FunctionType::ExnSpec *exnSpec = static_cast<FunctionType::ExnSpec *>(exnSpec0);
  // idempotency
  if (idmgr.printed(exnSpec)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("FunctionType_ExnSpec", exnSpec);
    // **** attributes
    printEmbed(exnSpec, types);
    tagPrinter.tagEnd();
  }

  // **** subtags
  travObjList_S(exnSpec, ExnSpec, types, Type);
}

void XmlTypeWriter::toXml_EnumType_Value(void /*EnumType::Value*/ *eValue0) {
  EnumType::Value *eValue = static_cast<EnumType::Value *>(eValue0);
  // idempotency
  if (idmgr.printed(eValue)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("EnumType_Value", eValue);
    // **** attributes
    printStrRef(name, eValue->name);
    printPtr(eValue, type);
    printXml_int(value, eValue->value);
    printPtr(eValue, decl);
    tagPrinter.tagEnd();
  }

  // **** subtags
  trav(eValue->type);
  trav(eValue->decl);           // Variable
}

void XmlTypeWriter::toXml_NamedAtomicType_properties(NamedAtomicType *nat) {
  printStrRef(name, nat->name);
  printPtr(nat, typedefVar);
  printXml(access, nat->access);
}

void XmlTypeWriter::toXml_NamedAtomicType_subtags(NamedAtomicType *nat) {
  trav(nat->typedefVar);        // Variable
}

void XmlTypeWriter::toXml(OverloadSet *oload) {
  // idempotency
  if (idmgr.printed(oload)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("OverloadSet", oload);
    // **** attributes
    printEmbed(oload, set);
    tagPrinter.tagEnd();
  }

  // **** subtags
  travObjList_S(oload, OverloadSet, set, Variable); // Variable
}

void XmlTypeWriter::toXml(BaseClass *bc) {
  // Since BaseClass objects are never manipulated polymorphically,
  // that is, every BaseClass pointer's static type equals its dynamic
  // type, 'bc' cannot actually be a BaseClassSubobj.

  // idempotency
  if (idmgr.printed(bc)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("BaseClass", bc);
    // **** attributes
    toXml_BaseClass_properties(bc);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_BaseClass_subtags(bc);
}

void XmlTypeWriter::toXml_BaseClass_properties(BaseClass *bc) {
  printPtr(bc, ct);
  printXml(access, bc->access);
  printXml_bool(isVirtual, bc->isVirtual);
}

void XmlTypeWriter::toXml_BaseClass_subtags(BaseClass *bc) {
  trav(bc->ct);
}

void XmlTypeWriter::toXml(BaseClassSubobj *bc) {
  // idempotency
  if (idmgr.printed(bc)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("BaseClassSubobj", bc);
    // **** attributes
    // * superclass
    toXml_BaseClass_properties(bc);
    // * members
    printEmbed(bc, parents);
    tagPrinter.tagEnd();
  }

  // **** subtags
  // * superclass
  toXml_BaseClass_subtags(bc);
  // * members
  travObjList_S(bc, BaseClassSubobj, parents, BaseClassSubobj);
}

void XmlTypeWriter::toXml(Scope *scope) {
  // are we really a CompoundType?
  if (CompoundType *cpd = dynamic_cast<CompoundType*>(scope)) {
    toXml(cpd);
    return;
  }
  // idempotency
  if (idmgr.printed(scope)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("Scope", scope);
    // **** attributes
    toXml_Scope_properties(scope);
    tagPrinter.tagEnd();
  }

  // **** subtags
  toXml_Scope_subtags(scope);
}

void XmlTypeWriter::toXml_Scope_properties(Scope *scope) {
  printEmbed(scope, variables);
  printEmbed(scope, typeTags);
  printXml_bool(canAcceptNames, scope->canAcceptNames);
  printPtr(scope, parentScope);
  printXml(scopeKind, scope->scopeKind);
  printPtr(scope, namespaceVar);
  printEmbed(scope, templateParams);
  printPtr(scope, curCompound);
  printXml_SourceLoc(curLoc, scope->curLoc);
}

void XmlTypeWriter::toXml_Scope_subtags(Scope *scope) {
  // FIX: these are like function template "partial specializations"
  // (if such things existed), as the 'Variable' paramter actually
  // also changes the implementation.
  travStringRefMap(scope, Scope, variables, Variable); // Variable
  travStringRefMap(scope, Scope, typeTags, Variable); // Variable
  trav(scope->parentScope);
  trav(scope->namespaceVar);    // Variable
  travObjList_S(scope, Scope, templateParams, Variable); // Variable
  trav(scope->curCompound);
}

void XmlTypeWriter::toXml(STemplateArgument *sta) {
  // idempotency
  if (idmgr.printed(sta)) return;
  XmlTagPrinter tagPrinter(*this);
  if (writingP()) {
    tagPrinter.printOpenTag("STemplateArgument", sta);

    // **** attributes
    printXml(kind, sta->kind);
    newline();

    switch(sta->kind) {
    default: xfailure("illegal STemplateArgument kind"); break;

    case STemplateArgument::STA_TYPE:
      printPtrUnion(sta, value.t, t);
      break;

    case STemplateArgument::STA_INT:
      printXml_int(i, sta->value.i);
      break;

    case STemplateArgument::STA_ENUMERATOR:
    case STemplateArgument::STA_REFERENCE:
    case STemplateArgument::STA_POINTER:
    case STemplateArgument::STA_MEMBER:
      printPtrUnion(sta, value.v, v);
      break;

    case STemplateArgument::STA_DEPEXPR:
      printPtrASTUnion(sta, value.e, e);
      break;

    case STemplateArgument::STA_TEMPLATE:
      xfailure("template template arguments not implemented");
      break;

    case STemplateArgument::STA_ATOMIC:
      printPtrUnion(sta, value.at, at);
      break;
    }
    tagPrinter.tagEnd();
  }

  // **** subtags

  // NOTE: I don't use the trav() macro here because it would be weird
  // to test the member of a union for being NULL; it should have a
  // well-defined value if it is the selected type of the tag.
  switch(sta->kind) {
  default: xfailure("illegal STemplateArgument kind"); break;
  case STemplateArgument::STA_TYPE:
    toXml(sta->value.t);
    break;

  case STemplateArgument::STA_INT:
    // nothing to do
    break;

  case STemplateArgument::STA_ENUMERATOR:
  case STemplateArgument::STA_REFERENCE:
  case STemplateArgument::STA_POINTER:
  case STemplateArgument::STA_MEMBER:
    trav(sta->value.v);         // Variable
    break;

  case STemplateArgument::STA_DEPEXPR:
    // (quarl) I don't get what's going on here; this looks weird.
    if (astVisitor) {
      sta->value.e->traverse(*astVisitor);
    }
    break;

  case STemplateArgument::STA_TEMPLATE:
    xfailure("template template arguments not implemented");
    break;

  case STemplateArgument::STA_ATOMIC:
    toXml(const_cast<AtomicType*>(sta->value.at));
    break;
  }
}

void XmlTypeWriter::toXml(TemplateInfo *ti) {
{'fraction_non_alphanumeric': 0.13742795389048992, 'fraction_numerical': 0.0012350761630300535, 'mean_word_length': 3.5024328081557, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 191, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4404232', 'n_tokens_mistral': 13437, 'n_tokens_neox': 13112, 'n_words': 2369}