changeset 791:5fe89bb8cbdd

Implemented syntax tree copying.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Tue, 26 Feb 2008 20:13:41 +0100
parents a83a07f6233d
children 05dfe88dd3bb
files trunk/src/dil/ast/Declaration.d trunk/src/dil/ast/Declarations.d trunk/src/dil/ast/DefaultVisitor.d trunk/src/dil/ast/Expression.d trunk/src/dil/ast/Expressions.d trunk/src/dil/ast/Node.d trunk/src/dil/ast/NodeCopier.d trunk/src/dil/ast/Parameters.d trunk/src/dil/ast/Statement.d trunk/src/dil/ast/Statements.d trunk/src/dil/ast/Type.d trunk/src/dil/ast/Types.d trunk/src/dil/semantic/Interpreter.d
diffstat 13 files changed, 550 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/dil/ast/Declaration.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Declaration.d	Tue Feb 26 20:13:41 2008 +0100
@@ -40,4 +40,5 @@
     this.prot = prot;
   }
 
+  override abstract Declaration copy();
 }
--- a/trunk/src/dil/ast/Declarations.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Declarations.d	Tue Feb 26 20:13:41 2008 +0100
@@ -6,10 +6,11 @@
 
 public import dil.ast.Declaration;
 import dil.ast.Node;
-import dil.ast.Expressions;
+import dil.ast.Expression;
 import dil.ast.Types;
 import dil.ast.Statements;
 import dil.ast.Parameters;
+import dil.ast.NodeCopier;
 import dil.lexer.IdTable;
 import dil.semantic.Symbols;
 import dil.Enums;
@@ -37,6 +38,13 @@
   {
     return cast(Declaration[])this.children;
   }
+
+  void decls(Declaration[] decls)
+  {
+    this.children = decls;
+  }
+
+  mixin(copyMethod);
 }
 
 /// Single semicolon.
@@ -46,19 +54,19 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
-/++
-  Illegal declarations encompass all tokens that don't
-  start a DeclarationDefinition.
-  See_Also: dil.lexer.Token.isDeclDefStartToken()
-+/
+/// Illegal declarations encompass all tokens that don't
+/// start a DeclarationDefinition.
+/// See_Also: dil.lexer.Token.isDeclDefStartToken()
 class IllegalDeclaration : Declaration
 {
   this()
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 /// FQN = fully qualified name
@@ -102,6 +110,8 @@
       pname = pname[0..$-1]; // Remove last separator
     return pname;
   }
+
+  mixin(copyMethod);
 }
 
 class ImportDeclaration : Declaration
@@ -136,6 +146,8 @@
     }
     return FQNs;
   }
+
+  mixin(copyMethod);
 }
 
 class AliasDeclaration : Declaration
@@ -147,6 +159,7 @@
     addChild(decl);
     this.decl = decl;
   }
+  mixin(copyMethod);
 }
 
 class TypedefDeclaration : Declaration
@@ -158,6 +171,7 @@
     addChild(decl);
     this.decl = decl;
   }
+  mixin(copyMethod);
 }
 
 class EnumDeclaration : Declaration
@@ -178,6 +192,8 @@
   }
 
   Enum symbol;
+
+  mixin(copyMethod);
 }
 
 class EnumMemberDeclaration : Declaration
@@ -194,6 +210,8 @@
   }
 
   EnumMember symbol;
+
+  mixin(copyMethod);
 }
 
 class TemplateDeclaration : Declaration
@@ -214,6 +232,8 @@
   }
 
   Template symbol; /// The template symbol for this declaration.
+
+  mixin(copyMethod);
 }
 
 abstract class AggregateDeclaration : Declaration
@@ -228,6 +248,7 @@
 //     this.tparams = tparams;
     this.decls = decls;
   }
+  mixin(copyMethod);
 }
 
 class ClassDeclaration : AggregateDeclaration
@@ -245,6 +266,8 @@
   }
 
   Class symbol; /// The class symbol for this declaration.
