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 FunctionValue_Script(string name, IExpr _expr, ITypeRef _retType, List <ITypeRef> _argTypes, List <Expr_Literal> defaultVals = null) { argDefaultValues = defaultVals; BuildArgHasDefaults(_argTypes.Count); originalName = name; expr = _expr; typeRef = new TypeRef_Function(_retType, _argTypes, argHasDefaults, false); Evaluate = (context, args, thisScope) => { Pb.Assert(null != originalName); Pb.Assert(args.Count == _argTypes.Count, "Internal error: Don't have enough arguments!"); if (context.IsRuntimeErrorSet()) { return(null); } object result; bool pushResult = false; if (null != staticClassDef) { pushResult = context.stack.PushClassCall_StaticOrTypeCheck(typeDef, staticClassDef, true, context); } else { pushResult = context.stack.PushCall(typeDef, originalName, thisScope, false, context); } if (!pushResult) { context.SetRuntimeError(RuntimeErrorType.StackOverflow, "FunctionValue_Script.Evaluate : stack overflow"); return(null); } { // Add name of this function as first variable in function scope. // This condition loosely mirrors the check in Expr_Literal. It's shitty that the code that // runs during TypeCheck is so far removed from this code that runs during Execute. if (null == typeDef.classType) { context.stack.AddVariable(originalName, false, typeDef, this); } // Add argument variables to function scope. if (null != args) { for (int ii = 0; ii < args.Count; ++ii) { context.AddLocalVariable(argNames[ii], valType.argTypes[ii], args[ii]); } } result = _EvaluateInternal(context); } context.stack.PopScope(); if (context.IsRuntimeErrorSet()) { return(null); } if (0 != (context.control.flags & ControlInfo.RETURN)) { result = context.control.result; context.control.result = null; context.control.flags -= ControlInfo.RETURN; } Pb.Assert(0 == context.control.flags); return(result); }; }