view src/dil/ast/NodeCopier.d @ 806:bcb74c9b895c

Moved out files in the trunk folder to the root.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sun, 09 Mar 2008 00:12:19 +0100
parents trunk/src/dil/ast/NodeCopier.d@9e6c6bb73e5f
children
line wrap: on
line source

/++
  Author: Aziz Köksal
  License: GPL3
+/
module dil.ast.NodeCopier;

import common;

/// Mixed into the body of a class that inherits from Node.
const string copyMethod = `
  override typeof(this) copy()
  {
    mixin copyNode!(typeof(this));
    return copyNode(this);
  }`;

/// A helper function that generates code for copying subnodes.
string doCopy_(string obj, string[] members)
{
  char[] result;
  foreach (member; members)
  {
    if (member.length > 2 && member[$-2..$] == "[]") // Array copy.
    {
      member = member[0..$-2];
      // obj.member = obj.member.dup;
      // foreach (ref m_; obj.member)
      //   m_ = m_.copy();
      result ~= obj~"."~member~" = "~obj~"."~member~".dup;"
      "foreach (ref m_; "~obj~"."~member~")"
        "m_ = m_.copy();";
    }
    else if (member[$-1] == '?') // Optional member copy.
    {
      member = member[0..$-1];
      // obj.member && (obj.member = obj.member.copy());
      result ~= obj~"."~member~" && ("~obj~"."~member~" = "~obj~"."~member~".copy());";
    }
    else // Non-optional member copy.
      // obj.member = obj.member.copy();
      result ~= obj~"."~member~" = "~obj~"."~member~".copy();";
  }
  return result;
}

string doCopy(string[] members)
{
  return doCopy_("x", members);
}

string doCopy(string member)
{
  return doCopy_("x", [member]);
}

// pragma(msg, doCopy("decls?"));

