Kernel-Methods.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. Smalltalk createPackage: 'Kernel-Methods'!
  2. Object subclass: #BlockClosure
  3. instanceVariableNames: ''
  4. package: 'Kernel-Methods'!
  5. !BlockClosure commentStamp!
  6. I represent a lexical closure.
  7. I am is directly mapped to JavaScript Function.
  8. ## API
  9. 1. Evaluation
  10. My instances get evaluated with the `#value*` methods in the 'evaluating' protocol.
  11. Example: ` [ :x | x + 1 ] value: 3 "Answers 4" `
  12. 2. Control structures
  13. Blocks are used (together with `Boolean`) for control structures (methods in the `controlling` protocol).
  14. Example: `aBlock whileTrue: [ ... ]`
  15. 3. Error handling
  16. I provide the `#on:do:` method for handling exceptions.
  17. Example: ` aBlock on: MessageNotUnderstood do: [ :ex | ... ] `!
  18. !BlockClosure methodsFor: 'accessing'!
  19. compiledSource
  20. <return self.toString()>
  21. !
  22. numArgs
  23. <return self.length>
  24. !
  25. receiver
  26. ^ nil
  27. ! !
  28. !BlockClosure methodsFor: 'controlling'!
  29. whileFalse
  30. self whileFalse: []
  31. !
  32. whileFalse: aBlock
  33. <while(!!smalltalk.assert(self._value())) {aBlock._value()}>
  34. !
  35. whileTrue
  36. self whileTrue: []
  37. !
  38. whileTrue: aBlock
  39. <while(smalltalk.assert(self._value())) {aBlock._value()}>
  40. ! !
  41. !BlockClosure methodsFor: 'converting'!
  42. asCompiledMethod: aString
  43. <return smalltalk.method({selector:aString, fn:self});>
  44. !
  45. currySelf
  46. "Transforms [ :selfarg :x :y | stcode ] block
  47. which represents JS function (selfarg, x, y, ...) {jscode}
  48. into function (x, y, ...) {jscode} that takes selfarg from 'this'.
  49. IOW, it is usable as JS method and first arg takes the receiver."
  50. <
  51. return function () {
  52. var args = [ this ];
  53. args.push.apply(args, arguments);
  54. return self.apply(null, args);
  55. }
  56. >
  57. ! !
  58. !BlockClosure methodsFor: 'error handling'!
  59. on: anErrorClass do: aBlock
  60. "All exceptions thrown in the Smalltalk stack are cought.
  61. Convert all JS exceptions to JavaScriptException instances."
  62. ^ self try: self catch: [ :error | | smalltalkError |
  63. smalltalkError := Smalltalk asSmalltalkException: error.
  64. (smalltalkError isKindOf: anErrorClass)
  65. ifTrue: [ aBlock value: smalltalkError ]
  66. ifFalse: [ smalltalkError resignal ] ]
  67. ! !
  68. !BlockClosure methodsFor: 'evaluating'!
  69. applyTo: anObject arguments: aCollection
  70. <return self.apply(anObject, aCollection)>
  71. !
  72. ensure: aBlock
  73. <try{return self._value()}finally{aBlock._value()}>
  74. !
  75. new
  76. "Use the receiver as a JS constructor.
  77. *Do not* use this method to instanciate Smalltalk objects!!"
  78. <return new self()>
  79. !
  80. newValue: anObject
  81. ^ self newWithValues: { anObject }
  82. !
  83. newValue: anObject value: anObject2
  84. ^ self newWithValues: { anObject. anObject2 }.
  85. !
  86. newValue: anObject value: anObject2 value: anObject3
  87. ^ self newWithValues: { anObject. anObject2. anObject3 }.
  88. !
  89. newWithValues: aCollection
  90. "Simulates JS new operator by combination of Object.create and .apply"
  91. <
  92. var object = Object.create(self.prototype);
  93. var result = self.apply(object, aCollection);
  94. return typeof result === "object" ? result : object;
  95. >
  96. !
  97. timeToRun
  98. "Answer the number of milliseconds taken to execute this block."
  99. ^ Date millisecondsToRun: self
  100. !
  101. value
  102. <return self();>
  103. !
  104. value: anArg
  105. <return self(anArg);>
  106. !
  107. value: firstArg value: secondArg
  108. <return self(firstArg, secondArg);>
  109. !
  110. value: firstArg value: secondArg value: thirdArg
  111. <return self(firstArg, secondArg, thirdArg);>
  112. !
  113. valueWithPossibleArguments: aCollection
  114. <return self.apply(null, aCollection);>
  115. ! !
  116. !BlockClosure methodsFor: 'timeout/interval'!
  117. fork
  118. ForkPool default fork: self
  119. !
  120. valueWithInterval: aNumber
  121. <
  122. var interval = setInterval(self, aNumber);
  123. return globals.Timeout._on_(interval);
  124. >
  125. !
  126. valueWithTimeout: aNumber
  127. <
  128. var timeout = setTimeout(self, aNumber);
  129. return globals.Timeout._on_(timeout);
  130. >
  131. ! !
  132. Object subclass: #CompiledMethod
  133. instanceVariableNames: ''
  134. package: 'Kernel-Methods'!
  135. !CompiledMethod commentStamp!
  136. I represent a class method of the system. I hold the source and compiled code of a class method.
  137. ## API
  138. My instances can be accessed using `Behavior >> #methodAt:`
  139. Object methodAt: 'asString'
  140. Source code access:
  141. (String methodAt: 'lines') source
  142. Referenced classes:
  143. (String methodAt: 'lines') referencedClasses
  144. Messages sent from an instance:
  145. (String methodAt: 'lines') messageSends!
  146. !CompiledMethod methodsFor: 'accessing'!
  147. arguments
  148. <return self.args || []>
  149. !
  150. category
  151. ^ self protocol
  152. !
  153. fn
  154. ^ self basicAt: 'fn'
  155. !
  156. fn: aBlock
  157. self basicAt: 'fn' put: aBlock
  158. !
  159. messageSends
  160. ^ self basicAt: 'messageSends'
  161. !
  162. methodClass
  163. ^ self basicAt: 'methodClass'
  164. !
  165. package
  166. "Answer the package the receiver belongs to:
  167. - if it is an extension method, answer the corresponding package
  168. - else answer the `methodClass` package"
  169. (self protocol beginsWith: '*') ifFalse: [
  170. ^ self methodClass package ].
  171. ^ Package
  172. named: self protocol allButFirst
  173. ifAbsent: [ self methodClass package ]
  174. !
  175. protocol
  176. ^ (self basicAt: 'protocol') ifNil: [ self defaultProtocol ]
  177. !
  178. protocol: aString
  179. | oldProtocol |
  180. oldProtocol := self protocol.
  181. self basicAt: 'protocol' put: aString.
  182. SystemAnnouncer current announce: (MethodMoved new
  183. method: self;
  184. oldProtocol: oldProtocol;
  185. yourself).
  186. self methodClass ifNotNil: [ :methodClass |
  187. methodClass organization addElement: aString.
  188. methodClass removeProtocolIfEmpty: oldProtocol ]
  189. !
  190. referencedClasses
  191. ^ self basicAt: 'referencedClasses'
  192. !
  193. selector
  194. ^ self basicAt: 'selector'
  195. !
  196. selector: aString
  197. self basicAt: 'selector' put: aString
  198. !
  199. source
  200. ^ (self basicAt: 'source') ifNil: [ '' ]
  201. !
  202. source: aString
  203. self basicAt: 'source' put: aString
  204. ! !
  205. !CompiledMethod methodsFor: 'defaults'!
  206. defaultProtocol
  207. ^ 'as yet unclassified'
  208. ! !
  209. !CompiledMethod methodsFor: 'evaluating'!
  210. sendTo: anObject arguments: aCollection
  211. ^ self fn applyTo: anObject arguments: aCollection
  212. ! !
  213. !CompiledMethod methodsFor: 'testing'!
  214. isCompiledMethod
  215. ^ true
  216. !
  217. isOverridden
  218. | selector |
  219. selector := self selector.
  220. self methodClass allSubclassesDo: [ :each |
  221. (each includesSelector: selector)
  222. ifTrue: [ ^ true ] ].
  223. ^ false
  224. !
  225. isOverride
  226. | superclass |
  227. superclass := self methodClass superclass.
  228. superclass ifNil: [ ^ false ].
  229. ^ (self methodClass superclass lookupSelector: self selector) notNil
  230. ! !
  231. Object subclass: #ForkPool
  232. instanceVariableNames: 'poolSize maxPoolSize queue worker'
  233. package: 'Kernel-Methods'!
  234. !ForkPool commentStamp!
  235. I am responsible for handling forked blocks.
  236. The pool size sets the maximum concurrent forked blocks.
  237. ## API
  238. The default instance is accessed with `#default`.
  239. The maximum concurrent forked blocks can be set with `#maxPoolSize:`.
  240. Forking is done via `BlockClosure >> #fork`!
  241. !ForkPool methodsFor: 'accessing'!
  242. maxPoolSize
  243. ^ maxPoolSize ifNil: [ self defaultMaxPoolSize ]
  244. !
  245. maxPoolSize: anInteger
  246. maxPoolSize := anInteger
  247. ! !
  248. !ForkPool methodsFor: 'actions'!
  249. fork: aBlock
  250. poolSize < self maxPoolSize ifTrue: [ self addWorker ].
  251. queue nextPut: aBlock
  252. ! !
  253. !ForkPool methodsFor: 'defaults'!
  254. defaultMaxPoolSize
  255. ^ self class defaultMaxPoolSize
  256. ! !
  257. !ForkPool methodsFor: 'initialization'!
  258. initialize
  259. super initialize.
  260. poolSize := 0.
  261. queue := Queue new.
  262. worker := self makeWorker
  263. !
  264. makeWorker
  265. | sentinel |
  266. sentinel := Object new.
  267. ^ [ | block |
  268. poolSize := poolSize - 1.
  269. block := queue nextIfAbsent: [ sentinel ].
  270. block == sentinel ifFalse: [
  271. [ block value ] ensure: [ self addWorker ] ]]
  272. ! !
  273. !ForkPool methodsFor: 'private'!
  274. addWorker
  275. worker valueWithTimeout: 0.
  276. poolSize := poolSize + 1
  277. ! !
  278. ForkPool class instanceVariableNames: 'default'!
  279. !ForkPool class methodsFor: 'accessing'!
  280. default
  281. ^ default ifNil: [ default := self new ]
  282. !
  283. defaultMaxPoolSize
  284. ^ 100
  285. !
  286. resetDefault
  287. default := nil
  288. ! !
  289. Object subclass: #Message
  290. instanceVariableNames: 'selector arguments'
  291. package: 'Kernel-Methods'!
  292. !Message commentStamp!
  293. In general, the system does not use instances of me for efficiency reasons.
  294. However, when a message is not understood by its receiver, the interpreter will make up an instance of it in order to capture the information involved in an actual message transmission.
  295. This instance is sent it as an argument with the message `#doesNotUnderstand:` to the receiver.
  296. See boot.js, `messageNotUnderstood` and its counterpart `Object >> #doesNotUnderstand:`
  297. ## API
  298. Besides accessing methods, `#sendTo:` provides a convenient way to send a message to an object.!
  299. !Message methodsFor: 'accessing'!
  300. arguments
  301. ^ arguments
  302. !
  303. arguments: anArray
  304. arguments := anArray
  305. !
  306. selector
  307. ^ selector
  308. !
  309. selector: aString
  310. selector := aString
  311. ! !
  312. !Message methodsFor: 'actions'!
  313. sendTo: anObject
  314. ^ anObject perform: self selector withArguments: self arguments
  315. ! !
  316. !Message methodsFor: 'printing'!
  317. printOn: aStream
  318. super printOn: aStream.
  319. aStream
  320. nextPutAll: '(';
  321. nextPutAll: self selector;
  322. nextPutAll: ')'
  323. ! !
  324. !Message class methodsFor: 'instance creation'!
  325. selector: aString arguments: anArray
  326. ^ self new
  327. selector: aString;
  328. arguments: anArray;
  329. yourself
  330. ! !
  331. Object subclass: #MessageSend
  332. instanceVariableNames: 'receiver message'
  333. package: 'Kernel-Methods'!
  334. !MessageSend commentStamp!
  335. I encapsulate message sends to objects. Arguments can be either predefined or supplied when the message send is performed.
  336. ## API
  337. Use `#value` to perform a message send with its predefined arguments and `#value:*` if additonal arguments have to supplied.!
  338. !MessageSend methodsFor: 'accessing'!
  339. arguments
  340. ^ message arguments
  341. !
  342. arguments: aCollection
  343. message arguments: aCollection
  344. !
  345. receiver
  346. ^ receiver
  347. !
  348. receiver: anObject
  349. receiver := anObject
  350. !
  351. selector
  352. ^ message selector
  353. !
  354. selector: aString
  355. message selector: aString
  356. ! !
  357. !MessageSend methodsFor: 'evaluating'!
  358. value
  359. ^ message sendTo: self receiver
  360. !
  361. value: anObject
  362. ^ message
  363. arguments: { anObject };
  364. sendTo: self receiver
  365. !
  366. value: firstArgument value: secondArgument
  367. ^ message
  368. arguments: { firstArgument. secondArgument };
  369. sendTo: self receiver
  370. !
  371. value: firstArgument value: secondArgument value: thirdArgument
  372. ^ message
  373. arguments: { firstArgument. secondArgument. thirdArgument };
  374. sendTo: self receiver
  375. !
  376. valueWithPossibleArguments: aCollection
  377. self arguments: aCollection.
  378. ^ self value
  379. ! !
  380. !MessageSend methodsFor: 'initialization'!
  381. initialize
  382. super initialize.
  383. message := Message new
  384. ! !
  385. !MessageSend methodsFor: 'printing'!
  386. printOn: aStream
  387. super printOn: aStream.
  388. aStream
  389. nextPutAll: '(';
  390. nextPutAll: self receiver;
  391. nextPutAll: ' >> ';
  392. nextPutAll: self selector;
  393. nextPutAll: ')'
  394. ! !
  395. Object subclass: #MethodContext
  396. instanceVariableNames: ''
  397. package: 'Kernel-Methods'!
  398. !MethodContext commentStamp!
  399. I hold all the dynamic state associated with the execution of either a method activation resulting from a message send. I am used to build the call stack while debugging.
  400. My instances are JavaScript `SmalltalkMethodContext` objects defined in `boot.js`.!
  401. !MethodContext methodsFor: 'accessing'!
  402. evaluatedSelector
  403. <return self.evaluatedSelector>
  404. !
  405. home
  406. <return self.homeContext>
  407. !
  408. index
  409. <return self.index || 0>
  410. !
  411. locals
  412. <return self.locals || {}>
  413. !
  414. method
  415. ^ self methodContext ifNotNil: [
  416. self methodContext receiver class lookupSelector: self methodContext selector ]
  417. !
  418. methodContext
  419. self isBlockContext ifFalse: [ ^ self ].
  420. ^ self outerContext ifNotNil: [ :outer |
  421. outer methodContext ]
  422. !
  423. outerContext
  424. <return self.outerContext || self.homeContext>
  425. !
  426. receiver
  427. <return self.receiver>
  428. !
  429. selector
  430. <
  431. if(self.selector) {
  432. return smalltalk.convertSelector(self.selector);
  433. } else {
  434. return nil;
  435. }
  436. >
  437. !
  438. sendIndexAt: aSelector
  439. <return self.sendIdx[aSelector] || 0>
  440. !
  441. sendIndexes
  442. <return self.sendIdx>
  443. !
  444. temps
  445. self deprecatedAPI.
  446. ^ self locals
  447. ! !
  448. !MethodContext methodsFor: 'converting'!
  449. asString
  450. ^ self isBlockContext
  451. ifTrue: [ 'a block (in ', self methodContext asString, ')' ]
  452. ifFalse: [ self receiver class name, ' >> ', self selector ]
  453. ! !
  454. !MethodContext methodsFor: 'printing'!
  455. printOn: aStream
  456. super printOn: aStream.
  457. aStream
  458. nextPutAll: '(';
  459. nextPutAll: self asString;
  460. nextPutAll: ')'
  461. ! !
  462. !MethodContext methodsFor: 'testing'!
  463. isBlockContext
  464. "Block context do not have selectors."
  465. ^ self selector isNil
  466. ! !
  467. Object subclass: #NativeFunction
  468. instanceVariableNames: ''
  469. package: 'Kernel-Methods'!
  470. !NativeFunction commentStamp!
  471. I am a wrapper around native functions, such as `WebSocket`.
  472. For 'normal' functions (whose constructor is the JavaScript `Function` object), use `BlockClosure`.
  473. ## API
  474. See the class-side `instance creation` methods for instance creation.
  475. Created instances will most probably be instance of `JSObjectProxy`.
  476. ## Usage example:
  477. | ws |
  478. ws := NativeFunction constructor: 'WebSocket' value: 'ws://localhost'.
  479. ws at: 'onopen' put: [ ws send: 'hey there from Amber' ]!
  480. !NativeFunction class methodsFor: 'instance creation'!
  481. constructor: aString
  482. <
  483. var native=eval(aString);
  484. return new native();
  485. >
  486. !
  487. constructor: aString value:anObject
  488. <
  489. var native=eval(aString);
  490. return new native(anObject);
  491. >
  492. !
  493. constructor: aString value:anObject value: anObject2
  494. <
  495. var native=eval(aString);
  496. return new native(anObject,anObject2);
  497. >
  498. !
  499. constructor: aString value:anObject value: anObject2 value:anObject3
  500. <
  501. var native=eval(aString);
  502. return new native(anObject,anObject2, anObject3);
  503. >
  504. ! !
  505. !NativeFunction class methodsFor: 'testing'!
  506. exists: aString
  507. ^ PlatformInterface existsGlobal: aString
  508. ! !
  509. Object subclass: #Timeout
  510. instanceVariableNames: 'rawTimeout'
  511. package: 'Kernel-Methods'!
  512. !Timeout commentStamp!
  513. I am wrapping the returns from `set{Timeout,Interval}`.
  514. ## Motivation
  515. Number suffices in browsers, but node.js returns an object.!
  516. !Timeout methodsFor: 'accessing'!
  517. rawTimeout: anObject
  518. rawTimeout := anObject
  519. ! !
  520. !Timeout methodsFor: 'timeout/interval'!
  521. clearInterval
  522. <
  523. var interval = self["@rawTimeout"];
  524. clearInterval(interval);
  525. >
  526. !
  527. clearTimeout
  528. <
  529. var timeout = self["@rawTimeout"];
  530. clearTimeout(timeout);
  531. >
  532. ! !
  533. !Timeout class methodsFor: 'instance creation'!
  534. on: anObject
  535. ^ self new rawTimeout: anObject; yourself
  536. ! !