+
+  mixin(copyMethod);
 }
 
 class InterfaceDeclaration : AggregateDeclaration
@@ -264,6 +287,8 @@
   alias dil.semantic.Symbols.Interface Interface;
 
   Interface symbol; /// The interface symbol for this declaration.
+
+  mixin(copyMethod);
 }
 
 class StructDeclaration : AggregateDeclaration
@@ -283,6 +308,8 @@
   }
 
   Struct symbol; /// The struct symbol for this declaration.
+
+  mixin(copyMethod);
 }
 
 class UnionDeclaration : AggregateDeclaration
@@ -296,6 +323,8 @@
   }
 
   Union symbol; /// The union symbol for this declaration.
+
+  mixin(copyMethod);
 }
 
 class ConstructorDeclaration : Declaration
@@ -312,6 +341,7 @@
     this.params = params;
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class StaticConstructorDeclaration : Declaration
@@ -325,6 +355,7 @@
 
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class DestructorDeclaration : Declaration
@@ -338,6 +369,7 @@
 
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class StaticDestructorDeclaration : Declaration
@@ -351,6 +383,7 @@
 
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class FunctionDeclaration : Declaration
@@ -388,6 +421,8 @@
     //                  ^ params.begin.prevNWS
     return params.begin.prevNWS.kind == TOK.RParen;
   }
+
+  mixin(copyMethod);
 }
 
 /// VariablesDeclaration := Type? Identifier ("=" Init)? ("," Identifier ("=" Init)?)* ";"
@@ -420,6 +455,8 @@
   }
 
   Variable[] variables;
+
+  mixin(copyMethod);
 }
 
 class InvariantDeclaration : Declaration
@@ -433,6 +470,7 @@
 
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class UnittestDeclaration : Declaration
@@ -446,6 +484,7 @@
 
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 abstract class ConditionalCompilationDeclaration : Declaration
@@ -487,6 +526,7 @@
     super(spec, cond, decls, elseDecls);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class VersionDeclaration : ConditionalCompilationDeclaration
@@ -496,6 +536,7 @@
     super(spec, cond, decls, elseDecls);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class StaticIfDeclaration : Declaration
@@ -514,6 +555,7 @@
     this.ifDecls = ifDecls;
     this.elseDecls = elseDecls;
   }
+  mixin(copyMethod);
 }
 
 class StaticAssertDeclaration : Declaration
@@ -529,6 +571,7 @@
     this.condition = condition;
     this.message = message;
   }
+  mixin(copyMethod);
 }
 
 class NewDeclaration : Declaration
@@ -545,6 +588,7 @@
     this.params = params;
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 class DeleteDeclaration : Declaration
@@ -561,6 +605,7 @@
     this.params = params;
     this.funcBody = funcBody;
   }
+  mixin(copyMethod);
 }
 
 abstract class AttributeDeclaration : Declaration
@@ -583,6 +628,7 @@
     mixin(set_kind);
     this.prot = prot;
   }
+  mixin(copyMethod);
 }
 
 class StorageClassDeclaration : AttributeDeclaration
@@ -595,6 +641,7 @@
 
     this.storageClass = storageClass;
   }
+  mixin(copyMethod);
 }
 
 class LinkageDeclaration : AttributeDeclaration
@@ -607,6 +654,7 @@
 
     this.linkageType = linkageType;
   }
+  mixin(copyMethod);
 }
 
 class AlignDeclaration : AttributeDeclaration
@@ -618,6 +666,7 @@
     mixin(set_kind);
     this.size = size;
   }
+  mixin(copyMethod);
 }
 
 class PragmaDeclaration : AttributeDeclaration
@@ -633,6 +682,7 @@
     this.ident = ident;
     this.args = args;
   }
+  mixin(copyMethod);
 }
 
 class MixinDeclaration : Declaration
@@ -665,4 +715,6 @@
   {
     return argument !is null;
   }
