Пример #1
0
        public static TypeDef_Class GetTypeDef_Class(string className, List <ITypeDef> genericTypes, bool isConst)
        {
            string name;

            name = className;
            if (genericTypes != null)
            {
                string genPart = "<";
                for (int ii = 0; ii < genericTypes.Count; ++ii)
                {
                    genPart += (ii == 0 ? "" : ", ") + genericTypes[ii].GetName();
                }
                genPart += ">";
                name    += genPart;
            }

            if (isConst)
            {
                name += " const";
            }

            if (_typeRegistry.ContainsKey(name))
            {
                return(_typeRegistry[name] as TypeDef_Class);
            }
            TypeDef_Class newDef = new TypeDef_Class(className, genericTypes, isConst);

#if PEBBLE_TRACETYPES
            Console.WriteLine("Registering new class type: " + name);
#endif
            _typeRegistry.Add(name, newDef);
            return(newDef);
        }
Пример #2
0
        // When creating a new class, call CreateClass XOR RegisterClass. Use the latter if you already have a ClassDef, otherwise
        // call the former and it will create one for you.
        public ClassDef CreateClass(string nameIn, TypeDef_Class typeDef, ClassDef par, List <string> genericTypeNames = null, bool isSealed = false, bool isUninstantiable = false)
        {
            ClassDef def = new ClassDef(nameIn, typeDef, par, genericTypeNames, isSealed, isUninstantiable);

            RegisterClass(def);
            return(def);
        }
Пример #3
0
        // Given two classes, return which is the ancestor of the other, or null.
        // If neither is the direct ancestor of the other, returns null.  If you
        // want to determine teh nearest common ancestor, use GetMostCommonType.
        public TypeDef_Class DetermineAncestor(TypeDef_Class typeA, TypeDef_Class typeB)
        {
            ClassDef a = _classes[typeA.className];
            ClassDef b = _classes[typeB.className];

            while (b != null)
            {
                if (a == b)
                {
                    return(typeA);
                }
                b = b.parent;
            }

            b = _classes[typeB.className];
            while (a != null)
            {
                if (a == b)
                {
                    return(typeB);
                }
                a = a.parent;
            }

            return(null);
        }
Пример #4
0
 public override bool Equals(object obj)
 {
     if (obj is TypeDef_Class)
     {
         TypeDef_Class other = obj as TypeDef_Class;
         return(other.className == className);
     }
     return(false);
 }
Пример #5
0
        // Convenience function for registering a List<> with a given type, because this gets done a number of times.
        public ClassDef RegisterIfUnregisteredList(ITypeDef valueType)
        {
            List <ITypeDef> genericTypes = new List <ITypeDef>();

            genericTypes.Add(valueType);

            TypeDef_Class listTypeDef = TypeFactory.GetTypeDef_Class("List", genericTypes, false);

            return(engine.defaultContext.RegisterIfUnregisteredTemplate(listTypeDef));
        }
Пример #6
0
        internal TypeDef_Function(ITypeDef _retType, List <ITypeDef> _argTypes, int _minArgs, bool _varargs, TypeDef_Class classTypeIn, bool _isConst, bool _isStaticFunction)
        {
            retType        = _retType;
            argTypes       = _argTypes;
            minArgs        = _minArgs;
            varargs        = _varargs;
            isConst        = _isConst;
            classType      = classTypeIn;
            isStaticMember = _isStaticFunction;

            Pb.Assert(!_varargs || minArgs == _argTypes.Count, "internal error: function cannot be both varArgs and have arguments with default values.");
        }
Пример #7
0
        ///////////////////////////

        // DO NOT CALL THIS DIRECTLY
        // Use context.CreateClass instead.
        public ClassDef(string nameIn, TypeDef_Class typeDefIn, ClassDef par, List <string> genericTypeNamesIn = null, bool isSealedIn = false, bool isUninstantiableIn = false)
        {
            name             = nameIn;
            typeDef          = typeDefIn;
            parent           = par;
            genericTypeNames = genericTypeNamesIn;
            if (null != par && null != par.childAllocator)
            {
                childAllocator = par.childAllocator;
            }
            isSealed         = isSealedIn;
            isUninstantiable = isUninstantiableIn;
        }
Пример #8
0
        //public override bool Equals(object obj) {
        //	throw new InvalidProgramException("INTERNAL ERROR: Attempt to use type before it has been evaluated. (Equals)");
        //}

        public override ITypeDef Resolve(ExecContext context, ref bool error)
        {
            if (name == "void")
            {
                return(IntrinsicTypeDefs.VOID);
            }

            ITypeDef def = context.GetTypeByName(name);

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

            if (null == _templateTypes)
            {
                if (_isConst && !def.IsConst())
                {
                    return(def.Clone(true));
                }
                return(def);
            }

            // If we have template types, then we must be a TypeDef_Class.

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

            for (int ii = 0; ii < _templateTypes.Count; ++ii)
            {
                genericTypes.Add(_templateTypes[ii].Resolve(context, ref error));
            }

            if (error)
            {
                return(null);
            }


            //TypeDef_Class result = new TypeDef_Class(name, genericTypes, _isConst);
            TypeDef_Class result = TypeFactory.GetTypeDef_Class(name, genericTypes, _isConst);

            if (null == context.RegisterIfUnregisteredTemplate(result))
            {
                error = true;
            }
            return(result);
        }
Пример #9
0
        public bool Comparable(ExecContext context, ITypeDef other)
        {
            if (!(other is TypeDef_Class))
            {
                return(false);
            }

            if (Equals(other))
            {
                return(true);
            }

            TypeDef_Class otherClassType = other as TypeDef_Class;

            return(null != context.DetermineAncestor(this, otherClassType));
        }
Пример #10
0
        public virtual bool CanStoreValue(ExecContext context, ITypeDef valueType)
        {
            if (valueType is TypeDef && null == ((TypeDef)valueType).GetHostType())
            {
                return(true);
            }

            TypeDef_Class classValueType = valueType as TypeDef_Class;

            if (null == classValueType)
            {
                return(false);
            }

            if (!context.IsChildClass(context.GetClass(className), context.GetClass(classValueType.className)))
            {
                return(false);
            }

            // If neither has generic types, we match.
            if (null == classValueType._genericTypes && null == _genericTypes)
            {
                return(true);
            }

            // If only one has generic types, we do not.
            if (null == classValueType._genericTypes || null == _genericTypes)
            {
                return(false);
            }

            // If they don't have the same number, we do not.
            if (classValueType._genericTypes.Count != _genericTypes.Count)
            {
                return(false);
            }

            for (int ii = 0; ii < _genericTypes.Count; ++ii)
            {
                if (_genericTypes[ii] != classValueType._genericTypes[ii])
                {
                    return(false);
                }
            }

            return(true);
        }
Пример #11
0
        private ITypeDef GetMostCommonType(TypeDef_Class typeA, TypeDef_Class typeB)
        {
            ClassDef a = _classes[typeA.className];

            while (a != null)
            {
                ClassDef b = _classes[typeB.className];
                while (b != null)
                {
                    if (a == b)
                    {
                        return(a.typeDef);
                    }
                    b = b.parent;
                }
                a = a.parent;
            }

            return(null);
        }
Пример #12
0
        // Register a template type, creating the ClassDef if necessary.
        public ClassDef RegisterIfUnregisteredTemplate(TypeDef_Class classType)
        {
            string fullName = classType.GetName();

            if (_classes.ContainsKey(fullName))
            {
                return(_classes[fullName]);
            }

            ClassDef parent = _classes[classType.className];

            Pb.Assert(null != parent, "Parent template not registered?");
            if (parent.isSealed)
            {
                engine.LogCompileError(ParseErrorType.ClassParentSealed, "Cannot derive from sealed class.");
                return(null);
            }

            // NOTE: All this code is assuming that the generic parent has no parents.
            // This is fine as long as 1) all generic classes are only defined in C#, and
            // 2) none of them have parents.

            if (parent.genericTypeNames.Count != classType.genericTypes.Count)
            {
                engine.LogCompileError(ParseErrorType.TemplateCountMismatch, "Template count mismatch: expected " + parent.genericTypeNames.Count + ", got " + classType.genericTypes.Count + ".");
                return(null);
            }

            ClassDef newClass = new ClassDef(classType.GetName(), classType, parent);

            _classes.Add(newClass.name, newClass);
            newClass.Initialize();
            newClass.FinalizeClass(this);

            return(newClass);
        }
Пример #13
0
        // D B A
        // G E B A
        // This is specifically for the conditional operator.
        //   typeof(true?D:G) is B
        public ITypeDef GetMostCommonType(ITypeDef typeA, ITypeDef typeB)
        {
            bool aIsClass = typeA is TypeDef_Class;

            if (aIsClass)
            {
                bool bIsClass = typeB is TypeDef_Class;
                if (bIsClass)
                {
                    TypeDef_Class classTypeA = typeA as TypeDef_Class;
                    TypeDef_Class classTypeB = typeB as TypeDef_Class;
                    return(GetMostCommonType(classTypeA, classTypeB));
                }
            }

            // If they aren't both classes then they must be equal or they
            // have no commonality.
            if (typeA.Equals(typeB))
            {
                return(typeA);
            }

            return(null);
        }
Пример #14
0
        public static TypeDef_Function GetTypeDef_Function(ITypeDef retType, List <ITypeDef> argTypes, int minArgs, bool _varargs, TypeDef_Class classType, bool isConst, bool isStatic)
        {
            if (minArgs < 0)
            {
                minArgs = argTypes.Count;
            }

            string args = "";

            for (int ii = 0; ii < argTypes.Count; ++ii)
            {
                string defaultValueString = "";
                if (ii >= minArgs)
                {
                    defaultValueString = " ?";
                }
                args += (ii == 0 ? "" : ", ") + argTypes[ii] + defaultValueString;
            }

            string classPart = "";

            if (null != classType)
            {
                classPart = ":" + classType.className;
            }

            string name = "function" + classPart + "<" + retType + "(" + args + ")>";

            if (_varargs)
            {
                name = name + " varargs";
            }
            if (isStatic)
            {
                name = name + " static";
            }
            if (isConst)
            {
                name = name + " const";
            }

            if (_typeRegistry.ContainsKey(name))
            {
                return(_typeRegistry[name] as TypeDef_Function);
            }

            TypeDef_Function newDef = new TypeDef_Function(retType, argTypes, minArgs, _varargs, classType, isConst, isStatic);

#if PEBBLE_TRACETYPES
            Console.WriteLine("Registering new function type: " + name);
#endif
            _typeRegistry.Add(name, newDef);
            return(newDef);
        }
