protected override IStatement DoConvertStatement(IStatement ist)
 {
     if (ist is IExpressionStatement)
     {
         bool isAccumulator       = false;
         IExpressionStatement ies = (IExpressionStatement)ist;
         if (ies.Expression is IAssignExpression)
         {
             IAssignExpression iae = (IAssignExpression)ies.Expression;
             AccumulationInfo  ac  = context.InputAttributes.Get <AccumulationInfo>(ies);
             if (ac != null)
             {
                 // This statement defines an accumulator.
                 // Delete the statement and replace with any remaining accumulations.
                 if (!ac.isInitialized)
                 {
                     context.AddStatementBeforeCurrent(ac.initializer);
                 }
                 ac.isInitialized = false;
                 context.AddStatementsBeforeCurrent(ac.statements);
                 isAccumulator = true;
             }
             object ivd = Recognizer.GetVariableDeclaration(iae.Target);
             if (ivd == null)
             {
                 ivd = Recognizer.GetFieldReference(iae.Target);
             }
             if (ivd != null)
             {
                 MessageArrayInformation mai = context.InputAttributes.Get <MessageArrayInformation>(ivd);
                 bool oneUse = (mai != null) && (mai.useCount == 1);
                 List <AccumulationInfo> ais = context.InputAttributes.GetAll <AccumulationInfo>(ivd);
                 foreach (AccumulationInfo ai in ais)
                 {
                     if (!context.InputAttributes.Has <OperatorStatement>(ist))
                     {
                         if (oneUse)
                         {
                             return(null);        // remove the statement
                         }
                         else
                         {
                             continue;
                         }
                     }
                     // assuming that we only accumulate one statement, we should always initialize
                     if (true || !ai.isInitialized)
                     {
                         // add the initializer in the same containers as the original accumulation statement
                         int        ancIndex = ai.containers.GetMatchingAncestorIndex(context);
                         Containers missing  = ai.containers.GetContainersNotInContext(context, ancIndex);
                         context.AddStatementBeforeAncestorIndex(ancIndex, Containers.WrapWithContainers(ai.initializer, missing.outputs));
                         ai.isInitialized = true;
                     }
                     // This statement defines a variable that contributes to an accumulator.
                     IList <IStatement> stmts    = Builder.StmtCollection();
                     IExpression        target   = iae.Target;
                     Type        exprType        = target.GetExpressionType();
                     IExpression accumulator     = ai.accumulator;
                     Type        accumulatorType = ai.type;
                     int         rank;
                     Type        eltType = Util.GetElementType(exprType, out rank);
                     if (rank == 1 && eltType == accumulatorType)
                     {
                         // This statement defines an array of items to be accumulated.
                         VariableInformation varInfo = context.InputAttributes.Get <VariableInformation>(mai.ci.decl);
                         int indexingDepth           = Recognizer.GetIndexingDepth(iae.Target);
                         if (mai.loopVarInfo != null)
                         {
                             indexingDepth -= mai.loopVarInfo.indexVarRefs.Length;
                         }
                         IExpression          size     = varInfo.sizes[indexingDepth][0];
                         IVariableDeclaration indexVar = varInfo.indexVars[indexingDepth][0];
                         IForStatement        ifs      = Builder.ForStmt(indexVar, size);
                         target = Builder.ArrayIndex(target, Builder.VarRefExpr(indexVar));
                         ifs.Body.Statements.Add(ai.GetAccumulateStatement(context, accumulator, target));
                         stmts.Add(ifs);
                     }
                     else
                     {
                         Stack <IList <IExpression> > indexStack = new Stack <IList <IExpression> >();
                         while (exprType != accumulatorType && target is IArrayIndexerExpression)
                         {
                             // The accumulator is an array type, and this statement defines an element of the accumulator type.
                             // Peel off the indices of the target.
                             IArrayIndexerExpression iaie = (IArrayIndexerExpression)target;
                             indexStack.Push(iaie.Indices);
                             target          = iaie.Target;
                             accumulatorType = Util.GetElementType(accumulatorType);
                         }
                         while (indexStack.Count > 0)
                         {
                             // Attach the indices of the target to the accumulator, in reverse order that they were peeled.
                             accumulator = Builder.ArrayIndex(accumulator, indexStack.Pop());
                         }
                         if (exprType == accumulatorType)
                         {
                             if (oneUse && !isAccumulator)
                             {
                                 // convert
                                 //   msg = expr;
                                 // into
                                 //   T temp = expr;
                                 //   acc = SetToProduct(acc, temp);
                                 // and move into ai.statement.
                                 tempVarCount++;
                                 string name = "_temp" + tempVarCount;
                                 IVariableDeclaration tempVar      = Builder.VarDecl(name, exprType);
                                 IStatement           newStatement = Builder.AssignStmt(Builder.VarDeclExpr(tempVar), iae.Expression);
                                 context.AddStatementBeforeCurrent(newStatement);
                                 context.AddStatementBeforeCurrent(ai.GetAccumulateStatement(context, accumulator, Builder.VarRefExpr(tempVar)));
                                 return(null);
                             }
                             else
                             {
                                 // must keep the original statement.
                                 // add
                                 //   acc = SetToProduct(acc, msg);
                                 // to ai.statements.
                                 context.AddStatementAfterCurrent(ai.GetAccumulateStatement(context, accumulator, iae.Target));
                             }
                         }
                         else
                         {
                             Error("Unrecognized variable type: " + StringUtil.TypeToString(exprType));
                         }
                     }
                     Containers containers = new Containers(context);
                     containers = containers.Remove(ai.containers);
                     IList <IStatement> output2 = Builder.StmtCollection();
                     Containers.AddStatementWithContainers(output2, stmts, containers.inputs);
                     foreach (IStatement ist2 in output2)
                     {
                         context.AddStatementAfterCurrent(ist2);
                     }
                 }
             }
         }
         if (!isAccumulator)
         {
             return(ist);
         }
         else
         {
             return(null);
         }
     }
     else
     {
         return(base.DoConvertStatement(ist));
     }
 }
        /// <summary>
        /// Converts variable declarations inside loops into array declarations at the top level.
        /// </summary>
        /// <param name="ivde"></param>
        /// <returns></returns>
        protected override IExpression ConvertVariableDeclExpr(IVariableDeclarationExpression ivde)
        {
            IVariableDeclaration ivd   = ivde.Variable;
            bool isLoneDeclaration     = (context.FindAncestorIndex <IExpressionStatement>() == context.Depth - 2);
            List <IForStatement> loops = context.FindAncestors <IForStatement>();

            if (loops.Count == 0)
            {
                List <IConditionStatement> ifs = context.FindAncestors <IConditionStatement>();
                if (ifs.Count == 0)
                {
                    return(ivde);
                }
                // Add declaration outside the if
                IStatement outermostContainer = ifs[0];
                int        ancIndex           = context.GetAncestorIndex(outermostContainer);
                var        defaultExpr        = Builder.DefaultExpr(ivd.VariableType);
                var        assignSt           = Builder.AssignStmt(ivde, defaultExpr);
                context.OutputAttributes.Set(assignSt, new Initializer());
                context.AddStatementBeforeAncestorIndex(ancIndex, assignSt);
                if (isLoneDeclaration)
                {
                    return(null);
                }
                else
                {
                    return(Builder.VarRefExpr(ivd));
                }
            }
            // ignore declaration of a loop variable
            if (Recognizer.LoopVariable(loops[loops.Count - 1]) == ivd)
            {
                return(ivde);
            }

            // Declaration is inside one or more loops, find their sizes and index variables
            Type        type      = Builder.ToType(ivd.VariableType);
            Type        arrayType = type;
            LoopVarInfo lvi       = new LoopVarInfo(loops);

            for (int i = 0; i < loops.Count; i++)
            {
                IForStatement loop = loops[i];
                lvi.indexVarRefs[i] = Builder.VarRefExpr(Recognizer.LoopVariable(loop));
                arrayType           = Util.MakeArrayType(arrayType, 1);
            }
            Predicate <int> isPartitionedAtDepth = (depth => context.InputAttributes.Has <Partitioned>(Recognizer.GetVariableDeclaration(lvi.indexVarRefs[depth])));
            Type            messageType          = Distributions.Distribution.IsDistributionType(type)
                                   ? MessageTransform.GetDistributionType(arrayType, type, type, 0, loops.Count, isPartitionedAtDepth)
                                   : MessageTransform.GetArrayType(arrayType, type, 0, isPartitionedAtDepth);

            lvi.arrayvd       = Builder.VarDecl(ivd.Name, messageType);
            loopVarInfos[ivd] = lvi;
            MessageArrayInformation mai = context.InputAttributes.Get <MessageArrayInformation>(ivd);

            if (mai != null)
            {
                mai.loopVarInfo = lvi;
            }
            context.InputAttributes.CopyObjectAttributesTo(ivd, context.OutputAttributes, lvi.arrayvd);
            context.InputAttributes.Remove <VariableInformation>(lvi.arrayvd);

            VariableInformation vi  = VariableInformation.GetVariableInformation(context, ivd);
            VariableInformation vi2 = VariableInformation.GetVariableInformation(context, lvi.arrayvd);

            vi2.IsStochastic = vi.IsStochastic;

            // Initialise the array to the appropriate sizes
            // TODO: change to work over loop brackets not loops
            IExpression expr = Builder.VarDeclExpr(lvi.arrayvd);

            for (int i = 0; i < loops.Count; i++)
            {
                IForStatement        loop     = loops[i];
                IExpression          loopSize = Recognizer.LoopSizeExpression(loop);
                IExpressionStatement assignSt = Builder.AssignStmt(expr,
                                                                   MessageTransform.GetArrayCreateExpression(expr, expr.GetExpressionType(),
                                                                                                             new IExpression[] { loopSize }));
                context.OutputAttributes.Set(assignSt.Expression, new DescriptionAttribute("Create array for replicates of '" + ivd.Name + "'"));
                context.OutputAttributes.Set(assignSt, new Initializer());

                if (expr is IVariableDeclarationExpression)
                {
                    expr = Builder.VarRefExpr(lvi.arrayvd);
                }
                expr = Builder.ArrayIndex(expr, lvi.indexVarRefs[i]);
                vi2.indexVars.Add(new IVariableDeclaration[] { Recognizer.GetVariableDeclaration(lvi.indexVarRefs[i]) });
                vi2.sizes.Add(new IExpression[] { loopSize });

                // Add declaration outside the loop
                int ancIndex = context.GetAncestorIndex(loop);
                context.AddStatementBeforeAncestorIndex(ancIndex, assignSt);
            }
            vi2.indexVars.AddRange(vi.indexVars);
            vi2.sizes.AddRange(vi.sizes);
            // If the variable declaration was a statement by itself, then return null (i.e. delete the statement).
            if (isLoneDeclaration)
            {
                return(null);
            }
            // Return a reference to the newly created array
            else
            {
                return(expr);
            }
        }