public Expression <Action <StringBuilder, T, Y> > Generate <T, Y>(ExpressContext expressContext, ScriptBlockStatement scriptBlockStatement) { ParameterExpression StringBuilderParmeter = Expression.Parameter(typeof(StringBuilder)); ParameterExpression inputParameter = Expression.Parameter(typeof(T), "Model"); ParameterExpression libraryParameter = Expression.Parameter(typeof(Y), "Library"); ParameterFinder parameterFinder = new ParameterFinder(); parameterFinder.AddParameter(libraryParameter); parameterFinder.AddParameter(inputParameter); var blockExpression = GetStatementExpression(expressContext, StringBuilderParmeter, scriptBlockStatement, parameterFinder); return(Expression.Lambda <Action <StringBuilder, T, Y> >(blockExpression, StringBuilderParmeter, inputParameter, libraryParameter)); }
public ExpressContext <T, L> GetExpressContext <T>(string templateText) { Func <string, ExpressContext <T, L> > CompileTemplate = _ => { ExpressContext <T, L> expressContext = new ExpressContext <T, L>(); logger.LogInformation("Compiling {templateText} for {type}", templateText, typeof(T)); try { var template = Template.Parse(templateText, null, null, null); expressContext.Messages.AddRange(template.Messages); if (template.HasErrors) { logger.LogError("Scriban Parsing Failed on {templateText} for {type}", templateText, typeof(T)); expressContext.CompiledTemplate = (sb, target, library) => { }; return(expressContext); } else { logger.LogInformation("Scriban Parsing Succeded on {templateText} for {type}", templateText, typeof(T)); } var expression = statementGenerator.Generate <T, L>(expressContext, template.Page.Body); expressContext.CompiledTemplate = expression.Compile(); return(expressContext); } catch (Exception ex) { // effectively swallow exceptions here, // as compilation could take a long time and we don't want to overload the server with repeated failing compiles logger.LogError(ex, "Compilation Failed on {templateText} for {type}", templateText, typeof(T)); Action <StringBuilder, T, L> emptyAction = (sb, target, library) => { }; expressContext.CompiledTemplate = emptyAction; return(expressContext); } }; string cacheKey = typeof(T) + templateText; var compiltedTemplate = functionary.GetOrAdd(cacheKey, CompileTemplate) as ExpressContext <T, L>; return(compiltedTemplate); }
public Expression GetStatementExpression(ExpressContext expressContext, ParameterExpression stringBuilderParameter, ScriptStatement scriptStatement, ParameterFinder parameterFinder) { var appendMethodInfo = typeof(StringBuilder).GetMethod("Append", new[] { typeof(string) }); switch (scriptStatement) { case ScriptRawStatement scriptRawStatement: var constant = Expression.Constant(scriptRawStatement.ToString()); var methodCall = Expression.Call(stringBuilderParameter, appendMethodInfo, constant); return(methodCall); case ScriptExpressionStatement scriptExpressionStatement: var expressionBody = expressionGenerator.GetExpressionBody(scriptExpressionStatement.Expression, parameterFinder, null); expressionBody = AddToString(expressionBody); var scriptmethodCall = Expression.Call(stringBuilderParameter, appendMethodInfo, expressionBody); return(scriptmethodCall); case ScriptIfStatement scriptIfStatement: var predicateExpression = expressionGenerator.GetExpressionBody(scriptIfStatement.Condition, parameterFinder, null); var trueStatementBlock = GetStatementExpression(expressContext, stringBuilderParameter, scriptIfStatement.Then, parameterFinder); if (scriptIfStatement.Else != null) { var elseStatment = GetStatementExpression(expressContext, stringBuilderParameter, scriptIfStatement.Else, parameterFinder); ConditionalExpression ifThenElseExpr = Expression.IfThenElse(predicateExpression, trueStatementBlock, elseStatment); return(ifThenElseExpr); } else { ConditionalExpression ifThenExpr = Expression.IfThen(predicateExpression, trueStatementBlock); return(ifThenExpr); } case ScriptElseStatement scriptElseStatement: var elseStatmentExpression = GetStatementExpression(expressContext, stringBuilderParameter, scriptElseStatement.Body, parameterFinder); return(elseStatmentExpression); case ScriptBlockStatement scriptBlockStatement: List <Expression> statements = new List <Expression>(); foreach (var statement in scriptBlockStatement.Statements) { try { statements.Add(GetStatementExpression(expressContext, stringBuilderParameter, statement, parameterFinder)); } catch (SpanException ex) { logger.LogError(ex, "Failed to build: {statement}", statement); expressContext.Messages.Add(new LogMessage(ParserMessageType.Error, ex.Span, ex.Message)); } catch (Exception ex) { logger.LogError(ex, "Statement Failed to build: {statement}", statement); expressContext.Messages.Add(new LogMessage(ParserMessageType.Error, scriptBlockStatement.Span, $"Statement Failed to build: {statement?.GetType()}")); } } var blockExpression = Expression.Block(statements); return(blockExpression); case ScriptForStatement scriptForStatement: // foreach(item in items) var itemsExpression = expressionGenerator.GetExpressionBody(scriptForStatement.Iterator, parameterFinder, null); var itemVariableName = (scriptForStatement.Variable as ScriptVariableGlobal).Name; var itemType = itemsExpression.Type.GenericTypeArguments[0]; ParameterExpression itemVariable = Expression.Parameter(itemType, itemVariableName); using (var scopedParameterFinder = parameterFinder.CreateScope()) { scopedParameterFinder.AddLocalVariable(itemVariable); var body = GetStatementExpression(expressContext, stringBuilderParameter, scriptForStatement.Body, scopedParameterFinder); var foreachExpression = ExpressionHelpers.ForEach(itemsExpression, itemVariable, body); return(foreachExpression); } default: throw new NotImplementedException("Unknown ScriptStatement"); } }
public string Render <T>(ExpressContext <T, L> expressContext, T value) { return(MapFunction(expressContext.CompiledTemplate, standardLibrary) (value)); }