/// <summary>Just print out the string; no reference to self because this /// is a literal--not sensitive to attribute values. /// </summary> public override int write(StringTemplate self, StringTemplateWriter outWriter) { if (str != null) { int n = outWriter.write(str); return n; } return 0; }
protected internal virtual int write(StringTemplate self, Object o, StringTemplateWriter outWriter, Object separator) { if (o == null) { return 0; } int n = 0; try { if (o is StringTemplate) { StringTemplate stToWrite = (StringTemplate) o; stToWrite.setEnclosingInstance(self); // if self is found up the enclosing instance chain, then // infinite recursion if (StringTemplate.inLintMode() && StringTemplate.isRecursiveEnclosingInstance(stToWrite)) { // throw exception since sometimes eval keeps going // even after I ignore this write of o. throw new System.SystemException("infinite recursion to " + stToWrite.getTemplateDeclaratorString() + " referenced in " + stToWrite.getEnclosingInstance().getTemplateDeclaratorString() + "; stack trace:\n" + stToWrite.getEnclosingInstanceStackTrace()); } else { n = stToWrite.write(outWriter); } return n; } // normalize anything iteratable to iterator o = convertAnythingIteratableToIterator(o); if (o is IEnumerator) { IEnumerator iter = (IEnumerator) o; String separatorString = null; if (separator != null) { separatorString = computeSeparator(self, outWriter, separator); } int i = 0; int charWrittenForValue = 0; Object iterValue = null; while (iter.MoveNext()) { if (i > 0) { bool valueIsPureConditional = false; if (iterValue is StringTemplate) { StringTemplate iterValueST = (StringTemplate) iterValue; IList chunks = (IList) iterValueST.getChunks(); Expr firstChunk = (Expr) chunks[0]; valueIsPureConditional = firstChunk is ConditionalExpr && ((ConditionalExpr) firstChunk).getElseSubtemplate() == null; } bool emptyIteratedValue = valueIsPureConditional && charWrittenForValue == 0; if (!emptyIteratedValue && separator != null) { n += outWriter.write(separatorString); } } iterValue = iter.Current; charWrittenForValue = write(self, iterValue, outWriter, separator); n += charWrittenForValue; i++; } } else { n = outWriter.write(o.ToString()); return n; } } catch (System.IO.IOException io) { self.error("problem writing object: " + o, io); } return n; }
/// <summary>A separator is normally just a string literal, but is still an AST that /// we must evaluate. The separator can be any expression such as a template /// include or string cat expression etc... /// </summary> protected internal virtual String computeSeparator(StringTemplate self, StringTemplateWriter outWriter, Object separator) { if (separator == null) { return null; } if (separator is StringTemplateAST) { StringTemplateAST separatorTree = (StringTemplateAST) separator; // must evaluate, writing to a string so we can hand on to it ASTExpr e = new ASTExpr(getEnclosingTemplate(), separatorTree, null); System.IO.StringWriter buf = new System.IO.StringWriter(); // create a new instance of whatever StringTemplateWriter // implementation they are using. Default is AutoIndentWriter. // Defalut behavior is to indent but without // any prior indents surrounding this attribute expression StringTemplateWriter sw = null; System.Type writerClass = outWriter.GetType(); try { System.Reflection.ConstructorInfo ctor = writerClass.GetConstructor(new System.Type[]{typeof(System.IO.TextWriter)}); sw = (StringTemplateWriter) ctor.Invoke(new Object[]{buf}); } catch (System.Exception exc) { // default new AutoIndentWriter(buf) self.error("cannot make implementation of StringTemplateWriter", exc); sw = new AutoIndentWriter(buf); } try { e.write(self, sw); } catch (System.IO.IOException ioe) { self.error("can't evaluate separator expression", ioe); } return buf.ToString(); } else { // just in case we expand in the future and it's something else return separator.ToString(); } }
/// <summary>How to spit out an object. If it's not a StringTemplate nor a /// List, just do o.toString(). If it's a StringTemplate, /// do o.write(out). If it's a Vector, do a write(out, /// o.elementAt(i)) for all elements. Note that if you do /// something weird like set the values of a multivalued tag /// to be vectors, it will effectively flatten it. /// /// If self is an embedded template, you might have specified /// a separator arg; used when is a vector. /// </summary> public virtual int writeAttribute(StringTemplate self, Object o, StringTemplateWriter outWriter) { Object separator = null; if (options != null) { separator = options["separator"]; } return write(self, o, outWriter, separator); }
/// <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. /// </summary> public override int write(StringTemplate self, StringTemplateWriter outWriter) { if (exprTree == null || self == null || outWriter == null) { return 0; } outWriter.pushIndentation(getIndentation()); //System.out.println("evaluating tree: "+exprTree.toStringList()); ActionEvaluator eval = new ActionEvaluator(self, this, outWriter); 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); } outWriter.popIndentation(); return n; }
/** Create an evaluator using attributes from self */ public ActionEvaluator(StringTemplate self, ASTExpr chunk, StringTemplateWriter @out) { this.self = self; this.chunk = chunk; this.@out = @out; }
/// <summary>Walk the chunks, asking them to write themselves out according /// to attribute values of 'this.attributes'. This is like evaluating or /// interpreting the StringTemplate as a program using the /// attributes. The chunks will be identical (point at same list) /// for all instances of this template. /// </summary> public virtual int write(StringTemplateWriter outWriter) { int n = 0; setPredefinedAttributes(); for (int i = 0; chunks != null && i < chunks.Count; i++) { Expr a = (Expr) chunks[i]; int chunkN = a.write(this, outWriter); // NEWLINE expr-with-no-output NEWLINE => NEWLINE // Indented $...$ have the indent stored with the ASTExpr // so the indent does not come out as a StringRef if (chunkN == 0 && (i - 1) >= 0 && chunks[i - 1] is NewlineRef && (i + 1) < chunks.Count && chunks[i + 1] is NewlineRef) { //System.out.println("found pure \\n blank \\n pattern"); i++; // make it skip over the next chunk, the NEWLINE } n += chunkN; } if (lintMode) { checkForTrouble(); } return n; }