/// Returns a deep copy of node.
T copyNode(T)(T node)
{
  assert(node !is null);

  // Firstly do a shallow copy.
  T x = cast(T)cast(void*)node.dup;

  // Now copy the subnodes.
  static if (is(Declaration) && is(T : Declaration))
  {
    alias T D;
    static if (is(D == CompoundDeclaration))
      mixin(doCopy("decls[]"));
    //EmptyDeclaration,
    //IllegalDeclaration,
    //ModuleDeclaration have no subnodes.
    static if (is(D == AliasDeclaration) ||
               is(D == TypedefDeclaration))
      mixin(doCopy("decl"));
    static if (is(D == EnumDeclaration))
      mixin(doCopy(["baseType?", "members[]"]));
    static if (is(D == EnumMemberDeclaration))
      mixin(doCopy("value"));
    static if (is(D == ClassDeclaration) || is( D == InterfaceDeclaration))
      mixin(doCopy(["bases[]", "decls"]));
    static if (is(D == StructDeclaration) || is(D == UnionDeclaration))
      mixin(doCopy("decls"));
    static if (is(D == ConstructorDeclaration))
      mixin(doCopy(["params", "funcBody"]));
    static if (is(D == StaticConstructorDeclaration) ||
               is(D == DestructorDeclaration) ||
               is(D == StaticDestructorDeclaration) ||
               is(D == InvariantDeclaration) ||
               is(D == UnittestDeclaration))
      mixin(doCopy("funcBody"));
    static if (is(D == FunctionDeclaration))
      mixin(doCopy(["returnType", "params", "funcBody"]));
    static if (is(D == VariablesDeclaration))
    {
      mixin(doCopy("typeNode?"));
      x.inits = x.inits.dup;
      foreach(ref init; x.inits)
        init && (init = init.copy());
    }
    static if (is(D == DebugDeclaration) || is(D == VersionDeclaration))
      mixin(doCopy(["decls?","elseDecls?"]));
    static if (is(D == StaticIfDeclaration))
      mixin(doCopy(["condition","ifDecls", "elseDecls?"]));
    static if (is(D == StaticAssertDeclaration))
      mixin(doCopy(["condition","message?"]));
    static if (is(D == TemplateDeclaration))
      mixin(doCopy(["tparams","decls"]));
    static if (is(D == NewDeclaration) || is(D == DeleteDeclaration))
      mixin(doCopy(["params","funcBody"]));
    static if (is(D == ProtectionDeclaration) ||
               is(D == StorageClassDeclaration) ||
               is(D == LinkageDeclaration) ||
               is(D == AlignDeclaration))
      mixin(doCopy("decls"));
    static if (is(D == PragmaDeclaration))
      mixin(doCopy(["args[]","decls"]));
    static if (is(D == MixinDeclaration))
      mixin(doCopy(["templateExpr?","argument?"]));
  }
  else
  static if (is(Expression) && is(T : Expression))
  {
    alias T E;
    static if (is(E == IllegalExpression))
    {}
    else
    static if (is(E == CondExpression))
      mixin(doCopy(["condition", "lhs", "rhs"]));
    else
    static if (is(E : BinaryExpression))
      mixin(doCopy(["lhs", "rhs"]));
    else
    static if (is(E : UnaryExpression))
    {
      static if (is(E == CastExpression))
        mixin(doCopy("type"));
      mixin(doCopy("e")); // Copy member in base class UnaryExpression.
      static if (is(E == IndexExpression))
        mixin(doCopy("args[]"));
      static if (is(E == SliceExpression))
        mixin(doCopy(["left?", "right?"]));
      static if (is(E == AsmPostBracketExpression))
        mixin(doCopy("e2"));
    }
    else
    {
      static if (is(E == NewExpression))
        mixin(doCopy(["newArgs[]", "type", "ctorArgs[]"]));
      static if (is(E == NewAnonClassExpression))
        mixin(doCopy(["newArgs[]", "bases[]", "ctorArgs[]", "decls"]));
      static if (is(E == AsmBracketExpression))
        mixin(doCopy("e"));
      static if (is(E == TemplateInstanceExpression))
        mixin(doCopy("targs?"));
      static if (is(E == ArrayLiteralExpression))
        mixin(doCopy("values[]"));
      static if (is(E == AArrayLiteralExpression))
        mixin(doCopy(["keys[]", "values[]"]));
      static if (is(E == AssertExpression))
        mixin(doCopy(["expr", "msg?"]));
      static if (is(E == MixinExpression) ||
                 is(E == ImportExpression))
        mixin(doCopy("expr"));
      static if (is(E == TypeofExpression) ||
                 is(E == TypeDotIdExpression) ||
                 is(E == TypeidExpression))
        mixin(doCopy("type"));
      static if (is(E == IsExpression))
        mixin(doCopy(["type", "specType?", "tparams?"]));
      static if (is(E == FunctionLiteralExpression))
        mixin(doCopy(["returnType?", "params?", "funcBody"]));
      static if (is(E == ParenExpression))
        mixin(doCopy("next"));
      static if (is(E == TraitsExpression))
        mixin(doCopy("targs"));
      // VoidInitializer has no subnodes.
      static if (is(E == ArrayInitExpression))
      {
        mixin(doCopy("values[]"));
        x.keys = x.keys.dup;
        foreach(ref key; x.keys)
          key && (key = key.copy());
      }
      static if (is(E == StructInitExpression))
        mixin(doCopy("values[]"));
      static if (is(E == StringExpression))
        x.str = x.str.dup;
    }
  }
  else
  static if (is(Statement) && is(T : Statement))
  {
    alias T S;
    static if (is(S == CompoundStatement))
      mixin(doCopy("stmnts[]"));
    //IllegalStatement,
    //EmptyStatement have no subnodes.
    static if (is(S == FuncBodyStatement))
      mixin(doCopy(["funcBody?", "inBody?", "outBody?"]));
    static if (is(S == ScopeStatement) || is(S == LabeledStatement))
      mixin(doCopy("s"));
    static if (is(S == ExpressionStatement))
      mixin(doCopy("e"));
    static if (is(S == DeclarationStatement))
      mixin(doCopy("decl"));
    static if (is(S == IfStatement))
    {
      if (x.variable)
        mixin(doCopy("variable"));
      else
        mixin(doCopy("condition"));
      mixin(doCopy(["ifBody", "elseBody?"]));
    }
    static if (is(S == WhileStatement))
      mixin(doCopy(["condition", "whileBody"]));
    static if (is(S == DoWhileStatement))
      mixin(doCopy(["doBody", "condition"]));
    static if (is(S == ForStatement))
      mixin(doCopy(["init?", "condition?", "increment?", "forBody"]));
    static if (is(S == ForeachStatement))
      mixin(doCopy(["params", "aggregate", "forBody"]));
    static if (is(S == ForeachRangeStatement))
      mixin(doCopy(["params", "lower", "upper", "forBody"]));
    static if (is(S == SwitchStatement))
      mixin(doCopy(["condition", "switchBody"]));
    static if (is(S == CaseStatement))
      mixin(doCopy(["values[]", "caseBody"]));
    static if (is(S == DefaultStatement))
      mixin(doCopy("defaultBody"));
    //ContinueStatement,
    //BreakStatement have no subnodes.
    static if (is(S == ReturnStatement))
      mixin(doCopy("e?"));
    static if (is(S == GotoStatement))
      mixin(doCopy("caseExpr?"));
    static if (is(S == WithStatement))
      mixin(doCopy(["e", "withBody"]));
    static if (is(S == SynchronizedStatement))
      mixin(doCopy(["e?", "syncBody"]));
    static if (is(S == TryStatement))
      mixin(doCopy(["tryBody", "catchBodies[]", "finallyBody?"]));
    static if (is(S == CatchStatement))
      mixin(doCopy(["param?", "catchBody"]));
    static if (is(S == FinallyStatement))
      mixin(doCopy("finallyBody"));
    static if (is(S == ScopeGuardStatement))
      mixin(doCopy("scopeBody"));
    static if (is(S == ThrowStatement))
      mixin(doCopy("e"));
    static if (is(S == VolatileStatement))
      mixin(doCopy("volatileBody?"));
    static if (is(S == AsmBlockStatement))
      mixin(doCopy("statements"));
    static if (is(S == AsmStatement))
      mixin(doCopy("operands[]"));
    //AsmAlignStatement,
    //IllegalAsmStatement have no subnodes.
    static if (is(S == PragmaStatement))
      mixin(doCopy(["args[]", "pragmaBody"]));
    static if (is(S == MixinStatement))
      mixin(doCopy("templateExpr"));
    static if (is(S == StaticIfStatement))
      mixin(doCopy(["condition", "ifBody", "elseBody?"]));
    static if (is(S == StaticAssertStatement))
      mixin(doCopy(["condition", "message?"]));
    static if (is(S == DebugStatement) || is(S == VersionStatement))
      mixin(doCopy(["mainBody", "elseBody?"]));
  }
  else
  static if (is(TypeNode) && is(T : TypeNode))
  {
    //IllegalType,
    //IntegralType,
    //ModuleScopeType,
    //IdentifierType have no subnodes.
    static if (is(T == QualifiedType))
      mixin(doCopy(["lhs", "rhs"]));
    static if (is(T == TypeofType))
      mixin(doCopy("e"));
    static if (is(T == TemplateInstanceType))
      mixin(doCopy("targs?"));
    static if (is(T == PointerType))
      mixin(doCopy("next"));
    static if (is(T == ArrayType))
      mixin(doCopy(["next", "assocType?", "e1?", "e2?"]));
    static if (is(T == FunctionType) || is(T == DelegateType))
      mixin(doCopy(["returnType", "params"]));
    static if (is(T == CFuncPointerType))
      mixin(doCopy(["next", "params?"]));
    static if (is(T == BaseClassType) ||
               is(T == ConstType) ||
               is(T == InvariantType))
      mixin(doCopy("next"));
  }
  else
  static if (is(Parameter) && is(T == Parameter))
  {
    mixin(doCopy(["type?", "defValue?"]));
  }
  else
  static if (is(Parameter) && is(T == Parameters) ||
             is(TemplateParameter) && is(T == TemplateParameters) ||
             is(TemplateArguments) && is(T == TemplateArguments))
  {
    mixin(doCopy("children[]"));
  }
  else
  static if (is(TemplateParameter) && is(T : TemplateParameter))
  {
    static if (is(N == TemplateAliasParameter) ||
               is(N == TemplateTypeParameter) ||
               is(N == TemplateThisParameter))
      mixin(doCopy(["specType", "defType"]));
    static if (is(N == TemplateValueParameter))
      mixin(doCopy(["valueType", "specValue?", "defValue?"]));
    //TemplateTupleParameter has no subnodes.
  }
  else
    static assert(0, "copying of "~typeof(x).stringof~" is not handled");
  return x;
}