more core docs
[io.git] / libs / iovm / io / A2_Object.io
blob2dfc82cd51c31881ced01db3a505d3bee9368736
1 /*
2 nil ioDoc(
3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
5 docObject("nil")
6 docDescription("nil is a singleton object that is used as a placeholder and to mean false in Io.")
9 nil do(
10 docSlot("clone", "returns self since nil is a singleton.")
11 clone := nil
13 docSlot("and(expression)", "Returns nil without evaluating expression.")
14 setSlot("and", nil)
16 elseif := Object getSlot("if")
18 docSlot("then(expression)", "Returns nil without evaluating expression.")
19 setSlot("then", nil)
21 docSlot("else(expression)", "Returns nil without evaluating expression.")
22 setSlot("else", method(v, v))
24 docSlot("or(anObject)", "Returns anObject if anObject is not nil. Otherwise returns nil.")
25 setSlot("or", method(v, if(v, v, nil)))
27 docSlot("print", "Prints 'nil'. Returns self.")
28 print := method(write("nil"))
30 setSlot("==", method(v, self isIdenticalTo(v)))
31 setSlot("!=", method(v, self isIdenticalTo(v) not))
33 docSlot("isNil", "Returns Lobby.")
34 isNil := Lobby
36 docSlot("ifNil(expression)", "Evaluates message.")
37 ifNil := method(v, v)
41 // if(a == 1) then(b) elseif(b == c) then(d) else(f)
42 // (a == 1) ifTrue(b) ifFalse(c)
44 true do(
45 // docSlot("then", "Evaluates the argument and returns nil.")
46 then := Object getSlot("evalArgAndReturnNil")
48 // docSlot("elseif", "Does not eval argument and returns true.")
49 elseif := true
51 // docSlot("else", "Does not eval argument and returns true.")
52 else := true
54 // docSlot("ifTrue", "Evaluates the argument and returns self.")
55 ifTrue := Object getSlot("evalArgAndReturnSelf")
57 // docSlot("ifFalse", "Does not eval argument and returns true.")
58 ifFalse := true
60 // docSlot("and", "Evaluates the argument and returns the result.")
61 setSlot("and", Object getSlot("evalArg"))
63 // docSlot("or", "Does not eval argument and returns true.")
64 setSlot("or", true)
66 // docSlot("asString", "Returns true.")
67 asString := "true"
69 // docSlot("asSimpleString", "Returns true.")
70 asSimpleString := "true"
72 // docSlot("not", "Does not eval argument and returns false.")
73 not := false
75 // docSlot("clone", "Returns self.")
76 clone := true
79 false do(
80 then := false
81 ifTrue := false
82 ifFalse := Object getSlot("evalArgAndReturnSelf")
83 elseif := Object getSlot("if")
84 else := Object getSlot("evalArgAndReturnNil")
85 setSlot("and", false)
86 setSlot("or", Object getSlot("evalArg"))
88 type := "false"
89 asString := "false"
90 asSimpleString := "false"
91 not := true
92 clone := false
95 nil do(
96 not := true
97 isNil := true
99 ifNonNil := Object getSlot("thisContext")
100 ifNil := Object getSlot("evalArgAndReturnSelf")
102 ifNilEval := Object getSlot("evalArg")
103 ifNonNilEval := Object getSlot("thisContext")
105 type := "nil"
106 asString := type
107 asSimpleString := type
109 setSlot("and", false)
110 setSlot("or", Object getSlot("evalArg"))
111 then := nil
112 else := nil
113 elseif := nil
114 clone := nil
117 // I think non-local returns can eliminate all this stopStatus stuff
119 Call do(
120 relayStopStatus := method(
121 ss := stopStatus(r := call evalArgAt(0))
122 call sender call setStopStatus(ss)
123 getSlot("r")
126 resetStopStatus := method(
127 setStopStatus(Normal)
131 Normal do(
132 stopLooping := false
133 isReturn := false
134 isBreak := false
135 isContinue := false
137 return := method(arg,
138 call setStopStatus(Return)
139 getSlot("arg")
143 Eol appendProto(Normal)
144 Continue appendProto(Normal) do(
145 isContinue := true
148 Break appendProto(Normal) do(
149 stopLooping := true
150 isBreak := true
153 Return appendProto(Normal) do(
154 stopLooping := true
155 isReturn := true
157 return := method(arg,
158 call setStopStatus(Return)
159 call sender call setStopStatus(Return)
160 getSlot("arg")
164 Object do(
165 not := nil
167 isNil := false
169 ifNil := Object getSlot("thisContext")
170 ifNonNil := Object getSlot("evalArgAndReturnSelf")
172 ifNonNilEval := Object getSlot("evalArg")
173 ifNilEval := Object getSlot("thisContext")
175 setSlot("and", Object getSlot("evalArg"))
176 setSlot("or", true)
179 Sequence do(
180 makeFirstCharacterLowercase := method(
181 if(self size > 0, self atPut(0, self at(0) asLowercase))
184 makeFirstCharacterUppercase := method(
185 if(self size > 0, self atPut(0, self at(0) asUppercase))
188 slicesBetween := method(startSeq, endSeq,
189 chunks := List clone
190 lastIndex := 0
191 while (startIndex := self findSeq(startSeq, lastIndex),
192 endIndex := self findSeq(endSeq, startIndex + startSeq size)
193 endIndex ifNil(break)
194 chunks append(self slice(startIndex + startSeq size, endIndex))
195 lastIndex := endIndex + endSeq size
197 chunks
201 Object do(
202 hasSlot := method(n,
203 getSlot("self") hasLocalSlot(n) or(getSlot("self") ancestorWithSlot(n) != nil)
206 docsSlot := method(
207 if(getSlot("self") hasLocalSlot("docs") not,
208 getSlot("self") docs := Object clone do(slots := Object clone)
210 getSlot("self") docs
214 docSlot := method(k, v,
215 entry := Object clone
216 entry description := v asSymbol
217 if (k containsSeq("("),
218 entry args := k afterSeq("(") beforeSeq(")") split(",") map(strip)
220 getSlot("self") docsSlot slots setSlot(k beforeSeq("("), entry)
223 docCopyright := method(v,
224 k := call message name asMutable removePrefix("doc") makeFirstCharacterLowercase
225 getSlot("self") docsSlot setSlot(k, v)
227 //docCopyright := nil // turnOffDocs
229 docLicense := getSlot("docCopyright")
230 docObject := getSlot("docCopyright")
231 docDescription := getSlot("docCopyright")
232 docCredits := getSlot("docCopyright")
233 docInclude := getSlot("docCopyright")
234 docDependsOn := getSlot("docCopyright")
235 docCategory := getSlot("docCopyright")
237 ioDoc := method(
238 if(call argAt(0),
239 getSlot("self") doMessage(call argAt(0))
243 //ioDoc := nil
245 docSlot("list(...)", "Returns a List containing the arguments.")
246 list := method(call message argsEvaluatedIn(call sender))
248 docSlot("..(arg)", ".. is an alias for: method(arg, self asString append(arg asString))")
249 setSlot("..", method(arg, getSlot("self") asString .. arg asString))
251 Map addKeysAndValues := method(keys, values, keys foreach(i, k, self atPut(k, values at(i))); self)
253 slotDescriptionMap := method(
254 slotNames := getSlot("self") slotNames sort
255 slotDescs := slotNames map(name, getSlot("self") getSlot(name) asSimpleString)
256 Map clone addKeysAndValues(slotNames, slotDescs)
259 apropos := method(keyword,
260 Protos Core foreachSlot(name, p,
261 slotDescriptions := getSlot("p") slotDescriptionMap ?select(k, v, k asMutable lowercase containsSeq(keyword))
263 if(slotDescriptions and slotDescriptions size > 0,
264 s := Sequence clone
265 slotDescriptions keys sortInPlace foreach(k,
266 s appendSeq(" ", k alignLeft(16), " = ", slotDescriptions at(k), "\n")
269 writeln(name)
270 writeln(s)
276 slotSummary := method(keyword,
277 if(getSlot("self") type == "Block" and getSlot("self") == getSlot("Block"),
278 return getSlot("self") asSimpleString
280 s := Sequence clone
281 s appendSeq(" ", getSlot("self") asSimpleString, ":\n")
282 slotDescriptions := slotDescriptionMap
283 if(keyword,
284 slotDescriptions = slotDescriptions select(k, v, k asMutable lowercase containsSeq(keyword))
286 slotDescriptions keys sortInPlace foreach(k,
287 s appendSeq(" ", k alignLeft(16), " = ", slotDescriptions at(k), "\n")
292 asString := getSlot("slotSummary")
294 asSimpleString := method(getSlot("self") type .. "_" .. getSlot("self") uniqueHexId)
296 docSlot("newSlot(slotName, aValue)",
297 """Creates a getter and setter for the slot with the name slotName
298 and sets it's default the value aValue. Returns self. For example,
299 newSlot("foo", 1) would create slot named foo with the value 1 as well as a setter method setFoo().""")
301 newSlot := method(name, value, doc,
302 getSlot("self") setSlot(name, getSlot("value"))
303 getSlot("self") setSlot("set" .. name asCapitalized,
304 doString("method(" .. name .. " = call evalArgAt(0); self)"))
305 if(doc, getSlot("self") docSlot(name, doc))
306 value
309 docSlot("launchFile(pathString)",
310 "Eval file at pathString as if from the command line in it's folder.")
312 launchFile := method(path, args,
313 args ifNil(args = List clone)
314 Lobby launchPath := path pathComponent
315 Directory setCurrentWorkingDirectory(Lobby launchPath)
316 System launchScript = path
317 self doFile(path)
320 docSlot("println", "Same as print, but also prints a new line. Returns self.")
321 println := method(getSlot("self") print; write("\n"); self)
323 docSlot("?(aMessage)", """
324 description: Sends the message aMessage to the receiver if it can respond to it. Example:
325 <pre>
326 MyObject test // performs test
327 MyObject ?test // performs test if MyObject has a slot named test
328 </pre>
329 The search for the slot only follows the receivers proto chain.
330 """)
332 setSlot("?",
333 method(
334 m := call argAt(0)
335 if (self getSlot(m name) != nil,
336 call relayStopStatus(m doInContext(self, call sender))
343 docSlot("ancestors",
344 "Returns a list of all of the receiver's ancestors as found by recursively following the protos links.")
346 ancestors := method(a,
347 if(a, if(a detect(x, x isIdenticalTo(self)), return a), a = List clone)
348 a append(self)
349 self protos foreach(ancestors(a))
353 docSlot("isKindOf(anObject)", "Returns true if anObject is in the receiver's ancestors.")
355 isKindOf := method(anObject, getSlot("self") ancestors contains(getSlot("anObject")))
357 docSlot("super(aMessage)",
358 """Sends the message aMessage to the receiver's proto with the context of self. Example:
359 <pre>
360 self test(1, 2) // performs test(1, 2) on self
361 super(test(1, 2)) // performs test(1, 2) on self proto but with the context of self
362 </pre>
363 """)
365 setSlot("super", method(
366 senderSlotContext := call sender call slotContext
367 m := call argAt(0)
368 m ifNil(Exception raise("Object super requires an argument"))
369 senderSlotContext ifNil(Exception raise("Object super called outside of block context"))
370 slotName := m name
371 ancestor := senderSlotContext ancestorWithSlot(slotName)
372 if(ancestor == nil,
373 slotName = "forward"
374 ancestor = senderSlotContext ancestorWithSlot(slotName)
376 if(ancestor isIdenticalTo(senderSlotContext), Exception raise("Object super slot " .. slotName .. " not found"))
377 b := ancestor getSlot(slotName)
378 if(getSlot("b") isActivatable == false,
381 getSlot("b") performOn(call sender call target, call sender, m, ancestor)
385 docSlot("resend",
386 """Send the message used to activate the current method to the Object's proto.
387 For example;
388 <pre>
389 Dog := Mammal clone do(
390 init := method(
391 resend
394 </pre>
395 calling Dog init will send an init method to Mammal, but using the Dog's context.
396 """)
398 setSlot("resend", method(
399 senderSlotContext := call sender call slotContext
400 senderSlotContext ifNil(Exception raise("Object resend called outside of block context"))
401 m := call sender call message
402 slotName := m name
403 ancestor := senderSlotContext ancestorWithSlot(slotName)
405 if(ancestor isIdenticalTo(nil),
406 slotName = "forward"
407 ancestor = senderSlotContext ancestorWithSlot(slotName)
410 if(ancestor isIdenticalTo(senderSlotContext),
411 Exception raise("Object resend slot " .. slotName .. " not found")
414 b := ancestor getSlot(slotName)
415 if(getSlot("b") != nil,
416 getSlot("b") performOn(call sender getSlot("self"), call sender call sender, m, ancestor)
418 getSlot("b")
423 docSlot("list(...)", "Returns a List containing the arguments.")
424 list := method(call message argsEvaluatedIn(call sender))
426 Object print := method(write(getSlot("self") asString); getSlot("self"))
428 docSlot("println", "Same as print, but also prints a new line. Returns self.")
429 println := method(getSlot("self") print; write("\n"); getSlot("self"))
431 docSlot("in(aList)", "Same as: aList contains(self)")
432 in := method(aList, aList contains(self))
434 uniqueHexId := method("0x" .. getSlot("self") uniqueId asString toBase(16))
436 lazySlot := method(
437 if(call argCount == 1,
438 m := method(
439 self setSlot(call message name, nil)
442 args := getSlot("m") message next arguments
443 args atPut(1, call argAt(0) clone)
444 getSlot("m") message next setArguments(args)
446 getSlot("m") clone
448 name := call evalArgAt(0)
449 m := ("self setSlot(\"" .. name .. "\", " .. call argAt(1) code .. ")") asMessage
450 self setSlot(name, method() setMessage(m))
455 foreachSlot := method(
456 self slotNames sort foreach(n,
457 call sender setSlot(call message argAt(0) name, n)
458 call sender setSlot(call message argAt(1) name, getSlot("self") getSlot(n))
459 r := call relayStopStatus(call evalArgAt(2))
460 if(call stopStatus isReturn, return getSlot("r"))
461 if(call stopStatus stopLooping,
462 call resetStopStatus
463 break
468 docSlot("switch(<key1>, <expression1>, <key2>, <expression2>, ...)", """
469 Execute an expression depending on the value of the caller. (This is an equivalent to C switch/case)
470 <pre>
471 hour := Date hour switch(
472 12, "midday",
473 0, "midnight",
474 17, "teatime",
475 Date hour asString
477 </pre>
478 """)
479 switch := method(
480 for(couple, 0, call argCount - 2, 2,
481 if(call evalArgAt(couple) == self,
482 return call relayStopStatus(call evalArgAt(couple + 1))
485 if(call argCount isOdd,
486 call relayStopStatus(call evalArgAt(call argCount - 1))
492 docSlot("isLaunchScript", "Returns true if the current file was run on the command line. Io's version of Python's __file__ == \"__main__\"")
493 isLaunchScript := method(
494 call message label == System launchScript
497 docSlot("doRelativeFile(pathString)",
498 "Evaluates the File in the context of the receiver. Returns the result. pathString is relative to the file calling doRelativeFile. (Duplicate of relativeDoFile)")
499 doRelativeFile := method(path,
500 self doFile(Path with(call message label pathComponent, path))
503 docSlot("relativeDoFile(pathString)",
504 "Evaluates the File in the context of the receiver. Returns the result. pathString is relative to the file calling doRelativeFile. (Duplicate of doRelativeFile)")
505 relativeDoFile := getSlot("doRelativeFile")