Kernel-Methods.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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 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 protocol beginsWith: '*') ifFalse: [
  179. ^ self methodClass package ].
  180. ^ Package
  181. named: self protocol allButFirst
  182. ifAbsent: [ self methodClass package ]
  183. !
  184. protocol
  185. ^ (self basicAt: 'protocol') ifNil: [ self defaultProtocol ]
  186. !
  187. protocol: aString
  188. | oldProtocol |
  189. oldProtocol := self protocol.
  190. self basicAt: 'protocol' put: aString.
  191. SystemAnnouncer current announce: (MethodMoved new
  192. method: self;
  193. oldProtocol: oldProtocol;
  194. yourself).
  195. self methodClass ifNotNil: [ :methodClass |
  196. methodClass organization addElement: aString.
  197. methodClass removeProtocolIfEmpty: oldProtocol ]
  198. !
  199. referencedClasses
  200. ^ self basicAt: 'referencedClasses'
  201. !
  202. selector
  203. ^ self basicAt: 'selector'
  204. !
  205. selector: aString
  206. self basicAt: 'selector' put: aString
  207. !
  208. source
  209. ^ (self basicAt: 'source') ifNil: [ '' ]
  210. !
  211. source: aString
  212. self basicAt: 'source' put: aString
  213. ! !
  214. !CompiledMethod methodsFor: 'browsing'!
  215. browse
  216. Finder findMethod: self
  217. ! !
  218. !CompiledMethod methodsFor: 'defaults'!
  219. defaultProtocol
  220. ^ 'as yet unclassified'
  221. ! !
  222. !CompiledMethod methodsFor: 'evaluating'!
  223. sendTo: anObject arguments: aCollection
  224. ^ self fn applyTo: anObject arguments: aCollection
  225. ! !
  226. !CompiledMethod methodsFor: 'testing'!
  227. isCompiledMethod
  228. ^ true
  229. !
  230. isOverridden
  231. | selector |
  232. selector := self selector.
  233. self methodClass allSubclassesDo: [ :each |
  234. (each includesSelector: selector)
  235. ifTrue: [ ^ true ] ].
  236. ^ false
  237. !
  238. isOverride
  239. | superclass |
  240. superclass := self methodClass superclass.
  241. superclass ifNil: [ ^ false ].
  242. ^ (self methodClass superclass lookupSelector: self selector) notNil
  243. ! !
  244. Object subclass: #ForkPool
  245. instanceVariableNames: 'poolSize maxPoolSize queue worker'
  246. package: 'Kernel-Methods'!
  247. !ForkPool commentStamp!
  248. I am responsible for handling forked blocks.
  249. The pool size sets the maximum concurrent forked blocks.
  250. ## API
  251. The default instance is accessed with `#default`.
  252. The maximum concurrent forked blocks can be set with `#maxPoolSize:`.
  253. Forking is done via `BlockClosure >> #fork`!
  254. !ForkPool methodsFor: 'accessing'!
  255. maxPoolSize
  256. ^ maxPoolSize ifNil: [ self defaultMaxPoolSize ]
  257. !
  258. maxPoolSize: anInteger
  259. maxPoolSize := anInteger
  260. ! !
  261. !ForkPool methodsFor: 'actions'!
  262. fork: aBlock
  263. poolSize < self maxPoolSize ifTrue: [ self addWorker ].
  264. queue nextPut: aBlock
  265. ! !
  266. !ForkPool methodsFor: 'defaults'!
  267. defaultMaxPoolSize
  268. ^ self class defaultMaxPoolSize
  269. ! !
  270. !ForkPool methodsFor: 'initialization'!
  271. initialize
  272. super initialize.
  273. poolSize := 0.
  274. queue := Queue new.
  275. worker := self makeWorker
  276. !
  277. makeWorker
  278. | sentinel |
  279. sentinel := Object new.
  280. ^ [ | block |
  281. poolSize := poolSize - 1.
  282. block := queue nextIfAbsent: [ sentinel ].
  283. block == sentinel ifFalse: [
  284. [ block value ] ensure: [ self addWorker ] ]]
  285. ! !
  286. !ForkPool methodsFor: 'private'!
  287. addWorker
  288. worker valueWithTimeout: 0.
  289. poolSize := poolSize + 1
  290. ! !
  291. ForkPool class instanceVariableNames: 'default'!
  292. !ForkPool class methodsFor: 'accessing'!
  293. default
  294. ^ default ifNil: [ default := self new ]
  295. !
  296. defaultMaxPoolSize
  297. ^ 100
  298. !
  299. resetDefault
  300. default := nil
  301. ! !
  302. Object subclass: #Message
  303. instanceVariableNames: 'selector arguments'
  304. package: 'Kernel-Methods'!
  305. !Message commentStamp!
  306. In general, the system does not use instances of me for efficiency reasons.
  307. 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.
  308. This instance is sent it as an argument with the message `#doesNotUnderstand:` to the receiver.
  309. See boot.js, `messageNotUnderstood` and its counterpart `Object >> #doesNotUnderstand:`
  310. ## API
  311. Besides accessing methods, `#sendTo:` provides a convenient way to send a message to an object.!
  312. !Message methodsFor: 'accessing'!
  313. arguments
  314. ^ arguments
  315. !
  316. arguments: anArray
  317. arguments := anArray
  318. !
  319. selector
  320. ^ selector
  321. !
  322. selector: aString
  323. selector := aString
  324. ! !
  325. !Message methodsFor: 'actions'!
  326. sendTo: anObject
  327. ^ anObject perform: self selector withArguments: self arguments
  328. ! !
  329. !Message methodsFor: 'printing'!
  330. printOn: aStream
  331. super printOn: aStream.
  332. aStream
  333. nextPutAll: '(';
  334. nextPutAll: self selector;
  335. nextPutAll: ')'
  336. ! !
  337. !Message class methodsFor: 'instance creation'!
  338. selector: aString arguments: anArray
  339. ^ self new
  340. selector: aString;
  341. arguments: anArray;
  342. yourself
  343. ! !
  344. Object subclass: #MessageSend
  345. instanceVariableNames: 'receiver message'
  346. package: 'Kernel-Methods'!
  347. !MessageSend commentStamp!
  348. I encapsulate message sends to objects. Arguments can be either predefined or supplied when the message send is performed.
  349. ## API
  350. Use `#value` to perform a message send with its predefined arguments and `#value:*` if additonal arguments have to supplied.!
  351. !MessageSend methodsFor: 'accessing'!
  352. arguments
  353. ^ message arguments
  354. !
  355. arguments: aCollection
  356. message arguments: aCollection
  357. !
  358. receiver
  359. ^ receiver
  360. !
  361. receiver: anObject
  362. receiver := anObject
  363. !
  364. selector
  365. ^ message selector
  366. !
  367. selector: aString
  368. message selector: aString
  369. ! !
  370. !MessageSend methodsFor: 'evaluating'!
  371. value
  372. ^ message sendTo: self receiver
  373. !
  374. value: anObject
  375. ^ message
  376. arguments: { anObject };
  377. sendTo: self receiver
  378. !
  379. value: firstArgument value: secondArgument
  380. ^ message
  381. arguments: { firstArgument. secondArgument };
  382. sendTo: self receiver
  383. !
  384. value: firstArgument value: secondArgument value: thirdArgument
  385. ^ message
  386. arguments: { firstArgument. secondArgument. thirdArgument };
  387. sendTo: self receiver
  388. !
  389. valueWithPossibleArguments: aCollection
  390. self arguments: aCollection.
  391. ^ self value
  392. ! !
  393. !MessageSend methodsFor: 'initialization'!
  394. initialize
  395. super initialize.
  396. message := Message new
  397. ! !
  398. !MessageSend methodsFor: 'printing'!
  399. printOn: aStream
  400. super printOn: aStream.
  401. aStream
  402. nextPutAll: '(';
  403. nextPutAll: self receiver;
  404. nextPutAll: ' >> ';
  405. nextPutAll: self selector;
  406. nextPutAll: ')'
  407. ! !
  408. Object subclass: #MethodContext
  409. instanceVariableNames: ''
  410. package: 'Kernel-Methods'!
  411. !MethodContext commentStamp!
  412. 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.
  413. My instances are JavaScript `SmalltalkMethodContext` objects defined in `boot.js`.!
  414. !MethodContext methodsFor: 'accessing'!
  415. evaluatedSelector
  416. <return self.evaluatedSelector>
  417. !
  418. home
  419. <return self.homeContext>
  420. !
  421. index
  422. <return self.index || 0>
  423. !
  424. locals
  425. <return self.locals || {}>
  426. !
  427. method
  428. ^ self methodContext ifNotNil: [
  429. self methodContext receiver class lookupSelector: self methodContext selector ]
  430. !
  431. methodContext
  432. self isBlockContext ifFalse: [ ^ self ].
  433. ^ self outerContext ifNotNil: [ :outer |
  434. outer methodContext ]
  435. !
  436. outerContext
  437. <return self.outerContext || self.homeContext>
  438. !
  439. receiver
  440. <return self.receiver>
  441. !
  442. selector
  443. <
  444. if(self.selector) {
  445. return smalltalk.convertSelector(self.selector);
  446. } else {
  447. return nil;
  448. }
  449. >
  450. !
  451. sendIndexAt: aSelector
  452. <return self.sendIdx[aSelector] || 0>
  453. !
  454. sendIndexes
  455. <return self.sendIdx>
  456. !
  457. temps
  458. self deprecatedAPI.
  459. ^ self locals
  460. ! !
  461. !MethodContext methodsFor: 'converting'!
  462. asString
  463. ^ self isBlockContext
  464. ifTrue: [ 'a block (in ', self methodContext asString, ')' ]
  465. ifFalse: [ self receiver class name, ' >> ', self selector ]
  466. ! !
  467. !MethodContext methodsFor: 'printing'!
  468. printOn: aStream
  469. super printOn: aStream.
  470. aStream
  471. nextPutAll: '(';
  472. nextPutAll: self asString;
  473. nextPutAll: ')'
  474. ! !
  475. !MethodContext methodsFor: 'testing'!
  476. isBlockContext
  477. "Block context do not have selectors."
  478. ^ self selector isNil
  479. ! !
  480. Object subclass: #NativeFunction
  481. instanceVariableNames: ''
  482. package: 'Kernel-Methods'!
  483. !NativeFunction commentStamp!
  484. I am a wrapper around native functions, such as `WebSocket`.
  485. For 'normal' functions (whose constructor is the JavaScript `Function` object), use `BlockClosure`.
  486. ## API
  487. See the class-side `instance creation` methods for instance creation.
  488. Created instances will most probably be instance of `JSObjectProxy`.
  489. ## Usage example:
  490. | ws |
  491. ws := NativeFunction constructor: 'WebSocket' value: 'ws://localhost'.
  492. ws at: 'onopen' put: [ ws send: 'hey there from Amber' ]!
  493. !NativeFunction class methodsFor: 'instance creation'!
  494. constructor: aString
  495. <
  496. var native=eval(aString);
  497. return new native();
  498. >
  499. !
  500. constructor: aString value:anObject
  501. <
  502. var native=eval(aString);
  503. return new native(anObject);
  504. >
  505. !
  506. constructor: aString value:anObject value: anObject2
  507. <
  508. var native=eval(aString);
  509. return new native(anObject,anObject2);
  510. >
  511. !
  512. constructor: aString value:anObject value: anObject2 value:anObject3
  513. <
  514. var native=eval(aString);
  515. return new native(anObject,anObject2, anObject3);
  516. >
  517. ! !
  518. !NativeFunction class methodsFor: 'testing'!
  519. exists: aString
  520. ^ PlatformInterface existsGlobal: aString
  521. ! !
  522. Object subclass: #Timeout
  523. instanceVariableNames: 'rawTimeout'
  524. package: 'Kernel-Methods'!
  525. !Timeout commentStamp!
  526. I am wrapping the returns from `set{Timeout,Interval}`.
  527. ## Motivation
  528. Number suffices in browsers, but node.js returns an object.!
  529. !Timeout methodsFor: 'accessing'!
  530. rawTimeout: anObject
  531. rawTimeout := anObject
  532. ! !
  533. !Timeout methodsFor: 'timeout/interval'!
  534. clearInterval
  535. <
  536. var interval = self["@rawTimeout"];
  537. clearInterval(interval);
  538. >
  539. !
  540. clearTimeout
  541. <
  542. var timeout = self["@rawTimeout"];
  543. clearTimeout(timeout);
  544. >
  545. ! !
  546. !Timeout class methodsFor: 'instance creation'!
  547. on: anObject
  548. ^ self new rawTimeout: anObject; yourself
  549. ! !