Пример #1
0
 // Type 2: a reference to a static member of a class.
 // * type is STATIC or FUNCTION (FUNCTION implying non-static function)
 // * ix is index into the given ClassDef's _statics or _memberFuncs
 public MemberRef(ClassDef staticOwnerIn, ClassDef.MemberType typeIn, int ixIn)
 {
     Pb.Assert(ClassDef.MemberType.STATIC == typeIn || ClassDef.MemberType.FUNCTION == typeIn);
     memberType = typeIn;
     ix         = ixIn;
     classDef   = staticOwnerIn;
 }
Пример #2
0
        public void PopScope()
        {
#if PEBBLE_DEBUG
            Pb.Assert(_callCount > 0, "PopScope called but no scopes to pop.");
#endif

            int lastToRemove = _callStack[_callCount - 1].varStackStart;
            while (_varCount > lastToRemove)
            {
                Variable var = _varStack[_varCount - 1];
                if (null != var)
                {
                    if (var.unique)
                    {
                        _varStack[_varCount - 1] = null;
                    }
                    else
                    {
                        var.name  = "<deleted>";
                        var.value = null;
                    }
                }
                --_varCount;
            }

            --_callCount;
#if PEBBLE_TRACESTACK
            TraceLog("PopScope");
#endif
        }
Пример #3
0
 public void RegisterClass(ClassDef def)
 {
     // AddClass()
     Pb.Assert(!_classes.ContainsKey(def.name), "ExecContext::AddClass - Class already exists!");
     _classes.Add(def.name, def);
     _types.Add(def.name, TypeFactory.GetTypeDef_Class(def.name, null, false));
 }
Пример #4
0
        protected void BuildArgHasDefaults(int argCount)
        {
            minArgs = argCount;

            if (null != argDefaultValues && 0 == argDefaultValues.Count)
            {
                argDefaultValues = null;
            }
            if (null == argDefaultValues)
            {
                return;
            }

            Pb.Assert(argDefaultValues.Count == argCount, "Default values array length doesn't match arg array length.");

            bool defaultFound = false;

            argHasDefaults = new List <bool>();
            for (int ii = 0; ii < argCount; ++ii)
            {
                argHasDefaults.Add(null != argDefaultValues[ii]);
                if (!defaultFound && null != argDefaultValues[ii])
                {
                    defaultFound = true;
                    minArgs      = ii;
                }
            }
        }
Пример #5
0
        public void PopToCallDepth(int length)
        {
#if PEBBLE_DEBUG
            Pb.Assert(length > _callCount, "Why are you setting length to something longer than the current length?");
#endif

            _varStack.RemoveRange(length, _varStack.Count - length);
        }
Пример #6
0
 // Call at the beginning of compilation to save current state.
 public void BeginCompile()
 {
     Pb.Assert(null == _preCompileState);
     _preCompileState            = new PreCompileState();
     _preCompileState.stackState = stack.GetState();
     _types.Apply();
     _classes.Apply();
 }
Пример #7
0
 public TypeRef(string nameIn, List <ITypeRef> templateTypes = null)
 {
     Pb.Assert(null != nameIn, "TypeRef constructor passed null name.");
     name = nameIn;
     if (null != templateTypes && templateTypes.Count > 0)
     {
         _templateTypes = templateTypes;
     }
 }
Пример #8
0
 public Variable Set(string nameIn, ITypeDef typeIn, object valueIn = null)
 {
     Pb.Assert(null != typeIn, "Can't have a variable without a type.");
     name   = nameIn;
     type   = typeIn;
     value  = valueIn;
     unique = false;
     return(this);
 }
Пример #9
0
 public ITypeDef ResolveTemplateTypes(List <ITypeDef> genericTypesIn, ref bool modified)
 {
     if (null != _genericTypes && genericTypes.Count > 0)
     {
         modified = true;
         Pb.Assert(_genericTypes.Count == genericTypesIn.Count);
         return(TypeFactory.GetTypeDef_Class(className, genericTypesIn, _isConst));
     }
     return(this);
 }
