minjs 0.1.7 → 0.1.10

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.
@@ -36,7 +36,17 @@ module Minjs
36
36
  end
37
37
 
38
38
  def to_js(options = {})
39
- @prog.to_js(options)
39
+ remove_empty_statement
40
+ @prog.to_js(options).sub(/;;\Z/, ";")
41
+ end
42
+
43
+ def remove_empty_statement(node = @prog)
44
+ node.traverse(nil) {|st, parent|
45
+ if st.kind_of? ECMA262::StatementList
46
+ st.remove_empty_statement
47
+ end
48
+ }
49
+ self
40
50
  end
41
51
 
42
52
  def compress(data, options = {})
@@ -58,27 +68,35 @@ module Minjs
58
68
  @logger.info '* grouping_statement'
59
69
  grouping_statement
60
70
 
61
- @logger.info '* block_to_statement'
62
- block_to_statement
63
-
64
71
  @logger.info '* reduce_if'
65
72
  reduce_if
66
73
 
74
+ @logger.info '* block_to_statement'
75
+ block_to_statement
76
+
67
77
  @logger.info '* if_to_cond'
68
78
  if_to_cond
69
79
 
80
+ @logger.info '* optimize_if_return'
81
+ optimize_if_return
82
+
70
83
  @logger.info '* compress_var'
84
+ compress_var(@prog, :longer => true)
71
85
  compress_var
72
86
 
73
87
  @logger.info '* reduce_exp'
74
88
  reduce_exp
75
89
 
90
+ grouping_statement
91
+ block_to_statement
92
+ if_to_cond
93
+
94
+ #feature
95
+ optimize_if_return2
96
+
76
97
  @logger.info '* remove_paren'
77
98
  remove_paren
78
99
 
79
- @logger.info '* return_to_exp'
80
- return_to_exp
81
-
82
100
  @heading_comments.reverse.each do |c|
83
101
  @prog.source_elements.source_elements.unshift(c)
84
102
  end
@@ -97,12 +115,14 @@ module Minjs
97
115
  nil
98
116
  }
99
117
  @prog = source_elements(@lex, @global_context)
100
- @prog
101
- end
102
118
 
103
- # def traverse(&block)
104
- # @prog.traverse(nil, &block)
105
- # end
119
+ #a = @prog.deep_dup
120
+ #a == @prog
121
+
122
+ remove_empty_statement
123
+ #@prog
124
+ self
125
+ end
106
126
 
107
127
  def next_sym(s)
108
128
  def c2i(c)
