resin 0.3.1 → 0.4.0

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.
Files changed (84) hide show
  1. data/amber/bin/amberc +10 -350
  2. data/amber/js/Benchfib.deploy.js +80 -89
  3. data/amber/js/Benchfib.js +80 -89
  4. data/amber/js/Canvas.deploy.js +558 -545
  5. data/amber/js/Canvas.js +563 -545
  6. data/amber/js/Compiler-AST.deploy.js +431 -243
  7. data/amber/js/Compiler-AST.js +487 -244
  8. data/amber/js/Compiler-Core.deploy.js +201 -1045
  9. data/amber/js/Compiler-Core.js +208 -1207
  10. data/amber/js/Compiler-Exceptions.deploy.js +37 -18
  11. data/amber/js/Compiler-Exceptions.js +42 -18
  12. data/amber/js/Compiler-IR.deploy.js +1071 -774
  13. data/amber/js/Compiler-IR.js +1194 -848
  14. data/amber/js/Compiler-Inlining.deploy.js +395 -373
  15. data/amber/js/Compiler-Inlining.js +395 -373
  16. data/amber/js/Compiler-Interpreter.deploy.js +1202 -0
  17. data/amber/js/Compiler-Interpreter.js +1631 -0
  18. data/amber/js/Compiler-Semantic.deploy.js +695 -600
  19. data/amber/js/Compiler-Semantic.js +721 -611
  20. data/amber/js/Compiler-Tests.deploy.js +699 -376
  21. data/amber/js/Compiler-Tests.js +834 -381
  22. data/amber/js/Compiler.deploy.js +8563 -1805
  23. data/amber/js/Compiler.js +11476 -2633
  24. data/amber/js/Examples.deploy.js +29 -29
  25. data/amber/js/Examples.js +29 -29
  26. data/amber/js/IDE.deploy.js +3292 -2649
  27. data/amber/js/IDE.js +3318 -2710
  28. data/amber/js/Importer-Exporter.deploy.js +393 -349
  29. data/amber/js/Importer-Exporter.js +398 -354
  30. data/amber/js/Kernel-Announcements.deploy.js +53 -44
  31. data/amber/js/Kernel-Announcements.js +55 -44
  32. data/amber/js/Kernel-Classes.deploy.js +566 -368
  33. data/amber/js/Kernel-Classes.js +660 -402
  34. data/amber/js/Kernel-Collections.deploy.js +1149 -1098
  35. data/amber/js/Kernel-Collections.js +1183 -1116
  36. data/amber/js/Kernel-Exceptions.deploy.js +173 -75
  37. data/amber/js/Kernel-Exceptions.js +215 -77
  38. data/amber/js/Kernel-Methods.deploy.js +530 -313
  39. data/amber/js/Kernel-Methods.js +632 -338
  40. data/amber/js/Kernel-Objects.deploy.js +1734 -1577
  41. data/amber/js/Kernel-Objects.js +1867 -1654
  42. data/amber/js/Kernel-Tests.deploy.js +1416 -973
  43. data/amber/js/Kernel-Tests.js +1495 -981
  44. data/amber/js/Kernel-Transcript.deploy.js +23 -24
  45. data/amber/js/Kernel-Transcript.js +25 -26
  46. data/amber/js/SUnit-Tests.deploy.js +402 -0
  47. data/amber/js/SUnit-Tests.js +518 -0
  48. data/amber/js/SUnit.deploy.js +535 -237
  49. data/amber/js/SUnit.js +634 -246
  50. data/amber/js/amber.js +90 -53
  51. data/amber/js/boot.js +441 -255
  52. data/amber/js/init.js +1 -3
  53. data/amber/js/lib/CodeMirror/codemirror.css +3 -0
  54. data/amber/js/lib/CodeMirror/codemirror.js +104 -55
  55. data/amber/js/lib/peg-0.7.0.min.js +9 -0
  56. data/amber/js/parser.js +1504 -802
  57. data/amber/js/parser.pegjs +170 -165
  58. data/amber/st/Canvas.st +6 -0
  59. data/amber/st/Compiler-AST.st +54 -3
  60. data/amber/st/Compiler-Core.st +6 -551
  61. data/amber/st/Compiler-Exceptions.st +4 -0
  62. data/amber/st/Compiler-IR.st +205 -87
  63. data/amber/st/Compiler-Interpreter.st +597 -0
  64. data/amber/st/Compiler-Semantic.st +46 -21
  65. data/amber/st/Compiler-Tests.st +254 -7
  66. data/amber/st/Compiler.st +3172 -1541
  67. data/amber/st/IDE.st +57 -93
  68. data/amber/st/Importer-Exporter.st +4 -7
  69. data/amber/st/Kernel-Announcements.st +8 -0
  70. data/amber/st/Kernel-Classes.st +149 -40
  71. data/amber/st/Kernel-Collections.st +43 -32
  72. data/amber/st/Kernel-Exceptions.st +70 -1
  73. data/amber/st/Kernel-Methods.st +165 -27
  74. data/amber/st/Kernel-Objects.st +215 -140
  75. data/amber/st/Kernel-Tests.st +195 -10
  76. data/amber/st/Kernel-Transcript.st +1 -3
  77. data/amber/st/SUnit-Tests.st +186 -0
  78. data/amber/st/SUnit.st +186 -14
  79. data/bin/resin +6 -0
  80. data/lib/resin/cli.rb +19 -0
  81. metadata +41 -25
  82. data/amber/js/lib/peg-0.6.2.min.js +0 -2
  83. data/bin/resin-compile +0 -6
  84. data/bin/runresin +0 -12
