public static ArrayList ListOrderBy( [DekiScriptParam("list value")] ArrayList list, [DekiScriptParam("key name or list of key names; sort direction is controlled by appendending \" ascending\" or \" descending\" to the key(s); when omitted, the direction is asending by default")] object keys, DekiScriptRuntime runtime ) { // check for trivial sort case if (keys is string) { string key = ((string)keys).Trim(); // the key cannot contain access operators if (key.IndexOfAny(new[] { '.', '[', ']' }) < 0) { return(ListOrderBy_IsReversed(ref key) ? ListSort(list, key, true, null, runtime) : ListSort(list, key, false, null, runtime)); } // let's change 'keys' into an array list for processing convenience ArrayList temp = new ArrayList { keys }; keys = temp; } // check that 'keys' has a valid type if (!(keys is ArrayList)) { throw new DekiScriptBadTypeException(Location.None, DekiScriptLiteral.AsScriptType(keys.GetType()), new[] { DekiScriptType.STR, DekiScriptType.LIST }); } // build comparison expression StringBuilder compare = new StringBuilder(); foreach (string key in (ArrayList)keys) { if (compare.Length > 0) { compare.Append(" || "); } // process sort field string field = key; if (ListOrderBy_IsReversed(ref field)) { compare.AppendFormat("(if($left.{0} < $right.{0}) 1; else if($left.{0} > $right.{0}) -1; else 0;)", field); } else { compare.AppendFormat("(if($left.{0} < $right.{0}) -1; else if($left.{0} > $right.{0}) 1; else 0;)", field); } } // sort list list.Sort(new DekiScriptComparer(runtime, DekiScriptParser.Parse(new Location("list.orderby(compare)"), compare.ToString()))); return(list); }
//--- Constructors --- public DekiScriptNativeInvocationTarget(object subject, MethodInfo method, Parameter[] parameters) { this.Method = method; // check if method is a coroutine Type nativeReturnType; ConstructorInfo resultTypeConstructor = null; ParameterInfo[] methodParams = method.GetParameters(); bool isCoroutine = (method.ReturnType == typeof(IEnumerator <IYield>)); if (isCoroutine) { // check if enough parameters are present if (methodParams.Length == 0) { throw new ArgumentException("handler is missing Result<T> parameter"); } // check that the last parameter is of type Result<T> Type lastParam = methodParams[methodParams.Length - 1].ParameterType; if (!lastParam.IsGenericType || (lastParam.GetGenericTypeDefinition() != typeof(Result <>))) { throw new ArgumentException(string.Format("handler last parameter must be generic type Result<T>, but is {0}", lastParam.FullName)); } resultTypeConstructor = lastParam.GetConstructor(Type.EmptyTypes); nativeReturnType = lastParam.GetGenericArguments()[0]; // remove last parameter from array since it represents the return type methodParams = ArrayUtil.Resize(methodParams, methodParams.Length - 1); } else { nativeReturnType = method.ReturnType; } ReturnType = DekiScriptLiteral.AsScriptType(nativeReturnType); // check if first parameter is a DekiScriptRuntime bool usesRuntime = false; if ((methodParams.Length > 0) && (methodParams[methodParams.Length - 1].ParameterType.IsA <DekiScriptRuntime>())) { usesRuntime = true; methodParams = ArrayUtil.Resize(methodParams, methodParams.Length - 1); } // retrieve method parameters and their attributes Parameters = new DekiScriptParameter[methodParams.Length]; for (int i = 0; i < methodParams.Length; ++i) { ParameterInfo param = methodParams[i]; Parameter details = parameters[i] ?? Parameter.Default; // add hint parameter Parameters[i] = new DekiScriptParameter(param.Name, DekiScriptLiteral.AsScriptType(param.ParameterType), details.Optional, details.Hint, param.ParameterType, DekiScriptNil.Value); } // determine access rights if (method.IsPrivate || method.IsFamily) { this.Access = DreamAccess.Private; } else if (method.IsAssembly) { this.Access = DreamAccess.Internal; } else { this.Access = DreamAccess.Public; } // create invocation callback if (resultTypeConstructor != null) { if (usesRuntime) { // invoke coroutine with runtime _invoke = (runtime, args) => { var arguments = new object[args.Length + 2]; AResult result = (AResult)resultTypeConstructor.Invoke(null); arguments[arguments.Length - 1] = result; arguments[arguments.Length - 2] = runtime; Array.Copy(args, arguments, args.Length); new Coroutine(method, result).Invoke(() => (IEnumerator <IYield>)method.InvokeWithRethrow(subject, arguments)); result.Block(); return(result.UntypedValue); }; } else { // invoke coroutine without runtime _invoke = (runtime, args) => { var arguments = new object[args.Length + 1]; AResult result = (AResult)resultTypeConstructor.Invoke(null); arguments[arguments.Length - 1] = result; Array.Copy(args, arguments, args.Length); new Coroutine(method, result).Invoke(() => (IEnumerator <IYield>)method.InvokeWithRethrow(subject, arguments)); result.Block(); return(result.UntypedValue); }; } } else { if (usesRuntime) { // invoke method with runtime _invoke = (runtime, args) => { var arguments = new object[args.Length + 1]; arguments[arguments.Length - 1] = runtime; Array.Copy(args, arguments, args.Length); return(method.InvokeWithRethrow(subject, arguments)); }; } else { // invoke method without runtime _invoke = (runtime, args) => method.InvokeWithRethrow(subject, args); } } }
public static string StringFormat( [DekiScriptParam("string with placeholders")] string text, [DekiScriptParam("values to insert into string", true)] object values ) { if (values == null) { return(text); } // check if values is either a map or a list Hashtable map = values as Hashtable; ArrayList list = values as ArrayList; if ((map == null) && (list == null)) { throw new DekiScriptBadTypeException(Location.None, DekiScriptLiteral.AsScriptType(values.GetType()), new[] { DekiScriptType.MAP, DekiScriptType.LIST }); } // loop over string and fetch values from map/list StringBuilder result = new StringBuilder(); int start = 0; int end = text.IndexOf('$'); while (end >= 0) { // append characters skipped if (start != end) { result.Append(text.Substring(start, end - start)); } ++end; start = end; // check if we reached the end of the text or if the current position is followed by a '$' sign if ((end < text.Length) && (text[end] != '$')) { // parse the identifier while ((end < text.Length) && ((text[end] == '_') || char.IsLetterOrDigit(text[end]))) { ++end; } string id = text.Substring(start, end - start); // fetch value for identifier and insert it if found if (id.Length > 0) { string value = null; if (map != null) { value = SysUtil.ChangeType <string>(map[id]); } else { int index; if (int.TryParse(id, out index) && (index >= 0) && (index < list.Count)) { value = SysUtil.ChangeType <string>(list[index]); } } if (!string.IsNullOrEmpty(value)) { result.Append(value); } } } else { result.Append("$"); ++end; } // find next '$' sign start = end; end = (end < text.Length) ? text.IndexOf('$', end) : -1; } // append rest of the string if (start < text.Length) { result.Append(text.Substring(start)); } return(result.ToString()); }