Kernel-Methods.st 14 KB

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