@@ -257,13 +257,9 @@ ifNotEmpty: aBlock
257
257
  !
258
258
 
259
259
  includes: anObject
260
- <
261
- var i = self.length;
262
- while (i--) {
263
- if (smalltalk.send(self[i], "__eq", [anObject])) {return true;}
264
- }
265
- return false
266
- >
260
+ | sentinel |
261
+ sentinel := Object new.
262
+ ^(self detect: [ :each | each = anObject] ifNone: [ sentinel ]) ~= sentinel
267
263
  !
268
264
 
269
265
  isEmpty
@@ -683,7 +679,7 @@ indexOf: anObject
683
679
  indexOf: anObject ifAbsent: aBlock
684
680
  <
685
681
  for(var i=0;i<self.length;i++) {
686
- if(smalltalk.send(self[i], '__eq', [anObject])) {return i+1}
682
+ if(self[i].__eq(anObject)) {return i+1}
687
683
  };
688
684
  return aBlock();
689
685
  >
@@ -776,6 +772,12 @@ withIndexDo: aBlock
776
772
  <for(var i=0;i<self.length;i++){aBlock(self[i], i+1);}>
777
773
  ! !
778
774
 
775
+ !SequenceableCollection methodsFor: 'testing'!
776
+
777
+ includes: anObject
778
+ ^(self indexOf: anObject ifAbsent: [nil]) notNil
779
+ ! !
780
+
779
781
  SequenceableCollection subclass: #Array
780
782
  instanceVariableNames: ''
781
783
  package: 'Kernel-Collections'!
@@ -810,9 +812,9 @@ remove: anObject ifAbsent: aBlock
810
812
  self.splice(i,1);
811
813
  return self;
812
814
  }
813
- }
814
- >.
815
- aBlock value
815
+ };
816
+ aBlock._value();
817
+ >
816
818
  !
817
819
 
818
820
  removeFrom: aNumber to: anotherNumber
@@ -995,8 +997,12 @@ unescaped
995
997
  !
996
998
 
997
999
  = aString
998
- aString class = self class ifFalse: [^false].
999
- <return String(self) === String(aString)>
1000
+ <
1001
+ if(!! aString._isString || !! aString._isString()) {
1002
+ return false;
1003
+ }
1004
+ return String(self) === String(aString)
1005
+ >
1000
1006
  !
1001
1007
 
1002
1008
  == aString
@@ -1038,22 +1044,12 @@ asNumber
1038
1044
  <return Number(self)>
1039
1045
  !
1040
1046
 
1047
+ asRegexp
1048
+ ^ RegularExpression fromString: self
1049
+ !
1050
+
1041
1051
  asSelector