@@ -186,19 +206,81 @@ module Minjs
186
206
  node.traverse(nil) {|st, parent|
187
207
  if st.kind_of? ECMA262::Prog
188
208
  vars = nil
189
- context = nil
190
- st.instance_eval{
191
- #
192
- # collect all of var variable in this function
193
- #
194
- vars = @context.var_env.record.binding.find_all {|k, v|
195
- v and v[:_parameter_list].nil? and !v[:value].kind_of?(ECMA262::StFunc)
196
- }.collect{|x|
197
- [
198
- ECMA262::IdentifierName.new(@context, x[0])
199
- ]
200
- }
209
+ context = st.context
210
+ #
211
+ # collect all of var variable in this function
212
+ #
213
+ var_vars = {}
214
+ context.var_env.record.binding.each do|k, v|
215
+ if v and v[:_parameter_list].nil? and !v[:value].kind_of?(ECMA262::StFunc)
216
+ var_vars[k] = true
217
+ end
218
+ end
219
+ #
220
+ # traverse block and convert var statement to assignment expression
221
+ # if variable has initializer
222
+ #
223
+ st.traverse(parent){|st2, parent2|
224
+ if st2.kind_of? ECMA262::StVar and st2.context.var_env == context.var_env
225
+ exp = nil
226
+ st2.vars.each do |name, initializer|
227
+ if initializer
228
+ if exp.nil?
229
+ exp = ECMA262::ExpAssign.new(name, initializer)
230
+ else
231
+ exp = ECMA262::ExpComma.new(exp, ECMA262::ExpAssign.new(name, initializer))
232
+ end
233
+ end
234
+ end
235
+ if exp
236
+ parent2.replace(st2, ECMA262::StExp.new(exp))
237
+ else
238
+ parent2.replace(st2, ECMA262::StEmpty.new())
239
+ end
240
+ elsif st2.kind_of? ECMA262::StForVar and st2.context.var_env == context.var_env
241
+ parent2.replace(st2, st2.to_st_for)
242
+ elsif st2.kind_of? ECMA262::StForInVar and st2.context.var_env == context.var_env
243
+ parent2.replace(st2, st2.to_st_for_in)
244
+ end
245
+ }
246
+ if var_vars.length > 0
247
+ elems = st.source_elements.source_elements
248
+ v = ECMA262::StVar.new(
249
+ context,
250
+ var_vars.collect do |k, v|
251
+ [ECMA262::IdentifierName.new(context, k)]
252
+ end
253
+ )
254
+
255
+ idx = 0
256
+ elems.each do |e|
257
+ found = false
258
+ e.traverse(nil){|ee, pp|
259
+ if ee.kind_of? ECMA262::IdentifierName and var_vars[ee.val.to_sym]
260
+ found = true
261
+ break
262
+ end
263
+ }
264
+ break if found
265
+ idx += 1
266
+ end
267
+
268
+ if idx == 0
269
+ elems.unshift(v)
270
+ else
271
+ elems[idx..0] = v
272
+ end
273
+ st.source_elements.remove_empty_statement
274
+ end
275
+ end
276
+ self
277
+ }
278
+ =begin
201
279
  st.traverse(parent) {|st2, parent2|
280
+ #
281
+ #if var statment has initializer,
282
+ #
283
+ #
202
284
  if st2.kind_of? ECMA262::StVar and st2.context.var_env == @context.var_env
203
285
  st2.instance_eval{
204
286
  blk = []
@@ -216,13 +298,12 @@ module Minjs
216
298
  parent2.replace(st2, st2.to_st_for_in)
217
299
  end
218
300
  }
219
- if vars.length > 0
220
- @source_elements.source_elements.unshift ECMA262::StVar.new(@context, vars)
221
- end
301
+
222
302
  }
223
303
  end
224
304
  }
225
305
  remove_block_in_block
306
+ =end
226
307
  self
227
308
  end
228
309
 
@@ -255,123 +336,194 @@ module Minjs
255
336
  end
256
337
 
257
338
  def block_to_statement(node = @prog)
