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); }
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); }
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); }
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); }
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); }
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); }
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); }