Пример #15
0
        public static void Register(Engine engine)
        {
            //@ class Math
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("Math", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("Math", ourType, null, null, true);

            classDef.Initialize();

            //@ static const num pi;
            //   pi is the ratio of a circle's circumpherence to its diameter. 3.1415...
            classDef.AddMemberLiteral("pi", IntrinsicTypeDefs.CONST_NUMBER, Math.PI, true);
            //@ static const num e;
            //   e is the base of the natural logarithm. 2.71828...
            classDef.AddMemberLiteral("e", IntrinsicTypeDefs.CONST_NUMBER, Math.E, true);
            //@ static const num tau;
            //   tau is the ratio of a circle's circumpherence to its radius. tau = 2 * pi
            classDef.AddMemberLiteral("tau", IntrinsicTypeDefs.CONST_NUMBER, Math.PI * 2, true);

            // Note on error handling:
            // The native math functions don't throw exceptions when inputs are invalid. Rather, the functions return one of C#'s "invalid" number values.
            // These values are illegal in Pebble, and there is code in Expr_Call to detect if a function has returned one of those values and which
            // generates a script runtime error if it does. Thus, there a lot of the MathLib functions don't do any argument or return value checking
            // themselves, but rather rely on Expr_Call to detect if a user fed a bad input into a function (ie. Sqrt(-1)).

            //@ static num Abs(num radians)
            //   Returns the absolute value of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Abs(a));
                };

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

            //@ static num Acos(num)
            //   Returns the arccosine of the input in radians.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Acos(a));
                };

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

            //@ static num Asin(num)
            //   Returns the arcsine of the input in radians
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Asin(a));
                };

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

            //@ static num Atan(num)
            //   Returns the arctangent of the input in radians.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Atan(a));
                };

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

            //@ static num Ceiling(num)
            //   If an exact integer, returns the integer, otherwise returns the next highest integer. aka, it rounds up.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Ceiling(a));
                };

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

            //@ static num Cos(num radians)
            //   Returns the cosine of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Cos(a));
                };

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

            //@ static num Exp(num power)
            //   Returns e raised to the given power.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Exp(a));
                };

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

            //@ static num Floor(num)
            //   If an exact integer, returns the integer, otherwise returns the next lower integer. aka, it rounds down.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Floor(a));
                };

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

            //@ static num Log(num)
            //   Returns the natural logarithm of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    double b = (double)args[1];
                    return(Math.Log(a, b));
                };

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

            //@ static num Min(num, num)
            //   Returns the lesser of the two inputs.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    double b = (double)args[1];
                    return(Math.Min(a, b));
                };

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

            //@ static num Max(num)
            //   Returns the greater of the two inputs.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    double b = (double)args[1];
                    return(Math.Max(a, b));
                };

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

            //@ static num Pow(num b, num p)
            //   Returns b raised to the power p.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    double b = (double)args[1];
                    return(Math.Pow(a, b));
                };

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

            //@ static num Rand()
            //   Returns a random number between 0 and 1.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    if (null == rand)
                    {
                        rand = new Random();
                    }
                    return(rand.NextDouble());
                };

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

            //@ static void RandSeed(num seed)
            //   Seeds the random number generator with the given value (converted to a signed 32-bit integer).
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double dseed = (double)args[0];
                    if (dseed > Int32.MaxValue || dseed < Int32.MinValue)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Math::RandSeed seed argument must be within the range of a C# Int32.");
                        return(null);
                    }
                    int seed = Convert.ToInt32(dseed);
                    rand = new Random(seed);
                    return(null);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList {
                    IntrinsicTypeDefs.NUMBER
                }, eval, false);
                classDef.AddMemberLiteral("RandSeed", newValue.valType, newValue, true);
            }

            //@ static num Round(num n[, num decimals])
            //   Rounds the input to the nearest integer, or optionally to the nearest specified decimal point.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a        = (double)args[0];
                    double b        = (double)args[1];
                    int    decimals = Convert.ToInt32(b);
                    if (decimals < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "2nd argument to Math.Round cannot be negative.");
                        return(null);
                    }
                    return(Math.Round(a, decimals));
                };

                // Note: Here is an example of how you provide default argument values for a host function.
                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(null);
                defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER));

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER
                }, eval, false, null, false, defaultArgVals);
                classDef.AddMemberLiteral("Round", newValue.valType, newValue, true);
            }

            //@ static num Sin(num radians)
            //   Returns the sine of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Sin(a));
                };

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

            //@ static num Sqrt(num)
            //   Returns the square root of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Sqrt(a));
                };

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

            //@ static num Tan(num radians)
            //   Returns the tangent of the input.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double a = (double)args[0];
                    return(Math.Tan(a));
                };

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

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("MathLib", RunTests);
        }
Пример #16
0
        public static void Register(Engine engine)
        {
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("Debug", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("Debug", ourType, null, null, true);

            classDef.Initialize();

            // string DumpClass(string className = "")
            //   Returns a string dump of the fields of a class with the given name.
            //   If no argument is given (or string is empty), instead returns a list of all classes.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string className = (string)args[0];

                    if ("" == className)
                    {
                        return(context.GetDebugTypeString(true, false, false));
                    }
                    else
                    {
                        ClassDef def = context.GetClass(className);
                        if (null == def)
                        {
                            return("Class '" + className + "' not found.");
                        }

                        return(def.GetDebugString());
                    }
                };

                // Note: Here is an example of how you provide default argument values for a host function.
                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(new Expr_Literal(null, "", IntrinsicTypeDefs.STRING));

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false, null, false, defaultArgVals);
                classDef.AddMemberLiteral("DumpClass", newValue.valType, newValue, true);
            }

            // string DumpStack()
            //   Returns a string printout of the stack at the point the function is called.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    return(context.ToString());
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("DumpStack", newValue.valType, newValue, true);
            }

            // string DumpTypes()
            //   Returns a string printout of the registered types.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    return(context.GetDebugTypeString());
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("DumpTypes", newValue.valType, newValue, true);
            }

            // string GetTotalMemory()
            //   Wraps GC.GetTotalMemory, which returns the number of bytes estimated to be allocated by C#.
            //   Note that this is NOT just memory allocated by Pebble.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    bool forceFullCorrection = (bool)args[0];

                    return(Convert.ToDouble(GC.GetTotalMemory(forceFullCorrection)));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.BOOL
                }, eval, false);
                classDef.AddMemberLiteral("GetTotalMemory", newValue.valType, newValue, true);
            }

            // functype<bool(bool, string)> SetAssertCallback(functype<bool(bool, string)>)
            //   Sets callback for assert results, returns previous callback.
            //   Callback gets success as first variable, message as second. If returns false, system throws an Assert runtime exception.
            {
                TypeRef_Function handlerTypeRef = new TypeRef_Function(new TypeRef("bool"), new List <ITypeRef>()
                {
                    new TypeRef("bool"), new TypeRef("string")
                });
                bool             error          = false;
                TypeDef_Function handlerTypeDef = (TypeDef_Function)handlerTypeRef.Resolve(engine.defaultContext, ref error);
                Pb.Assert(!error, "Internal error: SetAssertHandler initialization.");

                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    FunctionValue newHandler = (FunctionValue)args[0];
                    FunctionValue oldHandler = Expr_Assert.handler;
                    Expr_Assert.handler = newHandler;
                    return(oldHandler);
                };
                FunctionValue newValue = new FunctionValue_Host(handlerTypeDef, new ArgList {
                    handlerTypeDef
                }, eval, false);
                classDef.AddMemberLiteral("SetAssertCallback", newValue.valType, newValue, true);
            }

            //@ bool SetLogCompileErrors(bool log)
            //   Sets whether or not compile errors should be logged to the Engine's log function.
            //   Returns the previous value.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    bool oldValue = context.engine.logCompileErrors;
                    bool newVal   = (bool)args[0];
                    context.engine.logCompileErrors = newVal;
                    return(oldValue);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.BOOL
                }, eval, false);
                classDef.AddMemberLiteral("SetLogCompileErrors", newValue.valType, newValue, true);
            }

            // void TimerStart()
            //   Starts a debug timer. If one is already running it will be set to this new start time.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    timer = Stopwatch.StartNew();
                    return(null);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("TimerStart", newValue.valType, newValue, true);
            }

            // num TimerGet()
            //   Returns elapsed ms since TimerStart called, or -1 if TimerStart wasn't previously called.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    if (null == timer)
                    {
                        return(-1.0);
                    }
                    return(Convert.ToDouble(timer.ElapsedMilliseconds));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("TimerGet", newValue.valType, newValue, true);
            }

            classDef.FinalizeClass(engine.defaultContext);
        }
Пример #17
0
        public static void Register(Engine engine)
        {
            //@ class DateTime
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("DateTime", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("DateTime", ourType, null, null, true);

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

            classDef.Initialize();

            //@ DateTime Clone()
            //   Returns a copy of 'this' DateTime.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime thisDT = thisScope as PebDateTime;
                    PebDateTime pdt    = classDef.Allocate(context) as PebDateTime;
                    pdt.dt = new DateTime(thisDT.dt.Ticks);
                    return(pdt);
                };

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

            //@ static DateTime Create(num year, num month, num day, num hour, num minute, num second, num millisecond)
            //   Creates a new DateTime with the given values.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double year        = (double)args[0];
                    double month       = (double)args[1];
                    double day         = (double)args[2];
                    double hour        = (double)args[3];
                    double minute      = (double)args[4];
                    double second      = (double)args[5];
                    double millisecond = (double)args[6];

                    PebDateTime pdt = classDef.Allocate(context) as PebDateTime;
                    try {
                        pdt.dt = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day), Convert.ToInt32(hour), Convert.ToInt32(minute), Convert.ToInt32(second), Convert.ToInt32(millisecond));
                    } catch (ArgumentOutOfRangeException aoor) {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, aoor.ToString());
                        return(null);
                    } catch (Exception e) {
                        context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString());
                        return(null);
                    }
                    return(pdt);
                };

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

            //@ bool Equals(DateTime other)
            //   Returns true iff both this and the other DateTime have the same date and time exactly.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt      = thisScope as PebDateTime;
                    PebDateTime otherPdt = args[0] as PebDateTime;

                    if (null == otherPdt)
                    {
                        context.SetRuntimeError(RuntimeErrorType.NullAccessViolation, "DateTime::Equals - Argument is null.");
                        return(null);
                    }

                    return(pdt.dt.Year == otherPdt.dt.Year &&
                           pdt.dt.Month == otherPdt.dt.Month &&
                           pdt.dt.Day == otherPdt.dt.Day &&
                           pdt.dt.Hour == otherPdt.dt.Hour &&
                           pdt.dt.Minute == otherPdt.dt.Minute &&
                           pdt.dt.Second == otherPdt.dt.Second &&
                           pdt.dt.Millisecond == otherPdt.dt.Millisecond);
                };

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

            //@ static DateTime GetNow()
            //   Returns a new DateTime with the current date and time.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = classDef.Allocate(context) as PebDateTime;
                    pdt.dt = DateTime.Now;
                    return(pdt);
                };

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

            //@ bool IsDateSame(DateTime other)
            //   Returns true iff both this and the other DateTime have the same date. Time is ignored.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt      = thisScope as PebDateTime;
                    PebDateTime otherPdt = args[0] as PebDateTime;

                    if (null == otherPdt)
                    {
                        context.SetRuntimeError(RuntimeErrorType.NullAccessViolation, "DateTime::IsDateSame - Argument is null.");
                        return(null);
                    }

                    return
                        (pdt.dt.Year == otherPdt.dt.Year &&
                         pdt.dt.Month == otherPdt.dt.Month &&
                         pdt.dt.Day == otherPdt.dt.Day);
                };

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

            //@ DateTime Set(num year, num month, num day, num hour, num minute, num second, num millisecond)
            //   Gives this DateTime the given values
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    double year        = (double)args[0];
                    double month       = (double)args[1];
                    double day         = (double)args[2];
                    double hour        = (double)args[3];
                    double minute      = (double)args[4];
                    double second      = (double)args[5];
                    double millisecond = (double)args[6];

                    PebDateTime pdt = thisScope as PebDateTime;
                    DateTime    newdt;
                    try {
                        newdt = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day), Convert.ToInt32(hour), Convert.ToInt32(minute), Convert.ToInt32(second), Convert.ToInt32(millisecond));
                    } catch (ArgumentOutOfRangeException aoor) {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, aoor.ToString());
                        return(null);
                    } catch (Exception e) {
                        context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString());
                        return(null);
                    }
                    pdt.dt = newdt;
                    return(pdt);
                };

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

            //@ 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) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    string      result = (string)args[0] + "\tSet(" + pdt.dt.Year + ", " + pdt.dt.Month + ", " + pdt.dt.Day + ", " + pdt.dt.Hour + ", " + pdt.dt.Minute + ", " + pdt.dt.Second + ", " + pdt.dt.Millisecond + ");\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 this DateTime.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(pdt.dt.ToString());
                };

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

            //@ num GetYear()
            //   Returns the DateTime's year.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Year));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                }, eval, false, ourType);
                classDef.AddMemberLiteral("GetYear", newValue.valType, newValue, false);
            }
            //@ num GetMonth()
            //   Returns the DateTime's month.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Month));
                };

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

            //@ num GetDay()
            //   Returns the DateTime's day.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Day));
                };

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

            //@ num GetHour()
            //   Returns the DateTime's hour.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Hour));
                };

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

            //@ num GetMinute()
            //   Returns the DateTime's minute.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Minute));
                };

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

            //@ num GetSecond()
            //   Returns the DateTime's second.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Second));
                };

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

            //@ num GetMillisecond()
            //   Returns the DateTime's millisecond.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(Convert.ToDouble(pdt.dt.Millisecond));
                };

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

            //@ DateTime AddYears(num years)
            //   Returns a new DateTime that is 'years' (rounded to nearest integer) years ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddYears(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddMonths(num months)
            //   Returns a new DateTime that is 'months' (rounded to nearest integer) months ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddMonths(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddDays(num days)
            //   Returns a new DateTime that is 'days' (rounded to nearest integer) days ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddDays(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddHours(num hours)
            //   Returns a new DateTime that is 'hours' (rounded to nearest integer) hours ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddHours(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddMinutes(num minutes)
            //   Returns a new DateTime that is 'minutes' (rounded to nearest integer) minutes ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddMinutes(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddSeconds(num seconds)
            //   Returns a new DateTime that is 'seconds' (rounded to nearest integer) seconds ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddSeconds(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            //@ DateTime AddMilliseconds(num ms)
            //   Returns a new DateTime that is 'ms' (rounded to nearest integer) milliseconds ahead of this DateTime. Can be negative.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    double      d      = (double)args[0];
                    PebDateTime newpdt = classDef.Allocate(context) as PebDateTime;
                    newpdt.dt = pdt.dt.AddMilliseconds(Convert.ToInt32(d));
                    return(newpdt);
                };

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

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("DateTimeLib", RunTests);
        }
