Esempio n. 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);
        }
Esempio n. 2
0
        public virtual object GetDefaultValue(ExecContext context)
        {
            string     name   = GetName();
            ClassDef   parent = context.GetClass(name);
            ClassValue result = parent.Allocate(context);

            if (null == result)
            {
                return(null);
            }

            result.debugName = parent.name + " Inst";
            //result.typeDef = this;
            return(result);
        }
Esempio n. 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);
        }
Esempio n. 4
0
        public static void Register(Engine engine)
        {
            //@ class DateTime
            TypeDef_Class ourType  = TypeFactory.GetTypeDef_Class("DateTime", null, false);
            ClassDef      classDef = engine.defaultContext.CreateClass("DateTime", ourType, null, null, true);

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

            classDef.Initialize();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            //@ string ThisToScript(string prefix)
            //   ThisToScript is used by Serialize. A classes' ThisToScript function should return code which can rebuild the class.
            //   Note that it's only the content of the class, not the "new A" part. ie., it's the code that goes in the defstructor.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt    = thisScope as PebDateTime;
                    string      result = (string)args[0] + "\tSet(" + pdt.dt.Year + ", " + pdt.dt.Month + ", " + pdt.dt.Day + ", " + pdt.dt.Hour + ", " + pdt.dt.Minute + ", " + pdt.dt.Second + ", " + pdt.dt.Millisecond + ");\n";
                    return(result);
                };

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

            //@ string ToString()
            //   Returns a string representation of this DateTime.
            {
                FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => {
                    PebDateTime pdt = thisScope as PebDateTime;
                    return(pdt.dt.ToString());
                };

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            classDef.FinalizeClass(engine.defaultContext);

            UnitTests.testFuncDelegates.Add("DateTimeLib", RunTests);
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        public static void Register(Engine engine)
        {
            // *** Register required types.

            List <ITypeDef> genericTypes = new ArgList();

            genericTypes.Add(IntrinsicTypeDefs.STRING);

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

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

            // ***

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

            classDef.Initialize();

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

            Variable lastErrorVar = null;

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

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

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

                    lastErrorVar.value = "";

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

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

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

                    lastErrorVar.value = "";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    lastErrorVar.value = "";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            UnitTests.testFuncDelegates.Add("FileLib", RunTests);
        }
Esempio n. 7
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);
            }