339
+ node.traverse(nil) {|st, parent|
340
+ if st.kind_of? ECMA262::StBlock and !parent.kind_of?(ECMA262::StTry) and !parent.kind_of?(ECMA262::StIf)
341
+ if st.to_statement?
342
+ parent.replace(st, st.to_statement)
343
+ end
344
+ end
345
+ }
346
+ if_block_to_statement
347
+ end
348
+
349
+ #
350
+ # To determine removing "if block" is available or not is difficult.
351
+ # For example, next codes block must not be removed, because
352
+ # "else" cluase combined to second "if" statement.
353
+ #
354
+ #
355
+ # if(a){ //<= this block must not be removed
356
+ # while(true)
357
+ # if(b){
358
+ # ;
359
+ # }
360
+ # }
361
+ # else{
362
+ # ;
363
+ # }
364
+ def if_block_to_statement(node = @prog)
365
+ # The "else" cluase's block can be removed always
258
366
  node.traverse(nil) {|st, parent|
259
367
  if st.kind_of? ECMA262::StIf
260
- #
261
- # To determine removing "if block" is available or not is difficult.
262
- # For example, next codes block must not be removed, because
263
- # "else" cluase combined to second "if" statement.
264
- #
265
- #
266
- # if(a){ //<= this block must not be removed
267
- # while(true)
268
- # if(b){
269
- # ;
270
- # }
271
- # }
272
- # else{
273
- # ;
274
- # }
275
-
276
- # The "else" cluase's block can be removed without condition.
368
+ if st.else_st and st.else_st.kind_of? ECMA262::StBlock
369
+ st.else_st.remove_empty_statement
370
+ end
371
+
277
372
  if st.else_st and st.else_st.kind_of? ECMA262::StBlock and st.else_st.to_statement?
278
373
  st.replace(st.else_st, st.else_st.to_statement)
279
374
  end
280
- #
281
- # if "if" statement has no "else" clause, its block can be removed.
282
- #
283
- if st.else_st.nil? and st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
375
+ end
376
+ }
377
+ node.traverse(nil) {|st0, parent|
378
+ st = st0.deep_dup
379
+ if st.kind_of? ECMA262::StIf
380
+ if st.then_st and st.then_st.kind_of? ECMA262::StBlock
381
+ st.then_st.remove_empty_statement
382
+ end
383
+
384
+ if st.then_st and st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
284
385
  st.replace(st.then_st, st.then_st.to_statement)
285
- #
286
- # if "if" statement has "else" clause, check "then" branch.
287
- # If branch has no "if" statement or
288
- # has "if-else" statement, its block can be removed.
289
- #
290
- elsif st.else_st and st.then_st.kind_of? ECMA262::StBlock and st.then_st.to_statement?
291
- deblock = true
292
- last_st = st.then_st.last_statement.map{|x|
293
- if x.kind_of? ECMA262::StIf and x.else_st.nil?
294
- deblock = false
295
- end
296
- }
297
- if deblock
298
- st.replace(st.then_st, st.then_st.to_statement)
299
- end
386
+ end
387
+
388
+ _lex = Minjs::Lex.new(st.to_js)
389
+ _context = ECMA262::Context.new
390
+ _if = if_statement(_lex, _context)
391
+ if _if == st #
392
+ parent.replace(st0, st)
300
393
  end
301
394
  end
302
395
  }
396
+ self
397
+ end
398
+
399
+ #
400
+ # if(a)b;else c;
401
+ # =>
402
+ # a?b:c
403
+ #
404
+ # if(a)b
405
+ # =>
406
+ # a&&b;
407
+ #
408
+ def if_to_cond(node = @prog)
303
409
  node.traverse(nil) {|st, parent|
304
- if st.kind_of? ECMA262::StBlock and !parent.kind_of?(ECMA262::StTry) and !parent.kind_of?(ECMA262::StIf)
305
- if st.to_statement?
306
- parent.replace(st, st.to_statement)
410
+ if st.kind_of? ECMA262::StIf
411
+ if st.to_exp?
412
+ t = ECMA262::StExp.new(st.to_exp({}))
413
+ remove_paren(t)
414
+ if t.to_js.length <= st.to_js.length
415
+ parent.replace(st, t)
307
416
  end
417
+ end
308
418
  end
309
419
  }
420
+ if_to_return(node)
310
421
  self
311
422
  end