1042
- "If you change this method, change smalltalk.convertSelector too (see js/boot.js file)"
1043
-
1044
- | selector |
1045
- selector := '_', self.
1046
- selector := selector replace: ':' with: '_'.
1047
- selector := selector replace: '[+]' with: '_plus'.
1048
- selector := selector replace: '-' with: '_minus'.
1049
- selector := selector replace: '[*]' with: '_star'.
1050
- selector := selector replace: '[/]' with: '_slash'.
1051
- selector := selector replace: '>' with: '_gt'.
1052
- selector := selector replace: '<' with: '_lt'.
1053
- selector := selector replace: '=' with: '_eq'.
1054
- selector := selector replace: ',' with: '_comma'.
1055
- selector := selector replace: '[@]' with: '_at'.
1056
- ^selector
1052
+ <return smalltalk.selector(self)>
1057
1053
  !
1058
1054
 
1059
1055
  asString
@@ -1343,6 +1339,10 @@ asString
1343
1339
  <return self.value>
1344
1340
  !
1345
1341
 
1342
+ asSuperSelector
1343
+ ^self asString asSuperSelector
1344
+ !
1345
+
1346
1346
  asSymbol
1347
1347
  ^self
1348
1348
  ! !
@@ -1490,6 +1490,16 @@ includes: anObject
1490
1490
  Object subclass: #Queue
1491
1491
  instanceVariableNames: 'read readIndex write'
1492
1492
  package: 'Kernel-Collections'!
1493
+ !Queue commentStamp!
1494
+ A Queue am a one-sided queue.
1495
+
1496
+ A Queue uses two OrderedCollections inside,
1497
+ `read` is at the front, is not modified and only read using `readIndex`.
1498
+ `write` is at the back and is appended new items.
1499
+ When `read` is exhausted, `write` is promoted to `read` and new `write` is created.
1500
+
1501
+ As a consequence, no data moving is done by the Queue; write appending may do data moving
1502
+ when growing `write`, but this is left to engine to implement as good as it chooses to.!
1493
1503
 
1494
1504
  !Queue methodsFor: 'accessing'!
1495
1505
 
@@ -1498,7 +1508,7 @@ back: anObject
1498
1508
  !
1499
1509
 
1500
1510
  front
1501
- ^self frontIfAbsent: [ self error: 'Cannot read from empty Queue.']
1511
+ ^self frontIfAbsent: [ self error: 'Cannot read from empty Queue.' ]
1502
1512
  !
1503
1513
 
1504
1514
  frontIfAbsent: aBlock
@@ -1519,9 +1529,10 @@ frontIfAbsent: aBlock
1519
1529
  !Queue methodsFor: 'initialization'!
1520
1530
 
1521
1531
  initialize
1522
- read := #().
1523
- readIndex := 1.
1524
- write := OrderedCollection new
1532
+ super initialize.
1533
+ read := OrderedCollection new.
1534
+ write := OrderedCollection new.
1535
+ readIndex := 1
1525
1536
  ! !
1526
1537
 
1527
1538
  Object subclass: #RegularExpression
@@ -2,6 +2,13 @@ Smalltalk current createPackage: 'Kernel-Exceptions' properties: #{}!
2
2
  Object subclass: #Error
3
3
  instanceVariableNames: 'messageText'
4
4
  package: 'Kernel-Exceptions'!
5
+ !Error commentStamp!
6
+ From the ANSI standard:
7
+
8
+ This protocol describes the behavior of instances of class `Error`.
9
+ These are used to represent error conditions that prevent the normal continuation of processing.
10
+ Actual error exceptions used by an application may be subclasses of this class.
11
+ As `Error` is explicitly specified to be subclassable, conforming implementations must implement its behavior in a non-fragile manner.!
5
12
 
6
13
  !Error methodsFor: 'accessing'!
7
14
 
@@ -21,6 +28,12 @@ messageText: aString
21
28
  messageText := aString
22
29
  ! !
23
30
 
31
+ !Error methodsFor: 'initialization'!
32
+
33
+ initialize
34
+ self messageText: 'Errorclass: ', (self class name).
35
+ ! !
36
+
24
37
  !Error methodsFor: 'signaling'!
25
38
 
26
39
  signal
@@ -49,9 +62,54 @@ signal: aString
49
62
  signal: aString
50
63
  ! !
51
64
 
