/** <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> * 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; }
static System.Func<StringTemplate, IStringTemplateWriter, int> GetEvaluator( ASTExpr chunk, ITree condition ) { if ( EnableDynamicMethods ) { try { DynamicMethod method = null; #if CACHE_FUNCTORS if ( !_methods.TryGetValue( condition, out method ) ) #endif { Type[] parameterTypes = { typeof( ASTExpr ), typeof( StringTemplate ), typeof( IStringTemplateWriter ) }; method = new DynamicMethod( "ActionEvaluator" + _evaluatorNumber, typeof( int ), parameterTypes, typeof( ConditionalExpr ), true ); method.DefineParameter( 1, ParameterAttributes.None, "chunk" ); method.DefineParameter( 2, ParameterAttributes.None, "self" ); method.DefineParameter( 3, ParameterAttributes.None, "writer" ); _evaluatorNumber++; var gen = method.GetILGenerator(); ActionEvaluator evalCompiled = new ActionEvaluator( null, chunk, null, condition ); evalCompiled.actionCompiled( gen ); gen.Emit( OpCodes.Ret ); #if CACHE_FUNCTORS _methods[condition] = method; #endif } var dynamicEvaluator = (System.Func<StringTemplate, IStringTemplateWriter, int>)method.CreateDelegate( typeof( System.Func<StringTemplate, IStringTemplateWriter, int> ), chunk ); return dynamicEvaluator; } catch { // fall back to functional (or interpreted) version } } if ( EnableFunctionalMethods ) { try { ActionEvaluator evalFunctional = new ActionEvaluator( null, chunk, null, condition ); var functionalEvaluator = evalFunctional.actionFunctional(); HoldsActionFuncAndChunk holder = new HoldsActionFuncAndChunk() { func = functionalEvaluator, chunk = chunk }; return (System.Func<StringTemplate, IStringTemplateWriter, int>)System.Delegate.CreateDelegate( typeof( System.Func<StringTemplate, IStringTemplateWriter, int> ), holder, typeof( ASTExpr ).GetMethod( "CallFunctionalActionEvaluator" ) ); } catch { // fall back to interpreted version } } return ( self, writer ) => { ActionEvaluator eval = new ActionEvaluator( self, chunk, writer, condition ); return eval.action(); }; }