Пример #10
0
 // This creates an invalid VarStackRef.
 public VarStackRef(ErrorType error)
 {
     Pb.Assert(error != ErrorType.None);
     errorType       = error;
     callIndexOffset = -9000;
     varIndex        = -1;
     isGlobal        = false;
     memberRef       = MemberRef.invalid;
     typeDef         = null;
     variable        = null;
 }
Пример #11
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.");
        }
Пример #12
0
        // Call this after creating the class and adding members to it.
        public bool FinalizeClass(ExecContext context)
        {
            Pb.Assert(0 == context.control.flags);

            // Only initializing the members that this class has added is a cool idea, but
            // leaves us f****d when it comes to overrridden functions.
            // So, I'm being lazy here and initializing them all.
            for (int ii = 0; ii < _memberFuncs.Count; ++ii)
            {
                ClassMember member = _memberFuncs.Get(ii);

                if (null != member.initializer && (member.initializer is Expr_Literal || member.initializer is Expr_Value))
                {
                    // Make sure vftableVars has a slot for this function.
                    while (vftableVars.Count < ii + 1)
                    {
                        vftableVars.Add(null);
                    }

                    object initValue = member.initializer.Evaluate(context);
                    if (context.IsRuntimeErrorSet())
                    {
                        return(false);
                    }

                    // Create the variable for the function.
                    vftableVars[ii] = new Variable(member.name, member.typeDef, initValue);
                }
            }

            // Initialize the static members. Populates the staticVars list.
            for (int ii = 0; ii < _statics.Count; ++ii)
            {
                ClassMember member    = _statics.Get(ii);
                object      initValue = null;
                if (null != member.initializer)
                {
                    initValue = member.initializer.Evaluate(context);
                    if (context.IsRuntimeErrorSet())
                    {
                        context.engine.LogCompileError(ParseErrorType.StaticMemberEvaluationError, name + "::" + member.name + " - " + context.GetRuntimeErrorString());
                        return(false);
                    }
                }
                staticVars[ii] = new Variable(member.name, member.typeDef, initValue);
            }

            return(true);
        }
Пример #13
0
        public bool PushDefstructorScope(ClassValue instance, ExecContext context)
        {
            Pb.Assert(_callCount < CALLSTACKMAXDEPTH);
            if (CALLSTACKMAXDEPTH == _callCount)
            {
                return(false);
            }

#if PEBBLE_TRACESTACK
            TraceLog("PushDefstructorScope " + instance.classDef.name + " '" + instance.debugName + "'");
#endif
            _callStack[_callCount].Set(_varCount, instance, false);
            ++_callCount;

            return(true);
        }
Пример #14
0
        // Runtime access of static variable, having only the ClassDef.
        public Variable GetVariable(MemberRef memRef)
        {
            switch (memRef.memberType)
            {
            case MemberType.FUNCTION:
                return(vftableVars[memRef.ix]);

            case MemberType.STATIC:
                return(memRef.classDef.staticVars[memRef.ix]);

            default:
                Pb.Assert(false, "Attempt to get Variable for nonstatic field from ClassDef.");
                break;
            }

            return(null);
        }
