resin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +52 -0
- data/amber/css/amber.css +519 -0
- data/amber/css/documentation.css +84 -0
- data/amber/css/profstef.css +75 -0
- data/amber/css/style.css +313 -0
- data/amber/images/amber.png +0 -0
- data/amber/images/amber_small.png +0 -0
- data/amber/images/off.png +0 -0
- data/amber/images/offHover.png +0 -0
- data/amber/images/presentation.png +0 -0
- data/amber/images/profstef.png +0 -0
- data/amber/images/sprite.png +0 -0
- data/amber/images/tinylogo.png +0 -0
- data/amber/images/twitterwall.png +0 -0
- data/amber/js/Additional-Examples.deploy.js +15 -0
- data/amber/js/Additional-Examples.js +21 -0
- data/amber/js/Benchfib.deploy.js +132 -0
- data/amber/js/Benchfib.js +167 -0
- data/amber/js/Canvas.deploy.js +1304 -0
- data/amber/js/Canvas.js +1885 -0
- data/amber/js/Compiler.deploy.js +1871 -0
- data/amber/js/Compiler.js +2616 -0
- data/amber/js/Documentation.deploy.js +961 -0
- data/amber/js/Documentation.js +1376 -0
- data/amber/js/Examples.deploy.js +53 -0
- data/amber/js/Examples.js +73 -0
- data/amber/js/IDE.deploy.js +3468 -0
- data/amber/js/IDE.js +4883 -0
- data/amber/js/Kernel-Announcements.deploy.js +107 -0
- data/amber/js/Kernel-Announcements.js +152 -0
- data/amber/js/Kernel-Classes.deploy.js +675 -0
- data/amber/js/Kernel-Classes.js +956 -0
- data/amber/js/Kernel-Collections.deploy.js +3273 -0
- data/amber/js/Kernel-Collections.js +4644 -0
- data/amber/js/Kernel-Exceptions.deploy.js +244 -0
- data/amber/js/Kernel-Exceptions.js +349 -0
- data/amber/js/Kernel-Methods.deploy.js +510 -0
- data/amber/js/Kernel-Methods.js +739 -0
- data/amber/js/Kernel-Objects.deploy.js +2698 -0
- data/amber/js/Kernel-Objects.js +3858 -0
- data/amber/js/Kernel-Tests.deploy.js +1419 -0
- data/amber/js/Kernel-Tests.js +1929 -0
- data/amber/js/Kernel-Transcript.deploy.js +142 -0
- data/amber/js/Kernel-Transcript.js +202 -0
- data/amber/js/SUnit.deploy.js +351 -0
- data/amber/js/SUnit.js +501 -0
- data/amber/js/amber.js +250 -0
- data/amber/js/boot.js +587 -0
- data/amber/js/compat.js +22 -0
- data/amber/js/init.js +8 -0
- data/amber/js/lib/CodeMirror/LICENSE +19 -0
- data/amber/js/lib/CodeMirror/amber.css +21 -0
- data/amber/js/lib/CodeMirror/codemirror.css +67 -0
- data/amber/js/lib/CodeMirror/codemirror.js +2144 -0
- data/amber/js/lib/CodeMirror/smalltalk.js +134 -0
- data/amber/js/lib/jQuery/jquery-1.4.4.min.js +167 -0
- data/amber/js/lib/jQuery/jquery-1.6.4.min.js +4 -0
- data/amber/js/lib/jQuery/jquery-ui-1.8.16.custom.min.js +791 -0
- data/amber/js/lib/jQuery/jquery.textarea.js +267 -0
- data/amber/js/lib/peg-0.6.2.min.js +2 -0
- data/amber/js/lib/showdown.js +419 -0
- data/amber/js/parser.js +4005 -0
- data/amber/js/parser.pegjs +220 -0
- data/amber/st/Benchfib.st +124 -0
- data/amber/st/Canvas.st +556 -0
- data/amber/st/Compiler.st +1425 -0
- data/amber/st/Documentation.st +758 -0
- data/amber/st/Examples.st +38 -0
- data/amber/st/IDE.st +2336 -0
- data/amber/st/Kernel-Announcements.st +61 -0
- data/amber/st/Kernel-Classes.st +403 -0
- data/amber/st/Kernel-Collections.st +1673 -0
- data/amber/st/Kernel-Exceptions.st +124 -0
- data/amber/st/Kernel-Methods.st +287 -0
- data/amber/st/Kernel-Objects.st +1489 -0
- data/amber/st/Kernel-Tests.st +892 -0
- data/amber/st/Kernel-Transcript.st +70 -0
- data/amber/st/SUnit.st +172 -0
- data/bin/runresin +12 -0
- data/lib/resin.rb +0 -0
- data/lib/resin/app/app.rb +121 -0
- data/lib/resin/app/views/index.haml +10 -0
- metadata +216 -0
@@ -0,0 +1,1425 @@
|
|
1
|
+
Smalltalk current createPackage: 'Compiler' properties: #{}!
|
2
|
+
Object subclass: #ChunkParser
|
3
|
+
instanceVariableNames: 'stream'
|
4
|
+
category: 'Compiler'!
|
5
|
+
|
6
|
+
!ChunkParser methodsFor: 'accessing'!
|
7
|
+
|
8
|
+
stream: aStream
|
9
|
+
stream := aStream
|
10
|
+
! !
|
11
|
+
|
12
|
+
!ChunkParser methodsFor: 'reading'!
|
13
|
+
|
14
|
+
nextChunk
|
15
|
+
"The chunk format (Smalltalk Interchange Format or Fileout format)
|
16
|
+
is a trivial format but can be a bit tricky to understand:
|
17
|
+
- Uses the exclamation mark as delimiter of chunks.
|
18
|
+
- Inside a chunk a normal exclamation mark must be doubled.
|
19
|
+
- A non empty chunk must be a valid Smalltalk expression.
|
20
|
+
- A chunk on top level with a preceding empty chunk is an instruction chunk:
|
21
|
+
- The object created by the expression then takes over reading chunks.
|
22
|
+
|
23
|
+
This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."
|
24
|
+
|
25
|
+
| char result chunk |
|
26
|
+
result := '' writeStream.
|
27
|
+
[char := stream next.
|
28
|
+
char notNil] whileTrue: [
|
29
|
+
char = '!!' ifTrue: [
|
30
|
+
stream peek = '!!'
|
31
|
+
ifTrue: [stream next "skipping the escape double"]
|
32
|
+
ifFalse: [^result contents trimBoth "chunk end marker found"]].
|
33
|
+
result nextPut: char].
|
34
|
+
^nil "a chunk needs to end with !!"
|
35
|
+
! !
|
36
|
+
|
37
|
+
!ChunkParser class methodsFor: 'not yet classified'!
|
38
|
+
|
39
|
+
on: aStream
|
40
|
+
^self new stream: aStream
|
41
|
+
! !
|
42
|
+
|
43
|
+
Object subclass: #Importer
|
44
|
+
instanceVariableNames: ''
|
45
|
+
category: 'Compiler'!
|
46
|
+
|
47
|
+
!Importer methodsFor: 'fileIn'!
|
48
|
+
|
49
|
+
import: aStream
|
50
|
+
| chunk result parser lastEmpty |
|
51
|
+
parser := ChunkParser on: aStream.
|
52
|
+
lastEmpty := false.
|
53
|
+
[chunk := parser nextChunk.
|
54
|
+
chunk isNil] whileFalse: [
|
55
|
+
chunk isEmpty
|
56
|
+
ifTrue: [lastEmpty := true]
|
57
|
+
ifFalse: [
|
58
|
+
result := Compiler new loadExpression: chunk.
|
59
|
+
lastEmpty
|
60
|
+
ifTrue: [
|
61
|
+
lastEmpty := false.
|
62
|
+
result scanFrom: parser]]]
|
63
|
+
! !
|
64
|
+
|
65
|
+
Object subclass: #Exporter
|
66
|
+
instanceVariableNames: ''
|
67
|
+
category: 'Compiler'!
|
68
|
+
|
69
|
+
!Exporter methodsFor: 'fileOut'!
|
70
|
+
|
71
|
+
exportPackage: packageName
|
72
|
+
"Export a given package by name."
|
73
|
+
|
74
|
+
| package |
|
75
|
+
^String streamContents: [:stream |
|
76
|
+
package := Smalltalk current packageAt: packageName.
|
77
|
+
self exportPackageDefinitionOf: package on: stream.
|
78
|
+
package classes do: [:each |
|
79
|
+
stream nextPutAll: (self exportClass: each)].
|
80
|
+
self exportPackageExtensionsOf: package on: stream]
|
81
|
+
!
|
82
|
+
|
83
|
+
exportAll
|
84
|
+
"Export all packages in the system."
|
85
|
+
|
86
|
+
^String streamContents: [:stream |
|
87
|
+
Smalltalk current packages do: [:pkg |
|
88
|
+
stream nextPutAll: (self exportPackage: pkg name)]]
|
89
|
+
!
|
90
|
+
|
91
|
+
exportClass: aClass
|
92
|
+
"Export a single class. Subclasses override these methods."
|
93
|
+
|
94
|
+
^String streamContents: [:stream |
|
95
|
+
self exportDefinitionOf: aClass on: stream.
|
96
|
+
self exportMethodsOf: aClass on: stream.
|
97
|
+
self exportMetaDefinitionOf: aClass on: stream.
|
98
|
+
self exportMethodsOf: aClass class on: stream]
|
99
|
+
! !
|
100
|
+
|
101
|
+
!Exporter methodsFor: 'private'!
|
102
|
+
|
103
|
+
exportDefinitionOf: aClass on: aStream
|
104
|
+
aStream
|
105
|
+
nextPutAll: 'smalltalk.addClass(';
|
106
|
+
nextPutAll: '''', (self classNameFor: aClass), ''', ';
|
107
|
+
nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
|
108
|
+
nextPutAll: ', ['.
|
109
|
+
aClass instanceVariableNames
|
110
|
+
do: [:each | aStream nextPutAll: '''', each, '''']
|
111
|
+
separatedBy: [aStream nextPutAll: ', '].
|
112
|
+
aStream
|
113
|
+
nextPutAll: '], ''';
|
114
|
+
nextPutAll: aClass category, '''';
|
115
|
+
nextPutAll: ');'.
|
116
|
+
aClass comment notEmpty ifTrue: [
|
117
|
+
aStream
|
118
|
+
lf;
|
119
|
+
nextPutAll: 'smalltalk.';
|
120
|
+
nextPutAll: (self classNameFor: aClass);
|
121
|
+
nextPutAll: '.comment=';
|
122
|
+
nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
|
123
|
+
aStream lf
|
124
|
+
!
|
125
|
+
|
126
|
+
exportMetaDefinitionOf: aClass on: aStream
|
127
|
+
aClass class instanceVariableNames isEmpty ifFalse: [
|
128
|
+
aStream
|
129
|
+
nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
|
130
|
+
nextPutAll: '.iVarNames = ['.
|
131
|
+
aClass class instanceVariableNames
|
132
|
+
do: [:each | aStream nextPutAll: '''', each, '''']
|
133
|
+
separatedBy: [aStream nextPutAll: ','].
|
134
|
+
aStream nextPutAll: '];', String lf]
|
135
|
+
!
|
136
|
+
|
137
|
+
exportMethodsOf: aClass on: aStream
|
138
|
+
aClass methodDictionary values do: [:each |
|
139
|
+
(each category match: '^\*') ifFalse: [
|
140
|
+
self exportMethod: each of: aClass on: aStream]].
|
141
|
+
aStream lf
|
142
|
+
!
|
143
|
+
|
144
|
+
classNameFor: aClass
|
145
|
+
^aClass isMetaclass
|
146
|
+
ifTrue: [aClass instanceClass name, '.klass']
|
147
|
+
ifFalse: [
|
148
|
+
aClass isNil
|
149
|
+
ifTrue: ['nil']
|
150
|
+
ifFalse: [aClass name]]
|
151
|
+
!
|
152
|
+
|
153
|
+
exportMethod: aMethod of: aClass on: aStream
|
154
|
+
aStream
|
155
|
+
nextPutAll: 'smalltalk.addMethod(';lf;
|
156
|
+
nextPutAll: 'unescape(''', aMethod selector asSelector escaped, '''),';lf;
|
157
|
+
nextPutAll: 'smalltalk.method({';lf;
|
158
|
+
nextPutAll: 'selector: unescape(''', aMethod selector escaped, '''),';lf;
|
159
|
+
nextPutAll: 'category: ''', aMethod category, ''',';lf;
|
160
|
+
nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
|
161
|
+
nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;
|
162
|
+
nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
|
163
|
+
nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
|
164
|
+
nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.
|
165
|
+
aStream
|
166
|
+
lf;
|
167
|
+
nextPutAll: '}),';lf;
|
168
|
+
nextPutAll: 'smalltalk.', (self classNameFor: aClass);
|
169
|
+
nextPutAll: ');';lf;lf
|
170
|
+
!
|
171
|
+
|
172
|
+
exportPackageExtensionsOf: package on: aStream
|
173
|
+
| name |
|
174
|
+
name := package name.
|
175
|
+
Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
|
176
|
+
each methodDictionary values do: [:method |
|
177
|
+
method category = ('*', name) ifTrue: [
|
178
|
+
self exportMethod: method of: each on: aStream]]]
|
179
|
+
!
|
180
|
+
|
181
|
+
exportPackageDefinitionOf: package on: aStream
|
182
|
+
aStream
|
183
|
+
nextPutAll: 'smalltalk.addPackage(';
|
184
|
+
nextPutAll: '''', package name, ''', ', package propertiesAsJSON , ');'.
|
185
|
+
aStream lf
|
186
|
+
! !
|
187
|
+
|
188
|
+
Exporter subclass: #ChunkExporter
|
189
|
+
instanceVariableNames: ''
|
190
|
+
category: 'Compiler'!
|
191
|
+
|
192
|
+
!ChunkExporter methodsFor: 'not yet classified'!
|
193
|
+
|
194
|
+
exportDefinitionOf: aClass on: aStream
|
195
|
+
"Chunk format."
|
196
|
+
|
197
|
+
aStream
|
198
|
+
nextPutAll: (self classNameFor: aClass superclass);
|
199
|
+
nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
|
200
|
+
nextPutAll: ' instanceVariableNames: '''.
|
201
|
+
aClass instanceVariableNames
|
202
|
+
do: [:each | aStream nextPutAll: each]
|
203
|
+
separatedBy: [aStream nextPutAll: ' '].
|
204
|
+
aStream
|
205
|
+
nextPutAll: ''''; lf;
|
206
|
+
nextPutAll: ' category: ''', aClass category, '''!!'; lf.
|
207
|
+
aClass comment notEmpty ifTrue: [
|
208
|
+
aStream
|
209
|
+
nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
|
210
|
+
nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
|
211
|
+
aStream lf
|
212
|
+
!
|
213
|
+
|
214
|
+
exportMethod: aMethod of: aClass on: aStream
|
215
|
+
aStream
|
216
|
+
lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
|
217
|
+
nextPutAll: '!!'
|
218
|
+
!
|
219
|
+
|
220
|
+
exportMethodsOf: aClass on: aStream
|
221
|
+
|
222
|
+
aClass protocolsDo: [:category :methods |
|
223
|
+
(category match: '^\*') ifFalse: [
|
224
|
+
self
|
225
|
+
exportMethods: methods
|
226
|
+
category: category
|
227
|
+
of: aClass
|
228
|
+
on: aStream]]
|
229
|
+
!
|
230
|
+
|
231
|
+
exportMetaDefinitionOf: aClass on: aStream
|
232
|
+
|
233
|
+
aClass class instanceVariableNames isEmpty ifFalse: [
|
234
|
+
aStream
|
235
|
+
nextPutAll: (self classNameFor: aClass class);
|
236
|
+
nextPutAll: ' instanceVariableNames: '''.
|
237
|
+
aClass class instanceVariableNames
|
238
|
+
do: [:each | aStream nextPutAll: each]
|
239
|
+
separatedBy: [aStream nextPutAll: ' '].
|
240
|
+
aStream
|
241
|
+
nextPutAll: '''!!'; lf; lf]
|
242
|
+
!
|
243
|
+
|
244
|
+
classNameFor: aClass
|
245
|
+
^aClass isMetaclass
|
246
|
+
ifTrue: [aClass instanceClass name, ' class']
|
247
|
+
ifFalse: [
|
248
|
+
aClass isNil
|
249
|
+
ifTrue: ['nil']
|
250
|
+
ifFalse: [aClass name]]
|
251
|
+
!
|
252
|
+
|
253
|
+
chunkEscape: aString
|
254
|
+
"Replace all occurrences of !! with !!!! and trim at both ends."
|
255
|
+
|
256
|
+
^(aString replace: '!!' with: '!!!!') trimBoth
|
257
|
+
!
|
258
|
+
|
259
|
+
exportMethods: methods category: category of: aClass on: aStream
|
260
|
+
|
261
|
+
aStream
|
262
|
+
nextPutAll: '!!', (self classNameFor: aClass);
|
263
|
+
nextPutAll: ' methodsFor: ''', category, '''!!'.
|
264
|
+
methods do: [:each |
|
265
|
+
self exportMethod: each of: aClass on: aStream].
|
266
|
+
aStream nextPutAll: ' !!'; lf; lf
|
267
|
+
!
|
268
|
+
|
269
|
+
exportPackageExtensionsOf: package on: aStream
|
270
|
+
"We need to override this one too since we need to group
|
271
|
+
all methods in a given protocol under a leading methodsFor: chunk
|
272
|
+
for that class."
|
273
|
+
|
274
|
+
| name |
|
275
|
+
name := package name.
|
276
|
+
Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
|
277
|
+
each protocolsDo: [:category :methods |
|
278
|
+
category = ('*', name) ifTrue: [
|
279
|
+
self exportMethods: methods category: category of: each on: aStream]]]
|
280
|
+
!
|
281
|
+
|
282
|
+
exportPackageDefinitionOf: package on: aStream
|
283
|
+
"Chunk format."
|
284
|
+
|
285
|
+
aStream
|
286
|
+
nextPutAll: 'Smalltalk current createPackage: ''', package name,
|
287
|
+
''' properties: ', package properties storeString, '!!'; lf.
|
288
|
+
! !
|
289
|
+
|
290
|
+
Exporter subclass: #StrippedExporter
|
291
|
+
instanceVariableNames: ''
|
292
|
+
category: 'Compiler'!
|
293
|
+
|
294
|
+
!StrippedExporter methodsFor: 'private'!
|
295
|
+
|
296
|
+
exportDefinitionOf: aClass on: aStream
|
297
|
+
aStream
|
298
|
+
nextPutAll: 'smalltalk.addClass(';
|
299
|
+
nextPutAll: '''', (self classNameFor: aClass), ''', ';
|
300
|
+
nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
|
301
|
+
nextPutAll: ', ['.
|
302
|
+
aClass instanceVariableNames
|
303
|
+
do: [:each | aStream nextPutAll: '''', each, '''']
|
304
|
+
separatedBy: [aStream nextPutAll: ', '].
|
305
|
+
aStream
|
306
|
+
nextPutAll: '], ''';
|
307
|
+
nextPutAll: aClass category, '''';
|
308
|
+
nextPutAll: ');'.
|
309
|
+
aStream lf
|
310
|
+
!
|
311
|
+
|
312
|
+
exportMethod: aMethod of: aClass on: aStream
|
313
|
+
aStream
|
314
|
+
nextPutAll: 'smalltalk.addMethod(';lf;
|
315
|
+
nextPutAll: 'unescape(''', aMethod selector asSelector escaped, '''),';lf;
|
316
|
+
nextPutAll: 'smalltalk.method({';lf;
|
317
|
+
nextPutAll: 'selector: unescape(''', aMethod selector escaped, '''),';lf;
|
318
|
+
nextPutAll: 'fn: ', aMethod fn compiledSource;lf;
|
319
|
+
nextPutAll: '}),';lf;
|
320
|
+
nextPutAll: 'smalltalk.', (self classNameFor: aClass);
|
321
|
+
nextPutAll: ');';lf;lf
|
322
|
+
! !
|
323
|
+
|
324
|
+
Object subclass: #Node
|
325
|
+
instanceVariableNames: 'nodes'
|
326
|
+
category: 'Compiler'!
|
327
|
+
|
328
|
+
!Node methodsFor: 'accessing'!
|
329
|
+
|
330
|
+
nodes
|
331
|
+
^nodes ifNil: [nodes := Array new]
|
332
|
+
!
|
333
|
+
|
334
|
+
addNode: aNode
|
335
|
+
self nodes add: aNode
|
336
|
+
! !
|
337
|
+
|
338
|
+
!Node methodsFor: 'building'!
|
339
|
+
|
340
|
+
nodes: aCollection
|
341
|
+
nodes := aCollection
|
342
|
+
! !
|
343
|
+
|
344
|
+
!Node methodsFor: 'testing'!
|
345
|
+
|
346
|
+
isValueNode
|
347
|
+
^false
|
348
|
+
!
|
349
|
+
|
350
|
+
isBlockNode
|
351
|
+
^false
|
352
|
+
!
|
353
|
+
|
354
|
+
isBlockSequenceNode
|
355
|
+
^false
|
356
|
+
! !
|
357
|
+
|
358
|
+
!Node methodsFor: 'visiting'!
|
359
|
+
|
360
|
+
accept: aVisitor
|
361
|
+
aVisitor visitNode: self
|
362
|
+
! !
|
363
|
+
|
364
|
+
Node subclass: #MethodNode
|
365
|
+
instanceVariableNames: 'selector arguments source'
|
366
|
+
category: 'Compiler'!
|
367
|
+
|
368
|
+
!MethodNode methodsFor: 'accessing'!
|
369
|
+
|
370
|
+
selector
|
371
|
+
^selector
|
372
|
+
!
|
373
|
+
|
374
|
+
selector: aString
|
375
|
+
selector := aString
|
376
|
+
!
|
377
|
+
|
378
|
+
arguments
|
379
|
+
^arguments ifNil: [#()]
|
380
|
+
!
|
381
|
+
|
382
|
+
arguments: aCollection
|
383
|
+
arguments := aCollection
|
384
|
+
!
|
385
|
+
|
386
|
+
source
|
387
|
+
^source
|
388
|
+
!
|
389
|
+
|
390
|
+
source: aString
|
391
|
+
source := aString
|
392
|
+
! !
|
393
|
+
|
394
|
+
!MethodNode methodsFor: 'visiting'!
|
395
|
+
|
396
|
+
accept: aVisitor
|
397
|
+
aVisitor visitMethodNode: self
|
398
|
+
! !
|
399
|
+
|
400
|
+
Node subclass: #SendNode
|
401
|
+
instanceVariableNames: 'selector arguments receiver'
|
402
|
+
category: 'Compiler'!
|
403
|
+
|
404
|
+
!SendNode methodsFor: 'accessing'!
|
405
|
+
|
406
|
+
selector
|
407
|
+
^selector
|
408
|
+
!
|
409
|
+
|
410
|
+
selector: aString
|
411
|
+
selector := aString
|
412
|
+
!
|
413
|
+
|
414
|
+
arguments
|
415
|
+
^arguments ifNil: [arguments := #()]
|
416
|
+
!
|
417
|
+
|
418
|
+
arguments: aCollection
|
419
|
+
arguments := aCollection
|
420
|
+
!
|
421
|
+
|
422
|
+
receiver
|
423
|
+
^receiver
|
424
|
+
!
|
425
|
+
|
426
|
+
receiver: aNode
|
427
|
+
receiver := aNode
|
428
|
+
!
|
429
|
+
|
430
|
+
valueForReceiver: anObject
|
431
|
+
^SendNode new
|
432
|
+
receiver: (self receiver
|
433
|
+
ifNil: [anObject]
|
434
|
+
ifNotNil: [self receiver valueForReceiver: anObject]);
|
435
|
+
selector: self selector;
|
436
|
+
arguments: self arguments;
|
437
|
+
yourself
|
438
|
+
!
|
439
|
+
|
440
|
+
cascadeNodeWithMessages: aCollection
|
441
|
+
| first |
|
442
|
+
first := SendNode new
|
443
|
+
selector: self selector;
|
444
|
+
arguments: self arguments;
|
445
|
+
yourself.
|
446
|
+
^CascadeNode new
|
447
|
+
receiver: self receiver;
|
448
|
+
nodes: (Array with: first), aCollection;
|
449
|
+
yourself
|
450
|
+
! !
|
451
|
+
|
452
|
+
!SendNode methodsFor: 'visiting'!
|
453
|
+
|
454
|
+
accept: aVisitor
|
455
|
+
aVisitor visitSendNode: self
|
456
|
+
! !
|
457
|
+
|
458
|
+
Node subclass: #CascadeNode
|
459
|
+
instanceVariableNames: 'receiver'
|
460
|
+
category: 'Compiler'!
|
461
|
+
|
462
|
+
!CascadeNode methodsFor: 'accessing'!
|
463
|
+
|
464
|
+
receiver
|
465
|
+
^receiver
|
466
|
+
!
|
467
|
+
|
468
|
+
receiver: aNode
|
469
|
+
receiver := aNode
|
470
|
+
! !
|
471
|
+
|
472
|
+
!CascadeNode methodsFor: 'visiting'!
|
473
|
+
|
474
|
+
accept: aVisitor
|
475
|
+
aVisitor visitCascadeNode: self
|
476
|
+
! !
|
477
|
+
|
478
|
+
Node subclass: #AssignmentNode
|
479
|
+
instanceVariableNames: 'left right'
|
480
|
+
category: 'Compiler'!
|
481
|
+
|
482
|
+
!AssignmentNode methodsFor: 'accessing'!
|
483
|
+
|
484
|
+
left
|
485
|
+
^left
|
486
|
+
!
|
487
|
+
|
488
|
+
left: aNode
|
489
|
+
left := aNode.
|
490
|
+
left assigned: true
|
491
|
+
!
|
492
|
+
|
493
|
+
right
|
494
|
+
^right
|
495
|
+
!
|
496
|
+
|
497
|
+
right: aNode
|
498
|
+
right := aNode
|
499
|
+
! !
|
500
|
+
|
501
|
+
!AssignmentNode methodsFor: 'visiting'!
|
502
|
+
|
503
|
+
accept: aVisitor
|
504
|
+
aVisitor visitAssignmentNode: self
|
505
|
+
! !
|
506
|
+
|
507
|
+
Node subclass: #BlockNode
|
508
|
+
instanceVariableNames: 'parameters inlined'
|
509
|
+
category: 'Compiler'!
|
510
|
+
|
511
|
+
!BlockNode methodsFor: 'accessing'!
|
512
|
+
|
513
|
+
parameters
|
514
|
+
^parameters ifNil: [parameters := Array new]
|
515
|
+
!
|
516
|
+
|
517
|
+
parameters: aCollection
|
518
|
+
parameters := aCollection
|
519
|
+
!
|
520
|
+
|
521
|
+
inlined
|
522
|
+
^inlined ifNil: [false]
|
523
|
+
!
|
524
|
+
|
525
|
+
inlined: aBoolean
|
526
|
+
inlined := aBoolean
|
527
|
+
! !
|
528
|
+
|
529
|
+
!BlockNode methodsFor: 'testing'!
|
530
|
+
|
531
|
+
isBlockNode
|
532
|
+
^true
|
533
|
+
! !
|
534
|
+
|
535
|
+
!BlockNode methodsFor: 'visiting'!
|
536
|
+
|
537
|
+
accept: aVisitor
|
538
|
+
aVisitor visitBlockNode: self
|
539
|
+
! !
|
540
|
+
|
541
|
+
Node subclass: #SequenceNode
|
542
|
+
instanceVariableNames: 'temps'
|
543
|
+
category: 'Compiler'!
|
544
|
+
|
545
|
+
!SequenceNode methodsFor: 'accessing'!
|
546
|
+
|
547
|
+
temps
|
548
|
+
^temps ifNil: [#()]
|
549
|
+
!
|
550
|
+
|
551
|
+
temps: aCollection
|
552
|
+
temps := aCollection
|
553
|
+
! !
|
554
|
+
|
555
|
+
!SequenceNode methodsFor: 'testing'!
|
556
|
+
|
557
|
+
asBlockSequenceNode
|
558
|
+
^BlockSequenceNode new
|
559
|
+
nodes: self nodes;
|
560
|
+
temps: self temps;
|
561
|
+
yourself
|
562
|
+
! !
|
563
|
+
|
564
|
+
!SequenceNode methodsFor: 'visiting'!
|
565
|
+
|
566
|
+
accept: aVisitor
|
567
|
+
aVisitor visitSequenceNode: self
|
568
|
+
! !
|
569
|
+
|
570
|
+
SequenceNode subclass: #BlockSequenceNode
|
571
|
+
instanceVariableNames: ''
|
572
|
+
category: 'Compiler'!
|
573
|
+
|
574
|
+
!BlockSequenceNode methodsFor: 'testing'!
|
575
|
+
|
576
|
+
isBlockSequenceNode
|
577
|
+
^true
|
578
|
+
! !
|
579
|
+
|
580
|
+
!BlockSequenceNode methodsFor: 'visiting'!
|
581
|
+
|
582
|
+
accept: aVisitor
|
583
|
+
aVisitor visitBlockSequenceNode: self
|
584
|
+
! !
|
585
|
+
|
586
|
+
Node subclass: #ReturnNode
|
587
|
+
instanceVariableNames: ''
|
588
|
+
category: 'Compiler'!
|
589
|
+
|
590
|
+
!ReturnNode methodsFor: 'visiting'!
|
591
|
+
|
592
|
+
accept: aVisitor
|
593
|
+
aVisitor visitReturnNode: self
|
594
|
+
! !
|
595
|
+
|
596
|
+
Node subclass: #ValueNode
|
597
|
+
instanceVariableNames: 'value'
|
598
|
+
category: 'Compiler'!
|
599
|
+
|
600
|
+
!ValueNode methodsFor: 'accessing'!
|
601
|
+
|
602
|
+
value
|
603
|
+
^value
|
604
|
+
!
|
605
|
+
|
606
|
+
value: anObject
|
607
|
+
value := anObject
|
608
|
+
! !
|
609
|
+
|
610
|
+
!ValueNode methodsFor: 'testing'!
|
611
|
+
|
612
|
+
isValueNode
|
613
|
+
^true
|
614
|
+
! !
|
615
|
+
|
616
|
+
!ValueNode methodsFor: 'visiting'!
|
617
|
+
|
618
|
+
accept: aVisitor
|
619
|
+
aVisitor visitValueNode: self
|
620
|
+
! !
|
621
|
+
|
622
|
+
ValueNode subclass: #VariableNode
|
623
|
+
instanceVariableNames: 'assigned'
|
624
|
+
category: 'Compiler'!
|
625
|
+
|
626
|
+
!VariableNode methodsFor: 'accessing'!
|
627
|
+
|
628
|
+
assigned
|
629
|
+
^assigned ifNil: [false]
|
630
|
+
!
|
631
|
+
|
632
|
+
assigned: aBoolean
|
633
|
+
assigned := aBoolean
|
634
|
+
! !
|
635
|
+
|
636
|
+
!VariableNode methodsFor: 'visiting'!
|
637
|
+
|
638
|
+
accept: aVisitor
|
639
|
+
aVisitor visitVariableNode: self
|
640
|
+
! !
|
641
|
+
|
642
|
+
VariableNode subclass: #ClassReferenceNode
|
643
|
+
instanceVariableNames: ''
|
644
|
+
category: 'Compiler'!
|
645
|
+
|
646
|
+
!ClassReferenceNode methodsFor: 'visiting'!
|
647
|
+
|
648
|
+
accept: aVisitor
|
649
|
+
aVisitor visitClassReferenceNode: self
|
650
|
+
! !
|
651
|
+
|
652
|
+
Node subclass: #JSStatementNode
|
653
|
+
instanceVariableNames: 'source'
|
654
|
+
category: 'Compiler'!
|
655
|
+
|
656
|
+
!JSStatementNode methodsFor: 'accessing'!
|
657
|
+
|
658
|
+
source
|
659
|
+
^source ifNil: ['']
|
660
|
+
!
|
661
|
+
|
662
|
+
source: aString
|
663
|
+
source := aString
|
664
|
+
! !
|
665
|
+
|
666
|
+
!JSStatementNode methodsFor: 'visiting'!
|
667
|
+
|
668
|
+
accept: aVisitor
|
669
|
+
aVisitor visitJSStatementNode: self
|
670
|
+
! !
|
671
|
+
|
672
|
+
Object subclass: #NodeVisitor
|
673
|
+
instanceVariableNames: ''
|
674
|
+
category: 'Compiler'!
|
675
|
+
|
676
|
+
!NodeVisitor methodsFor: 'visiting'!
|
677
|
+
|
678
|
+
visit: aNode
|
679
|
+
aNode accept: self
|
680
|
+
!
|
681
|
+
|
682
|
+
visitNode: aNode
|
683
|
+
!
|
684
|
+
|
685
|
+
visitMethodNode: aNode
|
686
|
+
self visitNode: aNode
|
687
|
+
!
|
688
|
+
|
689
|
+
visitSequenceNode: aNode
|
690
|
+
self visitNode: aNode
|
691
|
+
!
|
692
|
+
|
693
|
+
visitBlockSequenceNode: aNode
|
694
|
+
self visitSequenceNode: aNode
|
695
|
+
!
|
696
|
+
|
697
|
+
visitBlockNode: aNode
|
698
|
+
self visitNode: aNode
|
699
|
+
!
|
700
|
+
|
701
|
+
visitReturnNode: aNode
|
702
|
+
self visitNode: aNode
|
703
|
+
!
|
704
|
+
|
705
|
+
visitSendNode: aNode
|
706
|
+
self visitNode: aNode
|
707
|
+
!
|
708
|
+
|
709
|
+
visitCascadeNode: aNode
|
710
|
+
self visitNode: aNode
|
711
|
+
!
|
712
|
+
|
713
|
+
visitValueNode: aNode
|
714
|
+
self visitNode: aNode
|
715
|
+
!
|
716
|
+
|
717
|
+
visitVariableNode: aNode
|
718
|
+
!
|
719
|
+
|
720
|
+
visitAssignmentNode: aNode
|
721
|
+
self visitNode: aNode
|
722
|
+
!
|
723
|
+
|
724
|
+
visitClassReferenceNode: aNode
|
725
|
+
self
|
726
|
+
nextPutAll: 'smalltalk.';
|
727
|
+
nextPutAll: aNode value
|
728
|
+
!
|
729
|
+
|
730
|
+
visitJSStatementNode: aNode
|
731
|
+
self
|
732
|
+
nextPutAll: 'function(){';
|
733
|
+
nextPutAll: aNode source;
|
734
|
+
nextPutAll: '})()'
|
735
|
+
!
|
736
|
+
|
737
|
+
visitDynamicArrayNode: aNode
|
738
|
+
self visitNode: aNode
|
739
|
+
!
|
740
|
+
|
741
|
+
visitDynamicDictionaryNode: aNode
|
742
|
+
self visitNode: aNode
|
743
|
+
! !
|
744
|
+
|
745
|
+
NodeVisitor subclass: #Compiler
|
746
|
+
instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced source argVariables'
|
747
|
+
category: 'Compiler'!
|
748
|
+
|
749
|
+
!Compiler methodsFor: 'accessing'!
|
750
|
+
|
751
|
+
parser
|
752
|
+
^SmalltalkParser new
|
753
|
+
!
|
754
|
+
|
755
|
+
currentClass
|
756
|
+
^currentClass
|
757
|
+
!
|
758
|
+
|
759
|
+
currentClass: aClass
|
760
|
+
currentClass := aClass
|
761
|
+
!
|
762
|
+
|
763
|
+
unknownVariables
|
764
|
+
^unknownVariables copy
|
765
|
+
!
|
766
|
+
|
767
|
+
pseudoVariables
|
768
|
+
^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
|
769
|
+
!
|
770
|
+
|
771
|
+
tempVariables
|
772
|
+
^tempVariables copy
|
773
|
+
!
|
774
|
+
|
775
|
+
knownVariables
|
776
|
+
^self pseudoVariables
|
777
|
+
addAll: self tempVariables;
|
778
|
+
addAll: self argVariables;
|
779
|
+
yourself
|
780
|
+
!
|
781
|
+
|
782
|
+
classNameFor: aClass
|
783
|
+
^aClass isMetaclass
|
784
|
+
ifTrue: [aClass instanceClass name, '.klass']
|
785
|
+
ifFalse: [
|
786
|
+
aClass isNil
|
787
|
+
ifTrue: ['nil']
|
788
|
+
ifFalse: [aClass name]]
|
789
|
+
!
|
790
|
+
|
791
|
+
source
|
792
|
+
^source ifNil: ['']
|
793
|
+
!
|
794
|
+
|
795
|
+
source: aString
|
796
|
+
source := aString
|
797
|
+
!
|
798
|
+
|
799
|
+
argVariables
|
800
|
+
^argVariables copy
|
801
|
+
!
|
802
|
+
|
803
|
+
safeVariableNameFor: aString
|
804
|
+
^(Smalltalk current reservedWords includes: aString)
|
805
|
+
ifTrue: [aString, '_']
|
806
|
+
ifFalse: [aString]
|
807
|
+
! !
|
808
|
+
|
809
|
+
!Compiler methodsFor: 'compiling'!
|
810
|
+
|
811
|
+
loadExpression: aString
|
812
|
+
| result |
|
813
|
+
DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
|
814
|
+
result := DoIt new doIt.
|
815
|
+
DoIt removeCompiledMethod: (DoIt methodDictionary at: 'doIt').
|
816
|
+
^result
|
817
|
+
!
|
818
|
+
|
819
|
+
load: aString forClass: aClass
|
820
|
+
| compiled |
|
821
|
+
compiled := self eval: (self compile: aString forClass: aClass).
|
822
|
+
self setupClass: aClass.
|
823
|
+
^compiled
|
824
|
+
!
|
825
|
+
|
826
|
+
compile: aString forClass: aClass
|
827
|
+
self currentClass: aClass.
|
828
|
+
self source: aString.
|
829
|
+
^self compile: aString
|
830
|
+
!
|
831
|
+
|
832
|
+
compileExpression: aString
|
833
|
+
self currentClass: DoIt.
|
834
|
+
self source: 'doIt ^[', aString, '] value'.
|
835
|
+
^self compileNode: (self parse: self source)
|
836
|
+
!
|
837
|
+
|
838
|
+
eval: aString
|
839
|
+
<return eval(aString)>
|
840
|
+
!
|
841
|
+
|
842
|
+
compile: aString
|
843
|
+
^self compileNode: (self parse: aString)
|
844
|
+
!
|
845
|
+
|
846
|
+
compileNode: aNode
|
847
|
+
stream := '' writeStream.
|
848
|
+
self visit: aNode.
|
849
|
+
^stream contents
|
850
|
+
!
|
851
|
+
|
852
|
+
parse: aString
|
853
|
+
^Smalltalk current parse: aString
|
854
|
+
!
|
855
|
+
|
856
|
+
parseExpression: aString
|
857
|
+
^self parse: 'doIt ^[', aString, '] value'
|
858
|
+
!
|
859
|
+
|
860
|
+
recompile: aClass
|
861
|
+
aClass methodDictionary do: [:each || method |
|
862
|
+
method := self load: each source forClass: aClass.
|
863
|
+
method category: each category.
|
864
|
+
aClass addCompiledMethod: method].
|
865
|
+
aClass isMetaclass ifFalse: [self recompile: aClass class]
|
866
|
+
!
|
867
|
+
|
868
|
+
recompileAll
|
869
|
+
Smalltalk current classes do: [:each |
|
870
|
+
Transcript show: each; cr.
|
871
|
+
[self recompile: each] valueWithTimeout: 100]
|
872
|
+
!
|
873
|
+
|
874
|
+
setupClass: aClass
|
875
|
+
<smalltalk.init(aClass)>
|
876
|
+
! !
|
877
|
+
|
878
|
+
!Compiler methodsFor: 'initialization'!
|
879
|
+
|
880
|
+
initialize
|
881
|
+
super initialize.
|
882
|
+
stream := '' writeStream.
|
883
|
+
unknownVariables := #().
|
884
|
+
tempVariables := #().
|
885
|
+
argVariables := #().
|
886
|
+
messageSends := #().
|
887
|
+
classReferenced := #()
|
888
|
+
! !
|
889
|
+
|
890
|
+
!Compiler methodsFor: 'optimizations'!
|
891
|
+
|
892
|
+
checkClass: aClassName for: receiver
|
893
|
+
stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
|
894
|
+
!
|
895
|
+
|
896
|
+
inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
|
897
|
+
| inlined |
|
898
|
+
inlined := false.
|
899
|
+
|
900
|
+
"-- BlockClosures --"
|
901
|
+
|
902
|
+
(aSelector = 'whileTrue:') ifTrue: [
|
903
|
+
(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
|
904
|
+
stream nextPutAll: '(function(){while('.
|
905
|
+
self visit: anObject.
|
906
|
+
stream nextPutAll: '()) {'.
|
907
|
+
self visit: aCollection first.
|
908
|
+
stream nextPutAll: '()}})()'.
|
909
|
+
inlined := true]].
|
910
|
+
|
911
|
+
(aSelector = 'whileFalse:') ifTrue: [
|
912
|
+
(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
|
913
|
+
stream nextPutAll: '(function(){while(!!'.
|
914
|
+
self visit: anObject.
|
915
|
+
stream nextPutAll: '()) {'.
|
916
|
+
self visit: aCollection first.
|
917
|
+
stream nextPutAll: '()}})()'.
|
918
|
+
inlined := true]].
|
919
|
+
|
920
|
+
(aSelector = 'whileTrue') ifTrue: [
|
921
|
+
anObject isBlockNode ifTrue: [
|
922
|
+
stream nextPutAll: '(function(){while('.
|
923
|
+
self visit: anObject.
|
924
|
+
stream nextPutAll: '()) {}})()'.
|
925
|
+
inlined := true]].
|
926
|
+
|
927
|
+
(aSelector = 'whileFalse') ifTrue: [
|
928
|
+
anObject isBlockNode ifTrue: [
|
929
|
+
stream nextPutAll: '(function(){while(!!'.
|
930
|
+
self visit: anObject.
|
931
|
+
stream nextPutAll: '()) {}})()'.
|
932
|
+
inlined := true]].
|
933
|
+
|
934
|
+
"-- Numbers --"
|
935
|
+
|
936
|
+
(aSelector = '+') ifTrue: [
|
937
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
938
|
+
self visit: anObject.
|
939
|
+
stream nextPutAll: ' + '.
|
940
|
+
self visit: aCollection first.
|
941
|
+
inlined := true]].
|
942
|
+
|
943
|
+
(aSelector = '-') ifTrue: [
|
944
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
945
|
+
self visit: anObject.
|
946
|
+
stream nextPutAll: ' - '.
|
947
|
+
self visit: aCollection first.
|
948
|
+
inlined := true]].
|
949
|
+
|
950
|
+
(aSelector = '*') ifTrue: [
|
951
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
952
|
+
self visit: anObject.
|
953
|
+
stream nextPutAll: ' * '.
|
954
|
+
self visit: aCollection first.
|
955
|
+
inlined := true]].
|
956
|
+
|
957
|
+
(aSelector = '/') ifTrue: [
|
958
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
959
|
+
self visit: anObject.
|
960
|
+
stream nextPutAll: ' / '.
|
961
|
+
self visit: aCollection first.
|
962
|
+
inlined := true]].
|
963
|
+
|
964
|
+
(aSelector = '<') ifTrue: [
|
965
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
966
|
+
self visit: anObject.
|
967
|
+
stream nextPutAll: ' < '.
|
968
|
+
self visit: aCollection first.
|
969
|
+
inlined := true]].
|
970
|
+
|
971
|
+
(aSelector = '<=') ifTrue: [
|
972
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
973
|
+
self visit: anObject.
|
974
|
+
stream nextPutAll: ' <= '.
|
975
|
+
self visit: aCollection first.
|
976
|
+
inlined := true]].
|
977
|
+
|
978
|
+
(aSelector = '>') ifTrue: [
|
979
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
980
|
+
self visit: anObject.
|
981
|
+
stream nextPutAll: ' > '.
|
982
|
+
self visit: aCollection first.
|
983
|
+
inlined := true]].
|
984
|
+
|
985
|
+
(aSelector = '>=') ifTrue: [
|
986
|
+
(self isNode: anObject ofClass: Number) ifTrue: [
|
987
|
+
self visit: anObject.
|
988
|
+
stream nextPutAll: ' >= '.
|
989
|
+
self visit: aCollection first.
|
990
|
+
inlined := true]].
|
991
|
+
|
992
|
+
"-- UndefinedObject --"
|
993
|
+
|
994
|
+
(aSelector = 'ifNil:') ifTrue: [
|
995
|
+
aCollection first isBlockNode ifTrue: [
|
996
|
+
stream nextPutAll: '(($receiver = '.
|
997
|
+
self visit: anObject.
|
998
|
+
stream nextPutAll: ') == nil || $receiver == undefined) ? '.
|
999
|
+
self visit: aCollection first.
|
1000
|
+
stream nextPutAll: '() : $receiver'.
|
1001
|
+
inlined := true]].
|
1002
|
+
|
1003
|
+
(aSelector = 'ifNotNil:') ifTrue: [
|
1004
|
+
aCollection first isBlockNode ifTrue: [
|
1005
|
+
stream nextPutAll: '(($receiver = '.
|
1006
|
+
self visit: anObject.
|
1007
|
+
stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
|
1008
|
+
self visit: aCollection first.
|
1009
|
+
stream nextPutAll: '() : nil'.
|
1010
|
+
inlined := true]].
|
1011
|
+
|
1012
|
+
(aSelector = 'ifNil:ifNotNil:') ifTrue: [
|
1013
|
+
(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
|
1014
|
+
stream nextPutAll: '(($receiver = '.
|
1015
|
+
self visit: anObject.
|
1016
|
+
stream nextPutAll: ') == nil || $receiver == undefined) ? '.
|
1017
|
+
self visit: aCollection first.
|
1018
|
+
stream nextPutAll: '() : '.
|
1019
|
+
self visit: aCollection second.
|
1020
|
+
stream nextPutAll: '()'.
|
1021
|
+
inlined := true]].
|
1022
|
+
|
1023
|
+
(aSelector = 'ifNotNil:ifNil:') ifTrue: [
|
1024
|
+
(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
|
1025
|
+
stream nextPutAll: '(($receiver = '.
|
1026
|
+
self visit: anObject.
|
1027
|
+
stream nextPutAll: ') == nil || $receiver == undefined) ? '.
|
1028
|
+
self visit: aCollection second.
|
1029
|
+
stream nextPutAll: '() : '.
|
1030
|
+
self visit: aCollection first.
|
1031
|
+
stream nextPutAll: '()'.
|
1032
|
+
inlined := true]].
|
1033
|
+
|
1034
|
+
^inlined
|
1035
|
+
!
|
1036
|
+
|
1037
|
+
isNode: aNode ofClass: aClass
|
1038
|
+
^aNode isValueNode and: [
|
1039
|
+
aNode value class = aClass or: [
|
1040
|
+
aNode value = 'self' and: [self currentClass = aClass]]]
|
1041
|
+
!
|
1042
|
+
|
1043
|
+
inline: aSelector receiver: receiver argumentNodes: aCollection
|
1044
|
+
| inlined |
|
1045
|
+
inlined := false.
|
1046
|
+
|
1047
|
+
"-- Booleans --"
|
1048
|
+
|
1049
|
+
(aSelector = 'ifFalse:') ifTrue: [
|
1050
|
+
aCollection first isBlockNode ifTrue: [
|
1051
|
+
self checkClass: 'Boolean' for: receiver.
|
1052
|
+
stream nextPutAll: '(!! $receiver ? '.
|
1053
|
+
self visit: aCollection first.
|
1054
|
+
stream nextPutAll: '() : nil)'.
|
1055
|
+
inlined := true]].
|
1056
|
+
|
1057
|
+
(aSelector = 'ifTrue:') ifTrue: [
|
1058
|
+
aCollection first isBlockNode ifTrue: [
|
1059
|
+
self checkClass: 'Boolean' for: receiver.
|
1060
|
+
stream nextPutAll: '($receiver ? '.
|
1061
|
+
self visit: aCollection first.
|
1062
|
+
stream nextPutAll: '() : nil)'.
|
1063
|
+
inlined := true]].
|
1064
|
+
|
1065
|
+
(aSelector = 'ifTrue:ifFalse:') ifTrue: [
|
1066
|
+
(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
|
1067
|
+
self checkClass: 'Boolean' for: receiver.
|
1068
|
+
stream nextPutAll: '($receiver ? '.
|
1069
|
+
self visit: aCollection first.
|
1070
|
+
stream nextPutAll: '() : '.
|
1071
|
+
self visit: aCollection second.
|
1072
|
+
stream nextPutAll: '())'.
|
1073
|
+
inlined := true]].
|
1074
|
+
|
1075
|
+
(aSelector = 'ifFalse:ifTrue:') ifTrue: [
|
1076
|
+
(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
|
1077
|
+
self checkClass: 'Boolean' for: receiver.
|
1078
|
+
stream nextPutAll: '(!! $receiver ? '.
|
1079
|
+
self visit: aCollection first.
|
1080
|
+
stream nextPutAll: '() : '.
|
1081
|
+
self visit: aCollection second.
|
1082
|
+
stream nextPutAll: '())'.
|
1083
|
+
inlined := true]].
|
1084
|
+
|
1085
|
+
"-- Numbers --"
|
1086
|
+
|
1087
|
+
(aSelector = '<') ifTrue: [
|
1088
|
+
self checkClass: 'Number' for: receiver.
|
1089
|
+
stream nextPutAll: '$receiver <'.
|
1090
|
+
self visit: aCollection first.
|
1091
|
+
inlined := true].
|
1092
|
+
|
1093
|
+
(aSelector = '<=') ifTrue: [
|
1094
|
+
self checkClass: 'Number' for: receiver.
|
1095
|
+
stream nextPutAll: '$receiver <='.
|
1096
|
+
self visit: aCollection first.
|
1097
|
+
inlined := true].
|
1098
|
+
|
1099
|
+
(aSelector = '>') ifTrue: [
|
1100
|
+
self checkClass: 'Number' for: receiver.
|
1101
|
+
stream nextPutAll: '$receiver >'.
|
1102
|
+
self visit: aCollection first.
|
1103
|
+
inlined := true].
|
1104
|
+
|
1105
|
+
(aSelector = '>=') ifTrue: [
|
1106
|
+
self checkClass: 'Number' for: receiver.
|
1107
|
+
stream nextPutAll: '$receiver >='.
|
1108
|
+
self visit: aCollection first.
|
1109
|
+
inlined := true].
|
1110
|
+
|
1111
|
+
(aSelector = '+') ifTrue: [
|
1112
|
+
self checkClass: 'Number' for: receiver.
|
1113
|
+
stream nextPutAll: '$receiver +'.
|
1114
|
+
self visit: aCollection first.
|
1115
|
+
inlined := true].
|
1116
|
+
|
1117
|
+
(aSelector = '-') ifTrue: [
|
1118
|
+
self checkClass: 'Number' for: receiver.
|
1119
|
+
stream nextPutAll: '$receiver -'.
|
1120
|
+
self visit: aCollection first.
|
1121
|
+
inlined := true].
|
1122
|
+
|
1123
|
+
(aSelector = '*') ifTrue: [
|
1124
|
+
self checkClass: 'Number' for: receiver.
|
1125
|
+
stream nextPutAll: '$receiver *'.
|
1126
|
+
self visit: aCollection first.
|
1127
|
+
inlined := true].
|
1128
|
+
|
1129
|
+
(aSelector = '/') ifTrue: [
|
1130
|
+
self checkClass: 'Number' for: receiver.
|
1131
|
+
stream nextPutAll: '$receiver /'.
|
1132
|
+
self visit: aCollection first.
|
1133
|
+
inlined := true].
|
1134
|
+
|
1135
|
+
^inlined
|
1136
|
+
! !
|
1137
|
+
|
1138
|
+
!Compiler methodsFor: 'testing'!
|
1139
|
+
|
1140
|
+
performOptimizations
|
1141
|
+
^self class performOptimizations
|
1142
|
+
! !
|
1143
|
+
|
1144
|
+
!Compiler methodsFor: 'visiting'!
|
1145
|
+
|
1146
|
+
visit: aNode
|
1147
|
+
aNode accept: self
|
1148
|
+
!
|
1149
|
+
|
1150
|
+
visitMethodNode: aNode
|
1151
|
+
| str currentSelector |
|
1152
|
+
currentSelector := aNode selector asSelector.
|
1153
|
+
nestedBlocks := 0.
|
1154
|
+
earlyReturn := false.
|
1155
|
+
messageSends := #().
|
1156
|
+
referencedClasses := #().
|
1157
|
+
unknownVariables := #().
|
1158
|
+
tempVariables := #().
|
1159
|
+
argVariables := #().
|
1160
|
+
stream
|
1161
|
+
nextPutAll: 'smalltalk.method({'; lf;
|
1162
|
+
nextPutAll: 'selector: "', aNode selector, '",'; lf.
|
1163
|
+
stream nextPutAll: 'source: unescape("', self source escaped, '"),';lf.
|
1164
|
+
stream nextPutAll: 'fn: function('.
|
1165
|
+
aNode arguments
|
1166
|
+
do: [:each |
|
1167
|
+
argVariables add: each.
|
1168
|
+
stream nextPutAll: each]
|
1169
|
+
separatedBy: [stream nextPutAll: ', '].
|
1170
|
+
stream
|
1171
|
+
nextPutAll: '){'; lf;
|
1172
|
+
nextPutAll: 'var self=this;'; lf.
|
1173
|
+
str := stream.
|
1174
|
+
stream := '' writeStream.
|
1175
|
+
aNode nodes do: [:each |
|
1176
|
+
self visit: each].
|
1177
|
+
earlyReturn ifTrue: [
|
1178
|
+
str nextPutAll: 'try{'].
|
1179
|
+
str nextPutAll: stream contents.
|
1180
|
+
stream := str.
|
1181
|
+
stream
|
1182
|
+
lf;
|
1183
|
+
nextPutAll: 'return self;'.
|
1184
|
+
earlyReturn ifTrue: [
|
1185
|
+
stream lf; nextPutAll: '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
|
1186
|
+
stream nextPutAll: '}'.
|
1187
|
+
stream
|
1188
|
+
nextPutAll: ',', String lf, 'messageSends: ';
|
1189
|
+
nextPutAll: messageSends asJavascript, ','; lf;
|
1190
|
+
nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
|
1191
|
+
nextPutAll: 'referencedClasses: ['.
|
1192
|
+
referencedClasses
|
1193
|
+
do: [:each | stream nextPutAll: each printString]
|
1194
|
+
separatedBy: [stream nextPutAll: ','].
|
1195
|
+
stream nextPutAll: ']'.
|
1196
|
+
stream nextPutAll: '})'
|
1197
|
+
!
|
1198
|
+
|
1199
|
+
visitBlockNode: aNode
|
1200
|
+
stream nextPutAll: '(function('.
|
1201
|
+
aNode parameters
|
1202
|
+
do: [:each |
|
1203
|
+
tempVariables add: each.
|
1204
|
+
stream nextPutAll: each]
|
1205
|
+
separatedBy: [stream nextPutAll: ', '].
|
1206
|
+
stream nextPutAll: '){'.
|
1207
|
+
aNode nodes do: [:each | self visit: each].
|
1208
|
+
stream nextPutAll: '})'
|
1209
|
+
!
|
1210
|
+
|
1211
|
+
visitSequenceNode: aNode
|
1212
|
+
aNode temps do: [:each || temp |
|
1213
|
+
temp := self safeVariableNameFor: each.
|
1214
|
+
tempVariables add: temp.
|
1215
|
+
stream nextPutAll: 'var ', temp, '=nil;'; lf].
|
1216
|
+
aNode nodes do: [:each |
|
1217
|
+
self visit: each.
|
1218
|
+
stream nextPutAll: ';']
|
1219
|
+
separatedBy: [stream lf]
|
1220
|
+
!
|
1221
|
+
|
1222
|
+
visitBlockSequenceNode: aNode
|
1223
|
+
| index |
|
1224
|
+
nestedBlocks := nestedBlocks + 1.
|
1225
|
+
aNode nodes isEmpty
|
1226
|
+
ifTrue: [
|
1227
|
+
stream nextPutAll: 'return nil;']
|
1228
|
+
ifFalse: [
|
1229
|
+
aNode temps do: [:each | | temp |
|
1230
|
+
temp := self safeVariableNameFor: each.
|
1231
|
+
tempVariables add: temp.
|
1232
|
+
stream nextPutAll: 'var ', temp, '=nil;'; lf].
|
1233
|
+
index := 0.
|
1234
|
+
aNode nodes do: [:each |
|
1235
|
+
index := index + 1.
|
1236
|
+
index = aNode nodes size ifTrue: [
|
1237
|
+
stream nextPutAll: 'return '].
|
1238
|
+
self visit: each.
|
1239
|
+
stream nextPutAll: ';']].
|
1240
|
+
nestedBlocks := nestedBlocks - 1
|
1241
|
+
!
|
1242
|
+
|
1243
|
+
visitReturnNode: aNode
|
1244
|
+
nestedBlocks > 0 ifTrue: [
|
1245
|
+
earlyReturn := true].
|
1246
|
+
earlyReturn
|
1247
|
+
ifTrue: [
|
1248
|
+
stream
|
1249
|
+
nextPutAll: '(function(){throw(';
|
1250
|
+
nextPutAll: '{name: ''stReturn'', selector: ';
|
1251
|
+
nextPutAll: currentSelector printString;
|
1252
|
+
nextPutAll: ', fn: function(){return ']
|
1253
|
+
ifFalse: [stream nextPutAll: 'return '].
|
1254
|
+
aNode nodes do: [:each |
|
1255
|
+
self visit: each].
|
1256
|
+
earlyReturn ifTrue: [
|
1257
|
+
stream nextPutAll: '}})})()']
|
1258
|
+
!
|
1259
|
+
|
1260
|
+
visitSendNode: aNode
|
1261
|
+
| str receiver superSend inlined |
|
1262
|
+
str := stream.
|
1263
|
+
(messageSends includes: aNode selector) ifFalse: [
|
1264
|
+
messageSends add: aNode selector].
|
1265
|
+
stream := '' writeStream.
|
1266
|
+
self visit: aNode receiver.
|
1267
|
+
superSend := stream contents = 'super'.
|
1268
|
+
receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
|
1269
|
+
stream := str.
|
1270
|
+
|
1271
|
+
self performOptimizations
|
1272
|
+
ifTrue: [
|
1273
|
+
(self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
|
1274
|
+
(self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
|
1275
|
+
ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
|
1276
|
+
ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
|
1277
|
+
ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
|
1278
|
+
!
|
1279
|
+
|
1280
|
+
visitCascadeNode: aNode
|
1281
|
+
| index |
|
1282
|
+
index := 0.
|
1283
|
+
(tempVariables includes: '$rec') ifFalse: [
|
1284
|
+
tempVariables add: '$rec'].
|
1285
|
+
stream nextPutAll: '(function($rec){'.
|
1286
|
+
aNode nodes do: [:each |
|
1287
|
+
index := index + 1.
|
1288
|
+
index = aNode nodes size ifTrue: [
|
1289
|
+
stream nextPutAll: 'return '].
|
1290
|
+
each receiver: (VariableNode new value: '$rec').
|
1291
|
+
self visit: each.
|
1292
|
+
stream nextPutAll: ';'].
|
1293
|
+
stream nextPutAll: '})('.
|
1294
|
+
self visit: aNode receiver.
|
1295
|
+
stream nextPutAll: ')'
|
1296
|
+
!
|
1297
|
+
|
1298
|
+
visitValueNode: aNode
|
1299
|
+
stream nextPutAll: aNode value asJavascript
|
1300
|
+
!
|
1301
|
+
|
1302
|
+
visitAssignmentNode: aNode
|
1303
|
+
stream nextPutAll: '('.
|
1304
|
+
self visit: aNode left.
|
1305
|
+
stream nextPutAll: '='.
|
1306
|
+
self visit: aNode right.
|
1307
|
+
stream nextPutAll: ')'
|
1308
|
+
!
|
1309
|
+
|
1310
|
+
visitClassReferenceNode: aNode
|
1311
|
+
(referencedClasses includes: aNode value) ifFalse: [
|
1312
|
+
referencedClasses add: aNode value].
|
1313
|
+
stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
|
1314
|
+
!
|
1315
|
+
|
1316
|
+
visitVariableNode: aNode
|
1317
|
+
| varName |
|
1318
|
+
(self currentClass allInstanceVariableNames includes: aNode value)
|
1319
|
+
ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
|
1320
|
+
ifFalse: [
|
1321
|
+
varName := self safeVariableNameFor: aNode value.
|
1322
|
+
(self knownVariables includes: varName)
|
1323
|
+
ifFalse: [
|
1324
|
+
unknownVariables add: aNode value.
|
1325
|
+
aNode assigned
|
1326
|
+
ifTrue: [stream nextPutAll: varName]
|
1327
|
+
ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
|
1328
|
+
ifTrue: [
|
1329
|
+
aNode value = 'thisContext'
|
1330
|
+
ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
|
1331
|
+
ifFalse: [stream nextPutAll: varName]]]
|
1332
|
+
!
|
1333
|
+
|
1334
|
+
visitJSStatementNode: aNode
|
1335
|
+
stream nextPutAll: (aNode source replace: '>>' with: '>')
|
1336
|
+
!
|
1337
|
+
|
1338
|
+
visitFailure: aFailure
|
1339
|
+
self error: aFailure asString
|
1340
|
+
!
|
1341
|
+
|
1342
|
+
send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
|
1343
|
+
^String streamContents: [:str || tmp |
|
1344
|
+
tmp := stream.
|
1345
|
+
str nextPutAll: 'smalltalk.send('.
|
1346
|
+
str nextPutAll: aReceiver.
|
1347
|
+
str nextPutAll: ', "', aSelector asSelector, '", ['.
|
1348
|
+
stream := str.
|
1349
|
+
aCollection
|
1350
|
+
do: [:each | self visit: each]
|
1351
|
+
separatedBy: [stream nextPutAll: ', '].
|
1352
|
+
stream := tmp.
|
1353
|
+
str nextPutAll: ']'.
|
1354
|
+
aBoolean ifTrue: [
|
1355
|
+
str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
|
1356
|
+
str nextPutAll: ')']
|
1357
|
+
!
|
1358
|
+
|
1359
|
+
visitDynamicArrayNode: aNode
|
1360
|
+
stream nextPutAll: '['.
|
1361
|
+
aNode nodes
|
1362
|
+
do: [:each | self visit: each]
|
1363
|
+
separatedBy: [stream nextPutAll: ','].
|
1364
|
+
stream nextPutAll: ']'
|
1365
|
+
!
|
1366
|
+
|
1367
|
+
visitDynamicDictionaryNode: aNode
|
1368
|
+
stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
|
1369
|
+
aNode nodes
|
1370
|
+
do: [:each | self visit: each]
|
1371
|
+
separatedBy: [stream nextPutAll: ','].
|
1372
|
+
stream nextPutAll: '])'
|
1373
|
+
! !
|
1374
|
+
|
1375
|
+
Compiler class instanceVariableNames: 'performOptimizations'!
|
1376
|
+
|
1377
|
+
!Compiler class methodsFor: 'accessing'!
|
1378
|
+
|
1379
|
+
performOptimizations
|
1380
|
+
^performOptimizations ifNil: [true]
|
1381
|
+
!
|
1382
|
+
|
1383
|
+
performOptimizations: aBoolean
|
1384
|
+
performOptimizations := aBoolean
|
1385
|
+
! !
|
1386
|
+
|
1387
|
+
!Compiler class methodsFor: 'compiling'!
|
1388
|
+
|
1389
|
+
recompile: aClass
|
1390
|
+
aClass methodDictionary do: [:each || method |
|
1391
|
+
method := self new load: each source forClass: aClass.
|
1392
|
+
method category: each category.
|
1393
|
+
aClass addCompiledMethod: method].
|
1394
|
+
aClass isMetaclass ifFalse: [self recompile: aClass class]
|
1395
|
+
!
|
1396
|
+
|
1397
|
+
recompileAll
|
1398
|
+
Smalltalk current classes do: [:each |
|
1399
|
+
self recompile: each]
|
1400
|
+
! !
|
1401
|
+
|
1402
|
+
Object subclass: #DoIt
|
1403
|
+
instanceVariableNames: ''
|
1404
|
+
category: 'Compiler'!
|
1405
|
+
|
1406
|
+
Node subclass: #DynamicArrayNode
|
1407
|
+
instanceVariableNames: ''
|
1408
|
+
category: 'Compiler'!
|
1409
|
+
|
1410
|
+
!DynamicArrayNode methodsFor: 'visiting'!
|
1411
|
+
|
1412
|
+
accept: aVisitor
|
1413
|
+
aVisitor visitDynamicArrayNode: self
|
1414
|
+
! !
|
1415
|
+
|
1416
|
+
Node subclass: #DynamicDictionaryNode
|
1417
|
+
instanceVariableNames: ''
|
1418
|
+
category: 'Compiler'!
|
1419
|
+
|
1420
|
+
!DynamicDictionaryNode methodsFor: 'visiting'!
|
1421
|
+
|
1422
|
+
accept: aVisitor
|
1423
|
+
aVisitor visitDynamicDictionaryNode: self
|
1424
|
+
! !
|
1425
|
+
|