+
+  mixin(copyMethod);
 }
--- a/trunk/src/dil/ast/DefaultVisitor.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/DefaultVisitor.d	Tue Feb 26 20:13:41 2008 +0100
@@ -109,7 +109,7 @@
     static if (is(E == IllegalExpression))
     {}
     else
-    static if (is(E : CondExpression))
+    static if (is(E == CondExpression))
       visitE(e.condition), visitE(e.lhs), visitE(e.rhs);
     else
     static if (is(E : BinaryExpression))
@@ -192,8 +192,8 @@
   {
     alias T S;
     static if (is(S == CompoundStatement))
-      foreach (node; s.children)
-        visitS(cast(Statement)cast(void*)node);
+      foreach (stmnt; s.stmnts)
+        visitS(stmnt);
     //IllegalStatement has no subnodes.
     static if (is(S == FuncBodyStatement))
       s.funcBody && visitS(s.funcBody),
@@ -265,7 +265,8 @@
     static if (is(S == AsmStatement))
       foreach (op; s.operands)
         visitE(op);
-    //AsmAlignStatement has no subnodes.
+    //AsmAlignStatement,
+    //IllegalAsmStatement have no subnodes.
     static if (is(S == PragmaStatement))
     {
       foreach (arg; s.args)
@@ -342,7 +343,7 @@
     //TemplateTupleParameter has no subnodes.
   }
   else
-    assert(0, "Missing default visit method for: "~t.classinfo.name);
+    static assert(0, "Missing default visit method for: "~typeof(t).stringof);
   return t;
 }
 
--- a/trunk/src/dil/ast/Expression.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Expression.d	Tue Feb 26 20:13:41 2008 +0100
@@ -17,4 +17,6 @@
   {
     super(NodeCategory.Expression);
   }
+
+  override abstract Expression copy();
 }
--- a/trunk/src/dil/ast/Expressions.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Expressions.d	Tue Feb 26 20:13:41 2008 +0100
@@ -10,6 +10,7 @@
 import dil.ast.Declarations;
 import dil.ast.Statements;
 import dil.ast.Parameters;
+import dil.ast.NodeCopier;
 import dil.lexer.Identifier;
 import dil.semantic.Types;
 import common;
@@ -20,6 +21,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 abstract class BinaryExpression : Expression
@@ -34,6 +36,7 @@
     this.rhs = rhs;
     this.tok = tok;
   }
+  mixin(copyMethod);
 }
 
 class CondExpression : BinaryExpression
@@ -46,6 +49,7 @@
     mixin(set_kind);
     this.condition = condition;
   }
+  mixin(copyMethod);
 }
 
 class CommaExpression : BinaryExpression
@@ -355,6 +359,7 @@
     addChild(e);
     this.e = e;
   }
+  mixin(copyMethod);
 }
 
 class AddressExpression : UnaryExpression
@@ -478,6 +483,7 @@
     this.type = type;
     this.ctorArgs = ctorArgs;
   }
+  mixin(copyMethod);
 }
 
 class NewAnonClassExpression : /*Unary*/Expression
@@ -500,6 +506,7 @@
     this.ctorArgs = ctorArgs;
     this.decls = decls;
   }
+  mixin(copyMethod);
 }
 
 class DeleteExpression : UnaryExpression
@@ -521,6 +528,7 @@
     mixin(set_kind);
     this.type = type;
   }
+  mixin(copyMethod);
 }
 
 class IndexExpression : UnaryExpression
@@ -533,6 +541,7 @@
     addChildren(args);
     this.args = args;
   }
+  mixin(copyMethod);
 }
 
 class SliceExpression : UnaryExpression
@@ -549,6 +558,7 @@
     this.left = left;
     this.right = right;
   }
+  mixin(copyMethod);
 }
 
 /// Module scope operator: '.' (IdentifierExpression|TemplateInstanceExpression)