65
+ Error subclass: #JavaScriptException
66
+ instanceVariableNames: 'exception'
67
+ package: 'Kernel-Exceptions'!
68
+ !JavaScriptException commentStamp!
69
+ A JavaScriptException is thrown when a non-Smalltalk exception occurs while in the Smalltalk stack.
70
+ See `boot.js` `inContext()` and `BlockClosure >> on:do:`!
71
+
72
+ !JavaScriptException methodsFor: 'accessing'!
73
+
74
+ context: aMethodContext
75
+ "Set the context from the outside.
76
+ See boot.js `inContext()` exception handling"
77
+
78
+ <self.context = aMethodContext>
79
+ !
80
+
81
+ exception
82
+ ^ exception
83
+ !
84
+
85
+ exception: anException
86
+ exception := anException
87
+ !
88
+
89
+ messageText
90
+ <return 'JavaScript exception: ' + self["@exception"].toString()>
91
+ ! !
92
+
93
+ !JavaScriptException class methodsFor: 'instance creation'!
94
+
95
+ on: anException
96
+ ^ self new
97
+ exception: anException;
98
+ yourself
99
+ !
100
+
101
+ on: anException context: aMethodContext
102
+ ^ self new
103
+ exception: anException;
104
+ context: aMethodContext;
105
+ yourself
106
+ ! !
107
+
52
108
  Error subclass: #MessageNotUnderstood
53
109
  instanceVariableNames: 'message receiver'
54
110
  package: 'Kernel-Exceptions'!
111
+ !MessageNotUnderstood commentStamp!
112
+ This exception is provided to support `Object>>doesNotUnderstand:`.!
55
113
 
56
114
  !MessageNotUnderstood methodsFor: 'accessing'!
57
115
 
@@ -78,6 +136,8 @@ receiver: anObject
78
136
  Error subclass: #NonBooleanReceiver
79
137
  instanceVariableNames: 'object'
80
138
  package: 'Kernel-Exceptions'!
139
+ !NonBooleanReceiver commentStamp!
140
+ NonBooleanReceiver exceptions may be thrown when executing inlined methods such as `#ifTrue:` with a non boolean receiver.!
81
141
 
82
142
  !NonBooleanReceiver methodsFor: 'accessing'!
83
143
 
@@ -92,6 +152,15 @@ object: anObject
92
152
  Object subclass: #ErrorHandler
93
153
  instanceVariableNames: ''
94
154
  package: 'Kernel-Exceptions'!
155
+ !ErrorHandler commentStamp!
156
+ ErrorHandler is used to manage Smalltalk errors.
157
+ See `boot.js` `handleError()` function.
158
+
159
+ Subclasses of `ErrorHandler` can register themselves as the current handler with
160
+ `ErrorHandler class >> register`.
161
+
162
+ Subclasses may override `#handleError:` to perform an action on the thrown exception.
163
+ The default behavior is to log the error and the context stack to the JavaScript console.!
95
164
 
96
165
  !ErrorHandler methodsFor: 'error handling'!
97
166
 
@@ -109,7 +178,7 @@ log: aString
109
178
  logContext: aContext
110
179
  aContext home ifNotNil: [
111
180
  self logContext: aContext home].
112
- self log: aContext receiver asString, '>>', aContext selector
181
+ self log: aContext receiver asString, '>>', aContext selector asString
113
182
  !
114
183
 
115
184
  logError: anError
@@ -40,13 +40,23 @@ whileTrue: aBlock
40
40
  <while(self()) {aBlock()}>
41
41
  ! !
42
42
 
43
+ !BlockClosure methodsFor: 'converting'!
44
+
45
+ asCompiledMethod: aString
46
+ <return smalltalk.method({selector:aString, fn:self});>
47
+ ! !
48
+
43
49
  !BlockClosure methodsFor: 'error handling'!
44
50
 
45
51
  on: anErrorClass do: aBlock
46
- ^self try: self catch: [:error |
47
- (error isKindOf: anErrorClass)
48
- ifTrue: [aBlock value: error]
49
- ifFalse: [error signal]]
52
+ "All exceptions thrown in the Smalltalk stack are cought.
53
+ Convert all JS exceptions to JavaScriptException instances."
54
+
55
+ ^self try: self catch: [ :error | | smalltalkError |
56
+ smalltalkError := Smalltalk current asSmalltalkException: error.
57
+ (smalltalkError isKindOf: anErrorClass)
58
+ ifTrue: [ aBlock value: smalltalkError ]
59
+ ifFalse: [ smalltalkError signal ] ]
50
60
  ! !
51
61
 
52
62
  !BlockClosure methodsFor: 'evaluating'!
