more core docs
[io.git] / libs / iovm / io / A4_Exception.io
blob95d8f2af33e657cafc766ea847de991487dd8793
2 Call do(
3 docSlot("description", "Returns a description of the receiver as a String.")
5 description := method(
6 m := self message
7 s := self target type .. " " .. m name
8 s alignLeft(36) .. " " .. m label lastPathComponent .. " " .. m lineNumber
11 delegateTo := method(target, altSender,
12 call relayStopStatus(target doMessage(self message clone setNext, altSender ifNilEval(self sender)))
15 delegateToMethod := method(target, methodName,
16 call relayStopStatus(target doMessage(self message clone setNext setName(methodName), self sender))
19 evalArgs := method(self message argsEvaluatedIn(sender))
20 hasArgs := method(argCount > 0)
21 argCount := method(self message argCount)
24 Message description := method(
25 self name alignLeft(36) .. self label lastPathComponent .. " " .. self lineNumber
28 Scheduler := Object clone do(
29 docSlot("yieldingCoros", "The List of yielding Coroutine objects.")
30 docSlot("setYieldingCoros(aListOfCoros)", "Sets the list of yielding Coroutine objects.")
31 newSlot("yieldingCoros", List clone)
33 docSlot("timers", "The List of active timers.")
34 docSlot("setTimers(aListOfTimers)", "Sets the list of active timers.")
35 newSlot("timers", List clone)
37 docSlot("currentCoroutine", "Returns the currently running coroutine.")
38 currentCoroutine := method(Coroutine currentCoroutine)
41 Coroutine do(
42 docSlot("stackSize", "Stack size allocated for each new coroutine. Coroutines will automatically chain themselves as need if more stack space is required.")
43 newSlot("stackSize", 128000) // PPC needs 128k for current parser
45 docSlot("exception", "Returns the current exception or nil if there is none.")
46 newSlot("exception")
48 docSlot("parentCoroutine", "Returns the parent coroutine this one was chained from or nil if it wasn't chained. When a Coroutine ends, it will attempt to resume it's parent.")
49 newSlot("parentCoroutine")
51 docSlot("runTarget", "The object which the coroutine will send a message to when it starts.")
52 newSlot("runTarget")
54 docSlot("runLocals", "The locals object in whose context the coroutine will send it's run message.")
55 newSlot("runLocals")
57 docSlot("runMessage", "The message to send to the runTarget when the coroutine starts.")
58 newSlot("runMessage")
60 docSlot("result", "The result set when the coroutine ends.")
61 newSlot("result")
63 docSlot("label", "A label slot useful for debugging purposes.")
64 newSlot("label", "")
66 docSlot("inException", "Set to true when processing an exception in the coroutine.")
67 newSlot("inException", false)
69 docSlot("yieldingCoros", "Reference to Scheduler yieldingCoros.")
70 newSlot("yieldingCoros", Scheduler yieldingCoros)
71 debugWriteln := nil
73 label := method(self uniqueId)
74 setLabel := method(s, self label = s .. "_" .. self uniqueId)
76 showYielding := method(s,
77 writeln(" ", label, " ", s)
78 yieldingCoros foreach(v, writeln(" ", v uniqueId))
81 isYielding := method(yieldingCoros contains(self))
83 yield := method(
84 //showYielding("yield")
85 //writeln("Coro ", self uniqueId, " yielding - yieldingCoros = ", yieldingCoros size)
86 if(yieldingCoros isEmpty, return)
87 yieldingCoros append(self)
88 next := yieldingCoros removeFirst
89 if(next == self, return)
90 //writeln(Scheduler currentCoroutine label, " yield - ", next label, " resume")
91 if(next, next resume)
94 resumeLater := method(
95 yieldingCoros remove(self)
96 yieldingCoros atInsert(0, self)
97 //writeln(self label, " resumeLater")
100 pause := method(
101 yieldingCoros remove(self)
102 if(isCurrent,
103 next := yieldingCoros removeFirst
104 if(next,
105 next resume,
106 //Exception raise("Scheduler: nothing left to resume so we are exiting")
107 writeln("Scheduler: nothing left to resume so we are exiting")
108 self showStack
109 System exit
112 yieldingCoros remove(self)
116 yieldCurrentAndResumeSelf := method(
117 //showYielding("yieldCurrentAndResumeSelf")
118 yieldingCoros remove(self)
119 isCurrent ifFalse(resume)
122 pauseCurrentAndResumeSelf := method(
123 //showYielding("pauseCurrentAndResumeSelf")
124 yieldingCoros remove(self)
125 isCurrent ifFalse(resume)
128 typeId := method(self type .. "_0x" .. self uniqueId asString toBase(16))
130 ignoredCoroutineMethodNames := list("setResult", "main", "pauseCurrentAndResumeSelf", "resumeParentCoroutine", "raiseException")
132 callStack := method(
133 stack := ioStack
134 stack selectInPlace(v, Object argIsCall(getSlot("v"))) reverse
135 stack selectInPlace(v,
136 (v target type == "Coroutine" and ignoredCoroutineMethodNames contains(v message name)) not
138 stack foreach(i, v, if(v target type == "Importer" and v message name == "import", stack sliceInPlace(i+1); break) )
139 stack := stack unique
140 stack
143 backTraceString := method(
144 if(Coroutine inException,
145 writeln("\n", exception type, ": ", exception error, "\n\n")
146 writeln("Coroutine Exception loop detected");
147 System exit
149 Coroutine setInException(true)
150 buf := Sequence clone
152 if(getSlot("CGI") != nil and CGI isInWebScript, buf appendSeq("<pre>"))
154 if(exception, buf appendSeq("\n ", exception type, ": ", exception error, "\n"))
156 if(callStack size > 0) then(
157 buf appendSeq(" ---------\n")
159 if(exception and exception caughtMessage,
160 buf appendSeq(" ", exception caughtMessage description, "\n")
163 frames := callStack
165 if(exception and exception originalCall,
166 index := frames indexOf(exception originalCall)
167 if(index,
168 frames sliceInPlace(index)
172 frames foreach(v,
173 buf appendSeq(" ", v description, "\n")
175 buf appendSeq("\n")
176 ) else(
177 buf appendSeq(" ---------\n")
178 m := exception caughtMessage
179 buf appendSeq(" message '" .. m name .. "' in '" .. m label .. "' on line " .. m lineNumber .. "\n")
180 buf appendSeq("\n")
183 Coroutine setInException(false)
187 showStack := method(write(backTraceString))
189 resumeParentCoroutine := method(
190 if(parentCoroutine, parentCoroutine pauseCurrentAndResumeSelf)
193 main := method(
194 setResult(self getSlot("runTarget") doMessage(runMessage, self getSlot("runLocals")))
195 resumeParentCoroutine
196 pause
199 raiseException := method(e,
200 self setException(e)
201 resumeParentCoroutine
205 Object wait := method(s,
206 endDate := Date clone now + Duration clone setSeconds(s)
207 loop(endDate isPast ifTrue(break); yield)
210 Message do(
211 codeOfLength := method(length,
212 c := self code
213 if (c size < length, c, c slice(0, length) .. "...") asMutable replaceSeq("\n", ";")
216 asStackEntry := method(
217 label := label lastPathComponent fileName
218 label alignLeft(19) .. lineNumber asString alignLeft(7) .. name
222 Object do(
223 try := method(
224 coro := Coroutine clone
225 coro setParentCoroutine(Scheduler currentCoroutine)
226 coro setRunTarget(call sender)
227 coro setRunLocals(call sender)
228 coro setRunMessage(call argAt(0))
229 coro run
230 if(coro exception, coro exception, nil)
233 coroFor := method(
234 coro := Coroutine clone
235 coro setRunTarget(call sender)
236 coro setRunLocals(call sender)
237 coro setRunMessage(call argAt(0))
238 coro
241 coroDo := method(
242 coro := Coroutine clone
243 coro setRunTarget(call sender)
244 coro setRunLocals(call sender)
245 coro setRunMessage(call argAt(0))
246 Coroutine yieldingCoros atInsert(0, Scheduler currentCoroutine)
247 coro run
248 coro
251 coroDoLater := method(
252 coro := Coroutine clone
253 coro setRunTarget(self)
254 coro setRunLocals(call sender)
255 coro setRunMessage(call argAt(0))
256 Coroutine yieldingCoros atInsert(0, coro)
257 coro
260 coroWith := method(
261 coro := Coroutine clone
262 coro setRunTarget(self)
263 coro setRunLocals(call sender)
264 coro setRunMessage(call argAt(0))
265 coro
268 currentCoro := method(Coroutine currentCoroutine)
271 nil do(
272 catch := nil
273 pass := nil
276 Protos Exception do(
277 type := "Exception"
278 newSlot("error")
279 newSlot("coroutine")
280 newSlot("caughtMessage")
281 newSlot("nestedException")
282 newSlot("originalCall")
284 raise := method(error, nestedException,
285 coro := Scheduler currentCoroutine
286 coro raiseException(self clone setError(error) setCoroutine(coro) setNestedException(nestedException))
289 raiseFrom := method(originalCall, error, nestedException,
290 coro := Scheduler currentCoroutine
291 coro raiseException(self clone setError(error) setCoroutine(coro) setNestedException(nestedException) setOriginalCall(originalCall))
294 catch := method(exceptionProto,
295 if (self isKindOf(exceptionProto), call evalArgAt(1); nil, self)
298 pass := method(Scheduler currentCoroutine raiseException(self))
300 showStack := method(
301 coroutine showStack
302 if(nestedException,
303 writeln("Nested Exception: '", nestedException, "'")
304 nestedException showStack