Пример #18
0
        // Note: The main reason there is no OpenReadText is there is no easy way to query for EOF.
        // It might be nice to not have to read large text files all at once, ie. via File::ReadLines,
        // but OTOH if you are reading files that are THAT big Pebble may not be best tool for
        // the job. If there is enough demand for it can add it later.

        public static void Register(Engine engine)
        {
            //@ class Stream
            //   Note that it is intentional that there is no OpenReadText method. It's easier to use
            //   the File library for reading text.
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("Stream", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("Stream", ourType, null, null, false);

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

            //@ bool Close()
            //   Closes the stream.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.Close());
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("Close", newValue.valType, newValue, false);
            }

            //@ bool IsReading()
            //   Return true iff the stream is open in read mode.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.IsReading());
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("IsReading", newValue.valType, newValue, false);
            }

            //@ bool IsWriting()
            //   Returns true iff the stream is open in write mode.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.IsWriting());
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("IsWriting", newValue.valType, newValue, false);
            }

            //@ bool IsOpen()
            //   Returs true iff the stream is open in either read or write mode.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.IsOpen());
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("IsOpen", newValue.valType, newValue, false);
            }

            //@ bool OpenReadBinary(string filepath)
            //   Opens the specified file for reading in binary mode.
            //   Returns false if there is an error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = args[0] as string;

                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.OpenFileRead(context, path));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, true);
                classDef.AddMemberLiteral("OpenReadBinary", newValue.valType, newValue, false);
            }

            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = args[0] as string;

                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.OpenFileWrite(context, path, false));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, true);
                classDef.AddMemberLiteral("OpenWriteBinary", newValue.valType, newValue, false);
            }

            //@ bool OpenWriteText(string filepath)
            //   Opens the specified file for writing in text mode.
            //   Returns false if there is an error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = args[0] as string;

                    PebbleStreamHelper helper = thisScope as PebbleStreamHelper;
                    return(helper.OpenFileWrite(context, path, true));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, true);
                classDef.AddMemberLiteral("OpenWriteText", newValue.valType, newValue, false);
            }

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("StreamLib", RunTests);
        }