312
-
313
- def if_block_to_statemet(node = @prog)
314
- end
315
-
316
- def if_to_cond(node = nil)
317
- node = @prog if node.nil?
423
+ #
424
+ # if(a)return b;else return c;
425
+ # => return a?b:c;
426
+ #
427
+ def if_to_return(node = @prog)
318
428
  node.traverse(nil) {|st, parent|
319
- #
320
- #feature
321
- #
322
- # if(a)return a;
323
- # return b;
324
- # => if(a)return a;else return b;
325
- #
326
-
327
- if st.kind_of? ECMA262::StIf and parent.kind_of? ECMA262::StatementList
328
- i = parent.index(st)
329
- if parent[i+1].nil? and !parent.kind_of?(ECMA262::SourceElements)
330
- next
429
+ if st.kind_of? ECMA262::StIf
430
+ if st.to_return?
431
+ t = st.to_return
432
+ remove_paren(t)
433
+ if t.to_js.length <= st.to_js.length
434
+ parent.replace(st, t)
435
+ end
331
436
  end
332
- if parent[i+1].nil? or parent[i+1].to_return?
333
- s = st
334
- while s.kind_of? ECMA262::StIf and s.else_st and s.then_st.to_return?
335
- s = s.else_st
437
+ end
438
+ }
439
+ self
440
+ end
441
+
442
+ #
443
+ # if(a)return b;
444
+ # return c;
445
+ #
446
+ # => if(a)return b;else return c;
447
+ # => return a?b:c;
448
+ #
449
+ def optimize_if_return(node = @prog)
450
+ retry_flag = true
451
+ while retry_flag
452
+ retry_flag = false
453
+ node.traverse(nil) {|st0, parent0|
454
+ if st0.kind_of? ECMA262::StIf and parent0.kind_of? ECMA262::StatementList
455
+ i = parent0.index(st0)
456
+ break if i.nil?
457
+ parent = parent0.deep_dup
458
+ st = parent[i]
459
+ #
460
+ if parent[i+1].nil? and !parent.kind_of?(ECMA262::SourceElements)
461
+ next
336
462
  end
337
- if s and s.kind_of? ECMA262::StIf and s.then_st.to_return?
338
- if parent[i+1]
339
- s.replace(s.else_st, parent[i+1])
340
- parent.replace(parent[i+1], ECMA262::StEmpty.new)
341
- else
342
- s.replace(s.else_st, ECMA262::StReturn.new(ECMA262::ExpVoid.new(ECMA262::ECMA262Numeric.new(0))))
463
+ if parent[i+1].nil? or parent[i+1].to_return?
464
+ s = st
465
+ while s.kind_of? ECMA262::StIf and s.else_st and s.then_st.to_return?
466
+ s = s.else_st
467
+ end
468
+ if s and s.kind_of? ECMA262::StIf and s.then_st.to_return?
469
+ if parent[i+1]
470
+ s.replace(s.else_st, parent[i+1])
471
+ parent.replace(parent[i+1], ECMA262::StEmpty.new)
472
+ else
473
+ s.replace(s.else_st, ECMA262::StReturn.new(ECMA262::ExpVoid.new(ECMA262::ECMA262Numeric.new(0))))
474
+ end
475
+ if_to_cond(parent)
476
+ if parent.to_js(:no_debug => true).length <= parent0.to_js(:no_debug => true).length
477
+ parent0.replace(st0, st)
478
+ if parent[i+1]
479
+ parent0.replace(parent0[i+1], ECMA262::StEmpty.new)
480
+ end
481
+ retry_flag = true
482
+ node = parent0
483
+ end
343
484
  end
344
485
  end
345
486
  end
346
- end
347
- }
487
+ }
488
+ end
489
+ self
490
+ end
491
+
492
+ #
493
+ # if(a)return b;else c;
494
+ # =>
495
+ # if(a)return b;c;
496
+ #
497
+ def optimize_if_return2(node = @prog)
348
498
  node.traverse(nil) {|st, parent|
349
- if st.kind_of? ECMA262::StIf and st.to_exp?
350
- if t = ECMA262::StExp.new(st.to_exp({}))
351
- parent.replace(st, t)
352
- end
353
- elsif st.kind_of? ECMA262::StIf and st.to_return?
354
- t = st.to_return
355
- if t.to_js().length < st.to_js().length
356
- parent.replace(st, st.to_return)
499
+ if st.kind_of? ECMA262::StIf and st.else_st and parent.kind_of? ECMA262::StatementList
500
+ st.remove_empty_statement
501
+ if (st.then_st.kind_of? ECMA262::StBlock and st.then_st[-1].kind_of? ECMA262::StReturn) or
502
+ st.then_st.kind_of? ECMA262::StReturn
503
+ idx = parent.index(st)
504
+ parent[idx+1..0] = st.else_st
505
+ st.replace(st.else_st, nil)
357
506
  end
358
507
  end
359
508
  }
360
- remove_paren
361
509
  self
362
510
  end
363
511
 
364
- def compress_var(node = @prog)
512
+ def compress_var(node = @prog, options = {})
513
+ if options[:longer]
514
+ var_sym = :aaaaaaaaaa
515
+ end
516
+
365
517
  #
366
518
  #traverse all statemtns and expression
367
519
  #
