2
0

Kernel-Methods.st 14 KB

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