Пример #19
0
        public static void Register(Engine engine)
        {
            //@ class String

            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("String", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("String", ourType, null, null, true);

            classDef.Initialize();

            // This makes sure List<num> is registered in the type library, as this class uses it and we can't rely
            // scripts to register it.
            engine.defaultContext.RegisterIfUnregisteredList(IntrinsicTypeDefs.NUMBER);

            //@ static num CompareTo(string, string)
            //   Wraps C# CompareTo function, which essentially returns a number < 0 if a comes before b
            //   alphabetically, > 0 if a comes after b, and 0 if they are identical.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    string b = (string)args[1];
                    return(Convert.ToDouble(a.CompareTo(b)));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("CompareTo", newValue.valType, newValue, true);
            }

            //@ static string Concat(any[, ...])
            //   Converts all arguments to strings and concatenates them. Same as ToString.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    return(CoreLib.StandardPrintFunction(context, args));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, true);
                classDef.AddMemberLiteral("Concat", newValue.valType, newValue, true);
            }

            //@ static bool EndsWith(string s, string search)
            //   Wrapper for C# EndsWith. Returns true if s ends with search.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    string b = (string)args[1];
                    return(a.EndsWith(b));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("EndsWith", newValue.valType, newValue, true);
            }

            //@ static bool Equals(string, string)
            //   Returns true iff the strings are exactly equal. The same thing as using the == operator.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    string b = (string)args[1];
                    return(a.Equals(b));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Equals", newValue.valType, newValue, true);
            }

            //@ static bool EqualsI(string, string)
            //   Returns true if the strings are equal, ignoring case. Equivalent to the ~= operator.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    string b = (string)args[1];
                    return(a.ToLower().Equals(b.ToLower()));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("EqualsI", newValue.valType, newValue, true);
            }

            //@ static string Format(string[, any, ...])
            //   Generated formatted strings. Wrapper for C# String.Format(string, object[]). See documentation of that function for details.
            //   Putting weird things like Lists or functions into the args will produce undefined results.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string   source = (string)args[0];
                    Object[] a      = new Object[args.Count - 1];
                    args.CopyTo(1, a, 0, args.Count - 1);
                    string result = "";
                    try {
                        result = String.Format(source, a);
                    } catch (Exception e) {
                        context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString());
                        return(null);
                    }
                    return(result);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.ANY
                }, eval, true);
                classDef.AddMemberLiteral("Format", newValue.valType, newValue, true);
            }

            //@ static List<string> GetCharList(string)
            //   Returns a list of strings containing one character of the input string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string source = (string)args[0];

                    PebbleList list = PebbleList.AllocateListString(context, "String::GetCharList result");
                    foreach (char c in source.ToCharArray())
                    {
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, Convert.ToString(c)));
                    }

                    return(list);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("GetCharList", newValue.valType, newValue, true);
            }

            //@ static List<num> GetUnicode(string)
            //   Returns the Unicode numeric values for the characters in the input string.
            //   Returns an empty list if the string is empty.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string source = (string)args[0];

                    PebbleList list = PebbleList.AllocateListString(context, "String::GetUnicode result");
                    foreach (char c in source.ToCharArray())
                    {
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.NUMBER, Convert.ToDouble(Convert.ToInt32(c))));
                    }

                    return(list);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("GetUnicode", newValue.valType, newValue, true);
            }

            //@ static num IndexOfChar(string toBeSearched, string searchChars, num startIndex = 0)
            //   Returns the index of the first instance of any of the characters in search.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a          = (string)args[0];
                    string b          = (string)args[1];
                    int    startIndex = Convert.ToInt32((double)args[2]);

                    if (0 == a.Length || 0 == b.Length)
                    {
                        return(-1.0);
                    }

                    int lowestIx = Int32.MaxValue;
                    foreach (char c in b)
                    {
                        int ix = a.IndexOf(c, startIndex);
                        if (ix >= 0 && ix < lowestIx)
                        {
                            lowestIx = ix;
                        }
                    }

                    if (lowestIx < Int32.MaxValue)
                    {
                        return(Convert.ToDouble(lowestIx));
                    }

                    return(-1.0);
                };

                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(null);
                defaultArgVals.Add(null);
                defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER));
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false, null, true, defaultArgVals);
                classDef.AddMemberLiteral("IndexOfChar", newValue.valType, newValue, true);
            }

            //@ static num IndexOfString(string toBeSearched, string searchString, num startIndex = 0)
            //   Returns the index of the first instance of the entire search string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a          = (string)args[0];
                    string b          = (string)args[1];
                    int    startIndex = Convert.ToInt32((double)args[2]);

                    if (0 == a.Length || 0 == b.Length)
                    {
                        return(-1.0);
                    }

                    int ix = a.IndexOf(b, startIndex);
                    return(Convert.ToDouble(ix));
                };

                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(null);
                defaultArgVals.Add(null);
                defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER));
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false, null, true, defaultArgVals);
                classDef.AddMemberLiteral("IndexOfString", newValue.valType, newValue, true);
            }

            //@ static num LastIndexOfChar(string toBeSearched, string searchChars, num startIndex = -1)
            //   Returns the index of the last instance of the entire search string,
            //   If startIndex is >= 0, starts searching backwards from the given index.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a          = (string)args[0];
                    string b          = (string)args[1];
                    int    startIndex = Convert.ToInt32((double)args[2]);

                    if (0 == a.Length || 0 == b.Length)
                    {
                        return(-1.0);
                    }

                    if (startIndex < 0)
                    {
                        startIndex = a.Length - 1;
                    }
                    else if (startIndex >= a.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "LastIndexOfChar startIndex argument is greater than the length of the string.");
                        return(null);
                    }

                    char[] chars    = b.ToCharArray();
                    int    lowestIx = Int32.MaxValue;
                    foreach (char c in b)
                    {
                        int ix = a.LastIndexOfAny(chars, startIndex);
                        if (ix >= 0 && ix < lowestIx)
                        {
                            lowestIx = ix;
                        }
                    }

                    if (lowestIx < Int32.MaxValue)
                    {
                        return(Convert.ToDouble(lowestIx));
                    }
                    return(-1.0);
                };

                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(null);
                defaultArgVals.Add(null);
                defaultArgVals.Add(new Expr_Literal(null, -1.0, IntrinsicTypeDefs.NUMBER));
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false, null, true, defaultArgVals);
                classDef.AddMemberLiteral("LastIndexOfChar", newValue.valType, newValue, true);
            }

            //@ static num LastIndexOfString(string toBeSearched, string searchString, num startIndex = -1)
            //   Returns the index of the last instance of the entire search string,
            //   If startIndex is > 0, starts searching backwards from the given index.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a          = (string)args[0];
                    string b          = (string)args[1];
                    int    startIndex = Convert.ToInt32((double)args[2]);

                    if (0 == a.Length || 0 == b.Length)
                    {
                        return(-1.0);
                    }

                    if (startIndex < 0)
                    {
                        startIndex = a.Length - 1;
                    }
                    else if (startIndex >= a.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "LastIndexOfString startIndex argument is greater than the length of the string.");
                        return(null);
                    }

                    int ix = a.LastIndexOf(b, startIndex);
                    return(Convert.ToDouble(ix));
                };

                List <Expr_Literal> defaultArgVals = new List <Expr_Literal>();
                defaultArgVals.Add(null);
                defaultArgVals.Add(null);
                defaultArgVals.Add(new Expr_Literal(null, -1.0, IntrinsicTypeDefs.NUMBER));
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false, null, true, defaultArgVals);
                classDef.AddMemberLiteral("LastIndexOfString", newValue.valType, newValue, true);
            }

            //@ static num Length(string)
            //   Returns the length of the string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    return(Convert.ToDouble(a.Length));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Length", newValue.valType, newValue, true);
            }

            //@ static string PadLeft(string, num n, string pad)
            //   Returns s with n instances of string pad to the left.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];

                    double nd = (double)args[1];
                    int    n  = Convert.ToInt32(nd);

                    string p = (string)args[2];
                    if (0 == p.Length)
                    {
                        p = " ";
                    }

                    char c = p[0];
                    return(a.PadLeft(n, c));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("PadLeft", newValue.valType, newValue, true);
            }

            //@ static string PadRight(string s, num n, string pad)
            //   Returns s with n instances of string pad to the left.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];

                    double nd = (double)args[1];
                    int    n  = Convert.ToInt32(nd);

                    string p = (string)args[2];
                    if (0 == p.Length)
                    {
                        p = " ";
                    }

                    char c = p[0];
                    return(a.PadRight(n, c));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("PadRight", newValue.valType, newValue, true);
            }

            //@ static string Replace(string str, string find, string replace)
            //   Replaces all instances of the given string with the replacement string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a       = (string)args[0];
                    string find    = (string)args[1];
                    string replace = (string)args[2];

                    if (0 == find.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Find argument to Replace() cannot be the empty string.");
                        return(null);
                    }

                    return(a.Replace(find, replace));
                };

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

            //@ static List<string> Split(string str, List<string> separators = null)
            //   Splits input string into a list of strings given the provided separators.
            //   If no separators are provided, uses the newline character.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];

                    string[] splitted;
                    if (null == args[1])
                    {
                        splitted = a.Split(_defaultSeparators, StringSplitOptions.None);
                    }
                    else
                    {
                        PebbleList delimsList = args[1] as PebbleList;
                        if (0 == delimsList.list.Count)
                        {
                            context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "String::Split : Separators list cannot be empty.");
                            return(null);
                        }

                        List <string> dlist = delimsList.GetNativeList();

                        // Usually I like to wrap native functions with a try-catch but I couldn't find a
                        // way to make this throw an exception.
                        splitted = a.Split(dlist.ToArray(), StringSplitOptions.None);
                    }

                    PebbleList list = PebbleList.AllocateListString(context, "String::Split result");
                    foreach (string s in splitted)
                    {
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, s));
                    }
                    return(list);
                };

                List <Expr_Literal> defaults = new List <Expr_Literal>();
                defaults.Add(null);
                defaults.Add(new Expr_Literal(null, null, IntrinsicTypeDefs.NULL));
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.LIST_STRING
                }, eval, false, null, true, defaults);
                classDef.AddMemberLiteral("Split", newValue.valType, newValue, true);
            }

            //@ static bool StartsWith(string s, string start)
            //   Returns true if s starts with start.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    string b = (string)args[1];
                    return(a.StartsWith(b));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("StartsWith", newValue.valType, newValue, true);
            }

            //@ static string Substring(string, startIx, length)
            //   Returns a substring of the input, starting at startIx, that is length characters long.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a     = (string)args[0];
                    double b     = (double)args[1];
                    double c     = (double)args[2];
                    int    start = Convert.ToInt32(b);
                    int    len   = Convert.ToInt32(c);
                    if (start < 0 || len < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative.");
                        return(null);
                    }
                    if (start + len > a.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string.");
                        return(null);
                    }

                    return(a.Substring(start, len));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER
                }, eval, false);
                classDef.AddMemberLiteral("Substring", newValue.valType, newValue, true);
            }

            //@ static string SubstringLeft(string str, num length)
            //   Returns the left 'length' characters of str.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a   = (string)args[0];
                    double b   = (double)args[1];
                    int    len = Convert.ToInt32(b);
                    if (len < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative.");
                        return(null);
                    }
                    if (len > a.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string.");
                        return(null);
                    }

                    return(a.Substring(0, len));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false);
                classDef.AddMemberLiteral("SubstringLeft", newValue.valType, newValue, true);
            }

            //@ static string SubstringRight(string, start)
            //   Returns the right part of the string starting at 'start'.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a     = (string)args[0];
                    double b     = (double)args[1];
                    int    start = Convert.ToInt32(b);
                    if (start < 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative.");
                        return(null);
                    }
                    if (start >= a.Length)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string.");
                        return(null);
                    }

                    return(a.Substring(a.Length - start));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER
                }, eval, false);
                classDef.AddMemberLiteral("SubstringRight", newValue.valType, newValue, true);
            }

            //@ static string ToLower(string)
            //   Converts the string to lowercase.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    return(a.ToLower());
                };

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

            //@ static string ToUpper(string)
            //   Converts the string to uppercase.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    return(a.ToUpper());
                };

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

            //@ static string Trim(string)
            //   Removes leading and trailing whitespace characters.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string a = (string)args[0];
                    return(a.Trim());
                };

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

            //@ static string UnicodeToString(List<num>)
            //   Takes a list of numeric Unicode character codes, converts them to characters, concatenates them, and returns the resultant string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebbleList list   = args[0] as PebbleList;
                    string     result = "";
                    try {
                        foreach (Variable v in list.list)
                        {
                            double d = (double)v.value;
                            result += Convert.ToChar(Convert.ToInt32(d));
                        }
                    } catch (Exception e) {
                        context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString());
                        return(null);
                    }

                    return(result);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.LIST_NUMBER
                }, eval, false);
                classDef.AddMemberLiteral("UnicodeToString", newValue.valType, newValue, true);
            }

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("StringLib", RunTests);
        }
Пример #20
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);
        }
