public override void ReportError(RecognitionException e) { StringTemplateGroup group = self.Group; if (group == StringTemplate.defaultGroup) { self.Error("action parse error; template context is " + self.GetEnclosingInstanceStackString(), e); } else { self.Error("action parse error in group " + self.Group.Name + " line " + self.GroupFileLine + "; template context is " + self.GetEnclosingInstanceStackString(), e); } }
public override void ReportError(RecognitionException e) { string header = GetErrorHeader(e); string message = GetErrorMessage(e, TokenNames); message = string.Format("{0}: {1}: {2}", "$...$ chunk lexer error", header, message); self.Error(message, e); }
protected object RawGetObjectProperty(StringTemplate self, object o, string propertyName) { Type c = o.GetType(); object val = null; // Special case: our automatically created Aggregates via // attribute name: "{obj.{prop1,prop2}}" if (c == typeof(StringTemplate.Aggregate)) { val = ((StringTemplate.Aggregate) o).Get(propertyName); return val; } // Special case: if it's a template, pull property from // it's attribute table. // TODO: TJP just asked himself why we can't do inherited attr here? else if (c == typeof(StringTemplate)) { IDictionary attributes = ((StringTemplate) o).Attributes; if (attributes != null) { val = attributes[propertyName]; return val; } } // Special case: if it's an IDictionary then pull using // key not the property method. // // Original intent was to DISALLOW general IDictionary interface // as people could pass in their database masquerading as a IDictionary. // Pragmatism won out ;-) if (typeof(IDictionary).IsAssignableFrom(c)) { IDictionary map = (IDictionary) o; if (propertyName.Equals("keys")) { val = map.Keys; } else if (propertyName.Equals("values")) { val = map.Values; } else if (map.Contains(propertyName)) { val = map[propertyName]; } else { if ( map.Contains(DEFAULT_MAP_VALUE_NAME) ) val = map[DEFAULT_MAP_VALUE_NAME]; } if (val == MAP_KEY_VALUE) { // no property defined; if a map in this group // then there may be a default value val = propertyName; } return val; } // try getXXX and isXXX properties // check cache PropertyLookupParams paramBag; //MemberInfo cachedMember = self.Group.GetCachedClassProperty(c, propertyName); //if ( cachedMember != null ) //{ // try // { // paramBag = new PropertyLookupParams(self, c, o, propertyName, null); // if ( cachedMember is PropertyInfo ) // { // // non-indexed property (since we don't cache indexers) // PropertyInfo pi = (PropertyInfo)cachedMember; // GetPropertyValue(pi, paramBag, ref val); // } // else if ( cachedMember is MethodInfo ) // { // MethodInfo mi = (MethodInfo)cachedMember; // GetMethodValue(mi, paramBag, ref val); // } // else if ( cachedMember is FieldInfo ) // { // // must be a field // FieldInfo fi = (FieldInfo)cachedMember; // GetFieldValue(fi, paramBag, ref val); // } // } // catch (Exception e) // { // self.Error("Can't get property '" + propertyName + // "' from '" + c.FullName + "' instance", e); // } // return val; //} // must look up using reflection // Search for propertyName as: // Property (non-indexed), Method(get_XXX, GetXXX, IsXXX, getXXX, isXXX), Field, this[string] string methodSuffix = Char.ToUpper(propertyName[0]) + propertyName.Substring(1); paramBag = new PropertyLookupParams(self, c, o, propertyName, methodSuffix); totalReflectionLookups++; if (!GetPropertyValueByName(paramBag, ref val)) { bool found = false; foreach (string prefix in new string[] { "get_", "Get", "Is", "get", "is" }) { paramBag.lookupName = prefix + methodSuffix; totalReflectionLookups++; if (found = GetMethodValueByName(paramBag, ref val)) break; } if (!found) { paramBag.lookupName = methodSuffix; totalReflectionLookups++; if (!GetFieldValueByName(paramBag, ref val)) { totalReflectionLookups++; PropertyInfo pi = c.GetProperty("Item", new Type[] { typeof(string) }); if (pi != null) { // TODO: we don't cache indexer PropertyInfo objects (yet?) // it would have complicated getting values from cached property objects try { val = pi.GetValue(o, new object[] { propertyName }); } catch(Exception ex) { self.Error("Can't get property " + propertyName + " via C# string indexer from " + c.FullName + " instance", ex); } } else { self.Error("Class " + c.FullName + " has no such attribute: " + propertyName + " in template context " + self.GetEnclosingInstanceStackString()); } } } } return val; }
/// <summary> /// Write o relative to self to out /// </summary> /// <remarks> /// John Snyders fixes here for formatString. Basically, any time /// you are about to write a value, check formatting. /// </remarks> protected internal virtual int Write(StringTemplate self, object o, IStringTemplateWriter output) { if (o == null) { if (nullValue == null) { return 0; } // continue with null option if specified o = nullValue; } int n = 0; try { if (o is StringTemplate) { StringTemplate stToWrite = (StringTemplate) o; // failsafe: perhaps enclosing instance not set // Or, it could be set to another context! This occurs // when you store a template instance as an attribute of more // than one template (like both a header file and C file when // generating C code). It must execute within the context of // the enclosing template. stToWrite.EnclosingInstance = self; // if self is found up the enclosing instance chain, then // infinite recursion if (StringTemplate.IsInLintMode && StringTemplate.IsRecursiveEnclosingInstance(stToWrite)) { // throw exception since sometimes eval keeps going // even after I ignore this write of o. throw new SystemException("infinite recursion to " + stToWrite.GetTemplateDeclaratorString() + " referenced in " + stToWrite.EnclosingInstance.GetTemplateDeclaratorString() + "; stack trace:\n" + stToWrite.GetEnclosingInstanceStackTrace()); } else { // if we have a wrap string, then inform writer it // might need to wrap if (wrapString != null) { n = output.WriteWrapSeparator(wrapString); } // check if formatting needs to be applied to the stToWrite if ( formatString != null ) { IAttributeRenderer renderer = self.GetAttributeRenderer(typeof(string)); if ( renderer != null ) { // you pay a penalty for applying format option to a template // because the template must be written to a temp StringWriter so it can // be formatted before being written to the real output. StringWriter buf = new StringWriter(); IStringTemplateWriter sw = self.Group.CreateInstanceOfTemplateWriter(buf); stToWrite.Write(sw); n = output.Write(renderer.ToString(buf.ToString(), formatString)); return n; } } n = stToWrite.Write(output); } return n; } // normalize anything iteratable to iterator o = ConvertAnythingIteratableToIterator(o); if (o is IEnumerator) { IEnumerator iter = (IEnumerator)o; bool seenPrevValue = false; while (iter.MoveNext()) { object iterValue = iter.Current; if (iterValue == null) { iterValue = nullValue; } if (iterValue != null) { if (seenPrevValue /*prevIterValue!=null*/ && (separatorString != null)) { n += output.WriteSeparator(separatorString); } seenPrevValue = true; int nw = Write(self, iterValue, output); n += nw; } } } else { IAttributeRenderer renderer = self.GetAttributeRenderer(o.GetType()); string v = null; if (renderer != null) { if (formatString != null) { v = renderer.ToString(o, formatString); } else { v = renderer.ToString(o); } } else { v = o.ToString(); } if (wrapString != null) { n = output.Write(v, wrapString); } else { n = output.Write(v); } return n; } } catch (IOException io) { self.Error("problem writing object: " + o, io); } return n; }
protected internal virtual void SetSoleFormalArgumentToIthValue(StringTemplate embedded, IDictionary argumentContext, object ithValue) { IDictionary formalArgs = embedded.FormalArguments; if (formalArgs != null) { string soleArgName = null; bool isAnonymous = (embedded.Name == StringTemplate.ANONYMOUS_ST_NAME); if (formalArgs.Count == 1 || (isAnonymous && formalArgs.Count > 0)) { if (isAnonymous && formalArgs.Count > 1) { embedded.Error("too many arguments on {...} template: " + CollectionUtils.DictionaryToString(formalArgs)); } // if exactly 1 arg or anonymous, give that the value of // "it" as a convenience like they said // $list:template(arg=it)$ IEnumerator iter = formalArgs.Keys.GetEnumerator(); // Retrieve first key iter.MoveNext(); soleArgName = (string) iter.Current; argumentContext[soleArgName] = ithValue; } } }
/// <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(); } }
//throws RecognitionException, TokenStreamException public void action( StringTemplate self ) { IToken a = null; IToken i = null; IToken rr = null; IToken rd = null; try { // for error handling switch ( LA(1) ) { case ACTION: { a = LT(1); match(ACTION); string indent = ((ChunkToken)a).Indentation; ASTExpr c = self.ParseAction(a.getText()); c.Indentation = indent; self.AddChunk(c); break; } case IF: { i = LT(1); match(IF); ConditionalExpr c = (ConditionalExpr)self.ParseAction(i.getText()); // create and precompile the subtemplate StringTemplate subtemplate = new StringTemplate(self.Group, null); subtemplate.EnclosingInstance = self; subtemplate.Name = i.getText() + "_subtemplate"; self.AddChunk(c); template(subtemplate); if ( c!=null ) c.Subtemplate = subtemplate; { switch ( LA(1) ) { case ELSE: { match(ELSE); // create and precompile the subtemplate StringTemplate elseSubtemplate = new StringTemplate(self.Group, null); elseSubtemplate.EnclosingInstance = self; elseSubtemplate.Name = "else_subtemplate"; template(elseSubtemplate); if ( c!=null ) c.ElseSubtemplate = elseSubtemplate; break; } case ENDIF: { break; } default: { throw new NoViableAltException(LT(1), getFilename()); } } } match(ENDIF); break; } case REGION_REF: { rr = LT(1); match(REGION_REF); // define implicit template and // convert <@r()> to <region__enclosingTemplate__r()> string regionName = rr.getText(); string mangledRef = null; bool err = false; // watch out for <@super.r()>; that does NOT def implicit region // convert to <super.region__enclosingTemplate__r()> if ( regionName.StartsWith("super.") ) { //Console.Out.Writeline("super region ref "+regionName); string regionRef = regionName.Substring("super.".Length,regionName.Length-"super.".Length); string templateScope = self.Group.GetUnMangledTemplateName(self.Name); StringTemplate scopeST = self.Group.LookupTemplate(templateScope); if ( scopeST==null ) { self.Group.Error("reference to region within undefined template: "+ templateScope); err=true; } if ( !scopeST.ContainsRegionName(regionRef) ) { self.Group.Error("template "+templateScope+" has no region called "+ regionRef); err=true; } else { mangledRef = self.Group.GetMangledRegionName(templateScope,regionRef); mangledRef = "super."+mangledRef; } } else { //Console.Out.WriteLine("region ref "+regionName); StringTemplate regionST = self.Group.DefineImplicitRegionTemplate(self,regionName); mangledRef = regionST.Name; } if ( !err ) { // treat as regular action: mangled template include string indent = ((ChunkToken)rr).Indentation; ASTExpr c = self.ParseAction(mangledRef+"()"); c.Indentation = indent; self.AddChunk(c); } break; } case REGION_DEF: { rd = LT(1); match(REGION_DEF); string combinedNameTemplateStr = rd.getText(); int indexOfDefSymbol = combinedNameTemplateStr.IndexOf("::="); if ( indexOfDefSymbol>=1 ) { string regionName = combinedNameTemplateStr.Substring(0,indexOfDefSymbol); string template = combinedNameTemplateStr.Substring(indexOfDefSymbol+3, combinedNameTemplateStr.Length - (indexOfDefSymbol+3)); StringTemplate regionST = self.Group.DefineRegionTemplate(self, regionName, template, StringTemplate.REGION_EMBEDDED); // treat as regular action: mangled template include string indent = ((ChunkToken)rd).Indentation; ASTExpr c = self.ParseAction(regionST.Name+"()"); c.Indentation = indent; self.AddChunk(c); } else { self.Error("embedded region definition screwed up"); } break; } default: { throw new NoViableAltException(LT(1), getFilename()); } } } catch (RecognitionException ex) { reportError(ex); recover(ex,tokenSet_1_); } }
public override void ReportError(RecognitionException e) { self.Error("<...> chunk lexer error", e); }
// HELP ROUTINES CALLED BY EVALUATOR TREE WALKER /// <summary> /// For <names,phones:{n,p | ...}> treat the names, phones as lists /// to be walked in lock step as n=names[i], p=phones[i]. /// </summary> public virtual object ApplyTemplateToListOfAttributes(StringTemplate self, IList attributes, StringTemplate templateToApply) { if (attributes == null || templateToApply == null || attributes.Count == 0) { return null; // do not apply if missing templates or empty values } IDictionary argumentContext = null; IList results = new StringTemplate.STAttributeList(); // convert all attributes to iterators even if just one value for (int a = 0; a < attributes.Count; a++) { object o = (object) attributes[a]; if (o != null) { o = ConvertAnythingToIterator(o); attributes[a] = o; // alter the list in place } } int numAttributes = attributes.Count; // ensure arguments line up HashList formalArguments = (HashList) templateToApply.FormalArguments; if (formalArguments == null || formalArguments.Count == 0) { self.Error("missing arguments in anonymous" + " template in context " + self.GetEnclosingInstanceStackString()); return null; } object[] formalArgumentNames = new object[formalArguments.Count]; formalArguments.Keys.CopyTo(formalArgumentNames, 0); if (formalArgumentNames.Length != numAttributes) { self.Error("number of arguments " + formalArguments.Keys.ToString() + " mismatch between attribute list and anonymous" + " template in context " + self.GetEnclosingInstanceStackString()); // truncate arg list to match smaller size int shorterSize = Math.Min(formalArgumentNames.Length, numAttributes); numAttributes = shorterSize; object[] newFormalArgumentNames = new object[shorterSize]; Array.Copy(formalArgumentNames, 0, newFormalArgumentNames, 0, shorterSize); formalArgumentNames = newFormalArgumentNames; } // keep walking while at least one attribute has values int i = 0; // iteration number from 0 while (true) { argumentContext = new Hashtable(); // get a value for each attribute in list; put into arg context // to simulate template invocation of anonymous template int numEmpty = 0; for (int a = 0; a < numAttributes; a++) { IEnumerator it = (IEnumerator) attributes[a]; if ((it != null) && it.MoveNext()) { string argName = (string) formalArgumentNames[a]; object iteratedValue = it.Current; argumentContext[argName] = iteratedValue; } else { numEmpty++; } } if (numEmpty == numAttributes) { break; } argumentContext[DEFAULT_INDEX_VARIABLE_NAME] = i+1; argumentContext[DEFAULT_INDEX0_VARIABLE_NAME] = i; StringTemplate embedded = templateToApply.GetInstanceOf(); embedded.EnclosingInstance = self; embedded.ArgumentContext = argumentContext; results.Add(embedded); i++; } return results; }
/** <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> * * <remarks> * 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. * </remarks> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( _exprTree == null || self == null || @out == null ) { return 0; } // handle options, anchor, wrap, separator... StringTemplateAST anchorAST = (StringTemplateAST)GetOption( "anchor" ); if ( anchorAST != null ) { // any non-empty expr means true; check presence @out.PushAnchorPoint(); } @out.PushIndentation( Indentation ); HandleExprOptions( self ); //System.out.println("evaluating tree: "+exprTree.toStringList()); #if COMPILE_EXPRESSIONS if ( EvaluateAction == null ) EvaluateAction = GetEvaluator( this, AST ); #else ActionEvaluator eval = new ActionEvaluator( self, this, @out, _exprTree ); #endif int n = 0; try { // eval and write out tree #if COMPILE_EXPRESSIONS n = EvaluateAction( self, @out ); #else n = eval.action(); #endif } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } @out.PopIndentation(); if ( anchorAST != null ) { @out.PopAnchorPoint(); } return n; }
/** <summary> * A 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> */ public virtual string EvaluateExpression( StringTemplate self, object expr ) { if ( expr == null ) { return null; } StringTemplateAST exprAST = expr as StringTemplateAST; if ( exprAST != null ) { #if COMPILE_EXPRESSIONS System.Func<StringTemplate, IStringTemplateWriter, int> value; #if CACHE_FUNCTORS if ( !_evaluators.TryGetValue( expr, out value ) ) #endif { value = GetEvaluator( this, exprAST ); #if CACHE_FUNCTORS _evaluators[expr] = value; #endif } #endif // must evaluate, writing to a string so we can hang on to it StringWriter buf = new StringWriter(); IStringTemplateWriter sw = self.Group.GetStringTemplateWriter( buf ); { try { #if COMPILE_EXPRESSIONS value( self, sw ); #else ActionEvaluator eval = new ActionEvaluator( self, this, sw, exprAST ); // eval tree eval.action(); #endif } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } } return buf.ToString(); } else { // just in case we expand in the future and it's something else return expr.ToString(); } }
/** <summary> * For <names,phones:{n,p | ...}> treat the names, phones as lists * to be walked in lock step as n=names[i], p=phones[i]. * </summary> */ public virtual object ApplyTemplateToListOfAttributes( StringTemplate self, IList attributes, StringTemplate templateToApply ) { if ( attributes == null || templateToApply == null || attributes.Count == 0 ) { return null; // do not apply if missing templates or empty values } Dictionary<string, object> argumentContext = null; // indicate it's an ST-created list var results = new StringTemplate.STAttributeList(); // convert all attributes to iterators even if just one value for ( int a = 0; a < attributes.Count; a++ ) { object o = attributes[a]; if ( o != null ) { o = ConvertAnythingToIterator( o ); attributes[a] = o; // alter the list in place } } int numAttributes = attributes.Count; // ensure arguments line up var formalArguments = templateToApply.FormalArguments; if ( formalArguments == null || formalArguments.Count == 0 ) { self.Error( "missing arguments in anonymous" + " template in context " + self.GetEnclosingInstanceStackString() ); return null; } string[] formalArgumentNames = formalArguments.Select( fa => fa.name ).ToArray(); if ( formalArgumentNames.Length != numAttributes ) { string formalArgumentsText = formalArguments.Select( fa => fa.name ).ToList().ToElementString(); self.Error( "number of arguments " + formalArgumentsText + " mismatch between attribute list and anonymous" + " template in context " + self.GetEnclosingInstanceStackString() ); // truncate arg list to match smaller size int shorterSize = Math.Min( formalArgumentNames.Length, numAttributes ); numAttributes = shorterSize; string[] newFormalArgumentNames = new string[shorterSize]; Array.Copy( formalArgumentNames, 0, newFormalArgumentNames, 0, shorterSize ); formalArgumentNames = newFormalArgumentNames; } // keep walking while at least one attribute has values int i = 0; // iteration number from 0 for ( ; ; ) { argumentContext = new Dictionary<string, object>(); // get a value for each attribute in list; put into arg context // to simulate template invocation of anonymous template int numEmpty = 0; for ( int a = 0; a < numAttributes; a++ ) { Iterator it = attributes[a] as Iterator; if ( it != null && it.hasNext() ) { string argName = formalArgumentNames[a]; object iteratedValue = it.next(); argumentContext[argName] = iteratedValue; } else { numEmpty++; } } if ( numEmpty == numAttributes ) { break; } argumentContext[DefaultIndexVariableName] = i + 1; argumentContext[DefaultIndex0VariableName] = i; StringTemplate embedded = templateToApply.GetInstanceOf(); embedded.EnclosingInstance = self; embedded.ArgumentContext = argumentContext; results.Add( embedded ); i++; } return results; }
/** <summary>Write o relative to self to out.</summary> * * <remarks> * John Snyders fixes here for formatString. Basically, any time * you are about to write a value, check formatting. * </remarks> */ protected virtual int Write( StringTemplate self, object o, IStringTemplateWriter @out ) { if ( o == null ) { if ( _nullValue == null ) { return Missing; } o = _nullValue; // continue with null option if specified } try { StringTemplate stToWrite = o as StringTemplate; if (stToWrite != null) return WriteTemplate(self, stToWrite, @out); // normalize o = ConvertAnythingIteratableToIterator(o); Iterator iter = o as Iterator; if (iter != null) return WriteIterableValue(self, iter, @out); return WriteObject(self, o, @out); } catch ( IOException io ) { self.Error( "problem writing object: " + o, io ); return 0; } }
protected virtual void SetSoleFormalArgumentToIthValue( StringTemplate embedded, IDictionary argumentContext, object ithValue ) { var formalArgs = embedded.FormalArguments; if ( formalArgs != null ) { string soleArgName = null; bool isAnonymous = embedded.Name == StringTemplate.ANONYMOUS_ST_NAME; if ( formalArgs.Count == 1 || ( isAnonymous && formalArgs.Count > 0 ) ) { if ( isAnonymous && formalArgs.Count > 1 ) { embedded.Error( "too many arguments on {...} template: " + formalArgs ); } // if exactly 1 arg or anonymous, give that the value of // "it" as a convenience like they said // $list:template(arg=it)$ var argNames = formalArgs.Select( fa => fa.name ); soleArgName = argNames.ToArray()[0]; argumentContext[soleArgName] = ithValue; } } }
protected virtual object RawGetObjectProperty( StringTemplate self, object o, object property ) { Type c = o.GetType(); object value = null; // Special case: our automatically created Aggregates via // attribute name: "{obj.{prop1,prop2}}" if ( c == typeof( StringTemplate.Aggregate ) ) { string propertyName2 = (string)property; value = ( (StringTemplate.Aggregate)o ).Get( (string)propertyName2 ); return value; } else if ( c == typeof( StringTemplate ) ) { // Special case: if it's a template, pull property from // it's attribute table. // TODO: TJP just asked himself why we can't do inherited attr here? var attributes = ( (StringTemplate)o ).Attributes; if ( attributes != null ) { string propertyName2 = (string)property; value = attributes.get( propertyName2 ); return value; } } // Special case: if it's a Map then pull using // key not the property method. IDictionary map = o as IDictionary; if ( map != null ) { if ( property.Equals( "keys" ) ) { value = map.Keys; } else if ( property.Equals( "values" ) ) { value = map.Values; } else if ( map.Contains( property ) ) { value = map[property]; } else if ( map.Contains( property.ToString() ) ) { // if we can't find the key, toString it value = map[property.ToString()]; } else { if ( map.Contains( DefaultMapValueName ) ) { value = map[DefaultMapValueName]; } } if ( value == MapKeyValue ) { value = property; } return value; } string propertyName = (string)property; var accessor = FindMember( c, propertyName ); if ( accessor != null ) { try { value = accessor( o ); } catch ( Exception e ) { self.Error( "Can't access property " + propertyName + " using method get/is" + propertyName + " or direct field access from " + c.Name + " instance", e ); } } else { self.Error( "Class " + c.Name + " has no such attribute: " + propertyName + " in template context " + self.GetEnclosingInstanceStackString(), null ); } return value; }
public override void ReportError(RecognitionException e) { self.Error("eval tree parse error", e); }
/** <summary> * To write out the value of a condition expr, invoke the evaluator in eval.g * to walk the condition tree computing the boolean value. If result * is true, then write subtemplate. * </summary> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( AST == null || self == null || @out == null ) { return 0; } //System.Console.Out.WriteLine( "evaluating conditional tree: " + AST.ToStringTree() ); #if !COMPILE_EXPRESSIONS ActionEvaluator eval = null; #endif int n = 0; try { bool testedTrue = false; // get conditional from tree and compute result #if COMPILE_EXPRESSIONS if ( EvaluateCondition == null ) EvaluateCondition = GetEvaluator( this, AST.GetChild( 0 ) ); bool includeSubtemplate = EvaluateCondition( self, @out ); // eval and write out tree #else ITree cond = AST.GetChild( 0 ); eval = new ActionEvaluator( self, this, @out, cond ); // eval and write out trees bool includeSubtemplate = eval.ifCondition(); #endif //System.Console.Out.WriteLine( "subtemplate " + _subtemplate ); // IF if ( includeSubtemplate ) { n = WriteSubTemplate( self, @out, _subtemplate ); testedTrue = true; } // ELSEIF else if ( _elseIfSubtemplates != null && _elseIfSubtemplates.Count > 0 ) { for ( int i = 0; i < _elseIfSubtemplates.Count; i++ ) { ElseIfClauseData elseIfClause = _elseIfSubtemplates[i]; #if COMPILE_EXPRESSIONS if ( elseIfClause.EvaluateCondition == null ) elseIfClause.EvaluateCondition = GetEvaluator( this, elseIfClause.expr.AST ); includeSubtemplate = elseIfClause.EvaluateCondition( self, @out ); #else eval = new ActionEvaluator( self, this, @out, elseIfClause.expr.AST ); includeSubtemplate = eval.ifCondition(); #endif if ( includeSubtemplate ) { WriteSubTemplate( self, @out, elseIfClause.st ); testedTrue = true; break; } } } // ELSE if ( !testedTrue && _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( @out ); } // cond==false and no else => Missing output not empty if (!testedTrue && _elseSubtemplate == null) n = Missing; } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + AST.ToStringTree(), re ); } return n; }
/// <summary> /// Call a string template with args and return result. Do not convert /// to a string yet. It may need attributes that will be available after /// this is inserted into another template. /// </summary> public virtual StringTemplate GetTemplateInclude(StringTemplate enclosing, string templateName, StringTemplateAST argumentsAST) { //Console.WriteLine("getTemplateInclude: look up "+enclosing.Group.Name+"::"+templateName); StringTemplateGroup group = enclosing.Group; StringTemplate embedded = group.GetEmbeddedInstanceOf(enclosing, templateName); if (embedded == null) { enclosing.Error("cannot make embedded instance of " + templateName + " in template " + enclosing.Name); return null; } embedded.ArgumentsAST = argumentsAST; EvaluateArguments(embedded); return embedded; }
/// <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; }
/// <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> * To write out the value of a condition expr, invoke the evaluator in eval.g * to walk the condition tree computing the boolean value. If result * is true, then write subtemplate. * </summary> */ public override int Write(StringTemplate self, IStringTemplateWriter @out) { if (AST == null || self == null || @out == null) { return(0); } //System.Console.Out.WriteLine( "evaluating conditional tree: " + AST.ToStringTree() ); #if !COMPILE_EXPRESSIONS ActionEvaluator eval = null; #endif int n = 0; try { bool testedTrue = false; // get conditional from tree and compute result #if COMPILE_EXPRESSIONS if (EvaluateCondition == null) { EvaluateCondition = GetEvaluator(this, AST.GetChild(0)); } bool includeSubtemplate = EvaluateCondition(self, @out); // eval and write out tree #else ITree cond = AST.GetChild(0); eval = new ActionEvaluator(self, this, @out, cond); // eval and write out trees bool includeSubtemplate = eval.ifCondition(); #endif //System.Console.Out.WriteLine( "subtemplate " + _subtemplate ); // IF if (includeSubtemplate) { n = WriteSubTemplate(self, @out, _subtemplate); testedTrue = true; } // ELSEIF else if (_elseIfSubtemplates != null && _elseIfSubtemplates.Count > 0) { for (int i = 0; i < _elseIfSubtemplates.Count; i++) { ElseIfClauseData elseIfClause = _elseIfSubtemplates[i]; #if COMPILE_EXPRESSIONS if (elseIfClause.EvaluateCondition == null) { elseIfClause.EvaluateCondition = GetEvaluator(this, elseIfClause.expr.AST); } includeSubtemplate = elseIfClause.EvaluateCondition(self, @out); #else eval = new ActionEvaluator(self, this, @out, elseIfClause.expr.AST); includeSubtemplate = eval.ifCondition(); #endif if (includeSubtemplate) { WriteSubTemplate(self, @out, elseIfClause.st); testedTrue = true; break; } } } // ELSE if (!testedTrue && _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(@out); } // cond==false and no else => Missing output not empty if (!testedTrue && _elseSubtemplate == null) { n = Missing; } } catch (RecognitionException re) { self.Error("can't evaluate tree: " + AST.ToStringTree(), re); } return(n); }
/** <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> * * <remarks> * 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. * </remarks> */ public override int Write( StringTemplate self, IStringTemplateWriter @out ) { if ( _exprTree == null || self == null || @out == null ) { return 0; } // handle options, anchor, wrap, separator... StringTemplateAST anchorAST = (StringTemplateAST)GetOption( "anchor" ); if ( anchorAST != null ) { // any non-empty expr means true; check presence @out.PushAnchorPoint(); } @out.PushIndentation( Indentation ); HandleExprOptions( self ); //System.out.println("evaluating tree: "+exprTree.toStringList()); ActionEvaluator eval = null; #if COMPILE_EXPRESSIONS bool compile = self.Group != null && self.Group.EnableCompiledExpressions; bool cache = compile && self.Group.EnableCachedExpressions; System.Func<StringTemplate, IStringTemplateWriter, int> evaluator = EvaluateAction; if (compile) { if (!cache || EvaluateAction == null) { // caching won't help here because AST is read only EvaluatorCacheMisses++; evaluator = GetEvaluator(this, AST); if (cache) EvaluateAction = evaluator; } else { EvaluatorCacheHits++; } } else #endif { eval = new ActionEvaluator(self, this, @out, _exprTree); } int n = 0; try { // eval and write out tree #if COMPILE_EXPRESSIONS if (compile) { n = evaluator(self, @out); } else #endif { n = eval.action(); } } catch ( RecognitionException re ) { self.Error( "can't evaluate tree: " + _exprTree.ToStringTree(), re ); } @out.PopIndentation(); if ( anchorAST != null ) { @out.PopAnchorPoint(); } return n; }