Пример #15
0
        public static TypeDef GetTypeDef(Type type, object defaultValue, bool isConst = false)
        {
            string name = "";

            if (null == type)
            {
                name = "null";
            }
            else
            {
                if (typeof(double) == type)
                {
                    name = "num";
                }
                else if (typeof(string) == type)
                {
                    name = "string";
                }
                else if (typeof(bool) == type)
                {
                    name = "bool";
                }
                else
                {
                    Pb.Assert(false, "Unknown intrinsic type.");
                }

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

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

            TypeDef newDef = new TypeDef(type, defaultValue, isConst);

#if PEBBLE_TRACETYPES
            Console.WriteLine("Registering new type: " + name);
#endif
            _typeRegistry.Add(name, newDef);
            return(newDef);
        }
Пример #16
0
        public static TypeDef_Enum GetTypeDef_Enum(string className, bool isConst)
        {
            string name;

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

            if (_typeRegistry.ContainsKey(name))
            {
                Pb.Assert(_typeRegistry[name] is TypeDef_Enum, "Messed up enum in typeRegistry.");
                return(_typeRegistry[name] as TypeDef_Enum);
            }
            TypeDef_Enum newDef = new TypeDef_Enum(className);

            _typeRegistry.Add(name, newDef);
            return(newDef);
        }
Пример #17
0
        public bool RestoreState(StackState state)
        {
#if PEBBLE_DEBUG
            Pb.Assert(state.varCount <= _varCount || state.callCount <= _callCount, "TODO: StackState invalid.");
#endif

            while (_varCount > state.varCount)
            {
                Variable var = _varStack[_varCount - 1];
                if (null != var)
                {
                    if (var.unique)
                    {
                        _varStack[_varCount - 1] = null;
                    }
                    else
                    {
                        var.value = null;
                        var.name  = "<deleted>";
                    }
                }
                --_varCount;
            }

            while (state.callCount < _callCount)
            {
                PopScope();
            }

#if PEBBLE_DEBUG
            Pb.Assert(state.callCount == _callCount, "whoops, call count different.");
#endif

#if PEBBLE_TRACESTACK
            TraceLog("RestoreState");
            TraceLog("");
#endif
            return(true);
        }
Пример #18
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);
        }
Пример #19
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);
        }
Пример #20
0
 /*
  * Registers a script function.
  * If any names are already used, returns false.
  */
 public bool AddBuiltInFunction(FunctionValue def, string name)
 {
     Pb.Assert(name != null);
     Pb.Assert(def.valType.isConst);
     return(CreateGlobalVariable(name, def.valType, def));
 }
Пример #21
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);
        }
Пример #22
0
 public virtual bool Comparable(ExecContext context, ITypeDef other)
 {
     Pb.Assert(false, "Can't call Comparable on Template.");
     return(false);
 }
Пример #23
0
 // Returns true if a variable of this type can store a value of valueType.
 public virtual bool CanStoreValue(ExecContext context, ITypeDef valueType)
 {
     Pb.Assert(false, "Can't CanStoreValue on Template.");
     return(false);
 }
Пример #24
0
            public bool Write(ExecContext context, PebbleStreamHelper stream, object value)
            {
                Pb.Assert(!(value is Variable));

                if (null != textWriter)
                {
                    string s = CoreLib.ValueToString(context, value, false);
                    textWriter.Write(s);
                    return(true);
                }

                if (null == value)
                {
                    writer.Write("null");
                }
                else if (value is FunctionValue)
                {
                    context.SetRuntimeError(RuntimeErrorType.SerializeUnknownType, "Cannot serialize functions.");
                    return(false);
                }
                else if (value is bool)
                {
                    writer.Write((bool)value);
                }
                else if (value is double)
                {
                    writer.Write((double)value);
                }
                else if (value is string)
                {
                    writer.Write((string)value);
                }
                else if (value is PebbleList)
                {
                    PebbleList plist = value as PebbleList;
                    // - Serialize full type, ie "List<string>".
                    writer.Write(plist.classDef.name);
                    // - Serialize count.
                    writer.Write(plist.list.Count);
                    // - Finally, serialize each object.
                    foreach (Variable listvar in plist.list)
                    {
                        if (!Write(context, stream, listvar.value))
                        {
                            return(false);
                        }
                    }
                }
                else if (value is PebbleDictionary)
                {
                    PebbleDictionary dic = value as PebbleDictionary;
                    // - class name
                    writer.Write(dic.classDef.name);
                    // - count
                    writer.Write((Int32)dic.dictionary.Count);
                    // - each key, value
                    foreach (var kvp in dic.dictionary)
                    {
                        if (!Write(context, stream, kvp.Key))
                        {
                            return(false);
                        }
                        if (!Write(context, stream, kvp.Value.value))
                        {
                            return(false);
                        }
                    }
                }
                else if (value is ClassValue_Enum)
                {
                    ClassValue_Enum enumVal = value as ClassValue_Enum;
                    writer.Write(enumVal.classDef.name);
                    writer.Write(enumVal.GetName());
                }
                else if (value is ClassValue)
                {
                    ClassValue classVal  = value as ClassValue;
                    MemberRef  serMemRef = classVal.classDef.GetMemberRef(null, "Serialize", ClassDef.SEARCH.NORMAL);
                    if (serMemRef.isInvalid)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeInvalidClass, "Class '" + classVal.classDef.name + "' cannot be serialized because it doesn't implement a serialization function.");
                        return(false);
                    }

                    writer.Write(classVal.classDef.name);

                    Variable      serVar  = classVal.Get(serMemRef);
                    FunctionValue serFunc = serVar.value as FunctionValue;
                    object        result  = serFunc.Evaluate(context, new List <object> {
                        stream
                    }, classVal);
                    if (context.IsRuntimeErrorSet())
                    {
                        return(false);
                    }
                    if (result is bool && false == (bool)result)
                    {
                        context.SetRuntimeError(RuntimeErrorType.SerializeFailed, "Serialize function of class '" + classVal.classDef.name + "' returned false.");
                        return(false);
                    }
                }
                else
                {
                    throw new Exception("Internal error: Unexpected type of value in stream Write.");
                }

                return(true);
            }
