LEOScript
IntroductionA script is a reference-counted data type that collects all the methods (functions and commands) of an object. After you create a script and populate it with handlers, it is intended to be immutable. If you want to remove a handler or otherwise change a script afterwards, create a new script. This way, if a script is changed, any still executing instances of that script can finish on their own. This is especially needed for scripts that modify themselves. For similar reasons, we reference the owning object using a LEOObjectID and LEOObjectSeed, so a script can delete the object owning it and still finish executing. Functions
LEOHandlerAddInstructionvoid LEOHandlerAddInstruction( LEOHandler *inHandler, LEOInstructionID instructionID, uint16_t param1, uint32_t param2 ); DiscussionAdd an instruction with the given instruction ID and parameters to a handler. Use this only when initially setting up a script and parsing/compiling bytecode into it. Pointers to instructions inside a handler may not stay valid after a call to this. See Also LEOHandlerAddVariableNameMappingvoid LEOHandlerAddVariableNameMapping( LEOHandler *inHandler, const char *inName, const char *inRealName, size_t inBPRelativeAddress ); Parameters
DiscussionAdd an entry to this handler so we can display a name for this variable. See Also LEOHandlerFindVariableByAddressvoid LEOHandlerFindVariableByAddress( LEOHandler *inHandler, long bpRelativeAddress, char **outName, char **outRealName, LEOContext *inContext ); DiscussionFind a variable's name in a handler based on its basePointer-relative offset. See Also LEOHandlerFindVariableByNamelong LEOHandlerFindVariableByName( LEOHandler *inHandler, const char *inName ); DiscussionFind a variable's basePointer-relative offset based on its real name. See Also LEOScriptAddBreakpointAtLinesize_t LEOScriptAddBreakpointAtLine( LEOScript *inScript, size_t inLineNumber ); DiscussionAdd a line number to our list of breakpoints. It is the responsibility of the debugger that you use (e.g. LEODebugger.h or LEORemoteDebugger.h) to look at each LINE_MARKER_INSTR instruction and verify whether it matches one of these lines, and to trigger accordingly. This can be used to e.g. implement clicking in the gutter of a script editor window to set a breakpoint. See Also LEOScriptAddCommandHandlerWithIDLEOHandler* LEOScriptAddCommandHandlerWithID( LEOScript *inScript, LEOHandlerID inHandlerName ); // Invalidates all LEOHandler pointers anyone may have into this script. DiscussionCreate a new command handler with the given handler ID and return a pointer to it. Use this only when initially setting up a script and parsing/compiling bytecode into it. Whenever you add a new handler to a script, all pointers to existing LEOHandlers in the script may be invalidated, including the ones previously returned by this call. See Also LEOScriptAddFunctionHandlerWithIDLEOHandler* LEOScriptAddFunctionHandlerWithID( LEOScript *inScript, LEOHandlerID inHandlerName ); // Invalidates all LEOHandler pointers anyone may have into this script. DiscussionCreate a new function handler with the given handler ID and return a pointer to it. Use this only when initially setting up a script and parsing/compiling bytecode into it. Whenever you add a new handler to a script, all pointers to existing LEOHandlers in the script may be invalidated, including the ones previously returned by this call. See Also LEOScriptAddStringsize_t LEOScriptAddString( LEOScript *inScript, const char *inString ); ParametersReturn Valuethe index into the strings table at which the string can now be found. DiscussionAdd a string to our strings table, so you can push it on the stack using the PUSH_STR_FROM_TABLE_INSTR instruction and operate on it in the script. See Also LEOScriptAddSyntaxErrorsize_t LEOScriptAddSyntaxError( LEOScript *inScript, const char *inErrMsg, uint16_t inFileID, size_t inErrorLine, size_t inErrorOffset ); Parameters
Return Valuethe index into the syntax error table at which the string can now be found. DiscussionAdd an error message and position information to our strings table, so it can be reported using the PARSE_ERROR_INSTR instruction. See Also LEOScriptCreateForOwnerLEOScript* LEOScriptCreateForOwner( LEOObjectID ownerObject, LEOObjectSeed ownerSeed, LEOGetParentScriptFuncPtr inGetParentScriptFunc ); // Gives referenceCount of 1. DiscussionCreates a script referencing the given owner. The LEOScript* is reference- counted and its reference count is set to 1, so when you're done with it, you must release it. When a script is executing, it should usually be retained so that deleting its owner doesn't pull out the rug from under the interpreter. See Also LEOScriptFindCommandHandlerWithIDLEOHandler* LEOScriptFindCommandHandlerWithID( LEOScript *inScript, LEOHandlerID inHandlerName ); DiscussionReturn a pointer to a command handler with the given handler ID (i.e. handler name). Returns NULL if no such handler exists. See Also LEOScriptFindFunctionHandlerWithIDLEOHandler* LEOScriptFindFunctionHandlerWithID( LEOScript *inScript, LEOHandlerID inHandlerName ); DiscussionReturn a pointer to a function handler with the given handler ID (i.e. handler name). Returns NULL if no such handler exists. See Also LEOScriptHasBreakpointAtLinebool LEOScriptHasBreakpointAtLine( LEOScript *inScript, size_t inLineNumber ); DiscussionReturns TRUE if a script has been told a breakpoint exists at the given 1-based line number, FALSE otherwise. See Also LEOScriptReleasevoid LEOScriptRelease( LEOScript *inScript ); // Subtracts 1 from referenceCount. If it hits 0, disposes of inScript. DiscussionGive up ownership of the given script. You acquire ownership by either creating the script, or by retaining it. Giving up ownership decreases its reference count by 1. When the last owner releases the object (and the reference count reaches 0), the script is freed. See Also LEOScriptRemoveAllBreakpointsvoid LEOScriptRemoveAllBreakpoints( LEOScript *inScript ); DiscussionRemove all breakpoint for lines in this script to undo what any calls to LEOScriptAddBreakpointAtLine did. See Also LEOScriptRemoveBreakpointAtLinevoid LEOScriptRemoveBreakpointAtLine( LEOScript *inScript, size_t inLineNumber ); DiscussionRemove a breakpoint from a given line, to undo what LEOScriptAddBreakpointAtLine did. See Also LEOScriptRetainLEOScript* LEOScriptRetain( LEOScript *inScript ); // Adds 1 to referenceCount. Returns inScript. Return ValueReturns inScript so you can assign it to a variable in a struct, or a global, or whatever makes sense. DiscussionAcquire ownership of the given script, so that when the current owner releases it the object still stays around for your use. Increases the reference count by 1. See Also TypedefsLEOGetParentScriptFuncPtr// ----------------------------------------------------------------------------- typedef struct LEOScript* ( *LEOGetParentScriptFuncPtr)( struct LEOScript *inScript, struct LEOContext *inContext, void *inParam ); ParametersDiscussionOnly the host application can know where in its hierarchy a script resides, and to which script unhandled messages should be forwarded. It can provide a function with this signature to let the interpreter look up the next script in the hierarchy. See Also LEOHandler// ----------------------------------------------------------------------------- typedef struct LEOHandler { LEOHandlerID handlerName; // Unique ID of handlers with this name. size_t numInstructions; LEOInstruction *instructions; size_t numVariables; LEOVariableNameMapping *varNames; } LEOHandler; FieldsDiscussionEvery method is represented by a struct like this: See Also LEOParseErrorEntry// ----------------------------------------------------------------------------- typedef struct LEOParseErrorEntry { char *errMsg; size_t errorLine; size_t errorOffset; uint16_t fileID; } LEOParseErrorEntry; FieldsDiscussionWe postpone the reporting of parse errors until someone actually attempts to run a script and try to muddle through parsing it until then. These entries hold the error position and message so we can report it then. The advantage of this is that if e.g. a mouseUp handler has a typo, but the mouseWithin handler in the same script is fine, at least the user will not get an error message whenever they move the mouse. Also, if both have a typo but the mouseUp handler comes first, you won't get the error message for the mouseUp handler on mouseWithin. Errors are reported where they occur, as you would expect from an interpreter. See Also LEOScript// ----------------------------------------------------------------------------- typedef struct LEOScript { size_t referenceCount; LEOObjectID ownerObject; // Deletion-safe reference to owning object. LEOObjectSeed ownerObjectSeed; size_t numFunctions; LEOHandler *functions; size_t numCommands; LEOHandler *commands; size_t numStrings; // Number of items in stringsTable. char **strings; // List of string constants in this script, which we can load. LEOGetParentScriptFuncPtr GetParentScript; size_t numParseErrors; // Number of elements in parseErrors array. LEOParseErrorEntry *parseErrors; // List of errors for the PARSE_ERROR_INSTR instruction to refer to. size_t numBreakpointLines; // Number of elements in breakpointLines array. size_t *breakpointLines; // List of line numbers where the user set a breakpoint. } LEOScript; Fields
DiscussionEvery object has a script, which is a grouping of functions and commands: See Also
LEOVariableNameMapping// ----------------------------------------------------------------------------- typedef struct LEOVariableNameMapping { char variableName[DBG_VAR_NAME_SIZE]; char realVariableName[DBG_VAR_NAME_SIZE]; // Name as the user sees it. long bpRelativeAddress; } LEOVariableNameMapping; Fields
DiscussionThis struct is used to keep information for the debugger and for error display about each local variable, and each global imported into local scope by adding a local variable containing a reference to the global. See Also |