/// <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; }