--@Name: "TryCatch" --@Version: 1.01 --@Author: Luke Wigley (luke@meccamedialight.com.au) --@LastUpdate: 13/10/04 --@Description -- A script that tries to allow a "try-catch-finally' mechanism for lingo. Start a "try" block -- by calling the #new handler on this script to create a new instance. By default, if an error -- occurs, this script will call the #Catch method of the originating script (you can over-ride -- the method names). -- -- You can explicitly end a tryblock by calling the EndTry() method. If you do not explicitly -- end it, it will automatically end when Director's call stack completes and a timeout that -- is automatically created gets a chance to kill the tryCatch instance (note - it would be -- better to explicitly end the try block since other handlers may be activated before the -- timeout gets a chance to kill the block) --@History -- v.1.01: Removed the errant abort commands; saved the timeout instance into a tempory var -- (to avoid the timeout bug that occurs when you do not save the returned instance) -- v.1.00: First go. -- Instance properties property TargetObj, CatchMethod, FinallyMethod -- Static Class Property property CStack on new (me, aTargetObj, aCatchMethod, aFinallyMethod) --@ Description: Create a new instance, appending it to the class 'Stack' list --* aTargetObj: The object attempting the try block --* CatchMethod: The "catch" method (default is #Catch) --* FinallyMethod: The "Finally" method (default is #Catch) TargetObj = aTargetObj if aCatchMethod.ilk = #symbol then CatchMethod = aCatchMethod else CatchMethod = #Catch if aFinallyMethod.ilk = #symbol then FinallyMethod = aFinallyMethod else FinallyMethod = #Finally me.script._appendToStack(me, TargetObj) the alertHook = me end on alertHook me, err, msg, errType --@ Description: Called by director, passing what little information that it does. -- Note - messages triggered by the alert function are allowed to pass -- (its assumed that these are deliberate) --* Err: The error (not very useful) --* Msg: The error description --* errType [#Symbol]: Who triggered the alert if errType = #Alert then return 0 else call(CatchMethod, [TargetObj], err, msg) if FinallyMethod.ilk = #Symbol then call(FinallyMethod, [TargetObj]) me.script._popStack() end if return 1 end on endTry (SO, whoWasTrying) --@ Explicitly end a try (if not explictly removed, then the -- the CStack will be cleared when the current handler-stack is -- complete and the timeout triggers the cleanup --* whoWasTrying: the object that initiated the try (optional) -- find the instance CStack = SO.CStack if NOT voidP(CStack) then mx = CStack.count if mx > 0 then if voidP(whoWasTrying) then TC = CStack[mx][1] this = CStack[mx][2] finalMethodToCall = TC.FinallyMethod if finalMethodToCall.ilk = #Symbol then call(finalMethodToCall, [this]) SO._popStack(this) else repeat with i = mx down to 1 this = CStack[i][2] if this = whoWasTrying then TC = CStack[i][1] -- ShowObjProps(TC) finalMethodToCall = TC.FinallyMethod if finalMethodToCall.ilk = #Symbol then call(finalMethodToCall, [this]) SO._popStack(this) end if end repeat end if end if end if end -- PRIVATE METHODS --------------------- on _appendToStack(SO, TC, obj) -- append the object to the CStack CStack = SO.CStack if voidP(CStack) then SO._Debug("creating new Stack") SO.CStack = [] end if SO.CStack.append([TC, obj]) tmp = timeout(SO.string).new(1, #_ClearStack, SO) SO._Debug("Opened new TryCatch instance. TryCatch.Class has " & SO.CStack.count & " entries in the stack") end on _popStack (SO, obj) -- pop the last object from the CStack CStack = SO.CStack if voidP(CStack) then SO.CStack = [] mx = SO.CStack.count if mx then if voidP(obj) then SO.CStack.deleteAt(mx) else if (obj = SO.CStack[mx][2]) then SO.CStack.deleteAt(mx) end if if SO.CStack.count = 0 then the alertHook = 0 else the alertHook = SO.CStack[SO.CStack.count ][1] SO._Debug("Removed TryCatch instance. TryCatch.Class has " & SO.CStack.count & " entries in the stack") end on _ClearStack (SO, aTimeOut) -- the last callstack has completed, so remove -- any tryCatches from CStack list aTimeOut.forget() CStack = SO.CStack if voidP(CStack) then return mx = SO.CStack.count if mx then SO._Debug("Auto clearing stack") SO.CStack.deleteAll() end if end on _Debug(me, msg) if member("Debugger").type = #Script then call(#mLog, [script("Debugger")], msg, me, #Minor) else put msg end