private ScriptExecutable m_ScriptExecutable; //函数执行命令 #endregion Fields #region Constructors public ScorpioScriptFunction(Script script, List<String> listParameters, ScriptExecutable scriptExecutable, bool bParams) { this.m_Script = script; this.m_ListParameters = new List<string>(listParameters); this.m_ScriptExecutable = scriptExecutable; this.m_ParameterCount = listParameters.Count; this.m_Params = bParams; this.m_ParamsArray = bParams ? script.CreateArray() : null; }
private static object Round(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count < 1 || parameters.Count > 2) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for math.round. Expecting at least 1 parameter <precision>? <value>"); } var value = ScriptValueConverter.ToDouble(callerContext.Span, parameters[parameters.Count - 1]); int precision = 0; if (parameters.Count == 2) { precision = ScriptValueConverter.ToInt(callerContext.Span, parameters[0]); } return Round(precision, value); }
public bool ExpandParameters(object value, ScriptArray expandedParameters) { // Handle parameters expansion for a function call when the operator ~ is used if (Operator == ScriptUnaryOperator.FunctionParametersExpand) { var valueEnumerator = value as IEnumerable; if (valueEnumerator != null) { foreach (var subValue in valueEnumerator) { expandedParameters.Add(subValue); } return true; } } return false; }
/// <summary> /// Returns no more than the specified number of items from the input list, starting from the first index position. /// </summary> /// <param name="list">The input list.</param> /// <param name="count">The number of elements to return from the input list. If this number is less than one, no item is returned.</param> /// <remarks> /// ```template-text /// {{ [4, 5, 6] | array.limit 2 }} /// ``` /// ```html /// [4, 5] /// ``` /// </remarks> public static ScriptArray Limit(IEnumerable list, int count) { if (list == null) { return(null); } ScriptArray result = new ScriptArray(); foreach (var item in list) { count--; if (count < 0) { break; } result.Add(item); } return(result); }
/// <summary> /// Removes an element at the specified `index` from the input `list` /// </summary> /// <param name="list">The input list</param> /// <param name="index">The index of a list to return elements</param> /// <returns>A new list with the element removed. If index is negative, remove at the end of the list.</returns> /// <remarks> /// ```scriban-html /// {{ [4, 5, 6, 7, 8] | array.remove_at 2 }} /// ``` /// ```html /// [4, 5, 7, 8] /// ``` /// If the `index` is negative, removes at the end of the list (notice that we need to put -1 in parenthesis to avoid confusing the parser with a binary `-` operation): /// ```scriban-html /// {{ [4, 5, 6, 7, 8] | array.remove_at (-1) }} /// ``` /// ```html /// [4, 5, 6, 7] /// ``` /// </remarks> public static IList RemoveAt(IList list, int index) { if (list == null) { return(new ScriptArray()); } list = new ScriptArray(list); // If index is negative, start from the end if (index < 0) { index = list.Count + index; } if (index >= 0 && index < list.Count) { list.RemoveAt(index); } return(list); }
/// <summary> /// Returns the remaining of the list after the specified offset /// </summary> /// <param name="list">The input list</param> /// <param name="index">The index of a list to return elements</param> /// <remarks> /// ```scriban-html /// {{ [4, 5, 6, 7, 8] | array.offset 2 }} /// ``` /// ```html /// [6, 7, 8] /// ``` /// </remarks> public static ScriptArray Offset(IEnumerable list, int index) { if (list == null) { return(null); } var result = new ScriptArray(); foreach (var item in list) { if (index <= 0) { result.Add(item); } else { index--; } } return(result); }
private static ScriptArray ReadScriptArray(GameBoxReader r) { ScriptVariable indexVar; var indexType = r.ReadByte(); // index if ((ScriptType)indexType == ScriptType.Struct) { indexVar = ReadScriptStruct(out int _, r); } else { indexVar = new ScriptVariable((ScriptType)indexType); } var arrayType = r.ReadByte(); // value var valueVar = (ScriptType)arrayType switch { ScriptType.Array => ReadScriptArray(r), ScriptType.Struct => ReadScriptStruct(out int _, r), _ => new ScriptVariable((ScriptType)arrayType), }; var array = new ScriptArray(new KeyValuePair <ScriptVariable, ScriptVariable>(indexVar, valueVar)); int counterArray = 0; while (r.ReadByte() == 0) { counterArray++; } r.BaseStream.Position -= 1; array.Unknown = counterArray; return(array); }
public static string Join(TemplateContext context, SourceSpan span, IEnumerable list, string delimiter, object function = null) { if (list == null) { return(string.Empty); } var scriptingFunction = function as IScriptCustomFunction; if (function != null && scriptingFunction == null) { throw new ArgumentException($"The parameter `{function}` is not a function. Maybe prefix it with @?", nameof(function)); } var text = new StringBuilder(); bool afterFirst = false; var arg = new ScriptArray(1); foreach (var obj in list) { if (afterFirst) { text.Append(delimiter); } var item = context.ObjectToString(obj); if (scriptingFunction != null) { arg[0] = item; var result = ScriptFunctionCall.Call(context, context.CurrentNode, scriptingFunction, arg); item = context.ObjectToString(result); } text.Append(item); afterFirst = true; } return(text.ToString()); }
private static void Write(Script script, ScorpioWriter writer, ScriptTable table, string tableName) { ScriptArray layout = (ScriptArray)script.GetValue(tableName); int sign = 0; for (int i = 0; i < layout.Count(); ++i) { ScriptObject config = layout.GetValue(i); if (table != null && table.HasValue(config.GetValue(Name).ObjectValue)) { sign = ScorpioUtil.AddSign(sign, ScorpioUtil.ToInt32(config.GetValue(Index).ObjectValue)); } } writer.WriteInt32(sign); for (int i = 0; i < layout.Count(); ++i) { ScriptObject config = layout.GetValue(i); string name = (string)config.GetValue(Name).ObjectValue; if (table != null && table.HasValue(name)) { string type = (string)config.GetValue(Type).ObjectValue; bool array = (bool)config.GetValue(Array).ObjectValue; if (array) { ScriptArray arr = table.GetValue(name) as ScriptArray; writer.WriteInt32(arr.Count()); for (int j = 0; j < arr.Count(); ++j) { WriteObject(script, writer, type, arr.GetValue(j)); } } else { WriteObject(script, writer, type, table.GetValue(name)); } } } }
public object Call(ScriptObject[] args) { string str = (args[0] as ScriptString).Value; int length = str.Length; if (length == 0) { return(null); } else if (length == 1) { return(Convert.ToInt32(str[0])); } else { ScriptArray array = m_script.CreateArray(); for (int i = 0; i < length; ++i) { array.Add(m_script.CreateObject(Convert.ToInt32(str[i]))); } return(array); } }
/// <summary> /// Searches an input string for multiple substrings that matches a regular expression pattern and returns an array with the match occurences. /// </summary> /// <param name="context">The template context (to fetch the timeout configuration)</param> /// <param name="text">The string to search for a match.</param> /// <param name="pattern">The regular expression pattern to match.</param> /// <param name="options">A string with regex options, that can contain the following option characters (default is `null`): /// - `i`: Specifies case-insensitive matching. /// - `m`: Multiline mode. Changes the meaning of `^` and `$` so they match at the beginning and end, respectively, of any line, and not just the beginning and end of the entire string. /// - `s`: Specifies single-line mode. Changes the meaning of the dot `.` so it matches every character (instead of every character except `\n`). /// - `x`: Eliminates unescaped white space from the pattern and enables comments marked with `#`. /// </param> /// <returns>An array of matches that contains all the match groups. The first group contains the entire match. The other elements contain regex matched groups `(..)`. An empty array returned means no match.</returns> /// <remarks> /// ```scriban-html /// {{ "this is a text123" | regex.matches `(\w+)` }} /// ``` /// ```html /// [["this", "this"], ["is", "is"], ["a", "a"], ["text123", "text123"]] /// ``` /// Notice that the first element returned in the sub array is the entire regex match, followed by the regex group matches. /// </remarks> public static ScriptArray Matches(TemplateContext context, string text, string pattern, string options = null) { var matches = Regex.Matches(text, pattern, GetOptions(options), context.RegexTimeOut); var allMatches = new ScriptArray(); foreach (Match match in matches) { if (match.Success) { var matchObject = new ScriptArray(); for (var i = 0; i < match.Groups.Count; i++) { Group @group = match.Groups[i]; matchObject.Add(@group.Value); } allMatches.Add(matchObject); } } // otherwise return an empty array return(allMatches); }
/// <summary> /// Concatenates two lists. /// </summary> /// <param name="list1">The 1st input list</param> /// <param name="list2">The 2nd input list</param> /// <returns>The concatenation of the two input lists</returns> /// <remarks> /// ```scriban-html /// {{ [1, 2, 3] | array.concat [4, 5] }} /// ``` /// ```html /// [1, 2, 3, 4, 5] /// ``` /// </remarks> public static IEnumerable Concat(IEnumerable list1, IEnumerable list2) { if (list2 == null && list1 == null) { return(null); } if (list2 == null) { return(list1); } if (list1 == null) { return(list2); } var result = new ScriptArray(list1); foreach (var item in list2) { result.Add(item); } return(result); }
public virtual object?Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { // If we access 'ndate' without any parameter, it calls the 'parse' function by default // otherwise it is the 'date' object itself return(arguments.Count switch { 0 => this, 1 => Parse(context, context.ObjectToString(arguments[0])), _ => throw new ScriptRuntimeException(callerContext.Span, $"Invalid number of parameters `{arguments.Count}` for `{DateVariable.Name}` object/function.") });
private static object Map(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count != 2) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for map. Expecting at 2 parameters: <property> <array>"); } var member = ScriptValueConverter.ToString(callerContext.Span, parameters[0]); var target = parameters[1]; return Map(context, target, member); }
protected override object EvaluateImpl(TemplateContext context) { var loopIterator = context.Evaluate(Iterator); var list = loopIterator as IList; if (list == null) { var iterator = loopIterator as IEnumerable; if (iterator != null) { list = new ScriptArray(iterator); } } if (list != null) { object loopResult = null; object previousValue = null; bool reversed = false; int startIndex = 0; int limit = list.Count; if (NamedArguments != null) { foreach (var option in NamedArguments) { switch (option.Name) { case "offset": startIndex = context.ToInt(option.Value.Span, context.Evaluate(option.Value)); break; case "reversed": reversed = true; break; case "limit": limit = context.ToInt(option.Value.Span, context.Evaluate(option.Value)); break; default: ProcessArgument(context, option); break; } } } var endIndex = Math.Min(limit + startIndex, list.Count) - 1; var index = reversed ? endIndex : startIndex; var dir = reversed ? -1 : 1; bool isFirst = true; int i = 0; BeforeLoop(context); var loopState = CreateLoopState(); context.SetValue(GetLoopVariable(context), loopState); loopState.Length = list.Count; while (!reversed && index <= endIndex || reversed && index >= startIndex) { if (!context.StepLoop(this)) { return(null); } // We update on next run on previous value (in order to handle last) var value = list[index]; bool isLast = reversed ? index == startIndex : index == endIndex; loopState.Index = index; loopState.LocalIndex = i; loopState.IsLast = isLast; loopState.ValueChanged = isFirst || !Equals(previousValue, value); context.SetValue(Variable, value); loopResult = LoopItem(context, loopState); if (!ContinueLoop(context)) { break; } previousValue = value; isFirst = false; index += dir; i++; } AfterLoop(context); context.SetValue(ScriptVariable.Continue, index); return(loopResult); } if (loopIterator != null) { throw new ScriptRuntimeException(Iterator.Span, $"Unexpected type `{loopIterator.GetType()}` for iterator"); } return(null); }
public object Evaluate(TemplateContext context, ScriptNode callerContext, ScriptArray parameters, ScriptBlockStatement blockStatement) { if (parameters.Count == 0) { throw new ScriptRuntimeException(callerContext.Span, "Expecting at least the name of the template to include for the <include> function"); } string templateName = null; try { templateName = ScriptValueConverter.ToString(callerContext.Span, parameters[0]); } catch (Exception ex) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected exception while converting first parameter for <include> function. Expecting a string", ex); } // If template name is empty, throw an exception if (templateName == null || string.IsNullOrEmpty(templateName = templateName.Trim())) { throw new ScriptRuntimeException(callerContext.Span, $"Include template name cannot be null or empty"); } // Compute a new parameters for the include var newParameters = new ScriptArray(parameters.Count - 1); for (int i = 1; i < parameters.Count; i++) { newParameters[i] = parameters[i]; } context.SetValue(ScriptVariable.Arguments, newParameters, true); Template template; if (!context.CachedTemplates.TryGetValue(templateName, out template)) { if (context.TemplateLoader == null) { throw new ScriptRuntimeException(callerContext.Span, $"Unable to include <{templateName}>. No TemplateLoader registered in TemplateContext.Options.TemplateLoader"); } string templateFilePath; var templateText = context.TemplateLoader.Load(context, callerContext.Span, templateName, out templateFilePath); if (templateText == null) { throw new ScriptRuntimeException(callerContext.Span, $"The result of including <{templateName}> cannot be null"); } // IF template file path is not defined, we use the template name instead templateFilePath = templateFilePath ?? templateName; // Clone parser options var parserOptions = context.TemplateLoaderParserOptions.Clone(); // Parse include in default modes (while top page can be using front matter) parserOptions.Mode = parserOptions.Mode == ScriptMode.ScriptOnly ? ScriptMode.ScriptOnly : ScriptMode.Default; template = Template.Parse(templateText, templateFilePath, parserOptions); // If the template has any errors, throw an exception if (template.HasErrors) { throw new ScriptParserRuntimeException(callerContext.Span, $"Error while parsing template <{templateName}> from [{templateFilePath}]", template.Messages); } context.CachedTemplates.Add(templateName, template); } // Query the pending includes stored in the context HashSet<string> pendingIncludes; object pendingIncludesObject; if (!context.Tags.TryGetValue(typeof(IncludeFunction), out pendingIncludesObject)) { pendingIncludesObject = pendingIncludes = new HashSet<string>(); context.Tags[typeof (IncludeFunction)] = pendingIncludesObject; } else { pendingIncludes = (HashSet<string>) pendingIncludesObject; } // Make sure that we cannot recursively include a template if (pendingIncludes.Contains(templateName)) { throw new ScriptRuntimeException(callerContext.Span, $"The include [{templateName}] cannot be used recursively"); } pendingIncludes.Add(templateName); context.PushOutput(); object result = null; try { template.Render(context); } finally { result = context.PopOutput(); pendingIncludes.Remove(templateName); } return result; }
private static object FromYaml(string yamlText, bool expectOnlyFrontMatter, out TextPosition position) { position = new TextPosition(); if (yamlText == null) { return(null); } var parser = new Parser(new StringReader(yamlText)); var reader = new EventReader(parser); if (!reader.Accept <StreamStart>()) { return(null); } reader.Expect <StreamStart>(); var docStart = reader.Expect <DocumentStart>(); var hasDocumentStart = true; object result = null; ScriptArray objects = null; // If we expect to read multiple documents, we will return an array of result if (expectOnlyFrontMatter && docStart.IsImplicit) { return(null); } Mark endPosition; while (true) { if (reader.Accept <StreamEnd>()) { var evt = reader.Expect <StreamEnd>(); endPosition = evt.End; break; } if (hasDocumentStart && reader.Accept <DocumentEnd>()) { reader.Expect <DocumentEnd>(); hasDocumentStart = false; if (expectOnlyFrontMatter) { reader.Accept <DocumentStart>(); var nextDocStart = reader.Expect <DocumentStart>(); endPosition = nextDocStart.End; break; } continue; } if (reader.Accept <DocumentStart>()) { reader.Expect <DocumentStart>(); hasDocumentStart = true; } var obj = ReadEvent(reader); if (result == null) { result = obj; } else { if (objects == null) { objects = new ScriptArray { result }; result = objects; } objects.Add(obj); } } position = new TextPosition(endPosition.Index, endPosition.Line, endPosition.Column); return(result); }
public ArrayVPairs(ScriptArray obj) { m_Enumerator = obj.GetIterator(); }
private ScriptArray ReadStrictArray(Stream src) { byte[] bs = new byte[4]; src.Read(bs, 0, 4); offset += 4; ScriptArray array = new ScriptArray(); uint count = ByteUtil.ByteToUInt(bs, 4); for (uint i = 0; i < count; i++) { array.Add(ReadElement(src)); } return array; }
public HtmlObject(ScriptObject parent) : base(parent) { HeadIncludes = new ScriptArray <string>(); // Import html object SetValue("head_includes", HeadIncludes, true); }
public object Evaluate(TemplateContext context, ScriptNode callerContext, ScriptArray parameters, ScriptBlockStatement blockStatement) { // Check parameters if ((hasObjectParams && parameters.Count < parametersInfo.Length - 1) || (!hasObjectParams && parameters.Count != parametersInfo.Length)) { throw new ScriptRuntimeException(callerContext.Span, $"Invalid number of arguments passed [{parameters.Count}] while expecting [{parametersInfo.Length}] for [{callerContext}]"); } // Convert arguments var arguments = new object[parametersInfo.Length]; object[] paramArguments = null; if (hasObjectParams) { paramArguments = new object[parameters.Count - lastParamsIndex]; arguments[lastParamsIndex] = paramArguments; } for (int i = 0; i < parameters.Count; i++) { var destType = hasObjectParams && i >= lastParamsIndex ? typeof(object) : parametersInfo[i].ParameterType; try { var argValue = ScriptValueConverter.ToObject(callerContext.Span, parameters[i], destType); if (hasObjectParams && i >= lastParamsIndex) { paramArguments[i - lastParamsIndex] = argValue; } else { arguments[i] = argValue; } } catch (Exception exception) { throw new ScriptRuntimeException(callerContext.Span, $"Unable to convert parameter #{i} of type [{parameters[i]?.GetType()}] to type [{destType}]", exception); } } // Call method try { var result = method.Invoke(target, arguments); return result; } catch (Exception exception) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected exception when calling {callerContext}", exception); } }
public object Evaluate(TemplateContext context, ScriptNode callerContext, ScriptArray parameters, ScriptBlockStatement blockStatement) { return customFunction(context, callerContext, parameters); }
public ArrayPairs(Script script, ScriptArray obj) { m_Script = script; m_Index = 0; m_Enumerator = obj.GetIterator(); }
/// <summary> /// Renders an state machine function /// </summary> /// <param name="context">Template context</param> /// <param name="callerContext">Caller context</param> /// <param name="arguments">Arguments to render the function with</param> /// <returns>Rendered state machine function</returns> private async ValueTask <object> RenderStateMachineFunction(TemplateContext context, ScriptNode callerContext, ScriptArray arguments) { if (arguments.Count != 1 || !(arguments[0] is ScribanExportStateFunction)) { _errorCollection.AddInvalidParameter(ScribanErrorUtil.FormatScribanSpan(callerContext.Span)); return("<<DID NOT PROVIDE VALID STATE MACHINE FUNCTION>>"); } ScribanExportStateFunction exportFunction = (ScribanExportStateFunction)arguments[0]; GoNorthProject curProject = await _exportCachedDbAccess.GetUserProject(); ExportTemplate eventFunctionTemplate = await _defaultTemplateProvider.GetDefaultTemplateByType(curProject.Id, TemplateType.ObjectStateFunction); ExportObjectData objectData = new ExportObjectData(); objectData.ExportData.Add(ExportConstants.ExportDataObject, exportFunction.ToStateFunction()); ExportPlaceholderFillResult fillResult = await _templatePlaceholderResolver.FillPlaceholders(TemplateType.ObjectStateFunction, eventFunctionTemplate.Code, objectData, eventFunctionTemplate.RenderingEngine); _errorCollection.Merge(fillResult.Errors); return(ScribanOutputUtil.IndentMultilineCode(context, fillResult.Code)); }
public ArrayKPairs(ScriptArray obj) { m_Index = 0; m_Enumerator = obj.GetIterator(); }
public object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { return(JsonConvert.SerializeObject(arguments[0])); }
public static object Call(TemplateContext context, ScriptNode callerContext, object functionObject, List<ScriptExpression> arguments = null) { if (callerContext == null) throw new ArgumentNullException(nameof(callerContext)); if (functionObject == null) { throw new ScriptRuntimeException(callerContext.Span, $"The target function [{callerContext}] is null"); } var function = functionObject as ScriptFunction; var externFunction = functionObject as IScriptCustomFunction; if (function == null && externFunction == null) { throw new ScriptRuntimeException(callerContext.Span, $"Invalid object function [{functionObject?.GetType()}]"); } ScriptBlockStatement blockDelegate = null; if (context.BlockDelegates.Count > 0) { blockDelegate = context.BlockDelegates.Pop(); } var argumentValues = new ScriptArray(); if (arguments != null) { foreach (var argument in arguments) { var value = context.Evaluate(argument); // Handle parameters expansion for a function call when the operator ^ is used var unaryExpression = argument as ScriptUnaryExpression; if (unaryExpression != null && unaryExpression.ExpandParameters(value, argumentValues)) { continue; } argumentValues.Add(value); } } // Handle pipe arguments here if (context.PipeArguments.Count > 0) { var additionalArgument = context.PipeArguments.Pop(); var value = context.Evaluate(additionalArgument); // Handle parameters expansion for a function call when the operator ~ is used var unaryExpression = additionalArgument as ScriptUnaryExpression; if (unaryExpression == null || !unaryExpression.ExpandParameters(value, argumentValues)) { argumentValues.Add(value); } } object result = null; context.EnterFunction(callerContext); try { if (externFunction != null) { result = externFunction.Evaluate(context, callerContext, argumentValues, blockDelegate); } else { context.SetValue(ScriptVariable.Arguments, argumentValues, true); // Set the block delegate if (blockDelegate != null) { context.SetValue(ScriptVariable.BlockDelegate, blockDelegate, true); } result = context.Evaluate(function.Body); } } finally { context.ExitFunction(); } // Restore the flow state to none context.FlowState = ScriptFlowState.None; return result; }
public static object Evaluate(TemplateContext context, SourceSpan span, ScriptBinaryOperator op, object leftValue, object rightValue) { if (op == ScriptBinaryOperator.EmptyCoalescing) { return(leftValue ?? rightValue); } switch (op) { case ScriptBinaryOperator.ShiftLeft: var leftList = leftValue as IList; if (leftList != null) { var newList = new ScriptArray(leftList) { rightValue }; return(newList); } break; case ScriptBinaryOperator.ShiftRight: var rightList = rightValue as IList; if (rightList != null) { var newList = new ScriptArray(rightList); newList.Insert(0, leftValue); return(newList); } break; case ScriptBinaryOperator.LiquidHasKey: { var leftDict = leftValue as IDictionary <string, object>; if (leftDict != null) { return(ObjectFunctions.HasKey(leftDict, context.ToString(span, rightValue))); } } break; case ScriptBinaryOperator.LiquidHasValue: { var leftDict = leftValue as IDictionary <string, object>; if (leftDict != null) { return(ObjectFunctions.HasValue(leftDict, context.ToString(span, rightValue))); } } break; case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.Add: case ScriptBinaryOperator.Substract: case ScriptBinaryOperator.Multiply: case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: case ScriptBinaryOperator.RangeInclude: case ScriptBinaryOperator.RangeExclude: case ScriptBinaryOperator.LiquidContains: case ScriptBinaryOperator.LiquidStartsWith: case ScriptBinaryOperator.LiquidEndsWith: if (leftValue is string || rightValue is string) { return(CalculateToString(context, span, op, leftValue, rightValue)); } else if (leftValue == EmptyScriptObject.Default || rightValue == EmptyScriptObject.Default) { return(CalculateEmpty(context, span, op, leftValue, rightValue)); } else { return(CalculateOthers(context, span, op, leftValue, rightValue)); } } throw new ScriptRuntimeException(span, $"Operator `{op.ToText()}` is not implemented for `{leftValue}` and `{rightValue}`"); }
private static object Round(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count < 1 || parameters.Count > 2) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for math.round. Expecting at least 1 parameter <precision>? <value>"); } var value = ScriptValueConverter.ToDouble(callerContext.Span, parameters[parameters.Count - 1]); int precision = 0; if (parameters.Count == 2) { precision = ScriptValueConverter.ToInt(callerContext.Span, parameters[0]); } return(Round(precision, value)); }
private static object Slice(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count < 2 || parameters.Count > 3) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for slice. Expecting at least 2 parameters <start> <length>? <text>"); } var text = ScriptValueConverter.ToString(callerContext.Span, parameters[parameters.Count - 1]); var start = ScriptValueConverter.ToInt(callerContext.Span, parameters[0]); var length = -1; if (parameters.Count == 3) { length = ScriptValueConverter.ToInt(callerContext.Span, parameters[1]); } return Slice(text, start, length); }
/// <summary> /// Renders an daily routine function list /// </summary> /// <param name="context">Template context</param> /// <param name="callerContext">Caller context</param> /// <param name="arguments">Arguments to render the list with</param> /// <returns>Rendered daily routine function list</returns> private async ValueTask <object> RenderDailyRoutineFunctionList(TemplateContext context, ScriptNode callerContext, ScriptArray arguments) { List <ScribanExportDailyRoutineFunction> functionList = ScribanParsingUtil.GetArrayFromScribanArgument <ScribanExportDailyRoutineFunction>(arguments, 0); if (functionList == null) { _errorCollection.AddInvalidParameter(ScribanErrorUtil.FormatScribanSpan(callerContext.Span)); return("<<DID NOT PROVIDE VALID FUNCTION LIST>>"); } GoNorthProject curProject = await _exportCachedDbAccess.GetUserProject(); ExportTemplate functionListTemplate = await _defaultTemplateProvider.GetDefaultTemplateByType(curProject.Id, TemplateType.ObjectDailyRoutineFunctionList); ExportObjectData objectData = new ExportObjectData(); objectData.ExportData.Add(ExportConstants.ExportDataObject, functionList.Select(f => f.ToDailyRoutineFunction()).ToList()); ExportPlaceholderFillResult fillResult = await _templatePlaceholderResolver.FillPlaceholders(TemplateType.ObjectDailyRoutineFunctionList, functionListTemplate.Code, objectData, functionListTemplate.RenderingEngine); _errorCollection.Merge(fillResult.Errors); return(ScribanOutputUtil.IndentMultilineCode(context, fillResult.Code)); }
public override object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { if (arguments.Count == 0) { throw new ScriptRuntimeException(callerContext.Span, "Expecting the name of the include for the 'markdown' function"); } var md = base.Invoke(context, callerContext, arguments, blockStatement) as string; var html = context.Markdown?.Render(md) ?? ""; return(html); }
/// <summary> /// Invokes the state machine function generation async /// </summary> /// <param name="context">Template context</param> /// <param name="callerContext">Caller context</param> /// <param name="arguments">Arguments</param> /// <param name="blockStatement">Block Statement</param> /// <returns>State machine function</returns> public override async ValueTask <object> InvokeAsync(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { return(await RenderStateMachineFunction(context, callerContext, arguments)); }
/// <summary> /// Invokes the state machine function generation /// </summary> /// <param name="context">Template context</param> /// <param name="callerContext">Caller context</param> /// <param name="arguments">Arguments</param> /// <param name="blockStatement">Block Statement</param> /// <returns>State machine function</returns> public override object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { return(RenderStateMachineFunction(context, callerContext, arguments).Result); }
public ValueTask <object> InvokeAsync(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { var result = this.Invoke(context, callerContext, arguments, blockStatement); return(new ValueTask <object>(result)); }
public static object AnyOf(Random random, ScriptArray array) { return(array[random.Next(array.Count)]); }
public override object Evaluate(TemplateContext context) { var leftValueOriginal = context.Evaluate(Left); var leftValue = leftValueOriginal; var rightValueOriginal = context.Evaluate(Right); object rightValue = rightValueOriginal; if (Operator == ScriptBinaryOperator.EmptyCoalescing) { return(leftValue ?? rightValue); } else if (Operator == ScriptBinaryOperator.And || Operator == ScriptBinaryOperator.Or) { var leftBoolValue = context.ToBool(leftValue); var rightBoolValue = context.ToBool(rightValue); if (Operator == ScriptBinaryOperator.And) { return(leftBoolValue && rightBoolValue); } else { return(leftBoolValue || rightBoolValue); } } else { switch (Operator) { case ScriptBinaryOperator.ShiftLeft: var leftList = leftValue as IList; if (leftList != null) { var newList = new ScriptArray(leftList) { rightValue }; return(newList); } break; case ScriptBinaryOperator.ShiftRight: var rightList = rightValue as IList; if (rightList != null) { var newList = new ScriptArray(rightList); newList.Insert(0, leftValue); return(newList); } break; case ScriptBinaryOperator.CompareEqual: case ScriptBinaryOperator.CompareNotEqual: case ScriptBinaryOperator.CompareGreater: case ScriptBinaryOperator.CompareLess: case ScriptBinaryOperator.CompareGreaterOrEqual: case ScriptBinaryOperator.CompareLessOrEqual: case ScriptBinaryOperator.Add: case ScriptBinaryOperator.Substract: case ScriptBinaryOperator.Multiply: case ScriptBinaryOperator.Divide: case ScriptBinaryOperator.DivideRound: case ScriptBinaryOperator.Modulus: case ScriptBinaryOperator.RangeInclude: case ScriptBinaryOperator.RangeExclude: var leftType = leftValue?.GetType(); var rightType = rightValue?.GetType(); if (leftValue is string || rightValue is string) { return(CalculateToString(context, leftValue, rightValue)); } else { return(Calculate(context, leftValue, leftType, rightValue, rightType)); } } } throw new ScriptRuntimeException(Span, $"Operator [{Operator.ToText()}] is not implemented for the left [{Left}] / right [{Right}]"); }
public object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, ScriptBlockStatement blockStatement) { if (arguments.Count == 0) { throw new ScriptRuntimeException(callerContext.Span, "Expecting at least the name of the template to include for the <include> function"); } var templateName = context.ObjectToString(arguments[0]); // If template name is empty, throw an exception if (string.IsNullOrEmpty(templateName)) { // In a liquid template context, we let an include to continue without failing if (context is LiquidTemplateContext) { return(null); } throw new ScriptRuntimeException(callerContext.Span, $"Include template name cannot be null or empty"); } var templateLoader = context.TemplateLoader; if (templateLoader == null) { throw new ScriptRuntimeException(callerContext.Span, $"Unable to include <{templateName}>. No TemplateLoader registered in TemplateContext.TemplateLoader"); } string templatePath; try { templatePath = templateLoader.GetPath(context, callerContext.Span, templateName); } catch (Exception ex) when(!(ex is ScriptRuntimeException)) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected exception while getting the path for the include name `{templateName}`", ex); } // If template path is empty (probably because template doesn't exist), throw an exception if (templatePath == null) { throw new ScriptRuntimeException(callerContext.Span, $"Include template path is null for `{templateName}"); } string indent = null; // Handle indent if (context.IndentWithInclude) { // Find the statement for the include var current = callerContext.Parent; while (current != null && !(current is ScriptStatement)) { current = current.Parent; } // Find the RawStatement preceding this include ScriptNode childNode = null; bool shouldContinue = true; while (shouldContinue && current != null) { if (current is ScriptList <ScriptStatement> statementList && childNode is ScriptStatement childStatement) { var indexOf = statementList.IndexOf(childStatement); // Case for first indent, if it is not the first statement in the doc // it's not a valid indent if (indent != null && indexOf > 0) { indent = null; break; } for (int i = indexOf - 1; i >= 0; i--) { var previousStatement = statementList[i]; if (previousStatement is ScriptEscapeStatement escapeStatement && escapeStatement.IsEntering) { if (i > 0 && statementList[i - 1] is ScriptRawStatement rawStatement) { var text = rawStatement.Text; for (int j = text.Length - 1; j >= 0; j--) { var c = text[j]; if (c == '\n') { shouldContinue = false; indent = text.Substring(j + 1); break; } if (!char.IsWhiteSpace(c)) { shouldContinue = false; break; } if (j == 0) { // We have a raw statement that has only white spaces // It could be the first raw statement of the document // so we continue but we handle it later indent = text.ToString(); } } } else { shouldContinue = false; } break; } } } childNode = current; current = childNode.Parent; } if (string.IsNullOrEmpty(indent)) { indent = null; } } Template template; if (!context.CachedTemplates.TryGetValue(templatePath, out template)) { string templateText; try { templateText = templateLoader.Load(context, callerContext.Span, templatePath); } catch (Exception ex) when(!(ex is ScriptRuntimeException)) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected exception while loading the include `{templateName}` from path `{templatePath}`", ex); } if (templateText == null) { throw new ScriptRuntimeException(callerContext.Span, $"The result of including `{templateName}->{templatePath}` cannot be null"); } // Clone parser options var parserOptions = context.TemplateLoaderParserOptions; var lexerOptions = context.TemplateLoaderLexerOptions; template = Template.Parse(templateText, templatePath, parserOptions, lexerOptions); // If the template has any errors, throw an exception if (template.HasErrors) { throw new ScriptParserRuntimeException(callerContext.Span, $"Error while parsing template `{templateName}` from `{templatePath}`", template.Messages); } context.CachedTemplates.Add(templatePath, template); } // Make sure that we cannot recursively include a template object result = null; context.EnterRecursive(callerContext); var previousIndent = context.CurrentIndent; context.CurrentIndent = indent; context.PushOutput(); var previousArguments = context.GetValue(ScriptVariable.Arguments); try { context.SetValue(ScriptVariable.Arguments, arguments, true, true); if (indent != null) { // We reset before and after the fact that we have a new line context.ResetPreviousNewLine(); } result = template.Render(context); if (indent != null) { context.ResetPreviousNewLine(); } } finally { context.PopOutput(); context.CurrentIndent = previousIndent; context.ExitRecursive(callerContext); // Remove the arguments context.DeleteValue(ScriptVariable.Arguments); if (previousArguments != null) { // Restore them if necessary context.SetValue(ScriptVariable.Arguments, previousArguments, true); } } return(result); }
private static object Slice(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count < 2 || parameters.Count > 3) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for slice. Expecting at least 2 parameters <start> <length>? <text>"); } var text = ScriptValueConverter.ToString(callerContext.Span, parameters[parameters.Count - 1]); var start = ScriptValueConverter.ToInt(callerContext.Span, parameters[0]); var length = -1; if (parameters.Count == 3) { length = ScriptValueConverter.ToInt(callerContext.Span, parameters[1]); } return(Slice(text, start, length)); }
public static object Call(TemplateContext context, ScriptNode callerContext, object functionObject, bool processPipeArguments, List <ScriptExpression> arguments = null) { if (callerContext == null) { throw new ArgumentNullException(nameof(callerContext)); } if (functionObject == null) { throw new ScriptRuntimeException(callerContext.Span, $"The target function `{callerContext}` is null"); } var function = functionObject as ScriptFunction; var externFunction = functionObject as IScriptCustomFunction; if (function == null && externFunction == null) { throw new ScriptRuntimeException(callerContext.Span, $"Invalid target function `{callerContext}`( as `{functionObject?.GetType()}`)"); } ScriptBlockStatement blockDelegate = null; if (context.BlockDelegates.Count > 0) { blockDelegate = context.BlockDelegates.Pop(); } // We can't cache this array because it might be collect by the function // So we absolutely need to generate a new array everytime we call a function ScriptArray argumentValues; // Handle pipe arguments here if (processPipeArguments && context.PipeArguments != null && context.PipeArguments.Count > 0) { var args = context.PipeArguments; argumentValues = new ScriptArray(args.Count); for (int i = 0; i < args.Count; i++) { argumentValues.Add(args[i]); } args.Clear(); } else { argumentValues = new ScriptArray(arguments?.Count ?? 0); } // Process direct arguments if (arguments != null) { foreach (var argument in arguments) { object value; // Handle named arguments var namedArg = argument as ScriptNamedArgument; if (namedArg != null) { // In case of a ScriptFunction, we write the named argument into the ScriptArray directly if (externFunction == null) { // We can't add an argument that is "size" for array if (argumentValues.CanWrite(namedArg.Name)) { argumentValues.SetValue(context, callerContext.Span, namedArg.Name, context.Evaluate(namedArg), false); continue; } // Otherwise pass as a regular argument value = context.Evaluate(namedArg); } else { // Named argument are passed as is to the IScriptCustomFunction value = argument; } } else { value = context.Evaluate(argument); } // Handle parameters expansion for a function call when the operator ^ is used var unaryExpression = argument as ScriptUnaryExpression; if (unaryExpression != null && unaryExpression.Operator == ScriptUnaryOperator.FunctionParametersExpand) { var valueEnumerator = value as IEnumerable; if (valueEnumerator != null) { foreach (var subValue in valueEnumerator) { argumentValues.Add(subValue); } continue; } } argumentValues.Add(value); } } object result = null; context.EnterFunction(callerContext); try { if (externFunction != null) { result = externFunction.Invoke(context, callerContext, argumentValues, blockDelegate); } else { context.SetValue(ScriptVariable.Arguments, argumentValues, true); // Set the block delegate if (blockDelegate != null) { context.SetValue(ScriptVariable.BlockDelegate, blockDelegate, true); } result = context.Evaluate(function.Body); } } finally { context.ExitFunction(); } // Restore the flow state to none context.FlowState = ScriptFlowState.None; return(result); }
private static object Sort(TemplateContext context, ScriptNode callerContext, ScriptArray parameters) { if (parameters.Count < 1 || parameters.Count > 2) { throw new ScriptRuntimeException(callerContext.Span, $"Unexpected number of arguments [{parameters.Count}] for sort. Expecting at least 1 parameter <property>? <array>"); } var target = parameters[parameters.Count - 1]; string member = null; if (parameters.Count == 2) { member = ScriptValueConverter.ToString(callerContext.Span, parameters[0]); } return Sort(context, target, member); }