/// <summary>
 /// To write out the value of a condition expr, we invoke the evaluator 
 /// in eval.g to walk the condition tree computing the boolean value.
 /// If result is true, then we write subtemplate.
 /// </summary>
 public override int Write(StringTemplate self, IStringTemplateWriter output)
 {
     if (exprTree == null || self == null || output == null)
     {
         return 0;
     }
     // System.out.println("evaluating conditional tree: "+exprTree.toStringList());
     ActionEvaluator eval = new ActionEvaluator(self, this, output);
     ActionParser.initializeASTFactory(eval.getASTFactory());
     int n = 0;
     try
     {
         // get conditional from tree and compute result
         AST cond = exprTree.getFirstChild();
         bool includeSubtemplate = eval.ifCondition(cond); // eval and write out tree
         // System.out.println("subtemplate "+subtemplate);
         if (includeSubtemplate)
         {
             /* To evaluate the IF chunk, make a new instance whose enclosingInstance
             * points at 'self' so get attribute works.  Otherwise, enclosingInstance
             * points at the template used to make the precompiled code.  We need a
             * new template instance every time we exec this chunk to get the new
             * "enclosing instance" pointer.
             */
             StringTemplate s = subtemplate.GetInstanceOf();
             s.EnclosingInstance = self;
             // make sure we evaluate in context of enclosing template's
             // group so polymorphism works. :)
             s.Group = self.Group;
             s.NativeGroup = self.NativeGroup;
             n = s.Write(output);
         }
         else if (elseSubtemplate != null)
         {
             // evaluate ELSE clause if present and IF condition failed
             StringTemplate s = elseSubtemplate.GetInstanceOf();
             s.EnclosingInstance = self;
             s.Group = self.Group;
             s.NativeGroup = self.NativeGroup;
             n = s.Write(output);
         }
     }
     catch (RecognitionException re)
     {
         self.Error("can't evaluate tree: " + exprTree.ToStringList(), re);
     }
     return n;
 }
        /// <summary>
        /// Evaluate an argument list within the context of the enclosing
        /// template but store the values in the context of self, the
        /// new embedded template.  For example, bold(item=item) means
        /// that bold.item should get the value of enclosing.item.
        /// </summary>
        protected internal virtual void EvaluateArguments(StringTemplate self)
        {
            StringTemplateAST argumentsAST = self.ArgumentsAST;
            if (argumentsAST == null || argumentsAST.getFirstChild() == null)
            {
                // return immediately if missing tree or no actual args
                return ;
            }

            // Evaluate args in the context of the enclosing template, but we
            // need the predefined args like 'it', 'attr', and 'i' to be
            // available as well so we put a dummy ST between the enclosing
            // context and the embedded context.  The dummy has the predefined
            // context as does the embedded.
            StringTemplate enclosing = self.EnclosingInstance;
            StringTemplate argContextST = new StringTemplate(self.Group, "");
            argContextST.Name = "<invoke " + self.Name + " arg context>";
            argContextST.EnclosingInstance = enclosing;
            argContextST.ArgumentContext = self.ArgumentContext;

            ActionEvaluator eval = new ActionEvaluator(argContextST, this, null);
            ActionParser.initializeASTFactory(eval.getASTFactory());
            /*
            System.out.println("eval args: "+argumentsAST.toStringList());
            System.out.println("ctx is "+self.getArgumentContext());
            */
            try
            {
                // using any initial argument context (such as when obj is set),
                // evaluate the arg list like bold(item=obj).  Since we pass
                // in any existing arg context, that context gets filled with
                // new values.  With bold(item=obj), context becomes:
                // {[obj=...],[item=...]}.
                IDictionary ac = eval.argList(argumentsAST, self, self.ArgumentContext);
                self.ArgumentContext = ac;
            }
            catch (RecognitionException re)
            {
                self.Error("can't evaluate tree: " + argumentsAST.ToStringList(), re);
            }
        }
        /// <summary>
        /// An EXPR is normally just a string literal, but is still an AST that
        /// we must evaluate.  The EXPR can be any expression such as a template
        /// include or string cat expression etc...
        /// 
        /// Evaluate with its own writer so that we can convert to string and then 
        /// reuse, don't want to compute all the time; must precompute w/o writing 
        /// to output buffer.
        /// </summary>
        protected internal string EvaluateExpression(StringTemplate self, object expr)
        {
            if (expr == null)
            {
                return null;
            }
            if (expr is StringTemplateAST)
            {
                StringTemplateAST exprTree = (StringTemplateAST) expr;
                // must evaluate, writing to a string so we can hand on to it
                StringWriter buf = new StringWriter();
                IStringTemplateWriter sw = self.group.CreateInstanceOfTemplateWriter(buf);
                ActionEvaluator eval = new ActionEvaluator(self, this, sw);

                try
                {
                    eval.action(exprTree);	// eval tree
                }
                catch (RecognitionException ex)
                {
                    self.Error("can't evaluate tree: " + exprTree.ToStringList(), ex);
                }
                return buf.ToString();
            }
            else
            {
                // just in case we expand in the future and it's something else
                return expr.ToString();
            }
        }
 /// <summary>
 /// To write out the value of an ASTExpr, invoke the evaluator in eval.g
 /// to walk the tree writing out the values.  For efficiency, don't
 /// compute a bunch of strings and then pack them together.  Write out directly.
 /// 
 /// Compute separator and wrap expressions, save as strings so we don't
 /// recompute for each value in a multi-valued attribute or expression.
 /// 
 /// If they set anchor option, then inform the writer to push current
 /// char position.
 /// </summary>
 public override int Write(StringTemplate self, IStringTemplateWriter output)
 {
     if (exprTree == null || self == null || output == null)
     {
         return 0;
     }
     output.PushIndentation(Indentation);
     // handle options, anchor, wrap, separator...
     StringTemplateAST anchorAST = (StringTemplateAST)GetOption("anchor");
     if (anchorAST != null)	// any non-empty expr means true; check presence
     {
         output.PushAnchorPoint();
     }
     HandleExprOptions(self);
     ActionEvaluator eval = new ActionEvaluator(self, this, output);
     ActionParser.initializeASTFactory(eval.getASTFactory());
     int n = 0;
     try
     {
         n = eval.action(exprTree); // eval and write out tree
     }
     catch (RecognitionException re)
     {
         self.Error("can't evaluate tree: " + exprTree.ToStringList(), re);
     }
     output.PopIndentation();
     if (anchorAST != null)
     {
         output.PopAnchorPoint();
     }
     return n;
 }