1
0

Kernel-Methods.st 14 KB

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