Пример #1
0
        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);
        }
Пример #2
0
        //--- 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());
        }