@@ -56,7 +66,7 @@ applyTo: anObject arguments: aCollection
56
66
  !
57
67
 
58
68
  ensure: aBlock
59
- <try{self()}finally{return aBlock._value()}>
69
+ <try{return self()}finally{aBlock._value()}>
60
70
  !
61
71
 
62
72
  new
@@ -80,7 +90,7 @@ newValue: anObject value: anObject2
80
90
  newValue: anObject value: anObject2 value: anObject3
81
91
  "Use the receiver as a JS constructor.
82
92
  *Do not* use this method to instanciate Smalltalk objects!!"
83
- <return new self(anObject, anObject2)>
93
+ <return new self(anObject, anObject2,anObject3)>
84
94
  !
85
95
 
86
96
  timeToRun
@@ -120,11 +130,17 @@ fork
120
130
  !
121
131
 
122
132
  valueWithInterval: aNumber
123
- <return setInterval(self, aNumber)>
133
+ <
134
+ var interval = setInterval(self, aNumber);
135
+ return smalltalk.Timeout._on_(interval);
136
+ >
124
137
  !
125
138
 
126
139
  valueWithTimeout: aNumber
127
- <return setTimeout(self, aNumber)>
140
+ <
141
+ var timeout = setTimeout(self, aNumber);
142
+ return smalltalk.Timeout._on_(timeout);
143
+ >
128
144
  ! !
129
145
 
130
146
  Object subclass: #CompiledMethod
@@ -215,33 +231,60 @@ source: aString
215
231
  Object subclass: #ForkPool
216
232
  instanceVariableNames: 'poolSize maxPoolSize queue worker'
217
233
  package: 'Kernel-Methods'!
234
+ !ForkPool commentStamp!
235
+ A ForkPool is responsible for handling forked blocks.
236
+ The pool size sets the maximum concurrent forked blocks.
218
237
 
219
- !ForkPool methodsFor: 'action'!
238
+ The default instance is accessed with `ForkPool default`!
220
239
 
221
- addWorker
222
- worker valueWithTimeout: 0.
223
- poolSize := poolSize + 1
240
+ !ForkPool methodsFor: 'accessing'!
241
+
242
+ maxPoolSize
243
+ ^ maxPoolSize ifNil: [ self defaultMaxPoolSize ]
224
244
  !
225
245
 
246
+ maxPoolSize: anInteger
247
+ maxPoolSize := anInteger
248
+ ! !
249
+
250
+ !ForkPool methodsFor: 'actions'!
251
+
226
252
  fork: aBlock
227
- poolSize < maxPoolSize ifTrue: [ self addWorker ].
253
+ poolSize < self maxPoolSize ifTrue: [ self addWorker ].
228
254
  queue back: aBlock
229
255
  ! !
230
256
 
257
+ !ForkPool methodsFor: 'defaults'!
258
+
259
+ defaultMaxPoolSize
260
+ ^ self class defaultMaxPoolSize
261
+ ! !
262
+
231
263
  !ForkPool methodsFor: 'initialization'!
232
264
 
233
265
  initialize
234
- | sentinel |
266
+ super initialize.
267
+
235
268
  poolSize := 0.
236
- maxPoolSize := self class defaultMaxPoolSize.
237
269
  queue := Queue new.
270
+ worker := self makeWorker
271
+ !
272
+
273
+ makeWorker
274
+ | sentinel |
238
275
  sentinel := Object new.
239
- worker := [
240
- | block |
276
+ ^[ | block |
241
277
  poolSize := poolSize - 1.
242
278
  block := queue frontIfAbsent: [ sentinel ].
243
279
  block == sentinel ifFalse: [
244
- [ block value ] ensure: [ self addWorker ]]].
280
+ [ block value ] ensure: [ self addWorker ]]]
281
+ ! !
282
+
283
+ !ForkPool methodsFor: 'private'!
284
+
285
+ addWorker
286
+ worker valueWithTimeout: 0.
287
+ poolSize := poolSize + 1
245
288
  ! !
246
289
 
247
290
  ForkPool class instanceVariableNames: 'default'!
@@ -300,7 +343,7 @@ printString
300
343
  !
301
344
 
302
345
  sendTo: anObject
303
- ^ Smalltalk current send: self selector to: anObject arguments: self arguments
346
+ ^ anObject perform: self selector withArguments: self arguments
304
347
  ! !
