Kernel-Objects.st 29 KB

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