520
+ scopes = []
368
521
  node.traverse(nil) {|st, parent|
369
- var_sym = :a
370
522
  if st.kind_of? ECMA262::StTry and st.catch
371
523
  _context = st.catch_context
372
524
  _parent = st
373
525
  _st = st.catch[1]
374
- elsif st.kind_of? ECMA262::StFunc #and st.context.var_env.outer
526
+ elsif st.kind_of? ECMA262::StFunc
375
527
  _context = st.context
376
528
  _parent = parent
377
529
  _st = st
@@ -380,9 +532,19 @@ module Minjs
380
532
  _context = nil
381
533
  _st = nil
382
534
  end
535
+ if _parent and _context and _st
536
+ scopes.push([st, parent, _parent, _context, _st])
537
+ end
538
+ }
539
+ #node.traverse(nil) {|st, parent|
540
+ scopes.reverse.each {|st, parent, _parent, _context, _st|
541
+ #p "*#{st.name.to_js}"
542
+ if !options[:longer]
543
+ var_sym = :a
544
+ end
383
545
  if _parent and _context and _st
384
546
  #
385
- # collect all variables under this function/catch
547
+ # collect and counting all variables under this function/catch
386
548
  #
387
549
  vars = {}
388
550
  if st.kind_of? ECMA262::StTry
@@ -402,13 +564,6 @@ module Minjs
402
564
  _context.var_env.record.binding.each do|k, v|
403
565
  var_vars[k] = (vars[k] || 1)
404
566
  end
405
- _st.traverse(parent) {|st2|
406
- if st2.kind_of? ECMA262::StFunc
407
- st2.context.var_env.record.binding.each do|k, v|
408
- var_vars[k] = (vars[k] || 1)
409
- end
410
- end
411
- }
412
567
  end
413
568
  #
414
569
  # collect all lexical variables under this catch clause
@@ -440,6 +595,7 @@ module Minjs
440
595
  # sort var_vars
441
596
  #
442
597
  var_vars = var_vars.sort {|(k1,v1), (k2,v2)| v2 <=> v1}
598
+ #p var_vars
443
599
  #
444
600
  # check var_vars
445
601
  #
@@ -450,22 +606,38 @@ module Minjs
450
606
  while(vars[var_sym])
451
607
  var_sym = next_sym(var_sym)
452
608
  end
453
- if name.to_s.bytesize > var_sym.to_s.bytesize
609
+ if (!options[:longer] && name.to_s.bytesize >= var_sym.to_s.bytesize) or
610
+ (options[:longer] && name.to_s.bytesize <= var_sym.to_s.bytesize)
454
611
  #
455
612
  # rename `name' to `var_sym'
456
613
  #
614
+ func_name = nil
615
+ if _st.kind_of? ECMA262::StFunc and _st.decl?
616
+ func_name = _st.name
617
+ end
457
618
  _st.traverse(_parent){|st2|
458
619
  if st2.kind_of? ECMA262::IdentifierName and st2.context.nil?
459
- ;# TODO, currently special identifier such as 'this' has no context
620
+ ;# this
460
621
  elsif st2.kind_of? ECMA262::IdentifierName and st2.context.var_env.outer == nil # global scope
461
622
  ;
462
623
  elsif st2.kind_of? ECMA262::IdentifierName and st2.val == name
463
- st2.instance_eval{
464
- @val = var_sym
465
- }
624
+ # scope of function's name is outer
625
+ if st2.eql?(func_name)
626
+ else
627
+ st2.instance_eval{
628
+ @val = var_sym
629
+ }
630
+ end
466
631
  elsif st2.kind_of? ECMA262::StFunc
467
- st2.context.var_env.record.binding[var_sym] = st2.context.var_env.record.binding[name]
468
- st2.context.var_env.record.binding.delete(name)
632
+ if st2.context.var_env.record.binding[name]
633
+ st2.context.var_env.record.binding[var_sym] = st2.context.var_env.record.binding[name]
634
+ st2.context.var_env.record.binding.delete(name)
635
+ end
636
+ elsif st2.kind_of? ECMA262::StTry
637
+ if st2.catch_context.lex_env.record.binding[name]
638
+ st2.catch_context.lex_env.record.binding[var_sym] = st2.catch_context.lex_env.record.binding[name]
639
+ st2.catch_context.lex_env.record.binding.delete(name)
640
+ end
469
641
  end
470
642
  }
471
643
  end
@@ -498,6 +670,16 @@ module Minjs
498
670
  st.catch[0].instance_eval{
499
671
  @val = var_sym
500
672
  }
673
+ elsif st2.kind_of? ECMA262::StFunc
674
+ if st2.context.var_env.record.binding[name]
675
+ st2.context.var_env.record.binding[var_sym] = st2.context.var_env.record.binding[name]
676
+ st2.context.var_env.record.binding.delete(name)
677
+ end
678
+ elsif st2.kind_of? ECMA262::StTry
679
+ if st2.catch_context.lex_env.record.binding[name]
680
+ st2.catch_context.lex_env.record.binding[var_sym] = st2.catch_context.lex_env.record.binding[name]
681
+ st2.catch_context.lex_env.record.binding.delete(name)
682
+ end
501
683
  end
502
684
  end
503
685
  end
@@ -533,7 +715,20 @@ module Minjs
533
715
  #if(true){<then>}else{<else>} => then
534
716
  #
535
717
  elsif st.kind_of? ECMA262::StIf
536
- if st.cond.respond_to? :to_ecma262_boolean
718
+ #if(a)z;else;
719
+ #if(a)z;else{}
720
+ # => {if(a)z;}
721
+ if st.else_st and st.else_st.empty?
722
+ st.replace(st.else_st, nil)
723
+ parent.replace(st, ECMA262::StBlock.new([st]))
724
+ end
725
+ #if(a);
726
+ # => a
727
+ #if(a){}
728
+ # => a
729
+ if st.then_st.empty? and st.else_st.nil?
730
+ parent.replace(st, ECMA262::StExp.new(st.cond))
731
+ elsif st.cond.respond_to? :to_ecma262_boolean
537
732
  if st.cond.to_ecma262_boolean
538
733
  parent.replace(st, st.then_st)
539
734
  elsif st.else_st
@@ -557,61 +752,6 @@ module Minjs
557
752
  self
558
753
  end
559
754
 
560
- def return_to_exp(node = @prog)
561
- node.traverse(nil) {|st, parent|
562
- if st.kind_of? ECMA262::StReturn
563
- if parent.kind_of? ECMA262::StatementList
564
- parent.remove_empty_statement
565
- if parent.statement_list[-1] == st and (prev=parent.statement_list[-2]).class == ECMA262::StExp
566
- if st.exp
567
- st.replace(st.exp, ECMA262::ExpComma.new(prev.exp, st.exp))
568
- parent.replace(prev, ECMA262::StEmpty.new())
569
- end
570
- end
571
- parent.remove_empty_statement
572
- end
573
- end
574
- }
575
- block_to_statement
576
- if_to_cond
577
- self
578
- end
579
- #
580
- # var a; a=1
581
- # => var a=1
582
- #
583
- def assignment_after_var_old(node = @prog)
584
- node.traverse(nil) {|st, parent|
585
- if st.kind_of? ECMA262::StExp and parent.kind_of? ECMA262::SourceElements
586
- if st.exp.kind_of? ECMA262::ExpAssign
587
- idx = parent.index(st)
588
- while idx > 0
589
- idx -= 1
590
- prevst = parent[idx]
591
- if prevst.kind_of? ECMA262::StEmpty
592
- next
593
- elsif prevst.kind_of? ECMA262::StVar
594
- i = 0
595
- prevst.normalization
596
- prevst.vars.each do |name, init|
597
- if st.exp.val == name and init.nil?
598
- prevst.vars[i] = [name, st.exp.val2]
599
- parent.replace(st, ECMA262::StEmpty.new())
600
- break
601
- end
602
- i += 1
603
- end
604
- prevst.normalization
605
- break
606
- else
607
- break
608
- end
609
- end
610
- end
611
- end
612
- }
613
- self
614
- end
615
755
  #
616
756
  # reduce_if
617
757
  #
@@ -653,58 +793,63 @@ module Minjs
653
793
  end
654
794
  false
655
795
  end
656
- node.traverse(nil) {|st, parent|
657
- if st.kind_of? ECMA262::StVar and parent.kind_of? ECMA262::SourceElements
658
- #
659
- # index of 'var statement' is 0, after calling reorder_var
660
- #
661
- catch(:break){
662
- idx = 1
663
- while true
664
- st2 = parent[idx]
665
- if st2.kind_of? ECMA262::StEmpty
666
- idx +=1
667
- next
668
- elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpAssign
669
- if rewrite_var(st, st2.exp.val, st2.exp.val2)
670
- parent.replace(st2, ECMA262::StEmpty.new())
671
- else
672
- throw :break
673
- end
674
- idx += 1
675
- next
676
- elsif st2.kind_of? ECMA262::StFor and st2.exp1.kind_of? ECMA262::ExpAssign
677
- if rewrite_var(st, st2.exp1.val, st2.exp1.val2)
678
- st2.replace(st2.exp1, nil)
679
- else
680
- throw :break
681
- end
682
- throw :break
683
- elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpComma
684
- exp_parent = st2
685
- exp = st2.exp
686
-
687
- while exp.val.kind_of? ECMA262::ExpComma
688
- exp_parent = exp
689
- exp = exp.val
690
- end
691
796
 
692
- if exp.val.kind_of? ECMA262::ExpAssign
693
- if rewrite_var(st, exp.val.val, exp.val.val2)
694
- exp_parent.replace(exp, exp.val2)
797
+ retry_flag = true
798
+ while retry_flag
799
+ retry_flag = false
800
+ node.traverse(nil) {|st, parent|
801
+ if st.kind_of? ECMA262::StVar and parent.kind_of? ECMA262::SourceElements
802
+ catch(:break){
803
+ idx = parent.index(st) + 1
804
+ while true
805
+ st2 = parent[idx]
806
+ if st2.kind_of? ECMA262::StEmpty or (st2.kind_of? ECMA262::StFunc and st2.decl?)
807
+ idx +=1
808
+ next
809
+ elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpAssign
810
+ if rewrite_var(st, st2.exp.val, st2.exp.val2)
811
+ parent.replace(st2, ECMA262::StEmpty.new())
812
+ retry_flag = true
813
+ else
814
+ throw :break
815
+ end
816
+ idx += 1
817
+ next
818
+ elsif st2.kind_of? ECMA262::StFor and st2.exp1.kind_of? ECMA262::ExpAssign
819
+ if rewrite_var(st, st2.exp1.val, st2.exp1.val2)
820
+ st2.replace(st2.exp1, nil)
821
+ retry_flag = true
822
+ else
823
+ throw :break
824
+ end
825
+ throw :break
826
+ elsif st2.kind_of? ECMA262::StExp and st2.exp.kind_of? ECMA262::ExpComma
827
+ exp_parent = st2
828
+ exp = st2.exp
829
+
830
+ while exp.val.kind_of? ECMA262::ExpComma
831
+ exp_parent = exp
832
+ exp = exp.val
833
+ end
834
+
835
+ if exp.val.kind_of? ECMA262::ExpAssign
836
+ if rewrite_var(st, exp.val.val, exp.val.val2)
837
+ exp_parent.replace(exp, exp.val2)
838
+ retry_flag = true
839
+ else
840
+ throw :break
841
+ end
695
842
  else
696
843
  throw :break
697
844
  end
698
845
  else
699
846
  throw :break
700
847
  end
701
- else
702
- throw :break
703
848
  end
704
- end
705
- }
706
- end
707
- }
849
+ }
850
+ end
851
+ }
852
+ end
708
853
  self
709
854
  end
710
855
  end
@@ -716,7 +861,7 @@ if $0 == __FILE__
716
861
  argv.each do |x|
717
862
  f.push(open(x.to_s).read())
718
863
  end
719
- prog = Minjs::Compressor.new(:debug => false)
720
- prog.compress(f.join("\n"))
721
- puts prog.to_js({})
864
+ comp = Minjs::Compressor.new(:debug => false)
865
+ comp.compress(f.join("\n"))
866
+ puts comp.to_js({})
722
867
  end