2
0

Kernel-Infrastructure.st 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. Smalltalk createPackage: 'Kernel-Infrastructure'!
  2. Object subclass: #InspectorHandler
  3. instanceVariableNames: ''
  4. package: 'Kernel-Infrastructure'!
  5. !InspectorHandler commentStamp!
  6. I am responsible for inspecting object.
  7. My class-side `inspector` inst var holds the current inspector I'm delegating object inspection to.
  8. The default inspector object is the transcript.!
  9. InspectorHandler class instanceVariableNames: 'inspector'!
  10. !InspectorHandler class methodsFor: 'accessing'!
  11. inspector
  12. ^ inspector ifNil: [ inspector := Transcript ]
  13. ! !
  14. !InspectorHandler class methodsFor: 'registration'!
  15. inspect: anObject
  16. ^ self inspector inspect: anObject
  17. !
  18. register: anInspector
  19. inspector := anInspector
  20. ! !
  21. Object subclass: #InterfacingObject
  22. instanceVariableNames: ''
  23. package: 'Kernel-Infrastructure'!
  24. !InterfacingObject commentStamp!
  25. I am superclass of all object that interface with user or environment. `Widget` and a few other classes are subclasses of me. I delegate all of the above APIs to `PlatformInterface`.
  26. ## API
  27. self alert: 'Hey, there is a problem'.
  28. self confirm: 'Affirmative?'.
  29. self prompt: 'Your name:'.
  30. self ajax: #{
  31. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  32. }.!
  33. !InterfacingObject methodsFor: 'actions'!
  34. ajax: anObject
  35. ^ PlatformInterface ajax: anObject
  36. !
  37. alert: aString
  38. ^ PlatformInterface alert: aString
  39. !
  40. confirm: aString
  41. ^ PlatformInterface confirm: aString
  42. !
  43. prompt: aString
  44. ^ PlatformInterface prompt: aString
  45. ! !
  46. InterfacingObject subclass: #Environment
  47. instanceVariableNames: ''
  48. package: 'Kernel-Infrastructure'!
  49. !Environment commentStamp!
  50. I provide an unified entry point to manipulate Amber packages, classes and methods.
  51. Typical use cases include IDEs, remote access and restricting browsing.!
  52. !Environment methodsFor: 'accessing'!
  53. allSelectors
  54. ^ Smalltalk vm allSelectors
  55. !
  56. availableClassNames
  57. ^ Smalltalk classes
  58. collect: [ :each | each name ]
  59. !
  60. availablePackageNames
  61. ^ Smalltalk packages
  62. collect: [ :each | each name ]
  63. !
  64. availableProtocolsFor: aClass
  65. | protocols |
  66. protocols := aClass protocols.
  67. aClass superclass ifNotNil: [ protocols addAll: (self availableProtocolsFor: aClass superclass) ].
  68. ^ protocols asSet asArray sort
  69. !
  70. classBuilder
  71. ^ ClassBuilder new
  72. !
  73. classNamed: aString
  74. ^ (Smalltalk globals at: aString asSymbol)
  75. ifNil: [ self error: 'Invalid class name' ]
  76. !
  77. classes
  78. ^ Smalltalk classes
  79. !
  80. doItReceiver
  81. ^ DoIt new
  82. !
  83. packages
  84. ^ Smalltalk packages
  85. !
  86. systemAnnouncer
  87. ^ (Smalltalk globals at: #SystemAnnouncer) current
  88. ! !
  89. !Environment methodsFor: 'actions'!
  90. commitPackage: aPackage
  91. aPackage commit
  92. !
  93. copyClass: aClass to: aClassName
  94. (Smalltalk globals at: aClassName)
  95. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  96. ClassBuilder new copyClass: aClass named: aClassName
  97. !
  98. eval: aString on: aReceiver
  99. | compiler |
  100. compiler := Compiler new.
  101. [ compiler parseExpression: aString ] on: Error do: [ :ex |
  102. ^ self alert: ex messageText ].
  103. ^ compiler evaluateExpression: aString on: aReceiver
  104. !
  105. inspect: anObject
  106. InspectorHandler inspector inspect: anObject
  107. !
  108. moveClass: aClass toPackage: aPackageName
  109. | package |
  110. package := Package named: aPackageName.
  111. package ifNil: [ self error: 'Invalid package name' ].
  112. package == aClass package ifTrue: [ ^ self ].
  113. aClass package: package
  114. !
  115. moveMethod: aMethod toClass: aClassName
  116. | destinationClass |
  117. destinationClass := self classNamed: aClassName.
  118. destinationClass == aMethod methodClass ifTrue: [ ^ self ].
  119. destinationClass
  120. compile: aMethod source
  121. protocol: aMethod protocol.
  122. aMethod methodClass
  123. removeCompiledMethod: aMethod
  124. !
  125. moveMethod: aMethod toProtocol: aProtocol
  126. aMethod protocol: aProtocol
  127. !
  128. registerErrorHandler: anErrorHandler
  129. ErrorHandler setCurrent: anErrorHandler
  130. !
  131. registerInspector: anInspector
  132. InspectorHandler register: anInspector
  133. !
  134. registerProgressHandler: aProgressHandler
  135. ProgressHandler setCurrent: aProgressHandler
  136. !
  137. removeClass: aClass
  138. Smalltalk removeClass: aClass
  139. !
  140. removeMethod: aMethod
  141. aMethod methodClass removeCompiledMethod: aMethod
  142. !
  143. removeProtocol: aString from: aClass
  144. (aClass methodsInProtocol: aString)
  145. do: [ :each | aClass removeCompiledMethod: each ]
  146. !
  147. renameClass: aClass to: aClassName
  148. (Smalltalk globals at: aClassName)
  149. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  150. ClassBuilder new renameClass: aClass to: aClassName
  151. !
  152. renameProtocol: aString to: anotherString in: aClass
  153. (aClass methodsInProtocol: aString)
  154. do: [ :each | each protocol: anotherString ]
  155. !
  156. setClassCommentOf: aClass to: aString
  157. aClass comment: aString
  158. ! !
  159. !Environment methodsFor: 'compiling'!
  160. addInstVarNamed: aString to: aClass
  161. self classBuilder
  162. addSubclassOf: aClass superclass
  163. named: aClass name
  164. instanceVariableNames: (aClass instanceVariableNames copy add: aString; yourself)
  165. package: aClass package name
  166. !
  167. compileClassComment: aString for: aClass
  168. aClass comment: aString
  169. !
  170. compileClassDefinition: aString
  171. [ self eval: aString on: DoIt new ]
  172. on: Error
  173. do: [ :error | self alert: error messageText ]
  174. !
  175. compileMethod: sourceCode for: class protocol: protocol
  176. ^ class
  177. compile: sourceCode
  178. protocol: protocol
  179. ! !
  180. !Environment methodsFor: 'error handling'!
  181. evaluate: aBlock on: anErrorClass do: exceptionBlock
  182. "Evaluate a block and catch exceptions happening on the environment stack"
  183. self try: aBlock catch: [ :exception |
  184. (exception isKindOf: (self classNamed: anErrorClass name))
  185. ifTrue: [ exceptionBlock value: exception ]
  186. ifFalse: [ exception signal ] ]
  187. ! !
  188. ProtoObject subclass: #JSObjectProxy
  189. instanceVariableNames: 'jsObject'
  190. package: 'Kernel-Infrastructure'!
  191. !JSObjectProxy commentStamp!
  192. I handle sending messages to JavaScript objects, making JavaScript object accessing from Amber fully transparent.
  193. My instances make intensive use of `#doesNotUnderstand:`.
  194. My instances are automatically created by Amber whenever a message is sent to a JavaScript object.
  195. ## Usage examples
  196. JSObjectProxy objects are instanciated by Amber when a Smalltalk message is sent to a JavaScript object.
  197. window alert: 'hello world'.
  198. window inspect.
  199. (window jQuery: 'body') append: 'hello world'
  200. Amber messages sends are converted to JavaScript function calls or object property access _(in this order)_. If n one of them match, a `MessageNotUnderstood` error will be thrown.
  201. ## Message conversion rules
  202. - `someUser name` becomes `someUser.name`
  203. - `someUser name: 'John'` becomes `someUser name = "John"`
  204. - `console log: 'hello world'` becomes `console.log('hello world')`
  205. - `(window jQuery: 'foo') css: 'background' color: 'red'` becomes `window.jQuery('foo').css('background', 'red')`
  206. __Note:__ For keyword-based messages, only the first keyword is kept: `window foo: 1 bar: 2` is equivalent to `window foo: 1 baz: 2`.!
  207. !JSObjectProxy methodsFor: 'accessing'!
  208. at: aString
  209. <return self['@jsObject'][aString]>
  210. !
  211. at: aString ifAbsent: aBlock
  212. "return the aString property or evaluate aBlock if the property is not defined on the object"
  213. <
  214. var obj = self['@jsObject'];
  215. return aString in obj ? obj[aString] : aBlock._value();
  216. >
  217. !
  218. at: aString ifPresent: aBlock
  219. "return the evaluation of aBlock with the value if the property is defined or return nil"
  220. <
  221. var obj = self['@jsObject'];
  222. return aString in obj ? aBlock._value_(obj[aString]) : nil;
  223. >
  224. !
  225. at: aString ifPresent: aBlock ifAbsent: anotherBlock
  226. "return the evaluation of aBlock with the value if the property is defined
  227. or return value of anotherBlock"
  228. <
  229. var obj = self['@jsObject'];
  230. return aString in obj ? aBlock._value_(obj[aString]) : anotherBlock._value();
  231. >
  232. !
  233. at: aString put: anObject
  234. <return self['@jsObject'][aString] = anObject>
  235. !
  236. jsObject
  237. ^ jsObject
  238. !
  239. jsObject: aJSObject
  240. jsObject := aJSObject
  241. !
  242. lookupProperty: aString
  243. "Looks up a property in JS object.
  244. Answer the property if it is present, or nil if it is not present."
  245. <return aString in self._jsObject() ? aString : nil>
  246. ! !
  247. !JSObjectProxy methodsFor: 'comparing'!
  248. = anObject
  249. anObject class == self class ifFalse: [ ^ false ].
  250. ^ self compareJSObjectWith: anObject jsObject
  251. ! !
  252. !JSObjectProxy methodsFor: 'enumerating'!
  253. asJSON
  254. "Answers the receiver in a stringyfy-friendly fashion"
  255. ^ jsObject
  256. !
  257. keysAndValuesDo: aBlock
  258. <
  259. var o = self['@jsObject'];
  260. for(var i in o) {
  261. aBlock._value_value_(i, o[i]);
  262. }
  263. >
  264. ! !
  265. !JSObjectProxy methodsFor: 'printing'!
  266. printOn: aStream
  267. aStream nextPutAll: self printString
  268. !
  269. printString
  270. <
  271. var js = self['@jsObject'];
  272. return js.toString
  273. ? js.toString()
  274. : Object.prototype.toString.call(js)
  275. >
  276. ! !
  277. !JSObjectProxy methodsFor: 'private'!
  278. compareJSObjectWith: aJSObject
  279. <return self["@jsObject"] === aJSObject>
  280. ! !
  281. !JSObjectProxy methodsFor: 'proxy'!
  282. addObjectVariablesTo: aDictionary
  283. <
  284. for(var i in self['@jsObject']) {
  285. aDictionary._at_put_(i, self['@jsObject'][i]);
  286. }
  287. >
  288. !
  289. doesNotUnderstand: aMessage
  290. ^ (self lookupProperty: aMessage selector asJavaScriptSelector)
  291. ifNil: [ super doesNotUnderstand: aMessage ]
  292. ifNotNil: [ :jsSelector |
  293. self
  294. forwardMessage: jsSelector
  295. withArguments: aMessage arguments ]
  296. !
  297. forwardMessage: aString withArguments: anArray
  298. <
  299. return smalltalk.send(self._jsObject(), aString, anArray);
  300. >
  301. !
  302. inspectOn: anInspector
  303. | variables |
  304. variables := Dictionary new.
  305. variables at: '#self' put: self jsObject.
  306. anInspector setLabel: self printString.
  307. self addObjectVariablesTo: variables.
  308. anInspector setVariables: variables
  309. ! !
  310. !JSObjectProxy class methodsFor: 'instance creation'!
  311. on: aJSObject
  312. ^ self new
  313. jsObject: aJSObject;
  314. yourself
  315. ! !
  316. Object subclass: #Organizer
  317. instanceVariableNames: ''
  318. package: 'Kernel-Infrastructure'!
  319. !Organizer commentStamp!
  320. I represent categorization information.
  321. ## API
  322. Use `#addElement:` and `#removeElement:` to manipulate instances.!
  323. !Organizer methodsFor: 'accessing'!
  324. addElement: anObject
  325. <self.elements.addElement(anObject)>
  326. !
  327. elements
  328. ^ (self basicAt: 'elements') copy
  329. !
  330. removeElement: anObject
  331. <self.elements.removeElement(anObject)>
  332. ! !
  333. Organizer subclass: #ClassOrganizer
  334. instanceVariableNames: ''
  335. package: 'Kernel-Infrastructure'!
  336. !ClassOrganizer commentStamp!
  337. I am an organizer specific to classes. I hold method categorization information for classes.!
  338. !ClassOrganizer methodsFor: 'accessing'!
  339. addElement: aString
  340. super addElement: aString.
  341. SystemAnnouncer current announce: (ProtocolAdded new
  342. protocol: aString;
  343. theClass: self theClass;
  344. yourself)
  345. !
  346. removeElement: aString
  347. super removeElement: aString.
  348. SystemAnnouncer current announce: (ProtocolRemoved new
  349. protocol: aString;
  350. theClass: self theClass;
  351. yourself)
  352. !
  353. theClass
  354. < return self.theClass >
  355. ! !
  356. Organizer subclass: #PackageOrganizer
  357. instanceVariableNames: ''
  358. package: 'Kernel-Infrastructure'!
  359. !PackageOrganizer commentStamp!
  360. I am an organizer specific to packages. I hold classes categorization information.!
  361. Object subclass: #Package
  362. instanceVariableNames: 'transport'
  363. package: 'Kernel-Infrastructure'!
  364. !Package commentStamp!
  365. I am similar to a "class category" typically found in other Smalltalks like Pharo or Squeak. Amber does not have class categories anymore, it had in the beginning but now each class in the system knows which package it belongs to.
  366. Each package has a name and can be queried for its classes, but it will then resort to a reverse scan of all classes to find them.
  367. ## API
  368. Packages are manipulated through "Smalltalk current", like for example finding one based on a name or with `Package class >> #name` directly:
  369. Smalltalk current packageAt: 'Kernel'
  370. Package named: 'Kernel'
  371. A package differs slightly from a Monticello package which can span multiple class categories using a naming convention based on hyphenation. But just as in Monticello a package supports "class extensions" so a package can define behaviors in foreign classes using a naming convention for method categories where the category starts with an asterisk and then the name of the owning package follows.
  372. You can fetch a package from the server:
  373. Package load: 'Additional-Examples'!
  374. !Package methodsFor: 'accessing'!
  375. basicTransport
  376. "Answer the transport literal JavaScript object as setup in the JavaScript file, if any"
  377. <return self.transport>
  378. !
  379. definition
  380. ^ String streamContents: [ :stream |
  381. stream
  382. nextPutAll: self class name;
  383. nextPutAll: String lf, String tab;
  384. nextPutAll: ' named: ';
  385. nextPutAll: '''', self name, '''';
  386. nextPutAll: String lf, String tab;
  387. nextPutAll: ' transport: (';
  388. nextPutAll: self transport definition, ')' ]
  389. !
  390. name
  391. <return self.pkgName>
  392. !
  393. name: aString
  394. <self.pkgName = aString>
  395. !
  396. organization
  397. ^ self basicAt: 'organization'
  398. !
  399. transport
  400. ^ transport ifNil: [
  401. transport := (PackageTransport fromJson: self basicTransport)
  402. package: self;
  403. yourself ]
  404. !
  405. transport: aPackageTransport
  406. transport := aPackageTransport.
  407. aPackageTransport package: self
  408. ! !
  409. !Package methodsFor: 'classes'!
  410. classes
  411. ^ self organization elements
  412. !
  413. setupClasses
  414. self classes
  415. do: [ :each | ClassBuilder new setupClass: each ];
  416. do: [ :each | each initialize ]
  417. !
  418. sortedClasses
  419. "Answer all classes in the receiver, sorted by superclass/subclasses and by class name for common subclasses (Issue #143)."
  420. ^ self class sortedClasses: self classes
  421. ! !
  422. !Package methodsFor: 'dependencies'!
  423. loadDependencies
  424. "Returns list of packages that need to be loaded
  425. before loading this package."
  426. | classes packages |
  427. classes := self loadDependencyClasses.
  428. ^ (classes collect: [ :each | each package ]) asSet
  429. remove: self ifAbsent: [];
  430. yourself
  431. !
  432. loadDependencyClasses
  433. "Returns classes needed at the time of loading a package.
  434. These are all that are used to subclass
  435. and to define an extension method"
  436. | starCategoryName |
  437. starCategoryName := '*', self name.
  438. ^ (self classes collect: [ :each | each superclass ]) asSet
  439. remove: nil ifAbsent: [];
  440. addAll: (Smalltalk classes select: [ :each | each protocols, each class protocols includes: starCategoryName ]);
  441. yourself
  442. ! !
  443. !Package methodsFor: 'printing'!
  444. printOn: aStream
  445. super printOn: aStream.
  446. aStream
  447. nextPutAll: ' (';
  448. nextPutAll: self name;
  449. nextPutAll: ')'
  450. ! !
  451. !Package methodsFor: 'testing'!
  452. isPackage
  453. ^ true
  454. ! !
  455. Package class instanceVariableNames: 'defaultCommitPathJs defaultCommitPathSt'!
  456. !Package class methodsFor: 'accessing'!
  457. named: aPackageName
  458. ^ Smalltalk
  459. packageAt: aPackageName
  460. ifAbsent: [
  461. Smalltalk createPackage: aPackageName ]
  462. !
  463. named: aPackageName ifAbsent: aBlock
  464. ^ Smalltalk packageAt: aPackageName ifAbsent: aBlock
  465. !
  466. named: aPackageName transport: aTransport
  467. | package |
  468. package := self named: aPackageName.
  469. package transport: aTransport.
  470. ^ package
  471. ! !
  472. !Package class methodsFor: 'sorting'!
  473. sortedClasses: classes
  474. "Answer classes, sorted by superclass/subclasses and by class name for common subclasses (Issue #143)"
  475. | children others nodes expandedClasses |
  476. children := #().
  477. others := #().
  478. classes do: [ :each |
  479. (classes includes: each superclass)
  480. ifFalse: [ children add: each ]
  481. ifTrue: [ others add: each ]].
  482. nodes := children collect: [ :each |
  483. ClassSorterNode on: each classes: others level: 0 ].
  484. nodes := nodes sorted: [ :a :b | a theClass name <= b theClass name ].
  485. expandedClasses := Array new.
  486. nodes do: [ :aNode |
  487. aNode traverseClassesWith: expandedClasses ].
  488. ^ expandedClasses
  489. ! !
  490. Object subclass: #PlatformInterface
  491. instanceVariableNames: ''
  492. package: 'Kernel-Infrastructure'!
  493. !PlatformInterface commentStamp!
  494. I am single entry point to UI and environment interface.
  495. My `initialize` tries several options (for now, browser environment only) to set myself up.
  496. ## API
  497. PlatformInterface alert: 'Hey, there is a problem'.
  498. PlatformInterface confirm: 'Affirmative?'.
  499. PlatformInterface prompt: 'Your name:'.
  500. PlatformInterface ajax: #{
  501. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  502. }.!
  503. PlatformInterface class instanceVariableNames: 'worker'!
  504. !PlatformInterface class methodsFor: 'accessing'!
  505. globals
  506. <return (new Function('return this'))();>
  507. !
  508. setWorker: anObject
  509. worker := anObject
  510. ! !
  511. !PlatformInterface class methodsFor: 'actions'!
  512. ajax: anObject
  513. ^ worker
  514. ifNotNil: [ worker ajax: anObject ]
  515. ifNil: [ self error: 'ajax: not available' ]
  516. !
  517. alert: aString
  518. ^ worker
  519. ifNotNil: [ worker alert: aString ]
  520. ifNil: [ self error: 'alert: not available' ]
  521. !
  522. confirm: aString
  523. ^ worker
  524. ifNotNil: [ worker confirm: aString ]
  525. ifNil: [ self error: 'confirm: not available' ]
  526. !
  527. existsGlobal: aString
  528. ^ PlatformInterface globals
  529. at: aString
  530. ifPresent: [ true ]
  531. ifAbsent: [ false ]
  532. !
  533. prompt: aString
  534. ^ worker
  535. ifNotNil: [ worker prompt: aString ]
  536. ifNil: [ self error: 'prompt: not available' ]
  537. ! !
  538. !PlatformInterface class methodsFor: 'initialization'!
  539. initialize
  540. | candidate |
  541. super initialize.
  542. BrowserInterface ifNotNil: [
  543. candidate := BrowserInterface new.
  544. candidate isAvailable ifTrue: [ self setWorker: candidate. ^ self ]
  545. ]
  546. ! !
  547. Object subclass: #ProgressHandler
  548. instanceVariableNames: ''
  549. package: 'Kernel-Infrastructure'!
  550. !ProgressHandler commentStamp!
  551. I am used to manage progress in collection iterations, see `SequenceableCollection >> #do:displayingProgress:`.
  552. Subclasses of can register themselves as the current handler with
  553. `ProgressHandler class >> register`.
  554. The default behavior is to simply iterate over the collection.!
  555. !ProgressHandler methodsFor: 'progress handling'!
  556. do: aBlock on: aCollection displaying: aString
  557. aCollection do: aBlock
  558. ! !
  559. ProgressHandler class instanceVariableNames: 'current'!
  560. !ProgressHandler class methodsFor: 'accessing'!
  561. current
  562. ^ current ifNil: [ current := self new ]
  563. !
  564. setCurrent: anHandler
  565. current := anHandler
  566. ! !
  567. !ProgressHandler class methodsFor: 'initialization'!
  568. initialize
  569. self register
  570. !
  571. register
  572. ProgressHandler setCurrent: self new
  573. ! !
  574. Object subclass: #SmalltalkImage
  575. instanceVariableNames: ''
  576. package: 'Kernel-Infrastructure'!
  577. !SmalltalkImage commentStamp!
  578. I represent the Smalltalk system, wrapping
  579. operations of variable `smalltalk` declared in `js/boot.js`.
  580. ## API
  581. I have only one instance, accessed with global variable `Smalltalk`.
  582. The `smalltalk` object holds all class and packages defined in the system.
  583. ## Classes
  584. Classes can be accessed using the following methods:
  585. - `#classes` answers the full list of Smalltalk classes in the system
  586. - `#at:` answers a specific class or `nil`
  587. ## Packages
  588. Packages can be accessed using the following methods:
  589. - `#packages` answers the full list of packages
  590. - `#packageAt:` answers a specific package or `nil`
  591. ## Parsing
  592. The `#parse:` method is used to parse Amber source code.
  593. It requires the `Compiler` package and the `js/parser.js` parser file in order to work.!
  594. !SmalltalkImage methodsFor: 'accessing'!
  595. at: aString
  596. <return smalltalk[aString]>
  597. !
  598. at: aKey ifAbsent: aBlock
  599. ^ (self includesKey: aKey)
  600. ifTrue: [ self at: aKey ]
  601. ifFalse: [ aBlock value ]
  602. !
  603. at: aString put: anObject
  604. <return smalltalk[aString]=anObject>
  605. !
  606. current
  607. "Backward compatibility for Smalltalk current ..."
  608. self deprecatedAPI.
  609. ^ self
  610. !
  611. globals
  612. "Future compatibility to be able to use Smalltalk globals at: ..."
  613. ^ self
  614. !
  615. includesKey: aKey
  616. <return smalltalk.hasOwnProperty(aKey)>
  617. !
  618. parse: aString
  619. | result |
  620. self
  621. try: [ result := self basicParse: aString ]
  622. catch: [ :ex | (self parseError: ex parsing: aString) signal ].
  623. ^ result
  624. source: aString;
  625. yourself
  626. !
  627. pseudoVariableNames
  628. ^ #('self' 'super' 'nil' 'true' 'false' 'thisContext')
  629. !
  630. readJSObject: anObject
  631. <return smalltalk.readJSObject(anObject)>
  632. !
  633. reservedWords
  634. "JavaScript reserved words"
  635. <return smalltalk.reservedWords>
  636. !
  637. version
  638. "Answer the version string of Amber"
  639. ^ '0.13.0-pre'
  640. !
  641. vm
  642. "Future compatibility to be able to use Smalltalk vm ..."
  643. <return smalltalk>
  644. ! !
  645. !SmalltalkImage methodsFor: 'accessing amd'!
  646. amdRequire
  647. ^ self at: 'amdRequire'
  648. !
  649. defaultAmdNamespace
  650. ^ self at: 'defaultAmdNamespace'
  651. !
  652. defaultAmdNamespace: aString
  653. self at: 'defaultAmdNamespace' put: aString
  654. ! !
  655. !SmalltalkImage methodsFor: 'classes'!
  656. classes
  657. <return smalltalk.classes()>
  658. !
  659. removeClass: aClass
  660. aClass isMetaclass ifTrue: [ self error: aClass asString, ' is a Metaclass and cannot be removed!!' ].
  661. self deleteClass: aClass.
  662. SystemAnnouncer current
  663. announce: (ClassRemoved new
  664. theClass: aClass;
  665. yourself)
  666. ! !
  667. !SmalltalkImage methodsFor: 'error handling'!
  668. asSmalltalkException: anObject
  669. "A JavaScript exception may be thrown.
  670. We then need to convert it back to a Smalltalk object"
  671. ^ ((self isSmalltalkObject: anObject) and: [ anObject isKindOf: Error ])
  672. ifTrue: [ anObject ]
  673. ifFalse: [ JavaScriptException on: anObject ]
  674. !
  675. parseError: anException parsing: aString
  676. ^ ParseError new messageText: 'Parse error on line ', (anException basicAt: 'line') ,' column ' , (anException basicAt: 'column') ,' : Unexpected character ', (anException basicAt: 'found')
  677. ! !
  678. !SmalltalkImage methodsFor: 'globals'!
  679. addGlobalJsVariable: aString
  680. self globalJsVariables add: aString
  681. !
  682. deleteGlobalJsVariable: aString
  683. self globalJsVariables remove: aString ifAbsent:[]
  684. !
  685. globalJsVariables
  686. "Array of global JavaScript variables"
  687. <return smalltalk.globalJsVariables>
  688. ! !
  689. !SmalltalkImage methodsFor: 'packages'!
  690. createPackage: packageName
  691. | package announcement |
  692. package := self basicCreatePackage: packageName.
  693. announcement := PackageAdded new
  694. package: package;
  695. yourself.
  696. SystemAnnouncer current announce: announcement.
  697. ^ package
  698. !
  699. packageAt: packageName
  700. <return smalltalk.packages[packageName]>
  701. !
  702. packageAt: packageName ifAbsent: aBlock
  703. ^ (self packageAt: packageName) ifNil: aBlock
  704. !
  705. packages
  706. "Return all Package instances in the system."
  707. <
  708. return Object.keys(smalltalk.packages).map(function(k) {
  709. return smalltalk.packages[k];
  710. })
  711. >
  712. !
  713. removePackage: packageName
  714. "Removes a package and all its classes."
  715. | pkg |
  716. pkg := self packageAt: packageName ifAbsent: [ self error: 'Missing package: ', packageName ].
  717. pkg classes do: [ :each |
  718. self removeClass: each ].
  719. self deletePackage: packageName
  720. !
  721. renamePackage: packageName to: newName
  722. "Rename a package."
  723. | pkg |
  724. pkg := self packageAt: packageName ifAbsent: [ self error: 'Missing package: ', packageName ].
  725. (self packageAt: newName) ifNotNil: [ self error: 'Already exists a package called: ', newName ].
  726. (self at: 'packages') at: newName put: pkg.
  727. pkg name: newName.
  728. self deletePackage: packageName.
  729. ! !
  730. !SmalltalkImage methodsFor: 'private'!
  731. basicCreatePackage: packageName
  732. "Create and bind a new bare package with given name and return it."
  733. <return smalltalk.addPackage(packageName)>
  734. !
  735. basicParse: aString
  736. <return smalltalk.parser.parse(aString)>
  737. !
  738. createPackage: packageName properties: aDict
  739. "Needed to import .st files: they begin with this call."
  740. self deprecatedAPI.
  741. aDict isEmpty ifFalse: [ self error: 'createPackage:properties: called with nonempty properties' ].
  742. ^ self createPackage: packageName
  743. !
  744. deleteClass: aClass
  745. "Deletes a class by deleting its binding only. Use #removeClass instead"
  746. <smalltalk.removeClass(aClass)>
  747. !
  748. deletePackage: packageName
  749. "Deletes a package by deleting its binding, but does not check if it contains classes etc.
  750. To remove a package, use #removePackage instead."
  751. <delete smalltalk.packages[packageName]>
  752. ! !
  753. !SmalltalkImage methodsFor: 'testing'!
  754. isSmalltalkObject: anObject
  755. "Consider anObject a Smalltalk object if it has a 'klass' property.
  756. Note that this may be unaccurate"
  757. <return typeof anObject.klass !!== 'undefined'>
  758. ! !
  759. SmalltalkImage class instanceVariableNames: 'current'!
  760. !SmalltalkImage class methodsFor: 'initialization'!
  761. initialize
  762. smalltalk at: 'Smalltalk' put: self current
  763. ! !
  764. !SmalltalkImage class methodsFor: 'instance creation'!
  765. current
  766. ^ current ifNil: [ current := super new ] ifNotNil: [ self deprecatedAPI. current ]
  767. !
  768. new
  769. self shouldNotImplement
  770. ! !
  771. !SequenceableCollection methodsFor: '*Kernel-Infrastructure'!
  772. do: aBlock displayingProgress: aString
  773. ProgressHandler current
  774. do: aBlock on: self displaying: aString
  775. ! !
  776. !String methodsFor: '*Kernel-Infrastructure'!
  777. asJavaScriptSelector
  778. "Return first keyword of the selector, without trailing colon."
  779. ^ self replace: '^([a-zA-Z0-9]*).*$' with: '$1'
  780. ! !