@@ -576,6 +586,7 @@
     mixin(set_kind);
     this.identifier = identifier;
   }
+  mixin(copyMethod);
 }
 
 class SpecialTokenExpression : Expression
@@ -588,6 +599,8 @@
   }
 
   Expression value; /// The expression created in the semantic phase.
+
+  mixin(copyMethod);
 }
 
 class TemplateInstanceExpression : Expression
@@ -601,6 +614,7 @@
     this.ident = ident;
     this.targs = targs;
   }
+  mixin(copyMethod);
 }
 
 class ThisExpression : Expression
@@ -609,6 +623,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class SuperExpression : Expression
@@ -617,6 +632,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class NullExpression : Expression
@@ -631,6 +647,8 @@
     this();
     this.type = type;
   }
+
+  mixin(copyMethod);
 }
 
 class DollarExpression : Expression
@@ -639,6 +657,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class BoolExpression : Expression
@@ -655,6 +674,8 @@
   }
 
   Expression value; /// IntExpression of type int.
+
+  mixin(copyMethod);
 }
 
 class IntExpression : Expression
@@ -686,6 +707,8 @@
     }
     this(token.ulong_, type);
   }
+
+  mixin(copyMethod);
 }
 
 class RealExpression : Expression
@@ -721,22 +744,23 @@
     }
     this(token.real_, type);
   }
+
+  mixin(copyMethod);
 }
 
-/++
-  This expression holds a complex number.
-  It is only created in the semantic phase.
-+/
+
+/// This expression holds a complex number.
+/// It is only created in the semantic phase.
 class ComplexExpression : Expression
 {
   creal number;
-
   this(creal number, Type type)
   {
     mixin(set_kind);
     this.number = number;
     this.type = type;
   }
+  mixin(copyMethod);
 }
 
 class CharExpression : Expression
@@ -747,6 +771,7 @@
     mixin(set_kind);
     this.character = character;
   }
+  mixin(copyMethod);
 }
 
 class StringExpression : Expression
@@ -783,6 +808,8 @@
     // TODO: convert to char[] if charType !is Types.Char.
     return cast(char[])str[0..$-1];
   }
+
+  mixin(copyMethod);
 }
 
 class ArrayLiteralExpression : Expression
@@ -794,6 +821,7 @@
     addOptChildren(values);
     this.values = values;
   }
+  mixin(copyMethod);
 }
 
 class AArrayLiteralExpression : Expression
@@ -808,6 +836,7 @@
     this.keys = keys;
     this.values = values;
   }
+  mixin(copyMethod);
 }
 
 class AssertExpression : Expression
@@ -821,6 +850,7 @@
     this.expr = expr;
     this.msg = msg;
   }
+  mixin(copyMethod);
 }
 
 class MixinExpression : Expression
@@ -832,6 +862,7 @@
     addChild(expr);
     this.expr = expr;
   }
+  mixin(copyMethod);
 }
 
 class ImportExpression : Expression
@@ -843,6 +874,7 @@
     addChild(expr);
     this.expr = expr;
   }
+  mixin(copyMethod);
 }
 
 class TypeofExpression : Expression
@@ -854,6 +886,7 @@
     addChild(type);
     this.type = type;
   }
+  mixin(copyMethod);
 }
 
 class TypeDotIdExpression : Expression
@@ -867,6 +900,7 @@
     this.type = type;
     this.ident = ident;
   }
+  mixin(copyMethod);
 }
 
 class TypeidExpression : Expression
@@ -878,6 +912,7 @@
     addChild(type);
     this.type = type;
   }
+  mixin(copyMethod);
 }
 
 class IsExpression : Expression
@@ -902,6 +937,7 @@
     this.specType = specType;
     this.tparams = tparams;
   }
+  mixin(copyMethod);
 }
 
 class FunctionLiteralExpression : Expression
@@ -931,6 +967,8 @@
     this.funcBody = funcBody;
     this();
   }
