Kernel-Methods.st 15 KB

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