Kernel-Objects.st 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681
  1. Smalltalk createPackage: 'Kernel-Objects'!
  2. nil subclass: #ProtoObject
  3. slots: {}
  4. package: 'Kernel-Objects'!
  5. !ProtoObject commentStamp!
  6. I implement the basic behavior required for any object in Amber.
  7. In most cases, subclassing `ProtoObject` is wrong and `Object` should be used instead. However subclassing `ProtoObject` can be useful in some special cases like proxy implementations.!
  8. !ProtoObject methodsFor: 'accessing'!
  9. class
  10. <inlineJS: 'return $self.a$cls'>
  11. !
  12. identityHash
  13. <inlineJS: '
  14. self._deprecatedAPI();
  15. var hash=self.identityHash;
  16. if (hash) return hash;
  17. hash=$core.nextId();
  18. Object.defineProperty(self, ''identityHash'', {value:hash});
  19. return hash;
  20. '>
  21. !
  22. instVarNamed: aString
  23. <inlineJS: 'return $self[aString]'>
  24. !
  25. instVarNamed: aString put: anObject
  26. <inlineJS: '$self[aString] = anObject'>
  27. !
  28. yourself
  29. ^ self
  30. ! !
  31. !ProtoObject methodsFor: 'comparing'!
  32. = anObject
  33. ^ self == anObject
  34. !
  35. == anObject
  36. <inlineJS: 'return self === anObject'>
  37. !
  38. ~= anObject
  39. ^ (self = anObject) = false
  40. !
  41. ~~ anObject
  42. ^ (self == anObject) = false
  43. ! !
  44. !ProtoObject methodsFor: 'converting'!
  45. asString
  46. ^ self printString
  47. ! !
  48. !ProtoObject methodsFor: 'error handling'!
  49. doesNotUnderstand: aMessage
  50. MessageNotUnderstood new
  51. receiver: self;
  52. message: aMessage;
  53. signal
  54. ! !
  55. !ProtoObject methodsFor: 'evaluating'!
  56. evaluate: aString on: anEvaluator
  57. ^ anEvaluator evaluate: aString receiver: self
  58. ! !
  59. !ProtoObject methodsFor: 'initialization'!
  60. initialize
  61. ! !
  62. !ProtoObject methodsFor: 'inspecting'!
  63. inspect
  64. Inspector inspect: self
  65. !
  66. inspectOn: anInspector
  67. ! !
  68. !ProtoObject methodsFor: 'message handling'!
  69. perform: aString
  70. ^ self perform: aString withArguments: #()
  71. !
  72. perform: aString with: anObject
  73. <inlineJS: 'return $core.send2(self, aString, [anObject])'>
  74. !
  75. perform: aString withArguments: aCollection
  76. <inlineJS: 'return $core.send2(self, aString, aCollection)'>
  77. ! !
  78. !ProtoObject methodsFor: 'printing'!
  79. printOn: aStream
  80. aStream nextPutAll: (self class name first isVowel
  81. ifTrue: [ 'an ' ]
  82. ifFalse: [ 'a ' ]).
  83. aStream nextPutAll: self class name
  84. !
  85. printString
  86. ^ String streamContents: [ :str |
  87. self printOn: str ]
  88. ! !
  89. !ProtoObject methodsFor: 'testing'!
  90. ifNil: aBlock
  91. "inlined in the Compiler"
  92. ^ self
  93. !
  94. ifNil: aBlock ifNotNil: anotherBlock
  95. "inlined in the Compiler"
  96. ^ anotherBlock value: self
  97. !
  98. ifNotNil: aBlock
  99. "inlined in the Compiler"
  100. ^ aBlock value: self
  101. !
  102. ifNotNil: aBlock ifNil: anotherBlock
  103. "inlined in the Compiler"
  104. ^ aBlock value: self
  105. !
  106. isKindOf: aClass
  107. ^ (self isMemberOf: aClass) or: [ self class inheritsFrom: aClass ]
  108. !
  109. isNil
  110. ^ false
  111. !
  112. notNil
  113. ^ true
  114. ! !
  115. !ProtoObject class methodsFor: 'initialization'!
  116. initialize
  117. ! !
  118. ProtoObject subclass: #Object
  119. slots: {}
  120. package: 'Kernel-Objects'!
  121. !Object commentStamp!
  122. **I am the root of the Smalltalk class system**. With the exception of unual subclasses of `ProtoObject`, all other classes in the system are subclasses of me.
  123. I provide default behavior common to all normal objects (some of it inherited from `ProtoObject`), such as:
  124. - accessing
  125. - copying
  126. - comparison
  127. - error handling
  128. - message sending
  129. - reflection
  130. Also utility messages that all objects should respond to are defined here.
  131. I have no instance variable.
  132. ##Access
  133. Instance variables can be accessed with `#instVarAt:` and `#instVarAt:put:`. `#instanceVariableNames` answers a collection of all instance variable names.
  134. Accessing JavaScript properties of an object is done through `#basicAt:`, `#basicAt:put:` and `basicDelete:`.
  135. ##Copying
  136. Copying an object is handled by `#copy` and `#deepCopy`. The first one performs a shallow copy of the receiver, while the second one performs a deep copy.
  137. The hook method `#postCopy` can be overriden in subclasses to copy fields as necessary to complete the full copy. It will be sent by the copy of the receiver.
  138. ##Comparison
  139. I understand equality `#=` and identity `#==` comparison.
  140. ##Error handling
  141. - `#halt` is the typical message to use for inserting breakpoints during debugging.
  142. - `#error:` throws a generic error exception
  143. - `#doesNotUnderstand:` handles the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message.
  144. Overriding this message can be useful to implement proxies for example.!
  145. !Object methodsFor: 'accessing'!
  146. basicAt: aString
  147. <inlineJS: 'return self[aString]'>
  148. !
  149. basicAt: aString put: anObject
  150. <inlineJS: 'return self[aString] = anObject'>
  151. !
  152. basicDelete: aString
  153. <inlineJS: 'delete self[aString]; return aString'>
  154. !
  155. divideBySelfToNumber: aNumber
  156. self error: 'I am not a number.'
  157. !
  158. divisionRemainderBySelfToNumber: aNumber
  159. self error: 'I am not a number.'
  160. !
  161. minusSelfToNumber: aNumber
  162. self error: 'I am not a number.'
  163. !
  164. plusSelfToNumber: aNumber
  165. self error: 'I am not a number.'
  166. !
  167. size
  168. self error: 'Object not indexable'
  169. !
  170. timesSelfToNumber: aNumber
  171. self error: 'I am not a number.'
  172. ! !
  173. !Object methodsFor: 'browsing'!
  174. browse
  175. Finder findClass: self class
  176. ! !
  177. !Object methodsFor: 'comparing'!
  178. isNumberEqualToSelf: aNumber
  179. ^ false
  180. !
  181. isNumberGreaterThanOrEqualToSelf: aNumber
  182. ^ false
  183. !
  184. isNumberGreaterThanSelf: aNumber
  185. ^ false
  186. !
  187. isNumberLessThanOrEqualToSelf: aNumber
  188. ^ false
  189. !
  190. isNumberLessThanSelf: aNumber
  191. ^ false
  192. !
  193. isStringEqualToSelf: aString
  194. ^ false
  195. !
  196. isStringGreaterThanOrEqualToSelf: aString
  197. ^ false
  198. !
  199. isStringGreaterThanSelf: aString
  200. ^ false
  201. !
  202. isStringLessThanOrEqualToSelf: aString
  203. ^ false
  204. !
  205. isStringLessThanSelf: aString
  206. ^ false
  207. ! !
  208. !Object methodsFor: 'converting'!
  209. -> anObject
  210. ^ Association key: self value: anObject
  211. !
  212. andSelfToNumber: aNumber
  213. self error: 'I am not a number.'
  214. !
  215. asJSONString
  216. ^ JSON stringify: self asJavaScriptObject
  217. !
  218. asJavaScriptObject
  219. | variables |
  220. self deprecatedAPI: 'Implement domain-specific #asJavaScriptObject on your classes instead.'.
  221. variables := HashedCollection new.
  222. self class allInstanceVariableNames do: [ :each |
  223. variables at: each put: (self instVarNamed: each) asJavaScriptObject ].
  224. ^ variables
  225. !
  226. asJavaScriptSource
  227. self deprecatedAPI: 'Implement domain-specific #asJavaScriptSource on your classes instead.'.
  228. ^ self asString
  229. !
  230. orSelfToNumber: aNumber
  231. self error: 'I am not a number.'
  232. !
  233. xorSelfToNumber: aNumber
  234. self error: 'I am not a number.'
  235. ! !
  236. !Object methodsFor: 'copying'!
  237. appendToString: aString
  238. self error: 'Cannot add self to a string.'
  239. !
  240. copy
  241. ^ self shallowCopy postCopy
  242. !
  243. deepCopy
  244. <inlineJS: '
  245. var copy = self.a$cls._new();
  246. Object.keys(self).forEach(function (i) {
  247. copy[i] = $recv(self[i])._deepCopy();
  248. });
  249. return copy;
  250. '>
  251. !
  252. postCopy
  253. !
  254. shallowCopy
  255. <inlineJS: '
  256. var copy = self.a$cls._new();
  257. Object.keys(self).forEach(function(i) {
  258. copy[i] = self[i];
  259. });
  260. return copy;
  261. '>
  262. ! !
  263. !Object methodsFor: 'error handling'!
  264. deprecatedAPI
  265. "Just a simple way to deprecate methods.
  266. #deprecatedAPI is in the 'error handling' protocol even if it doesn't throw an error,
  267. but it could in the future."
  268. console warn: thisContext home asString, ' is deprecated!! (in ', thisContext home home asString, ')'.
  269. !
  270. deprecatedAPI: aString
  271. "Just a simple way to deprecate methods.
  272. #deprecatedAPI is in the 'error handling' protocol even if it doesn't throw an error,
  273. but it could in the future."
  274. console warn: thisContext home asString, ' is deprecated!! (in ', thisContext home home asString, ')'.
  275. console warn: aString
  276. !
  277. error: aString
  278. Error signal: aString
  279. !
  280. halt
  281. Halt signal
  282. !
  283. shouldNotImplement
  284. self error: 'This method should not be implemented in ', self class name
  285. !
  286. subclassResponsibility
  287. self error: 'This method is a responsibility of a subclass'
  288. ! !
  289. !Object methodsFor: 'evaluating'!
  290. in: aValuable
  291. ^ aValuable value: self
  292. !
  293. value
  294. <inlineJS: 'return self.valueOf()'>
  295. ! !
  296. !Object methodsFor: 'message handling'!
  297. basicPerform: aString
  298. ^ self basicPerform: aString withArguments: #()
  299. !
  300. basicPerform: aString withArguments: aCollection
  301. <inlineJS: 'return self[aString].apply(self, aCollection);'>
  302. ! !
  303. !Object methodsFor: 'streaming'!
  304. putOn: aStream
  305. aStream nextPut: self
  306. ! !
  307. !Object methodsFor: 'testing'!
  308. isImmutable
  309. ^ false
  310. !
  311. isMemberOf: aClass
  312. ^ self class = aClass
  313. !
  314. isParseFailure
  315. ^ false
  316. !
  317. respondsTo: aSelector
  318. ^ self class canUnderstand: aSelector
  319. ! !
  320. !Object class methodsFor: 'helios'!
  321. accessorProtocolWith: aGenerator
  322. aGenerator accessorProtocolForObject
  323. !
  324. accessorsSourceCodesWith: aGenerator
  325. aGenerator accessorsForObject
  326. !
  327. initializeProtocolWith: aGenerator
  328. aGenerator initializeProtocolForObject
  329. !
  330. initializeSourceCodesWith: aGenerator
  331. aGenerator initializeForObject
  332. ! !
  333. !Object class methodsFor: 'initialization'!
  334. initialize
  335. "no op"
  336. ! !
  337. Object subclass: #Boolean
  338. slots: {}
  339. package: 'Kernel-Objects'!
  340. !Boolean commentStamp!
  341. I define the protocol for logic testing operations and conditional control structures for the logical values (see the `controlling` protocol).
  342. I have two instances, `true` and `false`.
  343. I am directly mapped to JavaScript Boolean. The `true` and `false` objects are the JavaScript boolean objects.
  344. ## Usage Example:
  345. aBoolean not ifTrue: [ ... ] ifFalse: [ ... ]!
  346. !Boolean methodsFor: 'comparing'!
  347. == aBoolean
  348. <inlineJS: '
  349. if (typeof aBoolean === "boolean") return (self == true) === aBoolean;
  350. else if (aBoolean !!= null && typeof aBoolean === "object") return (self == true) === aBoolean.valueOf();
  351. else return false;
  352. '>
  353. ! !
  354. !Boolean methodsFor: 'controlling'!
  355. & aBoolean
  356. <inlineJS: '
  357. if(self == true) {
  358. return aBoolean;
  359. } else {
  360. return false;
  361. }
  362. '>
  363. !
  364. and: aBlock
  365. ^ self
  366. ifTrue: "aBlock" [ aBlock value ]
  367. ifFalse: [ false ]
  368. !
  369. ifFalse: aBlock
  370. "inlined in the Compiler"
  371. ^ self ifTrue: [] ifFalse: aBlock
  372. !
  373. ifFalse: aBlock ifTrue: anotherBlock
  374. "inlined in the Compiler"
  375. ^ self ifTrue: anotherBlock ifFalse: aBlock
  376. !
  377. ifTrue: aBlock
  378. "inlined in the Compiler"
  379. ^ self ifTrue: aBlock ifFalse: []
  380. !
  381. ifTrue: aBlock ifFalse: anotherBlock
  382. "inlined in the Compiler"
  383. <inlineJS: '
  384. if(self == true) {
  385. return aBlock._value();
  386. } else {
  387. return anotherBlock._value();
  388. }
  389. '>
  390. !
  391. not
  392. ^ self = false
  393. !
  394. or: aBlock
  395. ^ self
  396. ifTrue: [ true ]
  397. ifFalse: "aBlock" [ aBlock value ]
  398. !
  399. | aBoolean
  400. <inlineJS: '
  401. if(self == true) {
  402. return true;
  403. } else {
  404. return aBoolean;
  405. }
  406. '>
  407. ! !
  408. !Boolean methodsFor: 'converting'!
  409. asBit
  410. ^ self ifTrue: [ 1 ] ifFalse: [ 0 ]
  411. !
  412. asJavaScriptObject
  413. ^ self
  414. !
  415. asJavaScriptSource
  416. ^ self asString
  417. !
  418. asString
  419. <inlineJS: 'return self.toString()'>
  420. ! !
  421. !Boolean methodsFor: 'copying'!
  422. deepCopy
  423. ^ self
  424. !
  425. shallowCopy
  426. ^ self
  427. ! !
  428. !Boolean methodsFor: 'printing'!
  429. printOn: aStream
  430. aStream nextPutAll: self asString
  431. ! !
  432. !Boolean methodsFor: 'testing'!
  433. isBoolean
  434. ^ true
  435. !
  436. isImmutable
  437. ^ true
  438. ! !
  439. Object subclass: #Date
  440. slots: {}
  441. package: 'Kernel-Objects'!
  442. !Date commentStamp!
  443. I am used to work with both dates and times. Therefore `Date today` and `Date now` are both valid in
  444. Amber and answer the same date object.
  445. Date directly maps to the `Date()` JavaScript constructor, and Amber date objects are JavaScript date objects.
  446. ## API
  447. The class-side `instance creation` protocol contains some convenience methods for creating date/time objects such as `#fromSeconds:`.
  448. Arithmetic and comparison is supported (see the `comparing` and `arithmetic` protocols).
  449. The `converting` protocol provides convenience methods for various convertions (to numbers, strings, etc.).!
  450. !Date methodsFor: 'accessing'!
  451. day
  452. ^ self dayOfWeek
  453. !
  454. day: aNumber
  455. self dayOfWeek: aNumber
  456. !
  457. dayOfMonth
  458. <inlineJS: 'return self.getDate()'>
  459. !
  460. dayOfMonth: aNumber
  461. <inlineJS: 'self.setDate(aNumber)'>
  462. !
  463. dayOfWeek
  464. <inlineJS: 'return self.getDay() + 1'>
  465. !
  466. dayOfWeek: aNumber
  467. <inlineJS: 'return self.setDay(aNumber - 1)'>
  468. !
  469. hours
  470. <inlineJS: 'return self.getHours()'>
  471. !
  472. hours: aNumber
  473. <inlineJS: 'self.setHours(aNumber)'>
  474. !
  475. milliseconds
  476. <inlineJS: 'return self.getMilliseconds()'>
  477. !
  478. milliseconds: aNumber
  479. <inlineJS: 'self.setMilliseconds(aNumber)'>
  480. !
  481. minutes
  482. <inlineJS: 'return self.getMinutes()'>
  483. !
  484. minutes: aNumber
  485. <inlineJS: 'self.setMinutes(aNumber)'>
  486. !
  487. month
  488. <inlineJS: 'return self.getMonth() + 1'>
  489. !
  490. month: aNumber
  491. <inlineJS: 'self.setMonth(aNumber - 1)'>
  492. !
  493. seconds
  494. <inlineJS: 'return self.getSeconds()'>
  495. !
  496. seconds: aNumber
  497. <inlineJS: 'self.setSeconds(aNumber)'>
  498. !
  499. time
  500. <inlineJS: 'return self.getTime()'>
  501. !
  502. time: aNumber
  503. <inlineJS: 'self.setTime(aNumber)'>
  504. !
  505. year
  506. <inlineJS: 'return self.getFullYear()'>
  507. !
  508. year: aNumber
  509. <inlineJS: 'self.setFullYear(aNumber)'>
  510. ! !
  511. !Date methodsFor: 'arithmetic'!
  512. + aNumber
  513. <inlineJS: 'return new Date($self.getTime() + aNumber)'>
  514. !
  515. - aDate
  516. <inlineJS: 'return self - aDate'>
  517. ! !
  518. !Date methodsFor: 'comparing'!
  519. < aDate
  520. <inlineJS: 'return self < aDate'>
  521. !
  522. <= aDate
  523. <inlineJS: 'return self <= aDate'>
  524. !
  525. = aDate
  526. ^ (aDate class == self class) and: [ self asMilliseconds == aDate asMilliseconds ]
  527. !
  528. > aDate
  529. <inlineJS: 'return self > aDate'>
  530. !
  531. >= aDate
  532. <inlineJS: 'return self >= aDate'>
  533. ! !
  534. !Date methodsFor: 'converting'!
  535. asDateString
  536. <inlineJS: 'return self.toDateString()'>
  537. !
  538. asLocaleString
  539. <inlineJS: 'return self.toLocaleString()'>
  540. !
  541. asMilliseconds
  542. ^ self time
  543. !
  544. asNumber
  545. ^ self asMilliseconds
  546. !
  547. asString
  548. <inlineJS: 'return self.toString()'>
  549. !
  550. asTimeString
  551. <inlineJS: 'return self.toTimeString()'>
  552. ! !
  553. !Date methodsFor: 'printing'!
  554. printOn: aStream
  555. aStream nextPutAll: self asString
  556. ! !
  557. !Date class methodsFor: 'accessing'!
  558. classTag
  559. "Returns a tag or general category for this class.
  560. Typically used to help tools do some reflection.
  561. Helios, for example, uses this to decide what icon the class should display."
  562. ^ 'magnitude'
  563. ! !
  564. !Date class methodsFor: 'instance creation'!
  565. fromMilliseconds: aNumber
  566. ^ self new: aNumber
  567. !
  568. fromSeconds: aNumber
  569. ^ self fromMilliseconds: aNumber * 1000
  570. !
  571. fromString: aString
  572. "Example: Date fromString('2011/04/15 00:00:00')"
  573. ^ self new: aString
  574. !
  575. millisecondsToRun: aBlock
  576. | t |
  577. t := Date now.
  578. aBlock value.
  579. ^ Date now - t
  580. !
  581. new: anObject
  582. <inlineJS: 'return new Date(anObject)'>
  583. !
  584. now
  585. ^ self today
  586. !
  587. today
  588. ^ self new
  589. ! !
  590. Object subclass: #Number
  591. slots: {}
  592. package: 'Kernel-Objects'!
  593. !Number commentStamp!
  594. I am the Amber representation for all numbers.
  595. I am directly mapped to JavaScript Number.
  596. ## API
  597. I provide all necessary methods for arithmetic operations, comparison, conversion and so on with numbers.
  598. My instances can also be used to evaluate a block a fixed number of times:
  599. 5 timesRepeat: [ Transcript show: 'This will be printed 5 times'; cr ].
  600. 1 to: 5 do: [ :aNumber| Transcript show: aNumber asString; cr ].
  601. 1 to: 10 by: 2 do: [ :aNumber| Transcript show: aNumber asString; cr ].!
  602. !Number methodsFor: 'arithmetic'!
  603. * aNumber
  604. <inlineJS: 'return typeof aNumber === "number" ?
  605. self * aNumber :
  606. $recv(aNumber)._timesSelfToNumber_(self)'>
  607. !
  608. + aNumber
  609. <inlineJS: 'return typeof aNumber === "number" ?
  610. self + aNumber :
  611. $recv(aNumber)._plusSelfToNumber_(self)'>
  612. !
  613. - aNumber
  614. <inlineJS: 'return typeof aNumber === "number" ?
  615. self - aNumber :
  616. $recv(aNumber)._minusSelfToNumber_(self)'>
  617. !
  618. / aNumber
  619. <inlineJS: 'return typeof aNumber === "number" ?
  620. self / aNumber :
  621. $recv(aNumber)._divideBySelfToNumber_(self)'>
  622. !
  623. // aNumber
  624. ^ (self / aNumber) floor
  625. !
  626. \\ aNumber
  627. <inlineJS: 'return typeof aNumber === "number" ?
  628. self % aNumber :
  629. $recv(aNumber)._divisionRemainderBySelfToNumber_(self)'>
  630. !
  631. abs
  632. <inlineJS: 'return Math.abs(self);'>
  633. !
  634. divideBySelfToNumber: aNumber
  635. <inlineJS: 'return aNumber / self'>
  636. !
  637. divisionRemainderBySelfToNumber: aNumber
  638. <inlineJS: 'return aNumber % self'>
  639. !
  640. max: aNumber
  641. <inlineJS: 'return Math.max(self, aNumber);'>
  642. !
  643. min: aNumber
  644. <inlineJS: 'return Math.min(self, aNumber);'>
  645. !
  646. min: aMin max: aMax
  647. ^ (self min: aMin) max: aMax
  648. !
  649. minusSelfToNumber: aNumber
  650. <inlineJS: 'return aNumber - self'>
  651. !
  652. negated
  653. ^ 0 - self
  654. !
  655. plusSelfToNumber: aNumber
  656. <inlineJS: 'return aNumber + self'>
  657. !
  658. timesSelfToNumber: aNumber
  659. <inlineJS: 'return aNumber * self'>
  660. ! !
  661. !Number methodsFor: 'comparing'!
  662. < aNumber
  663. <inlineJS: 'return typeof aNumber === "number" ?
  664. Number(self) < aNumber :
  665. $recv(aNumber)._isNumberLessThanSelf_(self)'>
  666. !
  667. <= aNumber
  668. <inlineJS: 'return typeof aNumber === "number" ?
  669. Number(self) <= aNumber :
  670. $recv(aNumber)._isNumberLessThanOrEqualToSelf_(self)'>
  671. !
  672. == aNumber
  673. <inlineJS: 'return typeof aNumber === "number" ?
  674. Number(self) === aNumber :
  675. $recv(aNumber)._isNumberEqualToSelf_(self)'>
  676. !
  677. > aNumber
  678. <inlineJS: 'return typeof aNumber === "number" ?
  679. Number(self) > aNumber :
  680. $recv(aNumber)._isNumberGreaterThanSelf_(self)'>
  681. !
  682. >= aNumber
  683. <inlineJS: 'return typeof aNumber === "number" ?
  684. Number(self) >= aNumber :
  685. $recv(aNumber)._isNumberGreaterThanOrEqualToSelf_(self)'>
  686. !
  687. isNumberEqualToSelf: aNumber
  688. <inlineJS: 'return aNumber === Number(self)'>
  689. !
  690. isNumberGreaterThanOrEqualToSelf: aNumber
  691. <inlineJS: 'return aNumber >= self'>
  692. !
  693. isNumberGreaterThanSelf: aNumber
  694. <inlineJS: 'return aNumber > self'>
  695. !
  696. isNumberLessThanOrEqualToSelf: aNumber
  697. <inlineJS: 'return aNumber <= self'>
  698. !
  699. isNumberLessThanSelf: aNumber
  700. <inlineJS: 'return aNumber < self'>
  701. ! !
  702. !Number methodsFor: 'converting'!
  703. & aNumber
  704. ^ self bitAnd: aNumber
  705. !
  706. @ aNumber
  707. ^ Point x: self y: aNumber
  708. !
  709. andSelfToNumber: aNumber
  710. <inlineJS: 'return aNumber & self'>
  711. !
  712. asJavaScriptObject
  713. ^ self
  714. !
  715. asJavaScriptSource
  716. ^ '(', self printString, ')'
  717. !
  718. asNumber
  719. ^ self
  720. !
  721. asPoint
  722. ^ Point x: self y: self
  723. !
  724. asString
  725. <inlineJS: 'return String(self)'>
  726. !
  727. atRandom
  728. ^ (Random new next * self) truncated + 1
  729. !
  730. bitAnd: aNumber
  731. <inlineJS: 'return typeof aNumber === "number" ?
  732. self & aNumber :
  733. $recv(aNumber)._andSelfToNumber_(self)'>
  734. !
  735. bitNot
  736. <inlineJS: 'return ~self'>
  737. !
  738. bitOr: aNumber
  739. <inlineJS: 'return typeof aNumber === "number" ?
  740. self | aNumber :
  741. $recv(aNumber)._orSelfToNumber_(self)'>
  742. !
  743. bitXor: aNumber
  744. <inlineJS: 'return typeof aNumber === "number" ?
  745. self ^ aNumber :
  746. $recv(aNumber)._xorSelfToNumber_(self)'>
  747. !
  748. ceiling
  749. <inlineJS: 'return Math.ceil(self);'>
  750. !
  751. degreesToRadians
  752. ^ self * Number radiansPerDegree
  753. !
  754. floor
  755. <inlineJS: 'return Math.floor(self);'>
  756. !
  757. orSelfToNumber: aNumber
  758. <inlineJS: 'return aNumber | self'>
  759. !
  760. printStringBase: aBase
  761. <inlineJS: 'return self.toString(aBase)'>
  762. !
  763. radiansToDegrees
  764. ^ self / Number radiansPerDegree
  765. !
  766. rounded
  767. <inlineJS: 'return Math.round(self);'>
  768. !
  769. to: aNumber
  770. | array first last count |
  771. first := self truncated.
  772. last := aNumber truncated + 1.
  773. count := 1.
  774. array := Array new.
  775. (last - first) timesRepeat: [
  776. array at: count put: first.
  777. count := count + 1.
  778. first := first + 1 ].
  779. ^ array
  780. !
  781. to: stop by: step
  782. | array value pos |
  783. value := self.
  784. array := Array new.
  785. pos := 1.
  786. step = 0 ifTrue: [ self error: 'step must be non-zero' ].
  787. step < 0
  788. ifTrue: [ [ value >= stop ] whileTrue: [
  789. array at: pos put: value.
  790. pos := pos + 1.
  791. value := value + step ]]
  792. ifFalse: [ [ value <= stop ] whileTrue: [
  793. array at: pos put: value.
  794. pos := pos + 1.
  795. value := value + step ]].
  796. ^ array
  797. !
  798. truncated
  799. <inlineJS: '
  800. if(self >= 0) {
  801. return Math.floor(self);
  802. } else {
  803. return Math.floor(self * (-1)) * (-1);
  804. };
  805. '>
  806. !
  807. xorSelfToNumber: aNumber
  808. <inlineJS: 'return aNumber ^ self'>
  809. !
  810. | aNumber
  811. ^ self bitOr: aNumber
  812. ! !
  813. !Number methodsFor: 'copying'!
  814. copy
  815. ^ self
  816. !
  817. deepCopy
  818. ^ self copy
  819. ! !
  820. !Number methodsFor: 'enumerating'!
  821. timesRepeat: aBlock
  822. | count |
  823. count := 1.
  824. [ count > self ] whileFalse: [
  825. aBlock value.
  826. count := count + 1 ]
  827. !
  828. to: stop by: step do: aBlock
  829. | value |
  830. value := self.
  831. step = 0 ifTrue: [ self error: 'step must be non-zero' ].
  832. step < 0
  833. ifTrue: [ [ value >= stop ] whileTrue: [
  834. aBlock value: value.
  835. value := value + step ]]
  836. ifFalse: [ [ value <= stop ] whileTrue: [
  837. aBlock value: value.
  838. value := value + step ]]
  839. !
  840. to: stop do: aBlock
  841. "Evaluate aBlock for each number from self to aNumber."
  842. | nextValue |
  843. nextValue := self.
  844. [ nextValue <= stop ]
  845. whileTrue:
  846. [ aBlock value: nextValue.
  847. nextValue := nextValue + 1 ]
  848. ! !
  849. !Number methodsFor: 'mathematical functions'!
  850. ** exponent
  851. ^ self raisedTo: exponent
  852. !
  853. arcCos
  854. <inlineJS: 'return Math.acos(self);'>
  855. !
  856. arcSin
  857. <inlineJS: 'return Math.asin(self);'>
  858. !
  859. arcTan
  860. <inlineJS: 'return Math.atan(self);'>
  861. !
  862. arcTan: aNumber
  863. <inlineJS: 'return Math.atan2(self, aNumber);'>
  864. !
  865. cos
  866. <inlineJS: 'return Math.cos(self);'>
  867. !
  868. ln
  869. <inlineJS: 'return Math.log(self);'>
  870. !
  871. ln1p
  872. <inlineJS: 'return Math.log1p(self);'>
  873. !
  874. log
  875. <inlineJS: 'return Math.log(self) / Math.LN10;'>
  876. !
  877. log: aNumber
  878. <inlineJS: 'return Math.log(self) / Math.log(aNumber);'>
  879. !
  880. raisedTo: exponent
  881. <inlineJS: 'return Math.pow(self, exponent);'>
  882. !
  883. sign
  884. self isZero
  885. ifTrue: [ ^ 0 ].
  886. self positive
  887. ifTrue: [ ^ 1 ]
  888. ifFalse: [ ^ -1 ].
  889. !
  890. sin
  891. <inlineJS: 'return Math.sin(self);'>
  892. !
  893. sqrt
  894. <inlineJS: 'return Math.sqrt(self)'>
  895. !
  896. squared
  897. ^ self * self
  898. !
  899. tan
  900. <inlineJS: 'return Math.tan(self);'>
  901. ! !
  902. !Number methodsFor: 'printing'!
  903. printOn: aStream
  904. aStream nextPutAll: self asString
  905. !
  906. printShowingDecimalPlaces: placesDesired
  907. <inlineJS: 'return self.toFixed(placesDesired)'>
  908. ! !
  909. !Number methodsFor: 'testing'!
  910. between: min and: max
  911. ^ self >= min and: [ self <= max ]
  912. !
  913. even
  914. ^ 0 = (self \\ 2)
  915. !
  916. isFinite
  917. "Answer whether the receiver is finite"
  918. <inlineJS: 'return Number.isFinite(self)'>
  919. !
  920. isImmutable
  921. ^ true
  922. !
  923. isNaN
  924. "Answer whether the receiver is IEEE-754 not-a-number"
  925. <inlineJS: 'return Number.isNaN(self)'>
  926. !
  927. isNumber
  928. ^ true
  929. !
  930. isZero
  931. ^ self = 0
  932. !
  933. negative
  934. "Answer whether the receiver is mathematically negative."
  935. ^ self < 0
  936. !
  937. odd
  938. ^ self even not
  939. !
  940. positive
  941. "Answer whether the receiver is positive or equal to 0. (ST-80 protocol)."
  942. ^ self >= 0
  943. ! !
  944. !Number class methodsFor: 'accessing'!
  945. classTag
  946. "Returns a tag or general category for this class.
  947. Typically used to help tools do some reflection.
  948. Helios, for example, uses this to decide what icon the class should display."
  949. ^ 'magnitude'
  950. ! !
  951. !Number class methodsFor: 'instance creation'!
  952. e
  953. <inlineJS: 'return Math.E;'>
  954. !
  955. negativeInfinity
  956. <inlineJS: 'return Number.NEGATIVE_INFINITY'>
  957. !
  958. pi
  959. <inlineJS: 'return Math.PI'>
  960. !
  961. positiveInfinity
  962. <inlineJS: 'return Number.POSITIVE_INFINITY'>
  963. !
  964. radiansPerDegree
  965. ^ (self pi) / 180
  966. ! !
  967. Object subclass: #Point
  968. slots: {#x. #y}
  969. package: 'Kernel-Objects'!
  970. !Point commentStamp!
  971. I represent an x-y pair of numbers usually designating a geometric coordinate.
  972. ## API
  973. Instances are traditionally created using the binary `#@` message to a number:
  974. 100@120
  975. Points can then be arithmetically manipulated:
  976. 100@100 + (10@10)
  977. ...or for example:
  978. (100@100) * 2
  979. **NOTE:** Creating a point with a negative y-value will need a space after `@` in order to avoid a parsing error:
  980. 100@ -100 "but 100@-100 would not parse"!
  981. !Point methodsFor: 'accessing'!
  982. x
  983. ^ x
  984. !
  985. x: aNumber
  986. x := aNumber
  987. !
  988. y
  989. ^ y
  990. !
  991. y: aNumber
  992. y := aNumber
  993. ! !
  994. !Point methodsFor: 'arithmetic'!
  995. * aPoint
  996. ^ Point x: self x * aPoint asPoint x y: self y * aPoint asPoint y
  997. !
  998. + aPoint
  999. ^ Point x: self x + aPoint asPoint x y: self y + aPoint asPoint y
  1000. !
  1001. - aPoint
  1002. ^ Point x: self x - aPoint asPoint x y: self y - aPoint asPoint y
  1003. !
  1004. / aPoint
  1005. ^ Point x: self x / aPoint asPoint x y: self y / aPoint asPoint y
  1006. ! !
  1007. !Point methodsFor: 'comparing'!
  1008. < aPoint
  1009. ^ self x < aPoint x and: [
  1010. self y < aPoint y ]
  1011. !
  1012. <= aPoint
  1013. ^ self x <= aPoint x and: [
  1014. self y <= aPoint y ]
  1015. !
  1016. = aPoint
  1017. ^ aPoint class = self class and: [
  1018. (aPoint x = self x) & (aPoint y = self y) ]
  1019. !
  1020. > aPoint
  1021. ^ self x > aPoint x and: [
  1022. self y > aPoint y ]
  1023. !
  1024. >= aPoint
  1025. ^ self x >= aPoint x and: [
  1026. self y >= aPoint y ]
  1027. ! !
  1028. !Point methodsFor: 'converting'!
  1029. asPoint
  1030. ^ self
  1031. ! !
  1032. !Point methodsFor: 'geometry'!
  1033. angle
  1034. ^ self y arcTan: self x
  1035. ! !
  1036. !Point methodsFor: 'point functions'!
  1037. dotProduct: aPoint
  1038. ^ (x * aPoint x) + (y * aPoint y)
  1039. !
  1040. normal
  1041. "Answer a Point representing the unit vector rotated 90 deg clockwise. For the zero point return -1@0."
  1042. | n d |
  1043. n := y negated @ x.
  1044. (d := (n x * n x + (n y * n y))) = 0
  1045. ifTrue: [ ^ -1 @0 ].
  1046. ^ n / d sqrt
  1047. !
  1048. normalized
  1049. | r |
  1050. r := self r.
  1051. r = 0
  1052. ifTrue: [ ^ Point x: 0 y: 0 ]
  1053. ifFalse: [ ^ Point x: x / r y: y / r ]
  1054. ! !
  1055. !Point methodsFor: 'polar coordinates'!
  1056. r
  1057. ^ ((x * x) + (y * y)) sqrt
  1058. ! !
  1059. !Point methodsFor: 'printing'!
  1060. printOn: aStream
  1061. "Print receiver in classic x@y notation."
  1062. x printOn: aStream.
  1063. aStream nextPutAll: '@'.
  1064. (y notNil and: [ y negative ]) ifTrue: [
  1065. "Avoid ambiguous @- construct"
  1066. aStream space ].
  1067. y printOn: aStream
  1068. ! !
  1069. !Point methodsFor: 'rectangle creation'!
  1070. corner: aPoint
  1071. ^ Rectangle origin: self corner: aPoint
  1072. !
  1073. extent: aPoint
  1074. ^ Rectangle origin: self extent: aPoint
  1075. !
  1076. rectangle: aPoint
  1077. ^ Rectangle point: self point: aPoint
  1078. ! !
  1079. !Point methodsFor: 'transforming'!
  1080. dist: aPoint
  1081. "Answer the distance between aPoint and the receiver."
  1082. | dx dy |
  1083. dx := aPoint x - x.
  1084. dy := aPoint y - y.
  1085. ^ (dx * dx + (dy * dy)) sqrt
  1086. !
  1087. translateBy: delta
  1088. "Answer a Point translated by delta (an instance of Point)."
  1089. ^ (delta x + x) @ (delta y + y)
  1090. ! !
  1091. !Point class methodsFor: 'accessing'!
  1092. classTag
  1093. "Returns a tag or general category for this class.
  1094. Typically used to help tools do some reflection.
  1095. Helios, for example, uses this to decide what icon the class should display."
  1096. ^ 'magnitude'
  1097. ! !
  1098. !Point class methodsFor: 'instance creation'!
  1099. x: aNumber y: anotherNumber
  1100. ^ self new
  1101. x: aNumber;
  1102. y: anotherNumber;
  1103. yourself
  1104. ! !
  1105. Object subclass: #Random
  1106. slots: {}
  1107. package: 'Kernel-Objects'!
  1108. !Random commentStamp!
  1109. I an used to generate a random number and I am implemented as a trivial wrapper around javascript `Math.random()`.
  1110. ## API
  1111. The typical use case it to use the `#next` method like the following:
  1112. Random new next
  1113. This will return a float x where x < 1 and x > 0. If you want a random integer from 1 to 10 you can use `#atRandom`
  1114. 10 atRandom
  1115. A random number in a specific interval can be obtained with the following:
  1116. (3 to: 7) atRandom
  1117. Be aware that `#to:` does not create an Interval as in other Smalltalk implementations but in fact an `Array` of numbers, so it's better to use:
  1118. 5 atRandom + 2
  1119. Since `#atRandom` is implemented in `SequencableCollection` you can easy pick an element at random:
  1120. #('a' 'b' 'c') atRandom
  1121. As well as letter from a `String`:
  1122. 'abc' atRandom
  1123. Since Amber does not have Characters this will return a `String` of length 1 like for example `'b'`.!
  1124. !Random methodsFor: 'accessing'!
  1125. next
  1126. <inlineJS: 'return Math.random()'>
  1127. !
  1128. next: anInteger
  1129. ^ (1 to: anInteger) collect: [ :each | self next ]
  1130. ! !
  1131. Object subclass: #Rectangle
  1132. slots: {#origin. #corner}
  1133. package: 'Kernel-Objects'!
  1134. !Rectangle commentStamp!
  1135. I represent a Rectangle defined by my two corners.
  1136. The simplest way to create an instance is using Point methods:
  1137. 1@1 corner: 2@2
  1138. WIll create a rectangle with 1@1 as the top left and 2@2 at the bottom right.
  1139. 1@1 extent: 1@1
  1140. Will create the same rectangle, defining an origin and a size instead of an origin and a corner.!
  1141. !Rectangle methodsFor: 'accessing'!
  1142. corner
  1143. ^ corner
  1144. !
  1145. origin
  1146. ^ origin
  1147. ! !
  1148. !Rectangle methodsFor: 'private'!
  1149. setPoint: pt1 point: pt2
  1150. origin := (pt1 x min: pt2 x)@(pt1 y min: pt2 y).
  1151. corner := (pt1 x max: pt2 x)@(pt1 y max: pt2 y).
  1152. ! !
  1153. !Rectangle methodsFor: 'testing'!
  1154. = aRectangle
  1155. ^ origin = aRectangle origin and: [ corner = aRectangle corner ]
  1156. !
  1157. containsPoint: aPoint
  1158. ^ origin <= aPoint and: [ corner >= aPoint ]
  1159. !
  1160. containsRect: aRect
  1161. ^ aRect origin >= origin and: [ aRect corner <= corner ]
  1162. !
  1163. printOn: aStream
  1164. origin printOn: aStream.
  1165. aStream nextPutAll: ' corner: '.
  1166. corner printOn: aStream.
  1167. ! !
  1168. !Rectangle class methodsFor: 'instance creation'!
  1169. origin: anOrigin corner: aCorner
  1170. ^ self basicNew setPoint: anOrigin point: aCorner.
  1171. !
  1172. origin: anOrigin extent: anExtent
  1173. ^ self basicNew setPoint: anOrigin point: anOrigin + anExtent.
  1174. !
  1175. point: anOrigin point: aCorner
  1176. ^ self basicNew setPoint: anOrigin point: aCorner.
  1177. ! !
  1178. Object subclass: #UndefinedObject
  1179. slots: {}
  1180. package: 'Kernel-Objects'!
  1181. !UndefinedObject commentStamp!
  1182. I describe the behavior of my sole instance, `nil`. `nil` represents a prior value for variables that have not been initialized, or for results which are meaningless.
  1183. `nil` is the Smalltalk equivalent of the `undefined` JavaScript object.
  1184. __note:__ When sending messages to the `undefined` JavaScript object, it will be replaced by `nil`.!
  1185. !UndefinedObject methodsFor: 'accessing'!
  1186. identityHash
  1187. ^ 'NIL'
  1188. ! !
  1189. !UndefinedObject methodsFor: 'converting'!
  1190. asJavaScriptObject
  1191. ^ null
  1192. !
  1193. asJavaScriptSource
  1194. ^ 'null'
  1195. ! !
  1196. !UndefinedObject methodsFor: 'copying'!
  1197. deepCopy
  1198. ^ self
  1199. !
  1200. shallowCopy
  1201. ^ self
  1202. ! !
  1203. !UndefinedObject methodsFor: 'evaluating'!
  1204. value
  1205. <inlineJS: 'return null'>
  1206. ! !
  1207. !UndefinedObject methodsFor: 'printing'!
  1208. printOn: aStream
  1209. aStream nextPutAll: 'nil'
  1210. ! !
  1211. !UndefinedObject methodsFor: 'testing'!
  1212. == anObject
  1213. ^ anObject isNil
  1214. !
  1215. ifNil: aBlock
  1216. "inlined in the Compiler"
  1217. ^ self ifNil: aBlock ifNotNil: []
  1218. !
  1219. ifNil: aBlock ifNotNil: anotherBlock
  1220. "inlined in the Compiler"
  1221. ^ aBlock value
  1222. !
  1223. ifNotNil: aBlock
  1224. "inlined in the Compiler"
  1225. ^ self
  1226. !
  1227. ifNotNil: aBlock ifNil: anotherBlock
  1228. "inlined in the Compiler"
  1229. ^ anotherBlock value
  1230. !
  1231. isImmutable
  1232. ^ true
  1233. !
  1234. isNil
  1235. ^ true
  1236. !
  1237. notNil
  1238. ^ false
  1239. ! !
  1240. !UndefinedObject class methodsFor: 'instance creation'!
  1241. new
  1242. self error: 'You cannot create new instances of UndefinedObject. Use nil'
  1243. ! !
  1244. Object setTraitComposition: {TIsInGroup} asTraitComposition!
  1245. UndefinedObject setTraitComposition: {TSubclassable} asTraitComposition!
  1246. ! !