+
+  mixin(copyMethod);
 }
 
 /// ParenthesisExpression := "(" Expression ")"
@@ -943,6 +981,7 @@
     addChild(next);
     this.next = next;
   }
+  mixin(copyMethod);
 }
 
 // version(D2)
@@ -958,6 +997,7 @@
     this.ident = ident;
     this.targs = targs;
   }
+  mixin(copyMethod);
 }
 // }
 
@@ -967,6 +1007,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class ArrayInitExpression : Expression
@@ -985,6 +1026,7 @@
     this.keys = keys;
     this.values = values;
   }
+  mixin(copyMethod);
 }
 
 class StructInitExpression : Expression
@@ -998,6 +1040,7 @@
     this.idents = idents;
     this.values = values;
   }
+  mixin(copyMethod);
 }
 
 class AsmTypeExpression : UnaryExpression
@@ -1037,6 +1080,7 @@
     addChild(e2);
     this.e2 = e2;
   }
+  mixin(copyMethod);
 }
 
 class AsmBracketExpression : Expression
@@ -1048,6 +1092,7 @@
     addChild(e);
     this.e = e;
   }
+  mixin(copyMethod);
 }
 
 class AsmLocalSizeExpression : Expression
@@ -1056,6 +1101,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class AsmRegisterExpression : Expression
@@ -1068,4 +1114,5 @@
     this.register = register;
     this.number = number;
   }
+  mixin(copyMethod);
 }
--- a/trunk/src/dil/ast/Node.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Node.d	Tue Feb 26 20:13:41 2008 +0100
@@ -77,6 +77,20 @@
   {
     return cast(Class)cast(void*)this;
   }
+
+  /// Returns a deep copy of this node.
+  abstract Node copy();
+
+  /// Returns a shallow copy of this object.
+  final Node dup()
+  {
+    // Find out the size of this object.
+    alias typeof(this.classinfo.init[0]) byte_t;
+    size_t size = this.classinfo.init.length;
+    // Copy this object's data.
+    byte_t[] data = (cast(byte_t*)this)[0..size].dup;
+    return cast(Node)data.ptr;
+  }
 }
 
 /// This string is mixed into the constructor of a class that inherits
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/dil/ast/NodeCopier.d	Tue Feb 26 20:13:41 2008 +0100
@@ -0,0 +1,324 @@
+/++
+  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,
+    //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 == ModuleScopeType) ||
+               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;
+}
--- a/trunk/src/dil/ast/Parameters.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Parameters.d	Tue Feb 26 20:13:41 2008 +0100
@@ -7,6 +7,7 @@
 import dil.ast.Node;
 import dil.ast.Type;
 import dil.ast.Expression;
+import dil.ast.NodeCopier;
 import dil.lexer.Identifier;
 import dil.Enums;
 
@@ -52,6 +53,8 @@
   {
     return !!(stc & StorageClass.Variadic);
   }
+
+  mixin(copyMethod);
 }
 
 /// Array of parameters.
@@ -78,6 +81,8 @@
 
   size_t length()
   { return children.length; }
+
+  mixin(copyMethod);
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~
@@ -93,6 +98,7 @@
     super(NodeCategory.Other);
     this.ident = ident;
   }
+  override abstract TemplateParameter copy();
 }
 
 /// E.g.: (alias T)
@@ -109,6 +115,7 @@
     this.specType = specType;
     this.defType = defType;
   }
+  mixin(copyMethod);
 }
 
 /// E.g.: (T t)
@@ -125,6 +132,7 @@
     this.specType = specType;
     this.defType = defType;
   }
+  mixin(copyMethod);
 }
 
 // version(D2)
@@ -143,6 +151,7 @@
     this.specType = specType;
     this.defType = defType;
   }
+  mixin(copyMethod);
 }
 // }
 
@@ -163,6 +172,7 @@
     this.specValue = specValue;
     this.defValue = defValue;
   }