305
348
 
306
349
  !Message class methodsFor: 'instance creation'!
@@ -318,17 +361,29 @@ Object subclass: #MethodContext
318
361
  !MethodContext commentStamp!
319
362
  MethodContext holds all the dynamic state associated with the execution of either a method activation resulting from a message send. That is used to build the call stack while debugging.
320
363
 
321
- MethodContext instances are JavaScript `SmalltalkMethodContext` objects defined in boot.js
322
-
323
- Current limitation: MethodContext instances are not created on Block evaluation. That means it's actually impossible to debug inside a Block.!
364
+ MethodContext instances are JavaScript `SmalltalkMethodContext` objects defined in boot.js!
324
365
 
325
366
  !MethodContext methodsFor: 'accessing'!
326
367
 
327
- asString
328
- ^self receiver class printString, ' >> ', self selector
368
+ home
369
+ <return self.methodContext || self.homeContext>
329
370
  !
330
371
 
331
- home
372
+ locals
373
+ <return self.locals>
374
+ !
375
+
376
+ method
377
+ ^self methodContext receiver class lookupSelector: self methodContext selector
378
+ !
379
+
380
+ methodContext
381
+ self isBlockContext ifFalse: [ ^ self ].
382
+
383
+ ^ self home
384
+ !
385
+
386
+ outerContext
332
387
  <return self.homeContext>
333
388
  !
334
389
 
@@ -345,10 +400,93 @@ receiver
345
400
  !
346
401
 
347
402
  selector
348
- <return smalltalk.convertSelector(self.selector)>
403
+ <
404
+ if(self.selector) {
405
+ return smalltalk.convertSelector(self.selector);
406
+ } else {
407
+ return nil;
408
+ }
409
+ >
349
410
  !
350
411
 
351
412
  temps
352
- <return self.temps>
413
+ self deprecatedAPI.
414
+
415
+ ^ self locals
416
+ ! !
417
+
418
+ !MethodContext methodsFor: 'converting'!
419
+
420
+ asString
421
+ ^self isBlockContext
422
+ ifTrue: [ 'a block (in ', self methodContext receiver class printString, ')' ]
423
+ ifFalse: [ self receiver class printString, ' >> ', self selector ]
424
+ ! !
425
+
426
+ !MethodContext methodsFor: 'testing'!
427
+
428
+ isBlockContext
429
+ "Block context do not have selectors."
430
+
431
+ ^ self selector isNil
432
+ ! !
433
+
434
+ Object subclass: #NativeFunction
435
+ instanceVariableNames: ''
436
+ package: 'Kernel-Methods'!
437
+ !NativeFunction commentStamp!
438
+ NativeFunction is a wrapper around native functions, such as `WebSocket`.
439
+ For 'normal' functions (whose constructor is the JavaScript `Function` object), use `BlockClosure`.
440
+
441
+ See the class-side `instance creation` methods.
442
+
443
+ Created instances will most probably be instance of `JSObjectProxy`.
444
+
445
+ Usage example:
446
+
447
+ | ws |
448
+ ws := NativeFunction constructor: 'WebSocket' value: 'ws://localhost'.
449
+ ws at: 'onopen' put: [ ws send: 'hey there from Amber' ]!
450
+
451
+ !NativeFunction class methodsFor: 'instance creation'!
452
+
453
+ constructor: aString
454
+ <
455
+ var native=eval(aString);
456
+ return new native();
457
+ >
458
+ !
459
+
460
+ constructor: aString value:anObject
461
+ <
462
+ var native=eval(aString);
463
+ return new native(anObject);
464
+ >
465
+ !
466
+
467
+ constructor: aString value:anObject value: anObject2
468
+ <
469
+ var native=eval(aString);
470
+ return new native(anObject,anObject2);
471
+ >
472
+ !
473
+
474
+ constructor: aString value:anObject value: anObject2 value:anObject3
475
+ <
476
+ var native=eval(aString);
477
+ return new native(anObject,anObject2, anObject3);
478
+ >
479
+ ! !
480
+
481
+ !NativeFunction class methodsFor: 'testing'!
482
+
483
+ exists: aString
484
+ <
485
+ if(aString in window) {
486
+ return true
487
+ } else {
488
+ return false
489
+ }
490
+ >
353
491
  ! !
354
492