Пример #21
0
        public static void Register(Engine engine)
        {
            // *** Register required types.

            List <ITypeDef> genericTypes = new ArgList();

            genericTypes.Add(IntrinsicTypeDefs.STRING);

            // This code makes sure that Result<string> is a registered class and type.
            TypeDef_Class resultTypeDef  = TypeFactory.GetTypeDef_Class("Result", genericTypes, false);
            ClassDef      resultClassDef = engine.defaultContext.RegisterIfUnregisteredTemplate(resultTypeDef);

            // This does List<string>.
            ClassDef listStringClassDef = engine.defaultContext.RegisterIfUnregisteredList(IntrinsicTypeDefs.STRING);

            // ***

            //@ class File
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("File", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("File", ourType, null, null, true);

            classDef.Initialize();

            //@ const string lastError;
            //   Stores the message of the last error generated by this library.
            classDef.AddMemberLiteral("lastError", IntrinsicTypeDefs.CONST_STRING, "", true);

            Variable lastErrorVar = null;

            //@ static string ClearLastError()
            //   Clears File::lastError, returning its previous value.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string lastError = (string)lastErrorVar.value;
                    lastErrorVar.value = "";
                    return(lastError);
                };

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

            //@ static bool Copy(string source, string dest)
            //   Copies a file from source to dest.
            //   Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string source = (string)args[0];
                    string dest   = (string)args[1];

                    lastErrorVar.value = "";

                    try {
                        File.Copy(source, dest);
                    } catch (Exception e) {
                        lastErrorVar.value = "Copy: " + e.ToString();
                        return(false);
                    }
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Copy", newValue.valType, newValue, true);
            }

            //@ static bool CreateDir(string path)
            //   Creates directory.
            //   Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    lastErrorVar.value = "";

                    // Doesn't throw exceptions.
                    if (Directory.Exists(path))
                    {
                        lastErrorVar.value = "CreateDir: Directory already exists.";
                        return(false);
                    }

                    try {
                        Directory.CreateDirectory(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "CreateDir: " + e.ToString();
                        return(false);
                    }
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("CreateDir", newValue.valType, newValue, true);
            }

            //@ static bool Delete(string path)
            //   Returns true if file deleted.
            //   Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    // Doesn't throw exceptions.
                    if (!File.Exists(path))
                    {
                        lastErrorVar.value = "Delete: File not found.";
                        return(false);
                    }

                    try {
                        File.Delete(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "Delete: " + e.ToString();
                        return(false);
                    }

                    lastErrorVar.value = "";
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Delete", newValue.valType, newValue, true);
            }

            //@ static bool DeleteDir(string path)
            //   Returns true if file deleted.
            //   Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    // Doesn't throw exceptions.
                    if (!Directory.Exists(path))
                    {
                        lastErrorVar.value = "DeleteDir: Directory not found.";
                        return(false);
                    }

                    try {
                        Directory.Delete(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "DeleteDir: " + e.ToString();
                        return(false);
                    }

                    lastErrorVar.value = "";
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("DeleteDir", newValue.valType, newValue, true);
            }

            //@ static string GetCurrentDirectory()
            //   Returns the full path of the current directory.
            //   Returns "" and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string result;
                    try {
                        result = Directory.GetCurrentDirectory();
                    } catch (Exception e) {
                        lastErrorVar.value = "GetCurrentDirectory: " + e.ToString();
                        return("");
                    }

                    lastErrorVar.value = "";
                    return(result);
                };

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

            //@ static List<string> GetDirs(string path)
            //   Returns list of subdirectories of path.
            //   Returns null and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    // Doesn't throw exceptions.
                    if (!Directory.Exists(path))
                    {
                        lastErrorVar.value = "GetDirs: Directory not found.";
                        return(null);
                    }

                    string[] files;
                    try {
                        files = Directory.GetDirectories(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "GetDirs: " + e.ToString();
                        return(null);
                    }

                    ClassValue inst = listStringClassDef.Allocate(context);
                    inst.debugName = "(GetDirs result)";

                    PebbleList list = (PebbleList)inst;
                    foreach (string file in files)
                    {
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, file));
                    }

                    lastErrorVar.value = "";
                    return(inst);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new List <ITypeDef> {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("GetDirs", newValue.valType, newValue, true);
            }

            //@ static List<string> GetFiles(string path)
            //   Returns list of all files in the given directory path.
            //   Filenames are NOT prefaced by path.
            //   Returns null and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    if (!Directory.Exists(path))
                    {
                        lastErrorVar.value = "GetFiles: Directory not found.";
                        return(null);
                    }

                    string[] files;
                    try {
                        files = Directory.GetFiles(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "GetFiles: " + e.ToString();
                        return(null);
                    }

                    ClassValue inst = listStringClassDef.Allocate(context);
                    inst.debugName = "(GetFiles result)";

                    PebbleList list    = (PebbleList)inst;
                    int        pathLen = path.Length + 1;
                    foreach (string file in files)
                    {
                        string justFile = file.Substring(pathLen);
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, justFile));
                    }

                    lastErrorVar.value = "";
                    return(inst);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new List <ITypeDef> {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("GetFiles", newValue.valType, newValue, true);
            }

            //@ static bool Exists(string path)
            //   Returns true if file exists, false if it doesn't.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    // Doesn't throw exceptions.
                    return(File.Exists(path));
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Exists", newValue.valType, newValue, true);
            }

            //@ static bool Move(string source, string dest)
            //   Move a file from source to dest.
            //   Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string source = (string)args[0];
                    string dest   = (string)args[1];

                    lastErrorVar.value = "";

                    try {
                        File.Move(source, dest);
                    } catch (Exception e) {
                        lastErrorVar.value = "Move: " + e.ToString();
                        return(false);
                    }
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Move", newValue.valType, newValue, true);
            }

            //@ static Result<string> Read(string path)
            //   Reads content of file as text. Returns an instance of Result<string>.
            //	 If succeeded, status = 0, value = file contents.
            //	 On error, status != 0, message = an error message.
            {
                // Note that this function cannot use lastError because strings cannot be null.
                // This is why ReadLines can just return a List<string>: the list can indicate error by being null.

                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    //ClassValue inst = resultClassDef.childAllocator();
                    ClassValue inst    = resultClassDef.Allocate(context);
                    Variable   status  = inst.GetByName("status");
                    Variable   value   = inst.GetByName("value");
                    Variable   message = inst.GetByName("message");

                    string result;
                    try {
                        result = File.ReadAllText(path);
                    } catch (Exception e) {
                        status.value  = -1.0;
                        message.value = "Read: " + e.ToString();
                        return(inst);
                    }

                    // The docs don't say this ever returns null, but just in case.
                    if (null == result)
                    {
                        status.value  = -1.0;
                        message.value = "Read: File.ReadAllText returned null.";
                    }

                    value.value = result;
                    return(inst);
                };

                FunctionValue newValue = new FunctionValue_Host(resultClassDef.typeDef, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Read", newValue.valType, newValue, true);
            }

            //@ static List<string> ReadLines(string path)
            //   Returns a list containing the lines of the given file.
            //	 On error, returns null and sets last error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    IEnumerable <string> result;
                    try {
                        // Note: ReadLines is a little more efficient on memory than ReadAllLines, but the .NET used by Unity 2017 doesn't support it.
                        // Shouldn't really matter. If you're processing huge files, probably Pebble isn't the way to go.
                        //result = File.ReadLines(path);
                        result = File.ReadAllLines(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "ReadLines: " + e.ToString();
                        return(null);
                    }

                    // The docs don't say this ever returns null, but just in case.
                    if (null == result)
                    {
                        lastErrorVar.value = "ReadLines: File.ReadLines returned null.";
                        return(null);
                    }

                    ClassDef   listClassDef = context.GetClass("List<string>");
                    ClassValue listinst     = listClassDef.childAllocator();
                    listinst.classDef  = listClassDef;
                    listinst.debugName = "(ReadLines result)";
                    PebbleList list = (PebbleList)listinst;

                    foreach (string line in result)
                    {
                        list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, line));
                    }

                    lastErrorVar.value = "";
                    return(listinst);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("ReadLines", newValue.valType, newValue, true);
            }

            //@ static bool SetCurrentDirectory(string newDir)
            //   Changes the current directory. Returns true on success.
            //	 Returns false and sets lastError on error.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path = (string)args[0];

                    try {
                        Directory.SetCurrentDirectory(path);
                    } catch (Exception e) {
                        lastErrorVar.value = "SetCurrentDirectory: " + e.ToString();
                        return(false);
                    }
                    lastErrorVar.value = "";
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("SetCurrentDirectory", newValue.valType, newValue, true);
            }

            //@ static bool Write(string path, string contents)
            //   Writes contents to file. If file exists it is overwritten.
            //	 Returns true on success.
            //	 On error returns false and sets lastError.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string path     = (string)args[0];
                    string contents = (string)args[1];

                    try {
                        File.WriteAllText(path, contents);
                    } catch (Exception e) {
                        lastErrorVar.value = "Write: " + e.ToString();
                        return(false);
                    }
                    lastErrorVar.value = "";
                    return(true);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                }, eval, false);
                classDef.AddMemberLiteral("Write", newValue.valType, newValue, true);
            }

            classDef.FinalizeClass(engine.defaultContext);
            lastErrorVar = classDef.staticVars[0];

            UnitTests.testFuncDelegates.Add("FileLib", RunTests);
        }
Пример #22
0
        public static void Register(Engine engine)
        {
            //@ class Dictionary<K, V>
            TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("Dictionary", new ArgList {
                IntrinsicTypeDefs.TEMPLATE_0, IntrinsicTypeDefs.TEMPLATE_1
            }, false);

            ClassDef classDef = engine.defaultContext.CreateClass("Dictionary", ourType, null, new List <string> {
                "K", "V"
            });

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

            //@ Dictionary<K, V> Add(K key, V value)
            //  Adds a new element to the dictionary.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object key   = args[0];
                    object value = args[1];

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

                    var dictionary     = scope.dictionary;
                    var dictionaryType = (TypeDef_Class)scope.classDef.typeDef;
                    var valueType      = dictionaryType.genericTypes[1];
                    if (dictionary.ContainsKey(key))
                    {
                        context.SetRuntimeError(RuntimeErrorType.KeyAlreadyExists, "Dictionary already contains key '" + key + "'.");
                        return(null);
                    }

                    dictionary.Add(key, new Variable(null, valueType, value));

                    return(thisScope);
                };

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

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

                    dictionary.Clear();
                    return(thisScope);
                };

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

            //@ bool ContainsKey(K)
            //  Returns true iff the dictionary contains an element with the given key.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object key = args[0];

                    PebbleDictionary pebDict = thisScope as PebbleDictionary;
                    var dictionary           = pebDict.dictionary;

                    return(dictionary.ContainsKey(key));
                };

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

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

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

            //@ V Get(K)
            //  Returns the value of the element with the given key.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object key = args[0];

                    PebbleDictionary pebDict = thisScope as PebbleDictionary;

                    // Bounds checking.
                    var dictionary = pebDict.dictionary;
                    if (!dictionary.ContainsKey(key))
                    {
                        context.SetRuntimeError(RuntimeErrorType.KeyNotFound, "Get: Key '" + key + "' not in dictionary.");
                        return(null);
                    }

                    return(dictionary[key].value);
                };

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

            //@ Dictionary<K, V> Remove(K key)
            //   Removes element with given key.
            //   Cannot be used in a foreach loop.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object key = args[0];

                    PebbleDictionary pebDict = thisScope as PebbleDictionary;
                    var dictionary           = pebDict.dictionary;
                    if (pebDict.enumeratingCount > 0)
                    {
                        context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Remove: Attempt to modify a dictionary that is being enumerated by a foreach loop.");
                        return(null);
                    }

                    if (!dictionary.ContainsKey(key))
                    {
                        context.SetRuntimeError(RuntimeErrorType.KeyNotFound, "Remove: Key '" + key + "' not in dictionary.");
                        return(null);
                    }

                    dictionary.Remove(key);
                    return(thisScope);
                };

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

            //@ Dictionary<K, V> Set(K key, V newValue)
            //   Replaces value of existing element with the given key.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object key   = args[0];
                    object value = args[1];

                    var dictionary = (thisScope as PebbleDictionary).dictionary;

                    // Bounds checking.
                    if (!dictionary.ContainsKey(key))
                    {
                        context.SetRuntimeError(RuntimeErrorType.KeyNotFound, "Get: Key '" + key + "' not in dictionary.");
                        return(null);
                    }

                    dictionary[key].value = value;

                    return(thisScope);
                };

                FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList {
                    IntrinsicTypeDefs.TEMPLATE_0, IntrinsicTypeDefs.TEMPLATE_1
                }, eval, false, ourType);
                classDef.AddMemberLiteral("Set", 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 dictionary = (thisScope as PebbleDictionary).dictionary;
                    //bool first = true;
                    foreach (KeyValuePair <object, Variable> kvp in dictionary)
                    {
                        result += prefix + "Add(" + CoreLib.ValueToScript(context, kvp.Key, prefix + "\t", false) + ", " + CoreLib.ValueToScript(context, kvp.Value.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 human readable version of at least the first few elements of the dictionary.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    var dictionary = (thisScope as PebbleDictionary).dictionary;

                    string result = "Dictionary(" + dictionary.Count + ")[";
                    int    count  = 0;
                    foreach (KeyValuePair <object, Variable> kvp in dictionary)
                    {
                        if (count != 0)
                        {
                            result += ", ";
                        }
                        result += "(" + CoreLib.ValueToString(context, kvp.Key, true) + ", " + CoreLib.ValueToString(context, kvp.Value.value, true) + ")";

                        if (++count >= 4)
                        {
                            break;
                        }
                    }
                    if (dictionary.Count > 4)
                    {
                        result += ", ...";
                    }
                    return(result + "]");
                };

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

            bool error = false;

            classDef.FinalizeClass(engine.defaultContext);
            Pb.Assert(!error);

            UnitTests.testFuncDelegates.Add("CoreDictionary", RunTests);
        }
Пример #23
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;
        }
Пример #24
0
 public static TypeDef_Function GetClassVersion(TypeDef_Function original, TypeDef_Class classType, bool isStatic)
 {
     return(GetTypeDef_Function(original.retType, original.argTypes, original.minArgs, original.varargs, classType, original.isConst, isStatic));
 }
