3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
6 docDescription("nil is a singleton object that is used as a placeholder and to mean false in Io.")
10 docSlot("clone", "returns self since nil is a singleton.")
13 docSlot("and(expression)", "Returns nil without evaluating expression.")
16 elseif := Object getSlot("if")
18 docSlot("then(expression)", "Returns nil without evaluating expression.")
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.")
36 docSlot("ifNil(expression)", "Evaluates message.")
41 // if(a
== 1) then(b
) elseif(b
== c
) then(d
) else(f
)
42 // (a
== 1) ifTrue(b
) ifFalse(c
)
45 // docSlot("then", "Evaluates the argument and returns nil.")
46 then := Object getSlot("evalArgAndReturnNil")
48 // docSlot("elseif", "Does not eval argument and returns true.")
51 // docSlot("else", "Does not eval argument and returns 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.")
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.")
66 // docSlot("asString", "Returns true.")
69 // docSlot("asSimpleString", "Returns true.")
70 asSimpleString
:= "true"
72 // docSlot("not", "Does not eval argument and returns false.")
75 // docSlot("clone", "Returns self.")
82 ifFalse := Object getSlot("evalArgAndReturnSelf")
83 elseif := Object getSlot("if")
84 else := Object getSlot("evalArgAndReturnNil")
86 setSlot("or", Object getSlot("evalArg"))
90 asSimpleString
:= "false"
99 ifNonNil
:= Object getSlot("thisContext")
100 ifNil := Object getSlot("evalArgAndReturnSelf")
102 ifNilEval
:= Object getSlot("evalArg")
103 ifNonNilEval
:= Object getSlot("thisContext")
107 asSimpleString
:= type
109 setSlot("and", false
)
110 setSlot("or", Object getSlot("evalArg"))
117 // I think non
-local returns can eliminate all this stopStatus stuff
120 relayStopStatus
:= method(
121 ss
:= stopStatus(r
:= call
evalArgAt(0))
122 call
sender call
setStopStatus(ss
)
126 resetStopStatus
:= method(
127 setStopStatus(Normal
)
137 return := method(arg
,
138 call
setStopStatus(Return
)
143 Eol
appendProto(Normal
)
144 Continue
appendProto(Normal
) do(
148 Break
appendProto(Normal
) do(
153 Return
appendProto(Normal
) do(
157 return := method(arg
,
158 call
setStopStatus(Return
)
159 call
sender call
setStopStatus(Return
)
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"))
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
,
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
203 getSlot("self") hasLocalSlot(n
) or(getSlot("self") ancestorWithSlot(n
) != nil
)
207 if(getSlot("self") hasLocalSlot("docs") not
,
208 getSlot("self") docs
:= Object clone do(slots
:= Object clone)
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")
239 getSlot("self") doMessage(call
argAt(0))
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,
265 slotDescriptions keys sortInPlace
foreach(k
,
266 s
appendSeq(" ", k
alignLeft(16), " = ", slotDescriptions
at(k
), "\n")
276 slotSummary
:= method(keyword
,
277 if(getSlot("self") type == "Block" and getSlot("self") == getSlot("Block"),
278 return getSlot("self") asSimpleString
281 s
appendSeq(" ", getSlot("self") asSimpleString
, ":\n")
282 slotDescriptions
:= slotDescriptionMap
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
))
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
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:
326 MyObject test // performs test
327 MyObject ?test // performs test if MyObject has a slot named test
329 The search for the slot only follows the receivers proto chain.
335 if (self getSlot(m name
) != nil
,
336 call
relayStopStatus(m
doInContext(self, call
sender))
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)
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:
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
365 setSlot("super", method(
366 senderSlotContext
:= call
sender call slotContext
368 m
ifNil(Exception raise("Object super requires an argument"))
369 senderSlotContext
ifNil(Exception raise("Object super called outside of block context"))
371 ancestor
:= senderSlotContext
ancestorWithSlot(slotName
)
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
)
386 """Send the message used to activate the current method to the Object's proto.
389 Dog := Mammal clone do(
395 calling Dog init will send an init method to Mammal, but using the Dog's context.
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
403 ancestor
:= senderSlotContext
ancestorWithSlot(slotName
)
405 if(ancestor
isIdenticalTo(nil
),
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
)
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))
437 if(call argCount
== 1,
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
)
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
,
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)
471 hour := Date hour switch(
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")