+  mixin(copyMethod);
 }
 
 /// E.g.: (T...)
@@ -174,6 +184,7 @@
     mixin(set_kind);
     this.ident = ident;
   }
+  mixin(copyMethod);
 }
 
 /// Array of template parameters.
@@ -194,6 +205,8 @@
   {
     return cast(TemplateParameter[])children;
   }
+
+  mixin(copyMethod);
 }
 
 /// Array of template arguments.
@@ -209,4 +222,6 @@
   {
     addChild(argument);
   }
+
+  mixin(copyMethod);
 }
--- a/trunk/src/dil/ast/Statement.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Statement.d	Tue Feb 26 20:13:41 2008 +0100
@@ -13,4 +13,6 @@
   {
     super(NodeCategory.Statement);
   }
+
+  override abstract Statement copy();
 }
--- a/trunk/src/dil/ast/Statements.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Statements.d	Tue Feb 26 20:13:41 2008 +0100
@@ -6,10 +6,11 @@
 
 public import dil.ast.Statement;
 import dil.ast.Node;
-import dil.ast.Expressions;
-import dil.ast.Declarations;
-import dil.ast.Types;
+import dil.ast.Expression;
+import dil.ast.Declaration;
+import dil.ast.Type;
 import dil.ast.Parameters;
+import dil.ast.NodeCopier;
 import dil.lexer.IdTable;
 
 class CompoundStatement : Statement
@@ -23,6 +24,18 @@
   {
     addChild(s);
   }
+
+  Statement[] stmnts()
+  {
+    return cast(Statement[])this.children;
+  }
+
+  void stmnts(Statement[] stmnts)
+  {
+    this.children = stmnts;
+  }
+
+  mixin(copyMethod);
 }
 
 class IllegalStatement : Statement
@@ -31,6 +44,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class EmptyStatement : Statement
@@ -39,6 +53,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class FuncBodyStatement : Statement
@@ -61,6 +76,8 @@
   {
     return funcBody is null;
   }
+
+  mixin(copyMethod);
 }
 
 class ScopeStatement : Statement
@@ -72,6 +89,7 @@
     addChild(s);
     this.s = s;
   }
+  mixin(copyMethod);
 }
 
 class LabeledStatement : Statement
@@ -85,6 +103,7 @@
     this.label = label;
     this.s = s;
   }
+  mixin(copyMethod);
 }
 
 class ExpressionStatement : Statement
@@ -96,6 +115,7 @@
     addChild(e);
     this.e = e;
   }
+  mixin(copyMethod);
 }
 
 class DeclarationStatement : Statement
@@ -107,6 +127,7 @@
     addChild(decl);
     this.decl = decl;
   }
+  mixin(copyMethod);
 }
 
 class IfStatement : Statement
@@ -130,6 +151,7 @@
     this.ifBody = ifBody;
     this.elseBody = elseBody;
   }
+  mixin(copyMethod);
 }
 
 class WhileStatement : Statement
@@ -145,6 +167,7 @@
     this.condition = condition;
     this.whileBody = whileBody;
   }
+  mixin(copyMethod);
 }
 
 class DoWhileStatement : Statement
@@ -160,6 +183,7 @@
     this.condition = condition;
     this.doBody = doBody;
   }
+  mixin(copyMethod);
 }
 
 class ForStatement : Statement
@@ -181,6 +205,7 @@
     this.increment = increment;
     this.forBody = forBody;
   }
+  mixin(copyMethod);
 }
 
 class ForeachStatement : Statement
@@ -200,6 +225,7 @@
     this.aggregate = aggregate;
     this.forBody = forBody;
   }
+  mixin(copyMethod);
 }
 
 // version(D2)
@@ -222,6 +248,7 @@
     this.upper = upper;
     this.forBody = forBody;
   }
+  mixin(copyMethod);
 }
 // }
 
@@ -239,6 +266,7 @@
     this.condition = condition;
     this.switchBody = switchBody;
   }
