Пример #1
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);
        }
Пример #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);
        }
Пример #3
0
 public ClassDef_Enum(PebbleEnum enumDefIn, string nameIn, TypeDef_Class typeDefIn) : base(nameIn, typeDefIn, null, null, true, true)
 {
     enumDef = enumDefIn;
 }