Ejemplo n.º 1
0
        // NOTE: isStatic = true has never been tested. Library functions are static but are neither flagged as static nor as class members,
        // so references can be saved to them by users already.
        public FunctionValue_Host(ITypeDef _retType, List <ITypeDef> _argTypes, EvaluateDelegate _Evaluate, bool _varargs = false, TypeDef_Class classType = null, bool isStatic = false, List <Expr_Literal> defaultArgVals = null)
        {
            argDefaultValues = defaultArgVals;
            BuildArgHasDefaults(_argTypes.Count);

            valType  = TypeFactory.GetTypeDef_Function(_retType, _argTypes, minArgs, _varargs, classType, true, isStatic);
            Evaluate = _Evaluate;
        }
Ejemplo n.º 2
0
        public virtual ITypeDef ResolveTemplateTypes(List <ITypeDef> genericTypes, ref bool modified)
        {
            List <ITypeDef> args = new List <ITypeDef>();

            for (int ii = 0; ii < argTypes.Count; ++ii)
            {
                args.Add(argTypes[ii].ResolveTemplateTypes(genericTypes, ref modified));
            }
            ITypeDef newRetType = retType.ResolveTemplateTypes(genericTypes, ref modified);

            if (null != classType)
            {
                classType.ResolveTemplateTypes(genericTypes, ref modified);
            }
            return(TypeFactory.GetTypeDef_Function(newRetType, args, minArgs, varargs, classType, isConst, isStaticMember));
        }
