Example #1
0
        public object EvaluateValues(ExecContext context)
        {
            bool   isNum       = valueType.CanStoreValue(context, IntrinsicTypeDefs.NUMBER);
            double nextInteger = 0;
            bool   isString    = valueType.CanStoreValue(context, IntrinsicTypeDefs.STRING);

            for (int ii = 0; ii < _values.Count; ++ii)
            {
                ClassValue_Enum val = (ClassValue_Enum)_classDef.Allocate(context);
                val.Get(mrName).value          = _values[ii].name;
                _classDef.staticVars[ii].value = val;

                if (null == _values[ii].initializer)
                {
                    if (isNum)
                    {
                        // If number, use next consecutive integer.
                        val.Get(mrValue).value = nextInteger;
                        nextInteger            = Math.Floor(nextInteger + 1);
                    }
                    else if (isString)
                    {
                        // If string, just use name.
                        val.Get(mrValue).value = _values[ii].name;
                    }
                    else
                    {
                        // Use the default value.
                        val.Get(mrValue).value = valueType.GetDefaultValue(context);
                    }
                }
                else
                {
                    object init = _values[ii].initializer.Evaluate(context);
                    if (context.IsRuntimeErrorSet())
                    {
                        return(null);
                    }
                    val.Get(mrValue).value = init;

                    if (isNum)
                    {
                        nextInteger = Math.Floor((double)init + 1);
                    }
                }
            }

            return(false);
        }
Example #2
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);
        }
Example #3
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);
        }
Example #4
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);
            }
Example #5
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);
            }