Пример #25
0
        public static void Register(Engine engine)
        {
            //*****************************
            // Create ScriptError enum.

            scriptErrorEnum = new PebbleEnum(engine.defaultContext, "ScriptError", IntrinsicTypeDefs.CONST_STRING);

            // Add a value for "no error" since enums can't be null.
            scriptErrorEnum.AddValue_Literal(engine.defaultContext, "NoError", "NoError");

            // Add both Parse and Runtime errors to the list.
            foreach (string name in Enum.GetNames(typeof(ParseErrorType)))
            {
                scriptErrorEnum.AddValue_Literal(engine.defaultContext, name, name);
            }
            foreach (string name in Enum.GetNames(typeof(RuntimeErrorType)))
            {
                scriptErrorEnum.AddValue_Literal(engine.defaultContext, name, name);
            }

            // Finalize.
            scriptErrorEnum.EvaluateValues(engine.defaultContext);

            // Save the value for NoError for convenience.
            scriptErrorEnum_noErrorValue = scriptErrorEnum.GetValue("NoError");

            //*******************************
            //@ class Result<T>
            //   This was added just in case users might have a need for a templated class that encapsulates a value and a status code.
            {
                TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("Result", new ArgList {
                    IntrinsicTypeDefs.TEMPLATE_0
                }, false);
                ClassDef classDef = engine.defaultContext.CreateClass("Result", ourType, null, new List <string> {
                    "T"
                });
                classDef.Initialize();

                //@ T value;
                //   The resultant value IF there was no error.
                classDef.AddMember("value", IntrinsicTypeDefs.TEMPLATE_0);
                //@ num status;
                //   A numeric status code. By convention, 0 means no error and anything else means error.
                classDef.AddMemberLiteral("status", IntrinsicTypeDefs.NUMBER, 0.0);
                //@ string message;
                //   A place to store error messages if desired.
                classDef.AddMember("message", IntrinsicTypeDefs.STRING);

                //@ bool IsSuccess()
                //   Returns true iff status == 0.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        ClassValue scope = thisScope as ClassValue;
                        return((double)scope.GetByName("status").value == 0.0);
                    };

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

                //@ string ToString()
                //   Returns a string representation of the Result.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        ClassValue scope  = thisScope as ClassValue;
                        double     status = (double)scope.GetByName("status").value;

                        string result = scope.classDef.typeDef.ToString() + "[";
                        if (0.0 == status)
                        {
                            result += CoreLib.ValueToString(context, scope.GetByName("value").value, true);
                        }
                        else
                        {
                            result += status + ": \"" + (string)scope.GetByName("message").value + "\"";
                        }

                        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);
                resultClassDef = classDef;
            }

            //*******************************
            //@ class ScriptResult<T>
            //   For returning the result of something that can error, like an Exec call.
            {
                TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("ScriptResult", new ArgList {
                    IntrinsicTypeDefs.TEMPLATE_0
                }, false);
                ClassDef classDef = engine.defaultContext.CreateClass("ScriptResult", ourType, null, new List <string> {
                    "T"
                });
                classDef.Initialize();

                //@ T value;
                //   The return value if there was no error.
                classDef.AddMember("value", IntrinsicTypeDefs.TEMPLATE_0);
                //@ ScriptError error;
                //   ScriptError.NoError if no error.
                classDef.AddMemberLiteral("error", CoreLib.scriptErrorEnum._classDef.typeDef, CoreLib.scriptErrorEnum_noErrorValue);
                //@ string message;
                //   Optional error message.
                classDef.AddMember("message", IntrinsicTypeDefs.STRING);

                //@ bool IsSuccess()
                //   Returns true iff error == ScriptError.NoError.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        ClassValue scope = thisScope as ClassValue;
                        return(scope.GetByName("error").value == CoreLib.scriptErrorEnum_noErrorValue);
                    };

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

                //@ string ToString()
                //   Returns a string representation of the ScriptError.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        ClassValue scope = thisScope as ClassValue;
                        var        error = (ClassValue_Enum)scope.GetByName("error").value;

                        string result = scope.classDef.typeDef.ToString() + "[";
                        if (CoreLib.scriptErrorEnum_noErrorValue == error)
                        {
                            result += CoreLib.ValueToString(context, scope.GetByName("value").value, true);
                        }
                        else
                        {
                            result += error.GetName() + ": \"" + (string)scope.GetByName("message").value + "\"";
                        }

                        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);
                resultClassDef = classDef;
            }

            // This code makes sure that Result<bool> is a registered class and type.
            List <ITypeDef> genericTypes = new ArgList();

            genericTypes.Add(IntrinsicTypeDefs.BOOL);
            scriptResultBoolTypeDef  = TypeFactory.GetTypeDef_Class("ScriptResult", genericTypes, false);
            scriptResultBoolClassDef = engine.defaultContext.RegisterIfUnregisteredTemplate(scriptResultBoolTypeDef);
            Pb.Assert(null != scriptResultBoolTypeDef && null != scriptResultBoolClassDef, "Error initializing ScriptResult<bool>.");


            ////////////////////////////////////////////////////////////////////////////
            // Register non-optional libraries.

            //CoreResult.Register(engine);
            // List and Dictionary probably need to be first because other libraries sometimes use them.
            CoreList.Register(engine);
            CoreDictionary.Register(engine);
            MathLib.Register(engine);
            RegexLib.Register(engine);
            StringLib.Register(engine);
            StreamLib.Register(engine);

            //@ global const num FORMAX;
            //   The highest value a for iterator can be. Attempting to exceed it generates an error.
            engine.defaultContext.CreateGlobal("FORMAX", IntrinsicTypeDefs.CONST_NUMBER, Expr_For.MAX);

            ////////////////////////////////////////////////////////////////////////////
            // Library functions

            //@ global ScriptResult<bool> Exec(string script)
            //   Executes the supplied script.
            //   Since this is not running "interactive" (or inline), the only way the script can
            //   have an external effect is if it affects global things (variables, class definitions).
            //   The returned ScriptResult's value is only true(success) or false (error).
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string script = (string)args[0];

                    ClassValue scriptResultInst = scriptResultBoolClassDef.Allocate(context);
                    Variable   value            = scriptResultInst.GetByName("value");
                    Variable   error            = scriptResultInst.GetByName("error");
                    Variable   message          = scriptResultInst.GetByName("message");

                    ScriptResult result = context.engine.RunScript(script, false, null, true);
                    if (null != result.parseErrors)
                    {
                        value.value   = false;
                        error.value   = scriptErrorEnum.GetValue(result.parseErrors[0].type.ToString());;
                        message.value = result.parseErrors[0].ToString();
                    }
                    else if (null != result.runtimeError)
                    {
                        value.value   = false;
                        error.value   = result.value;
                        message.value = result.runtimeError.ToString();
                    }
                    else
                    {
                        value.value   = true;
                        error.value   = scriptErrorEnum_noErrorValue;
                        message.value = "";
                    }

                    return(scriptResultInst);
                };
                FunctionValue newValue = new FunctionValue_Host(scriptResultBoolTypeDef, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                engine.AddBuiltInFunction(newValue, "Exec");
            }

            //@ global ScriptResult<bool> ExecInline(string)
            //   This executes the given script in the current scope. This is different from Exec, because Exec exists in its own scope.
            //   The returned ScriptResult's value is only true(success) or false (error).
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string script = (string)args[0];

                    ClassValue scriptResultInst = scriptResultBoolClassDef.Allocate(context);
                    Variable   value            = scriptResultInst.GetByName("value");
                    Variable   error            = scriptResultInst.GetByName("error");
                    Variable   message          = scriptResultInst.GetByName("message");

                    ScriptResult result = context.engine.RunInteractiveScript(script, false);
                    if (null != result.parseErrors)
                    {
                        value.value   = false;
                        error.value   = scriptErrorEnum.GetValue(result.parseErrors[0].type.ToString());;
                        message.value = result.parseErrors[0].ToString();
                    }
                    else if (null != result.runtimeError)
                    {
                        value.value   = false;
                        error.value   = result.value;
                        message.value = result.runtimeError.ToString();
                    }
                    else
                    {
                        value.value   = true;
                        error.value   = scriptErrorEnum_noErrorValue;
                        message.value = "";
                    }
                    return(scriptResultInst);
                };
                FunctionValue newValue = new FunctionValue_Host(scriptResultBoolTypeDef, new ArgList {
                    IntrinsicTypeDefs.STRING
                }, eval, false);
                engine.AddBuiltInFunction(newValue, "ExecInline");
            }

            //@ global string Print(...)
            //   Converts all arguments to strings, concatenates them, then outputs the result using the Engine' Log function.
            //   This function can be set to whatever the host program likes: see Engine.Log
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    string result = StandardPrintFunction(context, args);
                    context.engine.Log(result);
                    return(result);
                };

                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new List <ITypeDef> {
                    IntrinsicTypeDefs.ANY
                }, eval, true);
                engine.AddBuiltInFunction(newValue, "Print");
            }

            //@ global string ToScript(any)
            //   Returns a script which, when run, returns a value equal to the value passed into ToScript.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object val0 = args[0];
                    return(ValueToScript(context, val0));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, false);
                engine.AddBuiltInFunction(newValue, "ToScript");
            }


            /////////////////////////////////////////////////////////////////
            // Type Conversion

            //@ global bool ToBool(any)
            //   Attempts to convert input into a boolean value.
            //   0 and null are false. != 0 and non-null references are true. Strings are handled by Convert.ToBoolean,
            //   which can throw an exception if it doesn't know how to convert the string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object val = args[0];
                    if (null == val)
                    {
                        return(false);
                    }
                    else if (val is bool)
                    {
                        return((bool)val);
                    }
                    else if (val is double)
                    {
                        return(Convert.ToBoolean((double)val));
                    }
                    else if (val is string)
                    {
                        try {
                            return(Convert.ToBoolean((string)val));                            // this loves to throw errors
                        } catch (Exception e) {
                            context.SetRuntimeError(RuntimeErrorType.ConversionInvalid, "ToBool - C# error: " + e.ToString());
                            return(null);
                        }
                    }
                    else
                    {
                        return(true);
                    }
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, false);
                engine.AddBuiltInFunction(newValue, "ToBool");
            }

            //@ global num ToNum(any)
            //   Attempts to convert input to a num.
            //   true -> 1, false -> 0, null -> 0, non-null object reference -> 1. Strings are handled by Convert.ToDouble,
            //   which can throw an error if it doesn't know how to convert the string.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object val = args[0];
                    if (null == val)
                    {
                        return(0.0);
                    }
                    else if (val is double)
                    {
                        return((double)val);
                    }
                    else if (val is bool)
                    {
                        return((bool)val ? 1.0 : 0.0);
                    }
                    else if (val is string)
                    {
                        try {
                            return(Convert.ToDouble((string)val));                              // this loves to throw errors
                        } catch {
                            context.SetRuntimeError(RuntimeErrorType.ConversionInvalid, "ToNum - Cannot convert string \"" + ((string)val) + "\" to number.");
                            return(null);
                        }
                    }
                    else
                    {
                        return(1.0);
                    }
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, false);
                engine.AddBuiltInFunction(newValue, "ToNum");
            }

            //@ global string ToString(...)
            //   Converts all arguments to strings, concatenates them, and returns the result.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    return(StandardPrintFunction(context, args));
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, true);
                engine.AddBuiltInFunction(newValue, "ToString");
            }

            UnitTests.testFuncDelegates.Add("CoreLib", RunTests);
        }
