Kernel-Methods.st 14 KB

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