+  mixin(copyMethod);
 }
 
 class CaseStatement : Statement
@@ -255,6 +283,7 @@
     this.values = values;
     this.caseBody = caseBody;
   }
+  mixin(copyMethod);
 }
 
 class DefaultStatement : Statement
@@ -267,6 +296,7 @@
 
     this.defaultBody = defaultBody;
   }
+  mixin(copyMethod);
 }
 
 class ContinueStatement : Statement
@@ -277,6 +307,7 @@
     mixin(set_kind);
     this.ident = ident;
   }
+  mixin(copyMethod);
 }
 
 class BreakStatement : Statement
@@ -287,6 +318,7 @@
     mixin(set_kind);
     this.ident = ident;
   }
+  mixin(copyMethod);
 }
 
 class ReturnStatement : Statement
@@ -298,6 +330,7 @@
     addOptChild(e);
     this.e = e;
   }
+  mixin(copyMethod);
 }
 
 class GotoStatement : Statement
@@ -311,6 +344,7 @@
     this.ident = ident;
     this.caseExpr = caseExpr;
   }
+  mixin(copyMethod);
 }
 
 class WithStatement : Statement
@@ -326,6 +360,7 @@
     this.e = e;
     this.withBody = withBody;
   }
+  mixin(copyMethod);
 }
 
 class SynchronizedStatement : Statement
@@ -341,6 +376,7 @@
     this.e = e;
     this.syncBody = syncBody;
   }
+  mixin(copyMethod);
 }
 
 class TryStatement : Statement
@@ -359,6 +395,7 @@
     this.catchBodies = catchBodies;
     this.finallyBody = finallyBody;
   }
+  mixin(copyMethod);
 }
 
 class CatchStatement : Statement
@@ -373,6 +410,7 @@
     this.param = param;
     this.catchBody = catchBody;
   }
+  mixin(copyMethod);
 }
 
 class FinallyStatement : Statement
@@ -384,6 +422,7 @@
     addChild(finallyBody);
     this.finallyBody = finallyBody;
   }
+  mixin(copyMethod);
 }
 
 class ScopeGuardStatement : Statement
@@ -397,6 +436,7 @@
     this.condition = condition;
     this.scopeBody = scopeBody;
   }
+  mixin(copyMethod);
 }
 
 class ThrowStatement : Statement
@@ -408,6 +448,7 @@
     addChild(e);
     this.e = e;
   }
+  mixin(copyMethod);
 }
 
 class VolatileStatement : Statement
@@ -419,6 +460,7 @@
     addOptChild(volatileBody);
     this.volatileBody = volatileBody;
   }
+  mixin(copyMethod);
 }
 
 class AsmBlockStatement : Statement
@@ -430,6 +472,7 @@
     addChild(statements);
     this.statements = statements;
   }
+  mixin(copyMethod);
 }
 
 class AsmStatement : Statement
@@ -443,6 +486,7 @@
     this.ident = ident;
     this.operands = operands;
   }
+  mixin(copyMethod);
 }
 
 class AsmAlignStatement : Statement
@@ -453,6 +497,7 @@
     mixin(set_kind);
     this.number = number;
   }
+  mixin(copyMethod);
 }
 
 class IllegalAsmStatement : IllegalStatement
@@ -461,6 +506,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class PragmaStatement : Statement
@@ -478,6 +524,7 @@
     this.args = args;
     this.pragmaBody = pragmaBody;
   }
+  mixin(copyMethod);
 }
 
 class MixinStatement : Statement
@@ -491,6 +538,7 @@
     this.templateExpr = templateExpr;
     this.mixinIdent = mixinIdent;
   }
+  mixin(copyMethod);
 }
 
 class StaticIfStatement : Statement
@@ -507,6 +555,7 @@
     this.ifBody = ifBody;
     this.elseBody = elseBody;
   }
+  mixin(copyMethod);
 }
 
 class StaticAssertStatement : Statement