Пример #25
0
        public FunctionValue_Script(string name, IExpr _expr, ITypeRef _retType, List <ITypeRef> _argTypes, List <Expr_Literal> defaultVals = null)
        {
            argDefaultValues = defaultVals;
            BuildArgHasDefaults(_argTypes.Count);

            originalName = name;
            expr         = _expr;
            typeRef      = new TypeRef_Function(_retType, _argTypes, argHasDefaults, false);

            Evaluate = (context, args, thisScope) => {
                Pb.Assert(null != originalName);
                Pb.Assert(args.Count == _argTypes.Count, "Internal error: Don't have enough arguments!");

                if (context.IsRuntimeErrorSet())
                {
                    return(null);
                }

                object result;

                bool pushResult = false;
                if (null != staticClassDef)
                {
                    pushResult = context.stack.PushClassCall_StaticOrTypeCheck(typeDef, staticClassDef, true, context);
                }
                else
                {
                    pushResult = context.stack.PushCall(typeDef, originalName, thisScope, false, context);
                }

                if (!pushResult)
                {
                    context.SetRuntimeError(RuntimeErrorType.StackOverflow, "FunctionValue_Script.Evaluate : stack overflow");
                    return(null);
                }

                {
                    // Add name of this function as first variable in function scope.
                    // This condition loosely mirrors the check in Expr_Literal. It's shitty that the code that
                    // runs during TypeCheck is so far removed from this code that runs during Execute.
                    if (null == typeDef.classType)
                    {
                        context.stack.AddVariable(originalName, false, typeDef, this);
                    }

                    // Add argument variables to function scope.
                    if (null != args)
                    {
                        for (int ii = 0; ii < args.Count; ++ii)
                        {
                            context.AddLocalVariable(argNames[ii], valType.argTypes[ii], args[ii]);
                        }
                    }

                    result = _EvaluateInternal(context);
                }
                context.stack.PopScope();

                if (context.IsRuntimeErrorSet())
                {
                    return(null);
                }

                if (0 != (context.control.flags & ControlInfo.RETURN))
                {
                    result = context.control.result;
                    context.control.result = null;
                    context.control.flags -= ControlInfo.RETURN;
                }

                Pb.Assert(0 == context.control.flags);

                return(result);
            };
        }
Пример #26
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);
        }
Пример #27
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);
            }
Пример #28
0
 public ClassValue_Enum GetDefaultValue()
 {
     Pb.Assert(_classDef.staticVars.Count > 0);
     return(_classDef.staticVars[0].value as ClassValue_Enum);
 }
Пример #29
0
 public virtual bool IsNull()
 {
     Pb.Assert(false);
     return(false);
 }
Пример #30
0
 // Convenience function for adding members when you know their literal
 // value at compile time.
 public bool AddMemberLiteral(string name, ITypeDef typeDef, object value, bool isStatic = false)
 {
     Pb.Assert(null != typeDef);
     return(AddMember(name, typeDef, new Expr_Value(null, value, typeDef), isStatic));
 }