Ejemplo n.º 3
0
        public static void Register(Engine engine)
        {
            //@ class List<T>
            TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("List", new ArgList {
                IntrinsicTypeDefs.TEMPLATE_0
            }, false);
            ClassDef classDef = engine.defaultContext.CreateClass("List", ourType, null, new List <string> {
                "T"
            });

            classDef.childAllocator = () => {
                return(new PebbleList());
            };
            classDef.Initialize();

            //@ List<T> Add(T newValue, ...) or List<T> Push(T newValue, ...)
            //   Adds one or more elements to the end of the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleList scope = thisScope as PebbleList;
                    if (scope.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Add: Attempt to modify a list that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    var list        = scope.list;
                    var listType    = (TypeDef_Class)scope.classDef.typeDef;
                    var elementType = listType.genericTypes[0];
                    for (int ii = 0; ii < args.Count; ++ii)
                    {
                        object ret = args[ii];
                        list.Add(new Variable(null, elementType, ret));
                    }

                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.TEMPLATE_0
                }, eval, true, ourType);
                classDef.AddMemberLiteral("Add", newValue.valType, newValue);
                classDef.AddMemberLiteral("Push", newValue.valType, newValue);
            }

            //@ List<T> Clear()
            //   Removes all elements from the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleList pebList = thisScope as PebbleList;
                    if (pebList.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Clear: Attempt to modify a list that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    var list = pebList.list;
                    list.Clear();
                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Clear", newValue.valType, newValue);
            }

            //@ num Count()
            //   Returns the number of elements in the list.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var list = (thisScope as PebbleList).list;
                    return(System.Convert.ToDouble(list.Count));
                };

                FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Count", newValue.valType, newValue);
            }

            //@ T Get(num index)
            //   Returns the value of the element of the list at the given index.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double dix = (double)args[0];
                    int    ix  = (int)dix;

                    var list = (thisScope as PebbleList).list;

                    // Bounds checking.
                    if (ix < 0 || ix >= list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Get: Index " + ix + " out of bounds of array of length " + list.Count + ".");
                        return(null);
                    }

                    return(list[ix].value);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.TEMPLATE_0, new ArgList {
                    IntrinsicTypeDefs.NUMBER
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Get", newValue.valType, newValue);
            }

            //@ List<T> Insert(num index, T item)
            //   Inserts a new element into the list at the given index. Existing elements at and after the given index are pushed further down the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleList scope = thisScope as PebbleList;
                    if (scope.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Insert: Attempt to modify a list that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    var list        = scope.list;
                    var listType    = (TypeDef_Class)scope.classDef.typeDef;
                    var elementType = listType.genericTypes[0];
                    var indexDouble = (double)args[0];
                    var item        = args[1];
                    var index       = Convert.ToInt32(indexDouble);
                    if (index < 0 || index > list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Insert: array index out of bounds.");
                        return(null);
                    }

                    list.Insert(index, new Variable(null, elementType, item));

                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.TEMPLATE_0
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Insert", newValue.valType, newValue);
            }

            //@ T Pop()
            //   Returns the value of the last element of the list and removes it from the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleList pebList = thisScope as PebbleList;
                    if (pebList.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Pop: Attempt to remove an element from a list that is being enumerated in a foreach loop.");
                        return(null);
                    }

                    var list = pebList.list;
                    int ix   = list.Count - 1;
                    if (ix < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Pop: List is empty.");
                        return(null);
                    }

                    var result = list[ix].value;
                    list.RemoveAt(ix);
                    return(result);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.TEMPLATE_0, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Pop", newValue.valType, newValue);
            }

            //@ List<T> RemoveAt(num index)
            //   Removes element at the given index, and returns the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double dix = (double)args[0];
                    int    ix  = (int)dix;

                    PebbleList pebList = thisScope as PebbleList;
                    if (pebList.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "RemoveAt: Attempt to modify a list that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    var list = pebList.list;
                    if (ix < 0 || ix >= list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveAt: Index " + ix + " out of bounds of array of length " + list.Count + ".");
                        return(null);
                    }

                    list.RemoveAt(ix);
                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.NUMBER
                }, eval, false, ourType);
                classDef.AddMemberLiteral("RemoveAt", newValue.valType, newValue);
            }

            //@ List<T> RemoveRange(num start, num count)
            //   Removes elements in the given range of indices, and returns the list.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double dstart = (double)args[0];
                    int    start  = (int)dstart;
                    double dcount = (double)args[1];
                    int    count  = (int)dcount;

                    PebbleList pebList = thisScope as PebbleList;
                    if (pebList.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "RemoveRange: Attempt to modify a list that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    var list = pebList.list;
                    if (start < 0 || start >= list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Start " + start + " out of bounds of array of length " + list.Count + ".");
                        return(null);
                    }
                    if (count < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Count (" + count + ") cannot be negative.");
                        return(null);
                    }
                    if ((start + count) >= list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Count " + count + " exceeds array length (" + list.Count + ").");
                        return(null);
                    }

                    list.RemoveRange(start, count);
                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER
                }, eval, false, ourType);
                classDef.AddMemberLiteral("RemoveRange", newValue.valType, newValue);
            }

            //@ List<T> Reverse()
            //   Reverses the list and returns it.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var list = (thisScope as PebbleList).list;
                    list.Reverse();
                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Reverse", newValue.valType, newValue);
            }

            //@ List<T> Set(num index, T newValue)
            //   Changes the value of the element at the given index, and returns the list.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double dix = (double)args[0];
                    int    ix  = (int)dix;

                    object value = args[1];

                    var list = (thisScope as PebbleList).list;

                    // Bounds checking.
                    if (ix < 0 || ix >= list.Count)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Set: Index " + ix + " out of bounds of array of length " + list.Count + ".");
                        return(null);
                    }

                    list[ix].value = value;

                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.TEMPLATE_0
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Set", newValue.valType, newValue);
            }

            //@ List<T> Shuffle()
            //   Shuffles the list, putting the elements in random order.
            //	 Returns the list.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var list = (thisScope as PebbleList).list;

                    Random rng = new Random();

                    int n = list.Count;
                    while (n > 1)
                    {
                        --n;
                        int      k     = rng.Next(n + 1);
                        Variable value = list[k];
                        list[k] = list[n];
                        list[n] = value;
                    }

                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Shuffle", newValue.valType, newValue);
            }

            //@ List<T> Sort(functype<num(T, T>)> comparator)
            //   Sorts the list using the given comparator function.
            //   The comparator should behave the same as a C# Comparer. The first argument should be earlier in the
            //   list than the second, return a number < 0. If It should be later, return a number > 0. If their order
            //   is irrelevant, return 0.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var list = (thisScope as PebbleList).list;

                    if (null == args[0])
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Sort: comparator may not be null.");
                        return(null);
                    }

                    FunctionValue comparator = (FunctionValue)args[0];

                    List <object> argvals = new List <object>();
                    argvals.Add(0);
                    argvals.Add(0);

                    Comparison <Variable> hostComparator = new Comparison <Variable>(
                        (a, b) => {
                        argvals[0] = a.value;
                        argvals[1] = b.value;

                        // Note we use null instead of thisScope here. There is no way the sort function could be a
                        // class member because Sort's signature only takes function's whose type has no class.
                        double result = (double)comparator.Evaluate(context, argvals, null);
                        return(Convert.ToInt32(result));
                    }
                        );

                    list.Sort(hostComparator);
                    return(thisScope);
                };

                TypeDef_Function comparatorType = TypeFactory.GetTypeDef_Function(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.TEMPLATE_0, IntrinsicTypeDefs.TEMPLATE_0
                }, -1, false, null, false, false);

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    comparatorType
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Sort", newValue.valType, newValue);
            }

            //@ string ThisToScript(string prefix)
            //   ThisToScript is used by Serialize. A classes' ThisToScript function should return code which can rebuild the class.
            //   Note that it's only the content of the class, not the "new A" part. ie., it's the code that goes in the defstructor.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string result = "";
                    string prefix = (string)args[0] + "\t";

                    var list = (thisScope as PebbleList).list;
                    for (int ii = 0; ii < list.Count; ++ii)
                    {
                        result += prefix + "Add(" + CoreLib.ValueToScript(context, list[ii].value, prefix + "\t", false) + ");\n";
                    }

                    return(result);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false, ourType);
                classDef.AddMemberLiteral("ThisToScript", newValue.valType, newValue);
            }

            //@ string ToString()
            //   Returns a string representation of at least the first few elements of the list.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var    list   = (thisScope as PebbleList).list;
                    string result = "List(" + list.Count + ")[";
                    for (int ii = 0; ii < Math.Min(4, list.Count); ++ii)
                    {
                        if (ii > 0)
                        {
                            result += ", ";
                        }
                        result += CoreLib.ValueToString(context, list[ii].value, true);
                    }
                    if (list.Count > 4)
                    {
                        result += ", ...";
                    }
                    return(result + "]");
                };

                FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("ThisToString", newValue.valType, newValue);
            }

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("CoreList", RunTests);
        }