Пример #26
0
        public static void Register(Engine engine)
        {
            PebbleEnum consoleColorEnum = new PebbleEnum(engine.defaultContext, "ConsoleColor", IntrinsicTypeDefs.CONST_NUMBER);

            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Black", 0.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkBlue", 1.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkGreen", 2.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkCyan", 3.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkRed", 4.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkMagenta", 5.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkYellow", 6.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "LightGray", 7.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkGray", 8.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Blue", 9.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Green", 10.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Cyan", 11.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Red", 12.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Magenta", 13.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "Yellow", 14.0);
            consoleColorEnum.AddValue_Literal(engine.defaultContext, "White", 15.0);
            // Finalize.
            consoleColorEnum.EvaluateValues(engine.defaultContext);

            // **********************************

            Regex colorRegex = new Regex(@"(#\d+b?#)", RegexOptions.Compiled);

            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("Console", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("Console", ourType, null, null, true);

            classDef.Initialize();

            //@ global void Clear()
            //   Clears the screen.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    Console.Clear();
                    return(null);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("Clear", newValue.valType, newValue, true);
            }

            //@ global string GetCh()
            //   Waits for the user to press a key and returns it.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    ConsoleKeyInfo cki = Console.ReadKey(true);
                    return(cki.KeyChar.ToString());
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("GetCh", newValue.valType, newValue, true);
            }

            //@ global string Print(...)
            //   Alias of WriteLine.

            //@ global string ReadLine()
            //   Reads a line of input and returns it.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    return(Console.ReadLine());
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("ReadLine", newValue.valType, newValue, true);
            }

            //@ global void ResetColor()
            //   Resets foreground and background colors to their defaults.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    Console.ResetColor();
                    return(null);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList {
                }, eval, false);
                classDef.AddMemberLiteral("ResetColor", newValue.valType, newValue, true);
            }

            //@ global num SetBackgroundColor(ConsoleColor color)
            //   Sets the background color to the given value.
            //   Returns the previous color.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    ClassValue_Enum enumVal = args[0] as ClassValue_Enum;
                    int             iColor  = Convert.ToInt32((double)enumVal.GetValue());

                    int iPrevColor = Convert.ToInt32(Console.BackgroundColor);
                    Console.BackgroundColor = (ConsoleColor)iColor;
                    return(consoleColorEnum._classDef.staticVars[iPrevColor].value);
                };
                FunctionValue newValue = new FunctionValue_Host(consoleColorEnum.enumType, new ArgList {
                    consoleColorEnum.enumType
                }, eval, false);
                classDef.AddMemberLiteral("SetBackgroundColor", newValue.valType, newValue, true);
            }

            //@ global num SetForegroundColor(num color)
            //   Sets the foreground color to the given value. The valid values are 0-15.
            //   Returns the previous color.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    ClassValue_Enum enumVal = args[0] as ClassValue_Enum;
                    int             iColor  = Convert.ToInt32((double)enumVal.GetValue());

                    int iPrevColor = Convert.ToInt32(Console.ForegroundColor);
                    Console.ForegroundColor = (ConsoleColor)iColor;
                    return(consoleColorEnum._classDef.staticVars[iPrevColor].value);
                };
                FunctionValue newValue = new FunctionValue_Host(consoleColorEnum.enumType, new ArgList {
                    consoleColorEnum.enumType
                }, eval, false);
                classDef.AddMemberLiteral("SetForegroundColor", newValue.valType, newValue, true);
            }

            //@ global string Write(...)
            //   Works much like Print but doesn't automatically include a newline, so you can write partial lines.
            //   Also, if an argument is a ConsoleColor, rather than writing it the function temporarily sets the foreground color to the given color.
            //   Colors can be inserted into the string by using, for example, #1#, which will set the foreground color to 1, or #11b# which sets the background color to 11.
            //   This function restores the colors to what they were before the function was called.
            //   Returns the aggregated string, minus any provided colors.
            FunctionValue_Host.EvaluateDelegate evalWrite;
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    ConsoleColor startingForeground = Console.ForegroundColor;
                    ConsoleColor startingBackground = Console.BackgroundColor;

                    string result = "";
                    foreach (object val in args)
                    {
                        if (val is ClassValue_Enum)
                        {
                            ClassValue_Enum cve = (ClassValue_Enum)val;
                            if (cve.classDef == consoleColorEnum._classDef)
                            {
                                int color = Convert.ToInt32((double)cve.GetValue());
                                Console.ForegroundColor = (ConsoleColor)color;
                                continue;
                            }
                        }


                        if (val is string)
                        {
                            string v = val as string;

                            string[] splits = colorRegex.Split(v);
                            foreach (string str in splits)
                            {
                                if (str.Length > 2 && '#' == str[0] && '#' == str[str.Length - 1])
                                {
                                    int  iColor;
                                    bool background = false;
                                    if ('b' == str[str.Length - 2])
                                    {
                                        iColor     = Convert.ToInt32(str.Substring(1, str.Length - 3));
                                        background = true;
                                    }
                                    else
                                    {
                                        iColor = Convert.ToInt32(str.Substring(1, str.Length - 2));
                                    }

                                    if (iColor < 0 || iColor > 15)
                                    {
                                        context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Write: Color escapes must be between 0 and 15.");
                                        Console.ForegroundColor = startingForeground;
                                        Console.BackgroundColor = startingBackground;
                                        return(null);
                                    }
                                    if (background)
                                    {
                                        Console.BackgroundColor = (ConsoleColor)iColor;
                                    }
                                    else
                                    {
                                        Console.ForegroundColor = (ConsoleColor)iColor;
                                    }
                                }
                                else
                                {
                                    result += str;
                                    Console.Write(str);
                                }
                            }
                        }
                        else
                        {
                            string s = CoreLib.ValueToString(context, val, false);
                            result += s;
                            Console.Write(s);
                        }
                    }

                    Console.ForegroundColor = startingForeground;
                    Console.BackgroundColor = startingBackground;

                    return(result);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, true);
                classDef.AddMemberLiteral("Write", newValue.valType, newValue, true);

                evalWrite = eval;
            }

            //@ global string WriteLine(...)
            //   Works exactly like Write but just adds a newline at the end.
            //   Returns the aggregated string, minus any provided colors.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    object result = evalWrite(context, args, thisScope);
                    Console.Write("\n");
                    return(result);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                    IntrinsicTypeDefs.ANY
                }, eval, true);
                classDef.AddMemberLiteral("WriteLine", newValue.valType, newValue, true);
                classDef.AddMemberLiteral("Print", newValue.valType, newValue, true);
            }

            classDef.FinalizeClass(engine.defaultContext);
        }
Пример #27
0
        // Compile-time lookup of MemberRef.
        public MemberRef GetMemberRef(ExecContext context, string name, SEARCH searchType, ref ITypeDef typeDef)
        {
            // If there is an error during compliation then we can have an uninitialized
            // class on the stack. This check prevents us from throwing an exception
            // when that happens.
            // Kind of a kludge but handling errors during compilation is pretty chaotic
            // and I don't know what I could do other than to just abort on the first error.
            if (null == _fields)
            {
                return(MemberRef.invalid);
            }

            if (SEARCH.NORMAL == searchType || SEARCH.EITHER == searchType)
            {
                if (_fields.Exists(name))
                {
                    var member = _fields.Get(name);
                    typeDef = member.typeDef;

                    // If this member is getonly and we are not in this class's context, the type becomes const.
                    if (null != context && member.isGetonly)
                    {
                        ClassDef current = context.stack.GetCurrentClassDef();
                        if (null == current || (current != this && !current.IsChildOf(this)))
                        {
                            typeDef = TypeFactory.GetConstVersion(typeDef);
                        }
                    }

                    return(new MemberRef(member.index));
                }

                if (_memberFuncs.Exists(name))
                {
                    var member = _memberFuncs.Get(name);
                    typeDef = member.typeDef;
                    return(new MemberRef(this, MemberType.FUNCTION, member.index));
                }
            }

            if (SEARCH.STATIC == searchType || SEARCH.EITHER == searchType)
            {
                ClassDef def = this;
                while (null != def)
                {
                    if (def._statics.Exists(name))
                    {
                        ClassMember member = def._statics.Get(name);
                        typeDef = member.typeDef;

                        // If this member is getonly and we are not in this class's context, the type becomes const.
                        if (null != context && member.isGetonly)
                        {
                            ClassDef current = context.stack.GetCurrentClassDef();
                            if (null == current || (current != this && !current.IsChildOf(this)))
                            {
                                typeDef = TypeFactory.GetConstVersion(typeDef);
                            }
                        }

                        return(new MemberRef(def, MemberType.STATIC, member.index));
                    }
                    def = def.parent;
                }
            }

            return(MemberRef.invalid);
        }
