// When creating a new class, call CreateClass XOR RegisterClass. Use the latter if you already have a ClassDef, otherwise // call the former and it will create one for you. public ClassDef CreateClass(string nameIn, TypeDef_Class typeDef, ClassDef par, List <string> genericTypeNames = null, bool isSealed = false, bool isUninstantiable = false) { ClassDef def = new ClassDef(nameIn, typeDef, par, genericTypeNames, isSealed, isUninstantiable); RegisterClass(def); return(def); }
public void RegisterClass(ClassDef def) { // AddClass() Pb.Assert(!_classes.ContainsKey(def.name), "ExecContext::AddClass - Class already exists!"); _classes.Add(def.name, def); _types.Add(def.name, TypeFactory.GetTypeDef_Class(def.name, null, false)); }
// Type 2: a reference to a static member of a class. // * type is STATIC or FUNCTION (FUNCTION implying non-static function) // * ix is index into the given ClassDef's _statics or _memberFuncs public MemberRef(ClassDef staticOwnerIn, ClassDef.MemberType typeIn, int ixIn) { Pb.Assert(ClassDef.MemberType.STATIC == typeIn || ClassDef.MemberType.FUNCTION == typeIn); memberType = typeIn; ix = ixIn; classDef = staticOwnerIn; }
// Given two classes, return which is the ancestor of the other, or null. // If neither is the direct ancestor of the other, returns null. If you // want to determine teh nearest common ancestor, use GetMostCommonType. public TypeDef_Class DetermineAncestor(TypeDef_Class typeA, TypeDef_Class typeB) { ClassDef a = _classes[typeA.className]; ClassDef b = _classes[typeB.className]; while (b != null) { if (a == b) { return(typeA); } b = b.parent; } b = _classes[typeB.className]; while (a != null) { if (a == b) { return(typeB); } a = a.parent; } return(null); }
public override object GetDefaultValue(ExecContext context) { string name = GetName(); ClassDef classDef = context.GetClass(name); ClassDef_Enum enumDef = classDef as ClassDef_Enum; return(enumDef.enumDef.GetDefaultValue()); }
// ATM, this is only used by Exec. public void SetHardTerminal(int depth, string name = "<hardTerminal>") { _varStackStart = depth; _name = "hardTerminal"; _terminal = true; _hardTerminal = true; _classInstance = null; _classDef = null; _funcType = null; _isStatic = false; }
// This is for static function calls, or for class member function calls during typecheck // when we don't have or need an instance. public void Set(int depth, TypeDef_Function funcType, ClassDef classDef, bool isStaticIn) { _varStackStart = depth; _name = "class (" + classDef.name + ")"; _terminal = true; _hardTerminal = false; _classInstance = null; _classDef = classDef; _funcType = funcType; _isStatic = isStaticIn; }
// Terminal should be true in the "usual" case, which seems to be class member // functions. Should be false in the case of defstructors, because those aren't // real functions and thus not closures: they're just little blocks of code // inside the surrounding code that have access to class members. public void Set(int depth, ClassValue classInstance, bool terminalIn = true) { _varStackStart = depth; _name = "class (" + classInstance.classDef.name + ")"; _terminal = terminalIn; _hardTerminal = false; _classInstance = classInstance; _classDef = null; _funcType = null; _isStatic = false; }
// This is for function calls, both regular calls and class member calls. public void Set(int depth, string name, TypeDef_Function funcType, ClassValue classInstance, bool isStaticIn) { _varStackStart = depth; _name = "function call (" + name + ")"; _terminal = true; _hardTerminal = false; _classInstance = classInstance; _classDef = null; _funcType = funcType; _isStatic = isStaticIn; }
// This is for non-terminal blocks: for, if, and expr-lists. NOT fuction calls. public void Set(int depth, string name = "<scope>") { _varStackStart = depth; _name = name; _terminal = false; _hardTerminal = false; _classInstance = null; _classDef = null; _funcType = null; _isStatic = false; }
public static PebbleList AllocateListString(ExecContext context, string debugName = "(List<string> inst)") { if (null == _listClassDef) { _listClassDef = context.GetClass("List<string>"); } PebbleList listinst = (PebbleList)_listClassDef.childAllocator(); listinst.classDef = _listClassDef; listinst.debugName = debugName; return(listinst); }
/////////////////////////// // DO NOT CALL THIS DIRECTLY // Use context.CreateClass instead. public ClassDef(string nameIn, TypeDef_Class typeDefIn, ClassDef par, List <string> genericTypeNamesIn = null, bool isSealedIn = false, bool isUninstantiableIn = false) { name = nameIn; typeDef = typeDefIn; parent = par; genericTypeNames = genericTypeNamesIn; if (null != par && null != par.childAllocator) { childAllocator = par.childAllocator; } isSealed = isSealedIn; isUninstantiable = isUninstantiableIn; }
// Returns true if parent is in child's ancestor list. public bool IsChildClass(ClassDef parent, ClassDef child) { ClassDef test = child; while (null != test) { if (test == parent) { return(true); } test = test.parent; } 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 bool IsChildOf(ClassDef other) { ClassDef par = parent; while (null != par) { if (par.name == other.name) { return(true); } par = par.parent; } return(false); }
public bool PushClassCall_StaticOrTypeCheck(TypeDef_Function funcType, ClassDef classDef, bool isStatic, ExecContext context) { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } _callStack[_callCount].Set(_varCount, funcType, classDef, isStatic); ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushClassCall_StaticOrTypeCheck(" + classDef.name + ", " + (isStatic ? "static)" : "type check)")); #endif return(true); }
private ITypeDef GetMostCommonType(TypeDef_Class typeA, TypeDef_Class typeB) { ClassDef a = _classes[typeA.className]; while (a != null) { ClassDef b = _classes[typeB.className]; while (b != null) { if (a == b) { return(a.typeDef); } b = b.parent; } a = a.parent; } return(null); }
public PebbleEnum(ExecContext context, string _enumName, ITypeDef valueTypeIn) { enumName = _enumName; valueType = valueTypeIn; // Apparently need to register non-const first. ITypeDef nonConstEnumType = TypeFactory.GetTypeDef_Enum(_enumName, false); enumType = (TypeDef_Enum)TypeFactory.GetConstVersion(nonConstEnumType); _classDef = new ClassDef_Enum(this, _enumName, enumType); context.RegisterClass(_classDef); _classDef.childAllocator = () => { return(new ClassValue_Enum()); }; _classDef.Initialize(); //don't think this is needed _classDef.AddMemberLiteral("enumName", IntrinsicTypeDefs.CONST_STRING, _enumName, false); _classDef.AddMember("name", IntrinsicTypeDefs.CONST_STRING); _classDef.AddMember("value", valueType.Clone(true), null, false, true); { FunctionValue_Host.EvaluateDelegate eval = (_context, args, thisScope) => { ClassValue cv = thisScope as ClassValue; return(enumName + "::" + cv.Get(mrName).value); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false, _classDef.typeDef); _classDef.AddMemberLiteral("ThisToString", newValue.valType, newValue, false); } _classDef.FinalizeClass(context); if (mrName.isInvalid) { mrName = _classDef.GetMemberRef(null, "name", ClassDef.SEARCH.NORMAL); mrValue = _classDef.GetMemberRef(null, "value", ClassDef.SEARCH.NORMAL); } }
// Register a template type, creating the ClassDef if necessary. public ClassDef RegisterIfUnregisteredTemplate(TypeDef_Class classType) { string fullName = classType.GetName(); if (_classes.ContainsKey(fullName)) { return(_classes[fullName]); } ClassDef parent = _classes[classType.className]; Pb.Assert(null != parent, "Parent template not registered?"); if (parent.isSealed) { engine.LogCompileError(ParseErrorType.ClassParentSealed, "Cannot derive from sealed class."); return(null); } // NOTE: All this code is assuming that the generic parent has no parents. // This is fine as long as 1) all generic classes are only defined in C#, and // 2) none of them have parents. if (parent.genericTypeNames.Count != classType.genericTypes.Count) { engine.LogCompileError(ParseErrorType.TemplateCountMismatch, "Template count mismatch: expected " + parent.genericTypeNames.Count + ", got " + classType.genericTypes.Count + "."); return(null); } ClassDef newClass = new ClassDef(classType.GetName(), classType, parent); _classes.Add(newClass.name, newClass); newClass.Initialize(); newClass.FinalizeClass(this); return(newClass); }
// Compile-time lookup of MemberRef. public MemberRef GetMemberRef(ExecContext context, string name, SEARCH searchType, ref ITypeDef typeDef) { // If there is an error during compliation then we can have an uninitialized // class on the stack. This check prevents us from throwing an exception // when that happens. // Kind of a kludge but handling errors during compilation is pretty chaotic // and I don't know what I could do other than to just abort on the first error. if (null == _fields) { return(MemberRef.invalid); } if (SEARCH.NORMAL == searchType || SEARCH.EITHER == searchType) { if (_fields.Exists(name)) { var member = _fields.Get(name); typeDef = member.typeDef; // If this member is getonly and we are not in this class's context, the type becomes const. if (null != context && member.isGetonly) { ClassDef current = context.stack.GetCurrentClassDef(); if (null == current || (current != this && !current.IsChildOf(this))) { typeDef = TypeFactory.GetConstVersion(typeDef); } } return(new MemberRef(member.index)); } if (_memberFuncs.Exists(name)) { var member = _memberFuncs.Get(name); typeDef = member.typeDef; return(new MemberRef(this, MemberType.FUNCTION, member.index)); } } if (SEARCH.STATIC == searchType || SEARCH.EITHER == searchType) { ClassDef def = this; while (null != def) { if (def._statics.Exists(name)) { ClassMember member = def._statics.Get(name); typeDef = member.typeDef; // If this member is getonly and we are not in this class's context, the type becomes const. if (null != context && member.isGetonly) { ClassDef current = context.stack.GetCurrentClassDef(); if (null == current || (current != this && !current.IsChildOf(this))) { typeDef = TypeFactory.GetConstVersion(typeDef); } } return(new MemberRef(def, MemberType.STATIC, member.index)); } def = def.parent; } } return(MemberRef.invalid); }
// Type 1: a reference to a non-static member. // * NORMAL type is implied (functions can be looked up from the ClassDef) // * ix is index into _fields public MemberRef(int ixIn) { memberType = ClassDef.MemberType.NORMAL; ix = ixIn; classDef = null; }
public static void Register(Engine engine) { //@ class Math TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("Math", null, false); ClassDef classDef = engine.defaultContext.CreateClass("Math", ourType, null, null, true); classDef.Initialize(); //@ static const num pi; // pi is the ratio of a circle's circumpherence to its diameter. 3.1415... classDef.AddMemberLiteral("pi", IntrinsicTypeDefs.CONST_NUMBER, Math.PI, true); //@ static const num e; // e is the base of the natural logarithm. 2.71828... classDef.AddMemberLiteral("e", IntrinsicTypeDefs.CONST_NUMBER, Math.E, true); //@ static const num tau; // tau is the ratio of a circle's circumpherence to its radius. tau = 2 * pi classDef.AddMemberLiteral("tau", IntrinsicTypeDefs.CONST_NUMBER, Math.PI * 2, true); // Note on error handling: // The native math functions don't throw exceptions when inputs are invalid. Rather, the functions return one of C#'s "invalid" number values. // These values are illegal in Pebble, and there is code in Expr_Call to detect if a function has returned one of those values and which // generates a script runtime error if it does. Thus, there a lot of the MathLib functions don't do any argument or return value checking // themselves, but rather rely on Expr_Call to detect if a user fed a bad input into a function (ie. Sqrt(-1)). //@ static num Abs(num radians) // Returns the absolute value of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Abs(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Abs", newValue.valType, newValue, true); } //@ static num Acos(num) // Returns the arccosine of the input in radians. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Acos(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Acos", newValue.valType, newValue, true); } //@ static num Asin(num) // Returns the arcsine of the input in radians { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Asin(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Asin", newValue.valType, newValue, true); } //@ static num Atan(num) // Returns the arctangent of the input in radians. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Atan(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Atan", newValue.valType, newValue, true); } //@ static num Ceiling(num) // If an exact integer, returns the integer, otherwise returns the next highest integer. aka, it rounds up. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Ceiling(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Ceiling", newValue.valType, newValue, true); } //@ static num Cos(num radians) // Returns the cosine of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Cos(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Cos", newValue.valType, newValue, true); } //@ static num Exp(num power) // Returns e raised to the given power. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Exp(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Exp", newValue.valType, newValue, true); } //@ static num Floor(num) // If an exact integer, returns the integer, otherwise returns the next lower integer. aka, it rounds down. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Floor(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Floor", newValue.valType, newValue, true); } //@ static num Log(num) // Returns the natural logarithm of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; double b = (double)args[1]; return(Math.Log(a, b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Log", newValue.valType, newValue, true); } //@ static num Min(num, num) // Returns the lesser of the two inputs. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; double b = (double)args[1]; return(Math.Min(a, b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Min", newValue.valType, newValue, true); } //@ static num Max(num) // Returns the greater of the two inputs. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; double b = (double)args[1]; return(Math.Max(a, b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Max", newValue.valType, newValue, true); } //@ static num Pow(num b, num p) // Returns b raised to the power p. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; double b = (double)args[1]; return(Math.Pow(a, b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Pow", newValue.valType, newValue, true); } //@ static num Rand() // Returns a random number between 0 and 1. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { if (null == rand) { rand = new Random(); } return(rand.NextDouble()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { }, eval, false); classDef.AddMemberLiteral("Rand", newValue.valType, newValue, true); } //@ static void RandSeed(num seed) // Seeds the random number generator with the given value (converted to a signed 32-bit integer). { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double dseed = (double)args[0]; if (dseed > Int32.MaxValue || dseed < Int32.MinValue) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Math::RandSeed seed argument must be within the range of a C# Int32."); return(null); } int seed = Convert.ToInt32(dseed); rand = new Random(seed); return(null); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("RandSeed", newValue.valType, newValue, true); } //@ static num Round(num n[, num decimals]) // Rounds the input to the nearest integer, or optionally to the nearest specified decimal point. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; double b = (double)args[1]; int decimals = Convert.ToInt32(b); if (decimals < 0) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "2nd argument to Math.Round cannot be negative."); return(null); } return(Math.Round(a, decimals)); }; // Note: Here is an example of how you provide default argument values for a host function. List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(null); defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false, null, false, defaultArgVals); classDef.AddMemberLiteral("Round", newValue.valType, newValue, true); } //@ static num Sin(num radians) // Returns the sine of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Sin(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Sin", newValue.valType, newValue, true); } //@ static num Sqrt(num) // Returns the square root of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Sqrt(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Sqrt", newValue.valType, newValue, true); } //@ static num Tan(num radians) // Returns the tangent of the input. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double a = (double)args[0]; return(Math.Tan(a)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Tan", newValue.valType, newValue, true); } classDef.FinalizeClass(engine.defaultContext); UnitTests.testFuncDelegates.Add("MathLib", 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); }
// Type 0: Use this to indicate an invalid MemberRef. Used as error return values. // Don't create these, just use "invalid". private MemberRef(bool bad) { memberType = ClassDef.MemberType.NORMAL; ix = -1; classDef = null; }
public static void Register(Engine engine) { //@ class List<T> TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("List", new ArgList { IntrinsicTypeDefs.TEMPLATE_0 }, false); ClassDef classDef = engine.defaultContext.CreateClass("List", ourType, null, new List <string> { "T" }); classDef.childAllocator = () => { return(new PebbleList()); }; classDef.Initialize(); //@ List<T> Add(T newValue, ...) or List<T> Push(T newValue, ...) // Adds one or more elements to the end of the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { PebbleList scope = thisScope as PebbleList; if (scope.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Add: Attempt to modify a list that is being enumerated by a foreach loop."); return(null); } var list = scope.list; var listType = (TypeDef_Class)scope.classDef.typeDef; var elementType = listType.genericTypes[0]; for (int ii = 0; ii < args.Count; ++ii) { object ret = args[ii]; list.Add(new Variable(null, elementType, ret)); } return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { IntrinsicTypeDefs.TEMPLATE_0 }, eval, true, ourType); classDef.AddMemberLiteral("Add", newValue.valType, newValue); classDef.AddMemberLiteral("Push", newValue.valType, newValue); } //@ List<T> Clear() // Removes all elements from the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { PebbleList pebList = thisScope as PebbleList; if (pebList.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Clear: Attempt to modify a list that is being enumerated by a foreach loop."); return(null); } var list = pebList.list; list.Clear(); return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { }, eval, false, ourType); classDef.AddMemberLiteral("Clear", newValue.valType, newValue); } //@ num Count() // Returns the number of elements in the list. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { var list = (thisScope as PebbleList).list; return(System.Convert.ToDouble(list.Count)); }; FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { }, eval, false, ourType); classDef.AddMemberLiteral("Count", newValue.valType, newValue); } //@ T Get(num index) // Returns the value of the element of the list at the given index. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double dix = (double)args[0]; int ix = (int)dix; var list = (thisScope as PebbleList).list; // Bounds checking. if (ix < 0 || ix >= list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Get: Index " + ix + " out of bounds of array of length " + list.Count + "."); return(null); } return(list[ix].value); }; FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.TEMPLATE_0, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false, ourType); classDef.AddMemberLiteral("Get", newValue.valType, newValue); } //@ List<T> Insert(num index, T item) // Inserts a new element into the list at the given index. Existing elements at and after the given index are pushed further down the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { PebbleList scope = thisScope as PebbleList; if (scope.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Insert: Attempt to modify a list that is being enumerated by a foreach loop."); return(null); } var list = scope.list; var listType = (TypeDef_Class)scope.classDef.typeDef; var elementType = listType.genericTypes[0]; var indexDouble = (double)args[0]; var item = args[1]; var index = Convert.ToInt32(indexDouble); if (index < 0 || index > list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Insert: array index out of bounds."); return(null); } list.Insert(index, new Variable(null, elementType, item)); return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.TEMPLATE_0 }, eval, false, ourType); classDef.AddMemberLiteral("Insert", newValue.valType, newValue); } //@ T Pop() // Returns the value of the last element of the list and removes it from the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { PebbleList pebList = thisScope as PebbleList; if (pebList.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "Pop: Attempt to remove an element from a list that is being enumerated in a foreach loop."); return(null); } var list = pebList.list; int ix = list.Count - 1; if (ix < 0) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Pop: List is empty."); return(null); } var result = list[ix].value; list.RemoveAt(ix); return(result); }; FunctionValue_Host newValue = new FunctionValue_Host(IntrinsicTypeDefs.TEMPLATE_0, new ArgList { }, eval, false, ourType); classDef.AddMemberLiteral("Pop", newValue.valType, newValue); } //@ List<T> RemoveAt(num index) // Removes element at the given index, and returns the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double dix = (double)args[0]; int ix = (int)dix; PebbleList pebList = thisScope as PebbleList; if (pebList.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "RemoveAt: Attempt to modify a list that is being enumerated by a foreach loop."); return(null); } var list = pebList.list; if (ix < 0 || ix >= list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveAt: Index " + ix + " out of bounds of array of length " + list.Count + "."); return(null); } list.RemoveAt(ix); return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { IntrinsicTypeDefs.NUMBER }, eval, false, ourType); classDef.AddMemberLiteral("RemoveAt", newValue.valType, newValue); } //@ List<T> RemoveRange(num start, num count) // Removes elements in the given range of indices, and returns the list. // Cannot be used in a foreach loop. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double dstart = (double)args[0]; int start = (int)dstart; double dcount = (double)args[1]; int count = (int)dcount; PebbleList pebList = thisScope as PebbleList; if (pebList.enumeratingCount > 0) { context.SetRuntimeError(RuntimeErrorType.ForeachModifyingContainer, "RemoveRange: Attempt to modify a list that is being enumerated by a foreach loop."); return(null); } var list = pebList.list; if (start < 0 || start >= list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Start " + start + " out of bounds of array of length " + list.Count + "."); return(null); } if (count < 0) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Count (" + count + ") cannot be negative."); return(null); } if ((start + count) >= list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "RemoveRange: Count " + count + " exceeds array length (" + list.Count + ")."); return(null); } list.RemoveRange(start, count); return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false, ourType); classDef.AddMemberLiteral("RemoveRange", newValue.valType, newValue); } //@ List<T> Reverse() // Reverses the list and returns it. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { var list = (thisScope as PebbleList).list; list.Reverse(); return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { }, eval, false, ourType); classDef.AddMemberLiteral("Reverse", newValue.valType, newValue); } //@ List<T> Set(num index, T newValue) // Changes the value of the element at the given index, and returns the list. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { double dix = (double)args[0]; int ix = (int)dix; object value = args[1]; var list = (thisScope as PebbleList).list; // Bounds checking. if (ix < 0 || ix >= list.Count) { context.SetRuntimeError(RuntimeErrorType.ArrayIndexOutOfBounds, "Set: Index " + ix + " out of bounds of array of length " + list.Count + "."); return(null); } list[ix].value = value; return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.TEMPLATE_0 }, eval, false, ourType); classDef.AddMemberLiteral("Set", newValue.valType, newValue); } //@ List<T> Shuffle() // Shuffles the list, putting the elements in random order. // Returns the list. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { var list = (thisScope as PebbleList).list; Random rng = new Random(); int n = list.Count; while (n > 1) { --n; int k = rng.Next(n + 1); Variable value = list[k]; list[k] = list[n]; list[n] = value; } return(thisScope); }; FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { }, eval, false, ourType); classDef.AddMemberLiteral("Shuffle", newValue.valType, newValue); } //@ List<T> Sort(functype<num(T, T>)> comparator) // Sorts the list using the given comparator function. // The comparator should behave the same as a C# Comparer. The first argument should be earlier in the // list than the second, return a number < 0. If It should be later, return a number > 0. If their order // is irrelevant, return 0. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { var list = (thisScope as PebbleList).list; if (null == args[0]) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Sort: comparator may not be null."); return(null); } FunctionValue comparator = (FunctionValue)args[0]; List <object> argvals = new List <object>(); argvals.Add(0); argvals.Add(0); Comparison <Variable> hostComparator = new Comparison <Variable>( (a, b) => { argvals[0] = a.value; argvals[1] = b.value; // Note we use null instead of thisScope here. There is no way the sort function could be a // class member because Sort's signature only takes function's whose type has no class. double result = (double)comparator.Evaluate(context, argvals, null); return(Convert.ToInt32(result)); } ); list.Sort(hostComparator); return(thisScope); }; TypeDef_Function comparatorType = TypeFactory.GetTypeDef_Function(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.TEMPLATE_0, IntrinsicTypeDefs.TEMPLATE_0 }, -1, false, null, false, false); FunctionValue_Host newValue = new FunctionValue_Host(ourType, new ArgList { comparatorType }, eval, false, ourType); classDef.AddMemberLiteral("Sort", newValue.valType, newValue); } //@ 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) => { string result = ""; string prefix = (string)args[0] + "\t"; var list = (thisScope as PebbleList).list; for (int ii = 0; ii < list.Count; ++ii) { result += prefix + "Add(" + CoreLib.ValueToScript(context, list[ii].value, prefix + "\t", false) + ");\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 at least the first few elements of the list. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { var list = (thisScope as PebbleList).list; string result = "List(" + list.Count + ")["; for (int ii = 0; ii < Math.Min(4, list.Count); ++ii) { if (ii > 0) { result += ", "; } result += CoreLib.ValueToString(context, list[ii].value, true); } if (list.Count > 4) { result += ", ..."; } 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); UnitTests.testFuncDelegates.Add("CoreList", RunTests); }
public static void Register(Engine engine) { //@ class String TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("String", null, false); ClassDef classDef = engine.defaultContext.CreateClass("String", ourType, null, null, true); classDef.Initialize(); // This makes sure List<num> is registered in the type library, as this class uses it and we can't rely // scripts to register it. engine.defaultContext.RegisterIfUnregisteredList(IntrinsicTypeDefs.NUMBER); //@ static num CompareTo(string, string) // Wraps C# CompareTo function, which essentially returns a number < 0 if a comes before b // alphabetically, > 0 if a comes after b, and 0 if they are identical. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; return(Convert.ToDouble(a.CompareTo(b))); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("CompareTo", newValue.valType, newValue, true); } //@ static string Concat(any[, ...]) // Converts all arguments to strings and concatenates them. Same as ToString. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { return(CoreLib.StandardPrintFunction(context, args)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.ANY }, eval, true); classDef.AddMemberLiteral("Concat", newValue.valType, newValue, true); } //@ static bool EndsWith(string s, string search) // Wrapper for C# EndsWith. Returns true if s ends with search. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; return(a.EndsWith(b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("EndsWith", newValue.valType, newValue, true); } //@ static bool Equals(string, string) // Returns true iff the strings are exactly equal. The same thing as using the == operator. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; return(a.Equals(b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("Equals", newValue.valType, newValue, true); } //@ static bool EqualsI(string, string) // Returns true if the strings are equal, ignoring case. Equivalent to the ~= operator. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; return(a.ToLower().Equals(b.ToLower())); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("EqualsI", newValue.valType, newValue, true); } //@ static string Format(string[, any, ...]) // Generated formatted strings. Wrapper for C# String.Format(string, object[]). See documentation of that function for details. // Putting weird things like Lists or functions into the args will produce undefined results. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string source = (string)args[0]; Object[] a = new Object[args.Count - 1]; args.CopyTo(1, a, 0, args.Count - 1); string result = ""; try { result = String.Format(source, a); } catch (Exception e) { context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString()); return(null); } return(result); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.ANY }, eval, true); classDef.AddMemberLiteral("Format", newValue.valType, newValue, true); } //@ static List<string> GetCharList(string) // Returns a list of strings containing one character of the input string. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string source = (string)args[0]; PebbleList list = PebbleList.AllocateListString(context, "String::GetCharList result"); foreach (char c in source.ToCharArray()) { list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, Convert.ToString(c))); } return(list); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("GetCharList", newValue.valType, newValue, true); } //@ static List<num> GetUnicode(string) // Returns the Unicode numeric values for the characters in the input string. // Returns an empty list if the string is empty. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string source = (string)args[0]; PebbleList list = PebbleList.AllocateListString(context, "String::GetUnicode result"); foreach (char c in source.ToCharArray()) { list.list.Add(new Variable(null, IntrinsicTypeDefs.NUMBER, Convert.ToDouble(Convert.ToInt32(c)))); } return(list); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_NUMBER, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("GetUnicode", newValue.valType, newValue, true); } //@ static num IndexOfChar(string toBeSearched, string searchChars, num startIndex = 0) // Returns the index of the first instance of any of the characters in search. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; int startIndex = Convert.ToInt32((double)args[2]); if (0 == a.Length || 0 == b.Length) { return(-1.0); } int lowestIx = Int32.MaxValue; foreach (char c in b) { int ix = a.IndexOf(c, startIndex); if (ix >= 0 && ix < lowestIx) { lowestIx = ix; } } if (lowestIx < Int32.MaxValue) { return(Convert.ToDouble(lowestIx)); } return(-1.0); }; List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(null); defaultArgVals.Add(null); defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false, null, true, defaultArgVals); classDef.AddMemberLiteral("IndexOfChar", newValue.valType, newValue, true); } //@ static num IndexOfString(string toBeSearched, string searchString, num startIndex = 0) // Returns the index of the first instance of the entire search string. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; int startIndex = Convert.ToInt32((double)args[2]); if (0 == a.Length || 0 == b.Length) { return(-1.0); } int ix = a.IndexOf(b, startIndex); return(Convert.ToDouble(ix)); }; List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(null); defaultArgVals.Add(null); defaultArgVals.Add(new Expr_Literal(null, 0.0, IntrinsicTypeDefs.NUMBER)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false, null, true, defaultArgVals); classDef.AddMemberLiteral("IndexOfString", newValue.valType, newValue, true); } //@ static num LastIndexOfChar(string toBeSearched, string searchChars, num startIndex = -1) // Returns the index of the last instance of the entire search string, // If startIndex is >= 0, starts searching backwards from the given index. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; int startIndex = Convert.ToInt32((double)args[2]); if (0 == a.Length || 0 == b.Length) { return(-1.0); } if (startIndex < 0) { startIndex = a.Length - 1; } else if (startIndex >= a.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "LastIndexOfChar startIndex argument is greater than the length of the string."); return(null); } char[] chars = b.ToCharArray(); int lowestIx = Int32.MaxValue; foreach (char c in b) { int ix = a.LastIndexOfAny(chars, startIndex); if (ix >= 0 && ix < lowestIx) { lowestIx = ix; } } if (lowestIx < Int32.MaxValue) { return(Convert.ToDouble(lowestIx)); } return(-1.0); }; List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(null); defaultArgVals.Add(null); defaultArgVals.Add(new Expr_Literal(null, -1.0, IntrinsicTypeDefs.NUMBER)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false, null, true, defaultArgVals); classDef.AddMemberLiteral("LastIndexOfChar", newValue.valType, newValue, true); } //@ static num LastIndexOfString(string toBeSearched, string searchString, num startIndex = -1) // Returns the index of the last instance of the entire search string, // If startIndex is > 0, starts searching backwards from the given index. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; int startIndex = Convert.ToInt32((double)args[2]); if (0 == a.Length || 0 == b.Length) { return(-1.0); } if (startIndex < 0) { startIndex = a.Length - 1; } else if (startIndex >= a.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "LastIndexOfString startIndex argument is greater than the length of the string."); return(null); } int ix = a.LastIndexOf(b, startIndex); return(Convert.ToDouble(ix)); }; List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(null); defaultArgVals.Add(null); defaultArgVals.Add(new Expr_Literal(null, -1.0, IntrinsicTypeDefs.NUMBER)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false, null, true, defaultArgVals); classDef.AddMemberLiteral("LastIndexOfString", newValue.valType, newValue, true); } //@ static num Length(string) // Returns the length of the string. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; return(Convert.ToDouble(a.Length)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("Length", newValue.valType, newValue, true); } //@ static string PadLeft(string, num n, string pad) // Returns s with n instances of string pad to the left. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; double nd = (double)args[1]; int n = Convert.ToInt32(nd); string p = (string)args[2]; if (0 == p.Length) { p = " "; } char c = p[0]; return(a.PadLeft(n, c)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("PadLeft", newValue.valType, newValue, true); } //@ static string PadRight(string s, num n, string pad) // Returns s with n instances of string pad to the left. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; double nd = (double)args[1]; int n = Convert.ToInt32(nd); string p = (string)args[2]; if (0 == p.Length) { p = " "; } char c = p[0]; return(a.PadRight(n, c)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("PadRight", newValue.valType, newValue, true); } //@ static string Replace(string str, string find, string replace) // Replaces all instances of the given string with the replacement string. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string find = (string)args[1]; string replace = (string)args[2]; if (0 == find.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Find argument to Replace() cannot be the empty string."); return(null); } return(a.Replace(find, replace)); }; 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 str, List<string> separators = null) // Splits input string into a list of strings given the provided separators. // If no separators are provided, uses the newline character. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string[] splitted; if (null == args[1]) { splitted = a.Split(_defaultSeparators, StringSplitOptions.None); } else { PebbleList delimsList = args[1] as PebbleList; if (0 == delimsList.list.Count) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "String::Split : Separators list cannot be empty."); return(null); } List <string> dlist = delimsList.GetNativeList(); // Usually I like to wrap native functions with a try-catch but I couldn't find a // way to make this throw an exception. splitted = a.Split(dlist.ToArray(), StringSplitOptions.None); } PebbleList list = PebbleList.AllocateListString(context, "String::Split result"); foreach (string s in splitted) { list.list.Add(new Variable(null, IntrinsicTypeDefs.STRING, s)); } return(list); }; List <Expr_Literal> defaults = new List <Expr_Literal>(); defaults.Add(null); defaults.Add(new Expr_Literal(null, null, IntrinsicTypeDefs.NULL)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.LIST_STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.LIST_STRING }, eval, false, null, true, defaults); classDef.AddMemberLiteral("Split", newValue.valType, newValue, true); } //@ static bool StartsWith(string s, string start) // Returns true if s starts with start. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; string b = (string)args[1]; return(a.StartsWith(b)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("StartsWith", newValue.valType, newValue, true); } //@ static string Substring(string, startIx, length) // Returns a substring of the input, starting at startIx, that is length characters long. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; double b = (double)args[1]; double c = (double)args[2]; int start = Convert.ToInt32(b); int len = Convert.ToInt32(c); if (start < 0 || len < 0) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative."); return(null); } if (start + len > a.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string."); return(null); } return(a.Substring(start, len)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("Substring", newValue.valType, newValue, true); } //@ static string SubstringLeft(string str, num length) // Returns the left 'length' characters of str. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; double b = (double)args[1]; int len = Convert.ToInt32(b); if (len < 0) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative."); return(null); } if (len > a.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string."); return(null); } return(a.Substring(0, len)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("SubstringLeft", newValue.valType, newValue, true); } //@ static string SubstringRight(string, start) // Returns the right part of the string starting at 'start'. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; double b = (double)args[1]; int start = Convert.ToInt32(b); if (start < 0) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Numeric arguments to Substring cannot be negative."); return(null); } if (start >= a.Length) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Substring attempting to read past end string."); return(null); } return(a.Substring(a.Length - start)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING, IntrinsicTypeDefs.NUMBER }, eval, false); classDef.AddMemberLiteral("SubstringRight", newValue.valType, newValue, true); } //@ static string ToLower(string) // Converts the string to lowercase. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; return(a.ToLower()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("ToLower", newValue.valType, newValue, true); } //@ static string ToUpper(string) // Converts the string to uppercase. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; return(a.ToUpper()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("ToUpper", newValue.valType, newValue, true); } //@ static string Trim(string) // Removes leading and trailing whitespace characters. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string a = (string)args[0]; return(a.Trim()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING }, eval, false); classDef.AddMemberLiteral("Trim", newValue.valType, newValue, true); } //@ static string UnicodeToString(List<num>) // Takes a list of numeric Unicode character codes, converts them to characters, concatenates them, and returns the resultant string. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { PebbleList list = args[0] as PebbleList; string result = ""; try { foreach (Variable v in list.list) { double d = (double)v.value; result += Convert.ToChar(Convert.ToInt32(d)); } } catch (Exception e) { context.SetRuntimeError(RuntimeErrorType.NativeException, e.ToString()); return(null); } return(result); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.LIST_NUMBER }, eval, false); classDef.AddMemberLiteral("UnicodeToString", newValue.valType, newValue, true); } classDef.FinalizeClass(engine.defaultContext); UnitTests.testFuncDelegates.Add("StringLib", RunTests); }
public static void Register(Engine engine) { TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("Debug", null, false); ClassDef classDef = engine.defaultContext.CreateClass("Debug", ourType, null, null, true); classDef.Initialize(); // string DumpClass(string className = "") // Returns a string dump of the fields of a class with the given name. // If no argument is given (or string is empty), instead returns a list of all classes. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { string className = (string)args[0]; if ("" == className) { return(context.GetDebugTypeString(true, false, false)); } else { ClassDef def = context.GetClass(className); if (null == def) { return("Class '" + className + "' not found."); } return(def.GetDebugString()); } }; // Note: Here is an example of how you provide default argument values for a host function. List <Expr_Literal> defaultArgVals = new List <Expr_Literal>(); defaultArgVals.Add(new Expr_Literal(null, "", IntrinsicTypeDefs.STRING)); FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.STRING }, eval, false, null, false, defaultArgVals); classDef.AddMemberLiteral("DumpClass", newValue.valType, newValue, true); } // string DumpStack() // Returns a string printout of the stack at the point the function is called. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { return(context.ToString()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false); classDef.AddMemberLiteral("DumpStack", newValue.valType, newValue, true); } // string DumpTypes() // Returns a string printout of the registered types. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { return(context.GetDebugTypeString()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false); classDef.AddMemberLiteral("DumpTypes", newValue.valType, newValue, true); } // string GetTotalMemory() // Wraps GC.GetTotalMemory, which returns the number of bytes estimated to be allocated by C#. // Note that this is NOT just memory allocated by Pebble. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { bool forceFullCorrection = (bool)args[0]; return(Convert.ToDouble(GC.GetTotalMemory(forceFullCorrection))); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { IntrinsicTypeDefs.BOOL }, eval, false); classDef.AddMemberLiteral("GetTotalMemory", newValue.valType, newValue, true); } // functype<bool(bool, string)> SetAssertCallback(functype<bool(bool, string)>) // Sets callback for assert results, returns previous callback. // Callback gets success as first variable, message as second. If returns false, system throws an Assert runtime exception. { TypeRef_Function handlerTypeRef = new TypeRef_Function(new TypeRef("bool"), new List <ITypeRef>() { new TypeRef("bool"), new TypeRef("string") }); bool error = false; TypeDef_Function handlerTypeDef = (TypeDef_Function)handlerTypeRef.Resolve(engine.defaultContext, ref error); Pb.Assert(!error, "Internal error: SetAssertHandler initialization."); FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { FunctionValue newHandler = (FunctionValue)args[0]; FunctionValue oldHandler = Expr_Assert.handler; Expr_Assert.handler = newHandler; return(oldHandler); }; FunctionValue newValue = new FunctionValue_Host(handlerTypeDef, new ArgList { handlerTypeDef }, eval, false); classDef.AddMemberLiteral("SetAssertCallback", newValue.valType, newValue, true); } //@ bool SetLogCompileErrors(bool log) // Sets whether or not compile errors should be logged to the Engine's log function. // Returns the previous value. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { bool oldValue = context.engine.logCompileErrors; bool newVal = (bool)args[0]; context.engine.logCompileErrors = newVal; return(oldValue); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.BOOL, new ArgList { IntrinsicTypeDefs.BOOL }, eval, false); classDef.AddMemberLiteral("SetLogCompileErrors", newValue.valType, newValue, true); } // void TimerStart() // Starts a debug timer. If one is already running it will be set to this new start time. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { timer = Stopwatch.StartNew(); return(null); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList { }, eval, false); classDef.AddMemberLiteral("TimerStart", newValue.valType, newValue, true); } // num TimerGet() // Returns elapsed ms since TimerStart called, or -1 if TimerStart wasn't previously called. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { if (null == timer) { return(-1.0); } return(Convert.ToDouble(timer.ElapsedMilliseconds)); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.NUMBER, new ArgList { }, eval, false); classDef.AddMemberLiteral("TimerGet", newValue.valType, newValue, true); } classDef.FinalizeClass(engine.defaultContext); }
public static void Register(Engine engine) { PebbleEnum consoleColorEnum = new PebbleEnum(engine.defaultContext, "ConsoleColor", IntrinsicTypeDefs.CONST_NUMBER); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Black", 0.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkBlue", 1.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkGreen", 2.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkCyan", 3.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkRed", 4.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkMagenta", 5.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkYellow", 6.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "LightGray", 7.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "DarkGray", 8.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Blue", 9.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Green", 10.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Cyan", 11.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Red", 12.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Magenta", 13.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "Yellow", 14.0); consoleColorEnum.AddValue_Literal(engine.defaultContext, "White", 15.0); // Finalize. consoleColorEnum.EvaluateValues(engine.defaultContext); // ********************************** Regex colorRegex = new Regex(@"(#\d+b?#)", RegexOptions.Compiled); TypeDef_Class ourType = TypeFactory.GetTypeDef_Class("Console", null, false); ClassDef classDef = engine.defaultContext.CreateClass("Console", ourType, null, null, true); classDef.Initialize(); //@ global void Clear() // Clears the screen. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { Console.Clear(); return(null); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList { }, eval, false); classDef.AddMemberLiteral("Clear", newValue.valType, newValue, true); } //@ global string GetCh() // Waits for the user to press a key and returns it. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { ConsoleKeyInfo cki = Console.ReadKey(true); return(cki.KeyChar.ToString()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false); classDef.AddMemberLiteral("GetCh", newValue.valType, newValue, true); } //@ global string Print(...) // Alias of WriteLine. //@ global string ReadLine() // Reads a line of input and returns it. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { return(Console.ReadLine()); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false); classDef.AddMemberLiteral("ReadLine", newValue.valType, newValue, true); } //@ global void ResetColor() // Resets foreground and background colors to their defaults. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { Console.ResetColor(); return(null); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.VOID, new ArgList { }, eval, false); classDef.AddMemberLiteral("ResetColor", newValue.valType, newValue, true); } //@ global num SetBackgroundColor(ConsoleColor color) // Sets the background color to the given value. // Returns the previous color. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { ClassValue_Enum enumVal = args[0] as ClassValue_Enum; int iColor = Convert.ToInt32((double)enumVal.GetValue()); int iPrevColor = Convert.ToInt32(Console.BackgroundColor); Console.BackgroundColor = (ConsoleColor)iColor; return(consoleColorEnum._classDef.staticVars[iPrevColor].value); }; FunctionValue newValue = new FunctionValue_Host(consoleColorEnum.enumType, new ArgList { consoleColorEnum.enumType }, eval, false); classDef.AddMemberLiteral("SetBackgroundColor", newValue.valType, newValue, true); } //@ global num SetForegroundColor(num color) // Sets the foreground color to the given value. The valid values are 0-15. // Returns the previous color. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { ClassValue_Enum enumVal = args[0] as ClassValue_Enum; int iColor = Convert.ToInt32((double)enumVal.GetValue()); int iPrevColor = Convert.ToInt32(Console.ForegroundColor); Console.ForegroundColor = (ConsoleColor)iColor; return(consoleColorEnum._classDef.staticVars[iPrevColor].value); }; FunctionValue newValue = new FunctionValue_Host(consoleColorEnum.enumType, new ArgList { consoleColorEnum.enumType }, eval, false); classDef.AddMemberLiteral("SetForegroundColor", newValue.valType, newValue, true); } //@ global string Write(...) // Works much like Print but doesn't automatically include a newline, so you can write partial lines. // Also, if an argument is a ConsoleColor, rather than writing it the function temporarily sets the foreground color to the given color. // Colors can be inserted into the string by using, for example, #1#, which will set the foreground color to 1, or #11b# which sets the background color to 11. // This function restores the colors to what they were before the function was called. // Returns the aggregated string, minus any provided colors. FunctionValue_Host.EvaluateDelegate evalWrite; { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { ConsoleColor startingForeground = Console.ForegroundColor; ConsoleColor startingBackground = Console.BackgroundColor; string result = ""; foreach (object val in args) { if (val is ClassValue_Enum) { ClassValue_Enum cve = (ClassValue_Enum)val; if (cve.classDef == consoleColorEnum._classDef) { int color = Convert.ToInt32((double)cve.GetValue()); Console.ForegroundColor = (ConsoleColor)color; continue; } } if (val is string) { string v = val as string; string[] splits = colorRegex.Split(v); foreach (string str in splits) { if (str.Length > 2 && '#' == str[0] && '#' == str[str.Length - 1]) { int iColor; bool background = false; if ('b' == str[str.Length - 2]) { iColor = Convert.ToInt32(str.Substring(1, str.Length - 3)); background = true; } else { iColor = Convert.ToInt32(str.Substring(1, str.Length - 2)); } if (iColor < 0 || iColor > 15) { context.SetRuntimeError(RuntimeErrorType.ArgumentInvalid, "Write: Color escapes must be between 0 and 15."); Console.ForegroundColor = startingForeground; Console.BackgroundColor = startingBackground; return(null); } if (background) { Console.BackgroundColor = (ConsoleColor)iColor; } else { Console.ForegroundColor = (ConsoleColor)iColor; } } else { result += str; Console.Write(str); } } } else { string s = CoreLib.ValueToString(context, val, false); result += s; Console.Write(s); } } Console.ForegroundColor = startingForeground; Console.BackgroundColor = startingBackground; return(result); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.ANY }, eval, true); classDef.AddMemberLiteral("Write", newValue.valType, newValue, true); evalWrite = eval; } //@ global string WriteLine(...) // Works exactly like Write but just adds a newline at the end. // Returns the aggregated string, minus any provided colors. { FunctionValue_Host.EvaluateDelegate eval = (context, args, thisScope) => { object result = evalWrite(context, args, thisScope); Console.Write("\n"); return(result); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { IntrinsicTypeDefs.ANY }, eval, true); classDef.AddMemberLiteral("WriteLine", newValue.valType, newValue, true); classDef.AddMemberLiteral("Print", newValue.valType, newValue, true); } classDef.FinalizeClass(engine.defaultContext); }
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); }