Ejemplo n.º 4
0
        /*
         * public override string ToString() {
         *      string argString = "ARGS";
         *      return (_isConst ? "const " : "") + "<" + retType + "(" + argString + ")>";
         * }
         */

        public override ITypeDef Resolve(ExecContext context, ref bool error)
        {
            ITypeDef retValType = retType.Resolve(context, ref error);

            if (null == retValType)
            {
                context.engine.LogCompileError(ParseErrorType.TypeNotFound, "Type '" + retType + "' not found.");
                error = true;
                return(null);
            }

            if (null != argHasDefaults && argHasDefaults.Count < argTypes.Count)
            {
                context.engine.LogCompileError(ParseErrorType.DefaultArgGap, "An argument with a default value is followed by an argument without one.");
                error = true;
                return(null);
            }

            int minArgs = argTypes.Count;

            if (null != argHasDefaults)
            {
                int firstDefault = -1;
                for (int ii = 0; ii < argHasDefaults.Count; ++ii)
                {
                    if (argHasDefaults[ii])
                    {
                        if (firstDefault < 0)
                        {
                            firstDefault = ii;
                            minArgs      = ii;
                        }
                    }
                    else if (firstDefault >= 0)
                    {
                        context.engine.LogCompileError(ParseErrorType.DefaultArgGap, "An argument with a default value is followed by an argument without one.");
                        error = true;
                        return(null);
                    }
                }
            }

            List <ITypeDef> argValTypes = new List <ITypeDef>();

            for (int ii = 0; ii < argTypes.Count; ++ii)
            {
                ITypeDef argValType = argTypes[ii].Resolve(context, ref error);
                if (null == argValType)
                {
                    context.engine.LogCompileError(ParseErrorType.TypeNotFound, "Type '" + argTypes[ii] + "' not found.");
                    error = true;
                    return(null);
                }

                argValTypes.Add(argValType);
            }

            TypeDef_Class classType = null;

            if (null != className)
            {
                ClassDef classDef = context.GetClass(className);
                if (null == classDef)
                {
                    Pb.Assert(false, "Internal error: error resolving class type.");
                }
                classType = classDef.typeDef;
            }

            var ret = TypeFactory.GetTypeDef_Function(retValType, argValTypes, minArgs, varArgs, classType, _isConst, false);

            return(ret);
        }