Beispiel #1
0
        public bool AddValue_Default(ExecContext context, string valueName)
        {
            if (_names.ContainsKey(valueName))
            {
                return(false);
            }
            _names.Add(valueName, true);

            _classDef.AddMember(valueName, enumType, null, true);

            EnumValue ev = new EnumValue();

            ev.name = valueName;
            _values.Add(ev);
            return(true);
        }
Beispiel #2
0
        public PebbleEnum(ExecContext context, string _enumName, ITypeDef valueTypeIn)
        {
            enumName  = _enumName;
            valueType = valueTypeIn;

            // Apparently need to register non-const first.
            ITypeDef nonConstEnumType = TypeFactory.GetTypeDef_Enum(_enumName, false);

            enumType  = (TypeDef_Enum)TypeFactory.GetConstVersion(nonConstEnumType);
            _classDef = new ClassDef_Enum(this, _enumName, enumType);
            context.RegisterClass(_classDef);

            _classDef.childAllocator = () => {
                return(new ClassValue_Enum());
            };
            _classDef.Initialize();


            //don't think this is needed _classDef.AddMemberLiteral("enumName", IntrinsicTypeDefs.CONST_STRING, _enumName, false);
            _classDef.AddMember("name", IntrinsicTypeDefs.CONST_STRING);
            _classDef.AddMember("value", valueType.Clone(true), null, false, true);

            {
                FunctionValue_Host.EvaluateDelegate eval = (_context, args, thisScope) => {
                    ClassValue cv = thisScope as ClassValue;
                    return(enumName + "::" + cv.Get(mrName).value);
                };
                FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList {
                }, eval, false, _classDef.typeDef);
                _classDef.AddMemberLiteral("ThisToString", newValue.valType, newValue, false);
            }

            _classDef.FinalizeClass(context);

            if (mrName.isInvalid)
            {
                mrName  = _classDef.GetMemberRef(null, "name", ClassDef.SEARCH.NORMAL);
                mrValue = _classDef.GetMemberRef(null, "value", ClassDef.SEARCH.NORMAL);
            }
        }
Beispiel #3
0
        public static void Register(Engine engine)
        {
            //@ class RegexGroup
            //   Stores information about a Regex group match. Basically a wrapper for System.Text.RegularExpressions.Group.
            {
                TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("RegexGroup", null, false);
                ClassDef      classDef = engine.defaultContext.CreateClass("RegexGroup", ourType, null, null);
                classDef.Initialize();

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

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

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

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

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

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

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

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

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


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

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

                // ***


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

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

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

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

                            return(matchInst);
                        }

                        return(null);
                    };

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

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

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

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

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

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

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

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

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

                        return(matchListInst);
                    };

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

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

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

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

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

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

                        return(inst);
                    };

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

                // ***

                classDef.FinalizeClass(engine.defaultContext);
            }

            UnitTests.testFuncDelegates.Add("RegexLib", RunTests);
        }
Beispiel #4
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);
        }