resin 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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