@@ -520,6 +569,7 @@
     this.condition = condition;
     this.message = message;
   }
+  mixin(copyMethod);
 }
 
 abstract class ConditionalCompilationStatement : Statement
@@ -543,6 +593,7 @@
     super(cond, debugBody, elseBody);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 class VersionStatement : ConditionalCompilationStatement
@@ -552,4 +603,5 @@
     super(cond, versionBody, elseBody);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
--- a/trunk/src/dil/ast/Type.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Type.d	Tue Feb 26 20:13:41 2008 +0100
@@ -33,4 +33,6 @@
       type = type.next;
     return type;
   }
+
+  override abstract TypeNode copy();
 }
--- a/trunk/src/dil/ast/Types.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/ast/Types.d	Tue Feb 26 20:13:41 2008 +0100
@@ -8,6 +8,7 @@
 import dil.ast.Node;
 import dil.ast.Expression;
 import dil.ast.Parameters;
+import dil.ast.NodeCopier;
 import dil.lexer.Identifier;
 import dil.semantic.Types;
 import dil.Enums;
@@ -19,6 +20,7 @@
   {
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 /// char, int, float etc.
@@ -30,6 +32,7 @@
     mixin(set_kind);
     this.tok = tok;
   }
+  mixin(copyMethod);
 }
 
 /// Identifier
@@ -41,6 +44,7 @@
     mixin(set_kind);
     this.ident = ident;
   }
+  mixin(copyMethod);
 }
 
 /// Type "." Type
@@ -55,6 +59,7 @@
     addChild(rhs);
     this.rhs = rhs;
   }
+  mixin(copyMethod);
 }
 
 /// "." Type
@@ -65,6 +70,7 @@
     super(next);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 /// "typeof" "(" Expression ")" or$(BR)
@@ -89,6 +95,8 @@
   {
     return e is null;
   }
+
+  mixin(copyMethod);
 }
 
 /// Identifier "!" "(" TemplateParameters? ")"
@@ -103,6 +111,7 @@
     this.ident = ident;
     this.targs = targs;
   }
+  mixin(copyMethod);
 }
 
 /// Type *
@@ -113,6 +122,7 @@
     super(next);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 /// Dynamic array: T[] or$(BR)
@@ -165,6 +175,8 @@
   {
     return assocType !is null;
   }
+
+  mixin(copyMethod);
 }
 
 /// ReturnType "function" "(" Parameters? ")"
@@ -179,6 +191,7 @@
     addChild(params);
     this.params = params;
   }
+  mixin(copyMethod);
 }
 
 /// ReturnType "delegate" "(" Parameters? ")"
@@ -193,6 +206,7 @@
     addChild(params);
     this.params = params;
   }
+  mixin(copyMethod);
 }
 
 /// Type "(" BasicType2 Identifier ")" "(" Parameters? ")"
@@ -205,6 +219,7 @@
     mixin(set_kind);
     addOptChild(params);
   }
+  mixin(copyMethod);
 }
 
 /// "class" Identifier : BaseClasses
@@ -217,6 +232,7 @@
     mixin(set_kind);
     this.prot = prot;
   }
+  mixin(copyMethod);
 }
 
 // version(D2)
@@ -230,6 +246,7 @@
     super(next);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 
 /// "invariant" "(" Type ")"
@@ -241,5 +258,6 @@
     super(next);
     mixin(set_kind);
   }
+  mixin(copyMethod);
 }
 // } // version(D2)
--- a/trunk/src/dil/semantic/Interpreter.d	Mon Feb 25 03:37:20 2008 +0100
+++ b/trunk/src/dil/semantic/Interpreter.d	Tue Feb 26 20:13:41 2008 +0100
@@ -25,6 +25,7 @@
 
   static class Result : Expression
   {
+    override Result copy(){return null;}
   }
 
   static const Result NAR; /// Not a Result. Similar to NAN in floating point arithmetics.