Пример #28
0
            public bool Read(ExecContext context, PebbleStreamHelper stream, Variable variable)
            {
                if (variable.type.IsConst())
                {
                    context.SetRuntimeError(RuntimeErrorType.SerializeIntoConst, "Cannot serialize into const variables.");
                    return(false);
                }

                if (variable.type.CanStoreValue(context, IntrinsicTypeDefs.BOOL))
                {
                    variable.value = reader.ReadBoolean();
                }
                else if (variable.type == IntrinsicTypeDefs.NUMBER)
                {
                    variable.value = reader.ReadDouble();
                }
                else if (variable.type == IntrinsicTypeDefs.STRING)
                {
                    variable.value = reader.ReadString();
                }
                else if (variable.type.GetName().StartsWith("List<"))
                {
                    string listTypeName = reader.ReadString();
                    if ("null" == listTypeName)
                    {
                        variable.value = null;
                        return(true);
                    }

                    // Is it possible that the specific generic class isn't registered yet.
                    if (!EnsureGenericIsRegistered(context, listTypeName))
                    {
                        return(false);
                    }

                    ClassDef listDef = context.GetClass(listTypeName);
                    if (null == listDef)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Cannot deserialize list type '" + listTypeName + "' because it is unknown.");
                        return(false);
                    }

                    ClassValue listValue = listDef.Allocate(context);
                    PebbleList newlist   = listValue as PebbleList;
                    variable.value = listValue;

                    ITypeDef elementType = listDef.typeDef.genericTypes[0];

                    int count = reader.ReadInt32();
                    for (int ii = 0; ii < count; ++ii)
                    {
                        Variable newelem = new Variable(null, elementType);
                        if (!Read(context, stream, newelem))
                        {
                            return(false);
                        }
                        newlist.list.Add(newelem);
                    }
                }
                else if (variable.type.GetName().StartsWith("Dictionary<"))
                {
                    string listTypeName = reader.ReadString();
                    if ("null" == listTypeName)
                    {
                        variable.value = null;
                        return(true);
                    }

                    // Is it possible that the specific generic class isn't registered yet.
                    if (!EnsureGenericIsRegistered(context, listTypeName))
                    {
                        return(false);
                    }

                    ClassDef listDef = context.GetClass(listTypeName);
                    if (null == listDef)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Cannot deserialize list type '" + listTypeName + "' because it is unknown.");
                        return(false);
                    }

                    ClassValue       listValue = listDef.Allocate(context);
                    PebbleDictionary newlist   = listValue as PebbleDictionary;
                    variable.value = listValue;

                    ITypeDef keyType   = listDef.typeDef.genericTypes[0];
                    ITypeDef valueType = listDef.typeDef.genericTypes[1];

                    int      count      = reader.ReadInt32();
                    Variable tempKeyVar = new Variable("tempKeyVar", keyType);
                    for (int ii = 0; ii < count; ++ii)
                    {
                        if (!Read(context, stream, tempKeyVar))
                        {
                            return(false);
                        }

                        Variable newelem = new Variable(null, valueType);
                        if (!Read(context, stream, newelem))
                        {
                            return(false);
                        }
                        newlist.dictionary.Add(tempKeyVar.value, newelem);
                    }
                }
                else if (variable.type is TypeDef_Enum)
                {
                    string enumName  = reader.ReadString();
                    string valueName = reader.ReadString();

                    // This happens.
                    ITypeDef streamedType = context.GetTypeByName(enumName);
                    if (null == streamedType)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Attempt to load saved enum of unknown type '" + enumName + "'.");
                        return(false);
                    }

                    // I can't get this to happen.
                    if (!(streamedType is TypeDef_Enum))
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Type '" + enumName + "' saved as something other than an enum, but attempted to stream into an enum variable.");
                        return(false);
                    }

                    ClassDef enumClassDef = context.GetClass(enumName);
                    Pb.Assert(null != enumClassDef, "Somehow we got a type for an enum but not the def.");
                    ClassDef_Enum enumDef = enumClassDef as ClassDef_Enum;
                    Pb.Assert(null != enumClassDef, "Registered type is enum but def is classdef.");

                    // This happens.
                    ClassValue_Enum cve = enumDef.enumDef.GetValue(valueName);
                    if (null == cve)
                    {
                        context.SetRuntimeError(RuntimeErrorType.EnumValueNotFound, "Enum '" + enumName + "' does not have saved value '" + valueName + "'.");
                        return(false);
                    }

                    variable.value = cve;
                }
                else if (variable.type is TypeDef_Class)
                {
                    TypeDef_Class varType = variable.type as TypeDef_Class;

                    // Get class name.
                    string streamClassName = reader.ReadString();

                    if ("null" == streamClassName)
                    {
                        variable.value = null;
                        return(true);
                    }

                    ITypeDef streamedType = context.GetTypeByName(streamClassName);
                    if (null == streamedType)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Serialized type '" + streamClassName + "' not found.");
                        return(false);
                    }

                    if (!varType.CanStoreValue(context, streamedType))
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeTypeMismatch, "Cannot deserialize a '" + streamClassName + "' into a variable of type '" + varType.GetName() + "'.");
                        return(false);
                    }

                    TypeDef_Class streamedClassType = streamedType as TypeDef_Class;
                    Pb.Assert(null != streamedClassType, "Somehow a streamed type is not a class but *can* be stored in a class type?!");

                    ClassDef streamedClassDef = context.GetClass(streamClassName);
                    Pb.Assert(null != streamedClassDef, "Somehow we got a type for a class but not the def.");
                    MemberRef serMemRef = streamedClassDef.GetMemberRef(null, "Serialize", ClassDef.SEARCH.NORMAL);
                    if (serMemRef.isInvalid)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeInvalidClass, "Serialize function of class '" + streamClassName + "' not found.");
                        return(false);
                    }

                    ClassValue    streamedClassValue = streamedClassDef.Allocate(context);
                    Variable      serFuncVar         = streamedClassValue.Get(serMemRef);
                    FunctionValue serFuncVal         = serFuncVar.value as FunctionValue;
                    serFuncVal.Evaluate(context, new List <object>()
                    {
                        stream
                    }, streamedClassValue);
                    if (context.IsRuntimeErrorSet())
                    {
                        return(false);
                    }

                    variable.value = streamedClassValue;
                }
                else
                {
                    throw new Exception("Internal error: Unexpected type of value in stream Read.");
                }

                return(true);
            }
Пример #29
0
        public static void Register(Engine engine)
        {
            //@ class RegexGroup
            //   Stores information about a Regex group match. Basically a wrapper for System.Text.RegularExpressions.Group.
            {
                TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("RegexGroup", null, false);
                ClassDef      classDef = engine.defaultContext.CreateClass("RegexGroup", ourType, null, null);
                classDef.Initialize();

                //@ const num index;
                //   The index of the character at the start of this match.
                classDef.AddMember("index", IntrinsicTypeDefs.CONST_NUMBER);
                //@ const num length;
                //   The length of the substring of this match.
                classDef.AddMember("length", IntrinsicTypeDefs.CONST_NUMBER);
                //@ const string value;
                //   The substring of this match.
                classDef.AddMember("value", IntrinsicTypeDefs.CONST_STRING);

                classDef.FinalizeClass(engine.defaultContext);
                regexGroupClassDef = classDef;
            }

            // Make sure the List<RegexGroup> type is registered.
            listRegexGroupClassDef = engine.defaultContext.RegisterIfUnregisteredList(regexGroupClassDef.typeDef);

            //@ class RegexMatch
            //   Stores information about a single Regex substring match. Basically a wrapper for System.Text.RegularExpressions.Match.
            {
                TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("RegexMatch", null, false);
                ClassDef      classDef = engine.defaultContext.CreateClass("RegexMatch", ourType, null, null);
                classDef.Initialize();

                //@ const num index;
                //   The index of the character at the start of this match.
                classDef.AddMember("index", IntrinsicTypeDefs.CONST_NUMBER);
                //@ const num length;
                //   The length of the substring of this match.
                classDef.AddMember("length", IntrinsicTypeDefs.CONST_NUMBER);
                //@ const string value;
                //   The substring of this match.
                classDef.AddMember("value", IntrinsicTypeDefs.CONST_STRING);
                //@ List<RegexGroup> groups;
                //   The regex groups of this match. If there are no groups this will be null.
                classDef.AddMember("groups", listRegexGroupClassDef.typeDef);

                classDef.FinalizeClass(engine.defaultContext);
                regexMatchClassDef = classDef;
            }

            // ****************************************************************

            // Make sure the List<string> type is registered.
            ClassDef listStringClassDef = engine.defaultContext.RegisterIfUnregisteredList(IntrinsicTypeDefs.STRING);

            // Make sure List<RegexMatch> is registered.
            listMatchClassDef = engine.defaultContext.RegisterIfUnregisteredList(regexMatchClassDef.typeDef);


            // ****************************************************************

            //@ class Regex
            //    Provides static functions that implement regular expression matching for strings. Basically a wrapper for System.Text.RegularExpressions.Regex.
            {
                TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("Regex", null, false);
                ClassDef      classDef = engine.defaultContext.CreateClass("Regex", ourType, null, null, true, true);
                classDef.Initialize();

                // ***


                //@ static bool IsMatch(string input, string expression)
                //   Returns true if input matches the given regular expression.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        string a = (string)args[0];
                        string b = (string)args[1];
                        return(Regex.IsMatch(a, b));
                    };

                    FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList {
                        IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                    }, eval, false);
                    classDef.AddMemberLiteral("IsMatch", newValue.valType, newValue, true);
                }

                //@ static RegexMatch Match(string input, string pattern);
                //	  Returns the first match of the given pattern in the input string, or null if no match.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        string input   = (string)args[0];
                        string pattern = (string)args[1];
                        Match  match   = Regex.Match(input, pattern);

                        if (match.Success)
                        {
                            ClassValue matchInst = regexMatchClassDef.Allocate(context);
                            Variable   index     = matchInst.GetByName("index");
                            Variable   length    = matchInst.GetByName("length");
                            Variable   value     = matchInst.GetByName("value");
                            index.value  = Convert.ToDouble(match.Index);
                            length.value = Convert.ToDouble(match.Length);
                            value.value  = match.Value;

                            return(matchInst);
                        }

                        return(null);
                    };

                    FunctionValue newValue = new FunctionValue_Host(regexMatchClassDef.typeDef, new ArgList {
                        IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                    }, eval, false);
                    classDef.AddMemberLiteral("Match", newValue.valType, newValue, true);
                }

                //@ static List<RegexMatch> Matches(string input, string pattern);
                //    Returns a list of all the matches of the given regular expression in the input string, or null if no matches found.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        string          input    = (string)args[0];
                        string          pattern  = (string)args[1];
                        MatchCollection matchCol = Regex.Matches(input, pattern);
                        if (0 == matchCol.Count)
                        {
                            return(null);
                        }

                        ClassValue matchListInst = listMatchClassDef.Allocate(context);
                        PebbleList pebbleList    = matchListInst as PebbleList;

                        foreach (Match match in matchCol)
                        {
                            ClassValue matchInst = regexMatchClassDef.Allocate(context);
                            Variable   index     = matchInst.GetByName("index");
                            Variable   length    = matchInst.GetByName("length");
                            Variable   value     = matchInst.GetByName("value");
                            index.value  = Convert.ToDouble(match.Index);
                            length.value = Convert.ToDouble(match.Length);
                            value.value  = match.Value;

                            // Note: In this C# regex library, 0 is always the default group (it is the whole match).
                            // That doesn't seem to be a regex standard, and it's entirely rendundant, so I'm only
                            // taking the non-default groups. match.groups is 0 when there are no non-default groups.
                            if (match.Groups.Count > 1)
                            {
                                ClassValue groupListInst = listRegexGroupClassDef.Allocate(context);
                                PebbleList groupList     = groupListInst as PebbleList;
                                matchInst.GetByName("groups").value = groupListInst;

                                for (int ii = 1; ii < match.Groups.Count; ++ii)
                                {
                                    Group group = match.Groups[ii];

                                    ClassValue groupInst = regexGroupClassDef.Allocate(context);
                                    groupInst.GetByName("index").value  = Convert.ToDouble(group.Index);
                                    groupInst.GetByName("length").value = Convert.ToDouble(group.Length);
                                    groupInst.GetByName("value").value  = group.Value;

                                    groupList.list.Add(new Variable("(made my Regex::Matches)", groupInst.classDef.typeDef, groupInst));
                                }
                            }

                            pebbleList.list.Add(new Variable("(Regex::Matches)", regexMatchClassDef.typeDef, matchInst));
                        }

                        return(matchListInst);
                    };

                    FunctionValue newValue = new FunctionValue_Host(listMatchClassDef.typeDef, new ArgList {
                        IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                    }, eval, false);
                    classDef.AddMemberLiteral("Matches", newValue.valType, newValue, true);
                }

                //@ static string Replace(string input, string pattern, string replacement);
                //    Replace any matches of the given pattern in the input string with the replacement string.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        string input       = (string)args[0];
                        string pattern     = (string)args[1];
                        string replacement = (string)args[2];
                        return(Regex.Replace(input, pattern, replacement));
                    };

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

                //@ static List<string> Split(string input, string pattern);
                //    Splits an input string into an array of substrings at the positions defined by a regular expression match.
                {
                    FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                        string   input      = (string)args[0];
                        string   pattern    = (string)args[1];
                        string[] splitArray = Regex.Split(input, pattern);

                        ClassValue inst = listStringClassDef.Allocate(context);
                        inst.debugName = "(Regex::Split result)";

                        PebbleList list = (PebbleList)inst;
                        foreach (string str in splitArray)
                        {
                            list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, str));
                        }

                        return(inst);
                    };

                    FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList {
                        IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING
                    }, eval, false);
                    classDef.AddMemberLiteral("Split", newValue.valType, newValue, true);
                }

                // ***

                classDef.FinalizeClass(engine.defaultContext);
            }

            UnitTests.testFuncDelegates.Add("RegexLib", RunTests);
        }
Пример #30
0
 public ClassDef_Enum(PebbleEnum enumDefIn, string nameIn, TypeDef_Class typeDefIn) : base(nameIn, typeDefIn, null, null, true, true)
 {
     enumDef = enumDefIn;
 }