make doc update
[io.git] / libs / iovm / io / A2_Object.io
blob551c52a9a1741ed8b509891bbe4d2d898d886857
1 /*
2 //metadoc nil description nil is a singleton object that is used as a placeholder and to mean false in Io.")
4 nil do(
5 //doc nil clone returns self since nil is a singleton.
6 clone := nil
8 //doc nil and(expression) Returns nil without evaluating expression.
9 setSlot("and", nil)
11 elseif := Object getSlot("if")
13 //doc nil then(expression) Returns nil without evaluating expression.
14 setSlot("then", nil)
16 //doc nil else(expression) Returns nil without evaluating expression.
17 setSlot("else", method(v, v))
19 //doc nil or(anObject) Returns anObject if anObject is not nil. Otherwise returns nil.
20 setSlot("or", method(v, if(v, v, nil)))
22 //doc nil print Prints 'nil'. Returns self.
23 print := method(write("nil"))
25 setSlot("==", method(v, self isIdenticalTo(v)))
26 setSlot("!=", method(v, self isIdenticalTo(v) not))
28 //doc nil isNil Returns Lobby.
29 isNil := Lobby
31 //doc nil ifNil(expression) Evaluates message.
32 ifNil := method(v, v)
36 // if(a == 1) then(b) elseif(b == c) then(d) else(f)
37 // (a == 1) ifTrue(b) ifFalse(c)
39 true do(
40 //doc true then Evaluates the argument and returns nil.
41 then := Object getSlot("evalArgAndReturnNil")
43 //doc true elseif Does not eval argument and returns true.
44 elseif := true
46 //doc true else Does not eval argument and returns true.
47 else := true
49 //doc true ifTrue Evaluates the argument and returns self.
50 ifTrue := Object getSlot("evalArgAndReturnSelf")
52 //doc true ifFalse Does not eval argument and returns true.
53 ifFalse := true
55 //doc true and Evaluates the argument and returns the result.
56 setSlot("and", Object getSlot("evalArg"))
58 //doc true or Does not eval argument and returns true.
59 setSlot("or", true)
61 //doc true asString Returns true.
62 asString := "true"
64 //doc true asSimpleString Returns true.
65 asSimpleString := "true"
67 //doc true not Does not eval argument and returns false.
68 not := false
70 //doc true clone Returns self.
71 clone := true
74 false do(
75 then := false
76 ifTrue := false
77 ifFalse := Object getSlot("evalArgAndReturnSelf")
78 elseif := Object getSlot("if")
79 else := Object getSlot("evalArgAndReturnNil")
80 setSlot("and", false)
81 setSlot("or", Object getSlot("evalArg"))
83 type := "false"
84 asString := "false"
85 asSimpleString := "false"
86 not := true
87 clone := false
90 nil do(
91 not := true
92 isNil := true
94 ifNonNil := Object getSlot("thisContext")
95 ifNil := Object getSlot("evalArgAndReturnSelf")
97 ifNilEval := Object getSlot("evalArg")
98 ifNonNilEval := Object getSlot("thisContext")
100 type := "nil"
101 asString := type
102 asSimpleString := type
104 setSlot("and", false)
105 setSlot("or", Object getSlot("evalArg"))
106 then := nil
107 else := nil
108 elseif := nil
109 clone := nil
112 // I think non-local returns can eliminate all this stopStatus stuff
114 Call do(
115 relayStopStatus := method(
116 ss := stopStatus(r := call evalArgAt(0))
117 call sender call setStopStatus(ss)
118 getSlot("r")
121 resetStopStatus := method(
122 setStopStatus(Normal)
126 Normal do(
127 stopLooping := false
128 isReturn := false
129 isBreak := false
130 isContinue := false
132 return := method(arg,
133 call setStopStatus(Return)
134 getSlot("arg")
138 Eol appendProto(Normal)
139 Continue appendProto(Normal) do(
140 isContinue := true
143 Break appendProto(Normal) do(
144 stopLooping := true
145 isBreak := true
148 Return appendProto(Normal) do(
149 stopLooping := true
150 isReturn := true
152 return := method(arg,
153 call setStopStatus(Return)
154 call sender call setStopStatus(Return)
155 getSlot("arg")
159 Object do(
160 not := nil
162 isNil := false
164 ifNil := Object getSlot("thisContext")
165 ifNonNil := Object getSlot("evalArgAndReturnSelf")
167 ifNonNilEval := Object getSlot("evalArg")
168 ifNilEval := Object getSlot("thisContext")
170 setSlot("and", Object getSlot("evalArg"))
171 setSlot("or", true)
174 Sequence do(
175 makeFirstCharacterLowercase := method(
176 if(self size > 0, self atPut(0, self at(0) asLowercase))
179 makeFirstCharacterUppercase := method(
180 if(self size > 0, self atPut(0, self at(0) asUppercase))
183 slicesBetween := method(startSeq, endSeq,
184 chunks := List clone
185 lastIndex := 0
186 while (startIndex := self findSeq(startSeq, lastIndex),
187 endIndex := self findSeq(endSeq, startIndex + startSeq size)
188 endIndex ifNil(break)
189 chunks append(self slice(startIndex + startSeq size, endIndex))
190 lastIndex := endIndex + endSeq size
192 chunks
196 Object do(
197 hasSlot := method(n,
198 getSlot("self") hasLocalSlot(n) or(getSlot("self") ancestorWithSlot(n) != nil)
201 //doc Object list(...) Returns a List containing the arguments.
202 list := method(call message argsEvaluatedIn(call sender))
204 //doc Object ..(arg) .. is an alias for: method(arg, self asString append(arg asString))
205 setSlot("..", method(arg, getSlot("self") asString .. arg asString))
207 Map addKeysAndValues := method(keys, values, keys foreach(i, k, self atPut(k, values at(i))); self)
209 slotDescriptionMap := method(
210 slotNames := getSlot("self") slotNames sort
211 slotDescs := slotNames map(name, getSlot("self") getSlot(name) asSimpleString)
212 Map clone addKeysAndValues(slotNames, slotDescs)
215 apropos := method(keyword,
216 Protos Core foreachSlot(name, p,
217 slotDescriptions := getSlot("p") slotDescriptionMap ?select(k, v, k asMutable lowercase containsSeq(keyword))
219 if(slotDescriptions and slotDescriptions size > 0,
220 s := Sequence clone
221 slotDescriptions keys sortInPlace foreach(k,
222 s appendSeq(" ", k alignLeft(16), " = ", slotDescriptions at(k), "\n")
225 writeln(name)
226 writeln(s)
232 slotSummary := method(keyword,
233 if(getSlot("self") type == "Block" and getSlot("self") == getSlot("Block"),
234 return getSlot("self") asSimpleString
236 s := Sequence clone
237 s appendSeq(" ", getSlot("self") asSimpleString, ":\n")
238 slotDescriptions := slotDescriptionMap
239 if(keyword,
240 slotDescriptions = slotDescriptions select(k, v, k asMutable lowercase containsSeq(keyword))
242 slotDescriptions keys sortInPlace foreach(k,
243 s appendSeq(" ", k alignLeft(16), " = ", slotDescriptions at(k), "\n")
248 asString := getSlot("slotSummary")
250 asSimpleString := method(getSlot("self") type .. "_" .. getSlot("self") uniqueHexId)
252 /*doc Object newSlot(slotName, aValue)
253 Creates a getter and setter for the slot with the name slotName
254 and sets it's default the value aValue. Returns self. For example,
255 newSlot("foo", 1) would create slot named foo with the value 1 as well as a setter method setFoo().
258 newSlot := method(name, value, doc,
259 getSlot("self") setSlot(name, getSlot("value"))
260 getSlot("self") setSlot("set" .. name asCapitalized,
261 doString("method(" .. name .. " = call evalArgAt(0); self)"))
262 //if(doc, getSlot("self") docSlot(name, doc))
263 value
266 //doc Object launchFile(pathString) Eval file at pathString as if from the command line in it's folder.
268 launchFile := method(path, args,
269 args ifNil(args = List clone)
270 Lobby launchPath := path pathComponent
271 Directory setCurrentWorkingDirectory(Lobby launchPath)
272 System launchScript = path
273 self doFile(path)
276 //doc Object println Same as print, but also prints a new line. Returns self.
277 println := method(getSlot("self") print; write("\n"); self)
279 /*doc Object ?(aMessage)
280 description: Sends the message aMessage to the receiver if it can respond to it. Example:
281 <code>
282 MyObject test // performs test
283 MyObject ?test // performs test if MyObject has a slot named test
284 </code>
285 The search for the slot only follows the receivers proto chain.
288 setSlot("?",
289 method(
290 m := call argAt(0)
291 if (self getSlot(m name) != nil,
292 call relayStopStatus(m doInContext(self, call sender))
299 //doc Object ancestors Returns a list of all of the receiver's ancestors as found by recursively following the protos links.
301 ancestors := method(a,
302 if(a, if(a detect(x, x isIdenticalTo(self)), return a), a = List clone)
303 a append(self)
304 self protos foreach(ancestors(a))
308 //doc Object isKindOf(anObject) Returns true if anObject is in the receiver's ancestors.
310 isKindOf := method(anObject, getSlot("self") ancestors contains(getSlot("anObject")))
312 /*doc Object super(aMessage)
313 Sends the message aMessage to the receiver's proto with the context of self. Example:
314 <code>
315 self test(1, 2) // performs test(1, 2) on self
316 super(test(1, 2)) // performs test(1, 2) on self proto but with the context of self
317 </code>
320 setSlot("super", method(
321 senderSlotContext := call sender call slotContext
322 m := call argAt(0)
323 m ifNil(Exception raise("Object super requires an argument"))
324 senderSlotContext ifNil(Exception raise("Object super called outside of block context"))
325 slotName := m name
326 ancestor := senderSlotContext ancestorWithSlot(slotName)
327 if(ancestor == nil,
328 slotName = "forward"
329 ancestor = senderSlotContext ancestorWithSlot(slotName)
331 if(ancestor isIdenticalTo(senderSlotContext), Exception raise("Object super slot " .. slotName .. " not found"))
332 b := ancestor getSlot(slotName)
333 if(getSlot("b") isActivatable == false,
336 getSlot("b") performOn(call sender call target, call sender, m, ancestor)
340 /*doc Object resend
341 Send the message used to activate the current method to the Object's proto.
342 For example;
343 <code>
344 Dog := Mammal clone do(
345 init := method(
346 resend
349 </code>
350 calling Dog init will send an init method to Mammal, but using the Dog's context.
353 setSlot("resend", method(
354 senderSlotContext := call sender call slotContext
355 senderSlotContext ifNil(Exception raise("Object resend called outside of block context"))
356 m := call sender call message
357 slotName := m name
358 ancestor := senderSlotContext ancestorWithSlot(slotName)
360 if(ancestor isIdenticalTo(nil),
361 slotName = "forward"
362 ancestor = senderSlotContext ancestorWithSlot(slotName)
365 if(ancestor isIdenticalTo(senderSlotContext),
366 Exception raise("Object resend slot " .. slotName .. " not found")
369 b := ancestor getSlot(slotName)
370 if(getSlot("b") != nil,
371 getSlot("b") performOn(call sender getSlot("self"), call sender call sender, m, ancestor)
373 getSlot("b")
378 //doc Object list(...) Returns a List containing the arguments.
379 list := method(call message argsEvaluatedIn(call sender))
381 Object print := method(write(getSlot("self") asString); getSlot("self"))
383 //doc Object println Same as print, but also prints a new line. Returns self.
384 println := method(getSlot("self") print; write("\n"); getSlot("self"))
386 //doc Object in(aList) Same as: aList contains(self)
387 in := method(aList, aList contains(self))
389 uniqueHexId := method("0x" .. getSlot("self") uniqueId asString toBase(16))
391 lazySlot := method(
392 if(call argCount == 1,
393 m := method(
394 self setSlot(call message name, nil)
397 args := getSlot("m") message next arguments
398 args atPut(1, call argAt(0) clone)
399 getSlot("m") message next setArguments(args)
401 getSlot("m") clone
403 name := call evalArgAt(0)
404 m := ("self setSlot(\"" .. name .. "\", " .. call argAt(1) code .. ")") asMessage
405 self setSlot(name, method() setMessage(m))
410 foreachSlot := method(
411 self slotNames sort foreach(n,
412 call sender setSlot(call message argAt(0) name, n)
413 call sender setSlot(call message argAt(1) name, getSlot("self") getSlot(n))
414 r := call relayStopStatus(call evalArgAt(2))
415 if(call stopStatus isReturn, return getSlot("r"))
416 if(call stopStatus stopLooping,
417 call resetStopStatus
418 break
423 /*doc Object switch(<key1>, <expression1>, <key2>, <expression2>, ...)
424 Execute an expression depending on the value of the caller. (This is an equivalent to C switch/case)
425 <code>
426 hour := Date hour switch(
427 12, "midday",
428 0, "midnight",
429 17, "teatime",
430 Date hour asString
432 </code>
435 switch := method(
436 for(couple, 0, call argCount - 2, 2,
437 if(call evalArgAt(couple) == self,
438 return call relayStopStatus(call evalArgAt(couple + 1))
441 if(call argCount isOdd,
442 call relayStopStatus(call evalArgAt(call argCount - 1))
448 //doc Object isLaunchScript Returns true if the current file was run on the command line. Io's version of Python's __file__ == "__main__"
449 isLaunchScript := method(
450 call message label == System launchScript
453 /*doc Object doRelativeFile(pathString)
454 Evaluates the File in the context of the receiver. Returns the result.
455 pathString is relative to the file calling doRelativeFile. (Duplicate of relativeDoFile)
457 doRelativeFile := method(path,
458 self doFile(Path with(call message label pathComponent, path))
461 /*doc Object relativeDoFile(pathString)
462 Evaluates the File in the context of the receiver. Returns the result.
463 pathString is relative to the file calling doRelativeFile. (Duplicate of doRelativeFile)
465 relativeDoFile := getSlot("doRelativeFile")