opal 0.3.44 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/.travis.yml +0 -1
  2. data/CHANGELOG.md +52 -0
  3. data/README.md +3 -3
  4. data/Rakefile +32 -8
  5. data/bin/opal +69 -16
  6. data/config.ru +1 -1
  7. data/examples/native/app/app.rb +28 -9
  8. data/examples/rack/app/app.rb +1 -1
  9. data/lib/opal.rb +0 -1
  10. data/lib/opal/cli.rb +106 -0
  11. data/lib/opal/lexer.rb +4 -2
  12. data/lib/opal/parser.rb +603 -360
  13. data/lib/opal/processor.rb +20 -8
  14. data/lib/opal/server.rb +47 -0
  15. data/lib/opal/source_map.rb +63 -0
  16. data/lib/opal/sprockets_parser.rb +77 -0
  17. data/lib/opal/sprockets_source_map_header.rb +21 -0
  18. data/lib/opal/target_scope.rb +14 -7
  19. data/lib/opal/version.rb +1 -1
  20. data/opal.gemspec +2 -0
  21. data/opal/opal-browser/script_loader.rb +7 -7
  22. data/opal/opal-parser.js.erb +2 -2
  23. data/opal/opal-source-maps.js.erb +2 -0
  24. data/opal/opal.rb +3 -4
  25. data/opal/opal/array.rb +31 -28
  26. data/opal/opal/boolean.rb +4 -0
  27. data/opal/opal/class.rb +14 -5
  28. data/opal/opal/enumerable.rb +68 -8
  29. data/opal/opal/error.rb +1 -1
  30. data/opal/opal/hash.rb +15 -18
  31. data/opal/opal/kernel.rb +24 -10
  32. data/opal/opal/native.rb +31 -0
  33. data/opal/opal/nil_class.rb +7 -2
  34. data/opal/opal/numeric.rb +10 -1
  35. data/opal/opal/proc.rb +4 -0
  36. data/opal/opal/range.rb +1 -1
  37. data/opal/opal/regexp.rb +13 -3
  38. data/opal/opal/runtime.js +134 -51
  39. data/opal/opal/string.rb +45 -22
  40. data/opal/opal/time.rb +25 -7
  41. data/opal/source_map.rb +63 -0
  42. data/opal/source_map/generator.rb +251 -0
  43. data/opal/source_map/parser.rb +102 -0
  44. data/opal/source_map/vlq.rb +122 -0
  45. data/opal/strscan.rb +30 -12
  46. data/spec/opal/class/_inherited_spec.rb +1 -1
  47. data/spec/{rubyspec/core → opal}/class/bridge_class_spec.rb +5 -3
  48. data/spec/{rubyspec/core → opal}/class/extend_spec.rb +0 -0
  49. data/spec/{rubyspec/core → opal}/class/instance_methods_spec.rb +0 -0
  50. data/spec/{rubyspec/core → opal}/class/last_value_spec.rb +0 -1
  51. data/spec/{rubyspec/core → opal}/json/parse_spec.rb +0 -0
  52. data/spec/{rubyspec/core/kernel/block_given.rb → opal/kernel/block_given_spec.rb} +0 -0
  53. data/spec/{rubyspec/core → opal}/kernel/class_spec.rb +0 -0
  54. data/spec/{rubyspec/core → opal}/kernel/extend_spec.rb +0 -0
  55. data/spec/{rubyspec/core → opal}/kernel/format_spec.rb +0 -0
  56. data/spec/opal/kernel/freeze_spec.rb +15 -0
  57. data/spec/{rubyspec/core → opal}/kernel/match_spec.rb +0 -0
  58. data/spec/{rubyspec/core → opal}/kernel/method_spec.rb +0 -0
  59. data/spec/{rubyspec/core → opal}/kernel/methods_spec.rb +0 -0
  60. data/spec/{rubyspec/core → opal}/kernel/nil_spec.rb +0 -0
  61. data/spec/{rubyspec/core → opal}/kernel/p_spec.rb +0 -0
  62. data/spec/{rubyspec/core → opal}/kernel/printf_spec.rb +0 -0
  63. data/spec/{rubyspec/core → opal}/kernel/proc_spec.rb +0 -0
  64. data/spec/{rubyspec/core → opal}/kernel/rand_spec.rb +0 -0
  65. data/spec/{rubyspec/core → opal}/kernel/respond_to_spec.rb +0 -0
  66. data/spec/{rubyspec/core → opal}/kernel/sprintf_spec.rb +0 -0
  67. data/spec/{rubyspec/core → opal}/kernel/to_json_spec.rb +0 -0
  68. data/spec/{rubyspec/core → opal}/module/alias_method_spec.rb +0 -0
  69. data/spec/{rubyspec/core → opal}/module/ancestors_spec.rb +0 -0
  70. data/spec/{rubyspec/core → opal}/module/append_features_spec.rb +0 -0
  71. data/spec/{rubyspec/core → opal}/module/constants_spec.rb +0 -0
  72. data/spec/{rubyspec/core → opal}/module/module_function_spec.rb +0 -1
  73. data/spec/opal/native_spec.rb +85 -3
  74. data/spec/opal/numeric/equal_spec.rb +9 -0
  75. data/spec/opal/parser/irb_spec.rb +43 -0
  76. data/spec/{rubyspec/core → opal}/proc/proc_tricks_spec.rb +0 -0
  77. data/spec/opal/runtime/block_send_spec.rb +28 -0
  78. data/spec/{rubyspec/core/runtime → opal/runtime2}/call_spec.rb +0 -0
  79. data/spec/{rubyspec/core/runtime → opal/runtime2}/class_hierarchy_spec.rb +0 -0
  80. data/spec/{rubyspec/core/runtime → opal/runtime2}/def_spec.rb +0 -0
  81. data/spec/{rubyspec/core/runtime → opal/runtime2}/defined_spec.rb +0 -0
  82. data/spec/{rubyspec/core/runtime → opal/runtime2}/super_spec.rb +0 -0
  83. data/spec/opal/source_map_spec.rb +19 -0
  84. data/spec/opal/string/freeze_spec.rb +15 -0
  85. data/spec/{rubyspec/core → opal}/string/to_json_spec.rb +0 -0
  86. data/spec/ospec/runner.rb +3 -0
  87. data/spec/parser/str_spec.rb +4 -0
  88. data/spec/rubyspec/core/enumerable/fixtures/classes.rb +2 -2
  89. data/spec/rubyspec/core/enumerable/none_spec.rb +68 -0
  90. data/spec/rubyspec/core/enumerable/sort_by_spec.rb +31 -0
  91. data/spec/rubyspec/core/hash/size_spec.rb +1 -1
  92. data/spec/rubyspec/core/hash/to_native_spec.rb +3 -3
  93. data/spec/rubyspec/core/string/fixtures/classes.rb +49 -0
  94. data/spec/rubyspec/core/string/index_spec.rb +405 -0
  95. data/spec/rubyspec/filters/bugs/language/class.rb +0 -2
  96. data/spec/rubyspec/filters/bugs/language/module.rb +3 -0
  97. data/spec/rubyspec/language/array_spec.rb +1 -1
  98. data/spec/rubyspec/language/block_spec.rb +1 -1
  99. data/spec/rubyspec/language/module_spec.rb +5 -5
  100. data/spec/rubyspec/language/predefined_spec.rb +1 -2
  101. data/spec/rubyspec/library/stringscanner/element_reference_spec.rb +29 -0
  102. data/spec/rubyspec/spec_helper.rb +31 -0
  103. metadata +130 -76
  104. data/lib/opal/erb.rb +0 -41
  105. data/opal/erb.rb +0 -19
  106. data/spec/opal/erb/erb_spec.rb +0 -31
  107. data/spec/simple_erb_template.opalerb +0 -1
  108. data/spec/templates/foo/bar.opalerb +0 -1
  109. data/spec/templates/prefixed.opalerb +0 -1
@@ -487,6 +487,9 @@ module Opal
487
487
  if [:expr_beg, :expr_mid, :expr_class].include? @lex_state
488
488
  @lex_state = :expr_beg
489
489
  return '::@', scanner.matched
490
+ elsif space_seen && @lex_state == :expr_arg
491
+ @lex_state = :expr_beg
492
+ return '::@', scanner.matched
490
493
  end
491
494
 
492
495
  @lex_state = :expr_dot
@@ -665,8 +668,7 @@ module Opal
665
668
  return [result, result]
666
669
 
667
670
  elsif scanner.scan(/\?/)
668
- # FIXME: :expr_arg shouldnt really be here
669
- if [:expr_end, :expr_endarg, :expr_arg].include?(@lex_state)
671
+ if [:expr_end, :expr_endarg].include?(@lex_state)
670
672
  @lex_state = :expr_beg
671
673
  return '?', scanner.matched
672
674
  end
@@ -1,10 +1,33 @@
1
1
  require 'opal/lexer'
2
2
  require 'opal/grammar'
3
3
  require 'opal/target_scope'
4
+ require 'opal/version'
4
5
 
5
6
  module Opal
6
7
  class Parser
7
8
 
9
+ class Fragment
10
+
11
+ attr_reader :code
12
+
13
+ def initialize(code, sexp = nil)
14
+ @code = code
15
+ @sexp = sexp
16
+ end
17
+
18
+ def to_code
19
+ if @sexp
20
+ "/*:#{@sexp.line}*/#{@code}"
21
+ else
22
+ @code
23
+ end
24
+ end
25
+
26
+ def inspect
27
+ "fragment(#{@code.inspect})"
28
+ end
29
+ end
30
+
8
31
  # Generated code gets indented with two spaces on each scope
9
32
  INDENT = ' '
10
33
 
@@ -28,15 +51,10 @@ module Opal
28
51
  # Statements which should not have ';' added to them.
29
52
  STATEMENTS = [:xstr, :dxstr]
30
53
 
31
- # Holds an array of paths which this file "requires".
32
- # @return [Array<String>]
33
- attr_reader :requires
34
-
35
54
  attr_reader :result
36
55
 
37
56
  def parse(source, options = {})
38
57
  @sexp = Grammar.new.parse(source, options[:file])
39
- @requires = []
40
58
  @line = 1
41
59
  @indent = ''
42
60
  @unique = 0
@@ -47,14 +65,32 @@ module Opal
47
65
  }
48
66
 
49
67
  # options
50
- @file = options[:file] || '(file)'
51
- @method_missing = (options[:method_missing] != false)
52
- @optimized_operators = (options[:optimized_operators] != false)
53
- @arity_check = options[:arity_check]
54
- @const_missing = (options[:const_missing] != false)
55
- @dynamic_require_severity = (options[:dynamic_require_severity] || :error)
68
+ @file = options[:file] || '(file)'
69
+ @source_file = options[:source_file] || @file
70
+ @method_missing = (options[:method_missing] != false)
71
+ @optimized_operators = (options[:optimized_operators] != false)
72
+ @arity_check = options[:arity_check]
73
+ @const_missing = (options[:const_missing] != false)
74
+ @irb_vars = (options[:irb] == true)
75
+ @source_map = (options[:source_map_enabled] != false)
76
+
77
+ fragments = self.top(@sexp).flatten
56
78
 
57
- @result = top(@sexp)
79
+ code = @source_map ? fragments.map(&:to_code).join('') : fragments.map(&:code).join('')
80
+
81
+ @result = source_map_comment + version_comment + file_comment + code
82
+ end
83
+
84
+ def version_comment
85
+ "/* Generated by Opal #{Opal::VERSION} */\n"
86
+ end
87
+
88
+ def source_map_comment
89
+ @source_map ? "//@ sourceMappingURL=/__opal_source_maps__/#{@file}.js.map\n" : ''
90
+ end
91
+
92
+ def file_comment
93
+ @source_map ? "/*-file:#{@source_file}-*/" : ''
58
94
  end
59
95
 
60
96
  # This is called when a parsing/processing error occurs. This
@@ -101,6 +137,12 @@ module Opal
101
137
  sexp
102
138
  end
103
139
 
140
+ # @param [String] code the string of code
141
+ # @return [Fragment]
142
+ def fragment(code, sexp = nil)
143
+ Fragment.new(code, sexp)
144
+ end
145
+
104
146
  # Converts a ruby method name into its javascript equivalent for
105
147
  # a method/function call. All ruby method names get prefixed with
106
148
  # a '$', and if the name is a valid javascript identifier, it will
@@ -138,24 +180,35 @@ module Opal
138
180
  # @param [Array] sexp the sexp to process
139
181
  # @return [String]
140
182
  def top(sexp, options = {})
141
- code = nil
183
+ code, vars = nil, nil
184
+
185
+ # empty file = nil as our top sexp
186
+ sexp = s(:nil) unless sexp
142
187
 
143
188
  in_scope(:top) do
144
189
  indent {
145
- code = @indent + process(s(:scope, sexp), :stmt)
190
+ scope = s(:scope, sexp)
191
+ scope.line = sexp.line
192
+
193
+ code = process(scope, :stmt)
194
+ code.unshift fragment(@indent, sexp)
146
195
  }
147
196
 
148
197
  @scope.add_temp "self = __opal.top"
149
198
  @scope.add_temp "__scope = __opal"
150
- @scope.add_temp "nil = __opal.nil"
151
199
  @scope.add_temp "$mm = __opal.mm"
152
- @scope.add_temp "def = #{current_self}._klass.prototype" if @scope.defines_defn
200
+ @scope.add_temp "nil = __opal.nil"
201
+ @scope.add_temp "def = #{current_self}.constructor.prototype" if @scope.defines_defn
153
202
  @helpers.keys.each { |h| @scope.add_temp "__#{h} = __opal.#{h}" }
154
203
 
155
- code = INDENT + @scope.to_vars + "\n" + code
204
+ vars = [fragment(INDENT, sexp), @scope.to_vars, fragment("\n", sexp)]
205
+
206
+ if @irb_vars
207
+ code.unshift fragment("if (!Opal.irb_vars) { Opal.irb_vars = {}; }\n", sexp)
208
+ end
156
209
  end
157
210
 
158
- "(function(__opal) {\n#{ code }\n})(Opal);\n"
211
+ [fragment("(function(__opal) {\n", sexp), vars, code, fragment("\n})(Opal);\n", sexp)]
159
212
  end
160
213
 
161
214
  # Every time the parser enters a new scope, this is called with
@@ -271,7 +324,7 @@ module Opal
271
324
 
272
325
  @line = sexp.line
273
326
 
274
- __send__ meth, sexp, level
327
+ __send__(meth, sexp, level)
275
328
  end
276
329
 
277
330
  # The last sexps in method bodies, for example, need to be returned
@@ -371,21 +424,30 @@ module Opal
371
424
  result = []
372
425
  sexp << s(:nil) if sexp.empty?
373
426
 
427
+ join = (@scope.class_scope? ? "\n\n#@indent" : "\n#@indent")
428
+
374
429
  until sexp.empty?
375
430
  stmt = sexp.shift
376
- type = stmt.first
431
+
432
+ result << fragment(join, sexp) unless result.empty?
377
433
 
378
434
  # find any inline yield statements
379
435
  if yasgn = find_inline_yield(stmt)
380
- result << "#{process(yasgn, level)};"
436
+ result << process(yasgn, level)
437
+ result << fragment(";", yasgn)
381
438
  end
382
439
 
383
440
  expr = expression?(stmt) and LEVEL.index(level) < LEVEL.index(:list)
441
+
384
442
  code = process(stmt, level)
385
- result << (expr ? "#{code};" : code) unless code == ""
443
+
444
+ result << code
445
+ if expr
446
+ result << fragment(";", stmt)
447
+ end
386
448
  end
387
449
 
388
- result.join(@scope.class_scope? ? "\n\n#@indent" : "\n#@indent")
450
+ result
389
451
  end
390
452
 
391
453
  # When a block sexp gets generated, any inline yields (i.e. yield
@@ -440,28 +502,30 @@ module Opal
440
502
  def process_scope(sexp, level)
441
503
  stmt = sexp.shift
442
504
  if stmt
443
- stmt = returns stmt unless @scope.class_scope?
444
- code = process stmt, :stmt
505
+ unless @scope.class_scope?
506
+ stmt = returns stmt
507
+ end
508
+
509
+ process stmt, :stmt
445
510
  else
446
- code = "nil"
511
+ fragment("nil", sexp)
447
512
  end
448
-
449
- code
450
513
  end
451
514
 
452
515
  # s(:js_return, sexp)
453
516
  def process_js_return(sexp, level)
454
- "return #{process sexp.shift, :expr}"
517
+ [fragment("return ", sexp), process(sexp.shift, :expr)]
455
518
  end
456
519
 
457
520
  # s(:js_tmp, str)
458
521
  def process_js_tmp(sexp, level)
459
- sexp.shift.to_s
522
+ fragment(sexp.shift.to_s, sexp)
460
523
  end
461
524
 
462
525
  def process_operator(sexp, level)
463
526
  meth, recv, arg = sexp
464
527
  mid = mid_to_jsid meth.to_s
528
+ result = []
465
529
 
466
530
  if @optimized_operators
467
531
  with_temp do |a|
@@ -469,21 +533,27 @@ module Opal
469
533
  l = process recv, :expr
470
534
  r = process arg, :expr
471
535
 
472
- "(%s = %s, %s = %s, typeof(%s) === 'number' ? %s %s %s : %s%s(%s))" %
473
- [a, l, b, r, a, a, meth.to_s, b, a, mid, b]
536
+ result << fragment("(#{a} = ", sexp)
537
+ result << l
538
+ result << fragment(", #{b} = ", sexp)
539
+ result << r
540
+ result << fragment(", typeof(#{a}) === 'number' ? #{a} #{meth} #{b} ", sexp)
541
+ result << fragment(": #{a}#{mid}(#{b}))", sexp)
474
542
  end
475
543
  end
476
544
  else
477
545
  "#{process recv, :recv}#{mid}(#{process arg, :expr})"
478
546
  end
547
+
548
+ result
479
549
  end
480
550
 
481
551
  def js_block_given(sexp, level)
482
552
  @scope.uses_block!
483
553
  if @scope.block_name
484
- "(#{@scope.block_name} !== nil)"
554
+ fragment("(#{@scope.block_name} !== nil)", sexp)
485
555
  else
486
- "false"
556
+ fragment("false", sexp)
487
557
  end
488
558
  end
489
559
 
@@ -491,7 +561,7 @@ module Opal
491
561
  @scope.uses_block!
492
562
  name = @scope.block_name
493
563
 
494
- reverse ? "#{ name } === nil" : "#{ name } !== nil"
564
+ fragment((reverse ? "#{ name } === nil" : "#{ name } !== nil"), sexp)
495
565
  end
496
566
 
497
567
  # s(:lit, 1)
@@ -500,11 +570,15 @@ module Opal
500
570
  val = sexp.shift
501
571
  case val
502
572
  when Numeric
503
- level == :recv ? "(#{val.inspect})" : val.inspect
573
+ if level == :recv
574
+ fragment("(#{val.inspect})", sexp)
575
+ else
576
+ fragment(val.inspect, sexp)
577
+ end
504
578
  when Symbol
505
- val.to_s.inspect
579
+ fragment(val.to_s.inspect, sexp)
506
580
  when Regexp
507
- val == // ? /^/.inspect : val.inspect
581
+ fragment((val == // ? /^/.inspect : val.inspect), sexp)
508
582
  when Range
509
583
  @helpers[:range] = true
510
584
  "__range(#{val.begin}, #{val.end}, #{val.exclude_end?})"
@@ -514,31 +588,37 @@ module Opal
514
588
  end
515
589
 
516
590
  def process_dregx(sexp, level)
517
- parts = sexp.map do |part|
591
+ result = []
592
+
593
+ sexp.each do |part|
594
+ result << fragment(" + ", sexp) unless result.empty?
595
+
518
596
  if String === part
519
- part.inspect
597
+ result << fragment(part.inspect, sexp)
520
598
  elsif part[0] == :str
521
- process part, :expr
599
+ result << process(part, :expr)
522
600
  else
523
- process part[1], :expr
601
+ result << process(part[1], :expr)
524
602
  end
525
603
  end
526
604
 
527
- "(new RegExp(#{parts.join ' + '}))"
605
+ [fragment("(new RegExp(", sexp), result, fragment("))", sexp)]
528
606
  end
529
607
 
530
608
  def process_dot2(sexp, level)
531
609
  lhs = process sexp[0], :expr
532
610
  rhs = process sexp[1], :expr
533
611
  @helpers[:range] = true
534
- "__range(%s, %s, false)" % [lhs, rhs]
612
+
613
+ [fragment("__range(", sexp), lhs, fragment(", ", sexp), rhs, fragment(", false)", sexp)]
535
614
  end
536
615
 
537
616
  def process_dot3(sexp, level)
538
617
  lhs = process sexp[0], :expr
539
618
  rhs = process sexp[1], :expr
540
619
  @helpers[:range] = true
541
- "__range(%s, %s, true)" % [lhs, rhs]
620
+
621
+ [fragment("__range(", sexp), lhs, fragment(", ", sexp), rhs, fragment(", true)", sexp)]
542
622
  end
543
623
 
544
624
  # s(:str, "string")
@@ -546,9 +626,9 @@ module Opal
546
626
  str = sexp.shift
547
627
  if str == @file
548
628
  @uses_file = true
549
- @file.inspect
629
+ fragment(@file.inspect, sexp)
550
630
  else
551
- str.inspect
631
+ fragment(str.inspect, sexp)
552
632
  end
553
633
  end
554
634
 
@@ -556,28 +636,30 @@ module Opal
556
636
  part = sexp[0]
557
637
  case part[0]
558
638
  when :self
559
- "self".inspect
639
+ fragment("self".inspect, sexp)
560
640
  when :nil
561
- "nil".inspect
641
+ fragment("nil".inspect, sexp)
562
642
  when :true
563
- "true".inspect
643
+ fragment("true".inspect, sexp)
564
644
  when :false
565
- "false".inspect
645
+ fragment("false".inspect, sexp)
566
646
  when :call
567
647
  mid = mid_to_jsid part[2].to_s
568
- recv = part[1] ? process(part[1], :expr) : current_self
569
- "(#{recv}#{mid} ? 'method' : nil)"
648
+ recv = part[1] ? process(part[1], :expr) : fragment(current_self, sexp)
649
+ [fragment("(", sexp), recv, fragment("#{mid} ? 'method' : nil)", sexp)]
570
650
  when :xstr
571
- "(typeof(#{process part, :expression}) !== 'undefined')"
651
+ [fragment("(typeof(", sexp), process(part, :expr), fragment(") !== 'undefined')", sexp)]
572
652
  when :const
573
- "(__scope.#{part[1].to_s} != null)"
653
+ fragment("(__scope.#{part[1].to_s} != null)", sexp)
574
654
  when :colon2
575
- "false"
655
+ fragment("false", sexp)
576
656
  when :ivar
577
657
  ivar_name = part[1].to_s[1..-1]
578
658
  with_temp do |t|
579
- "((#{t} = #{current_self}[#{ivar_name.inspect}], #{t} != null && #{t} !== nil) ? 'instance-variable' : nil)"
659
+ fragment("((#{t} = #{current_self}[#{ivar_name.inspect}], #{t} != null && #{t} !== nil) ? 'instance-variable' : nil)", sexp)
580
660
  end
661
+ when :lvar
662
+ fragment("local-variable", sexp)
581
663
  else
582
664
  raise "bad defined? part: #{part[0]}"
583
665
  end
@@ -586,7 +668,8 @@ module Opal
586
668
  # s(:not, sexp)
587
669
  def process_not(sexp, level)
588
670
  with_temp do |tmp|
589
- "(#{tmp} = #{process(sexp.shift, :expr)}, (#{tmp} === nil || #{tmp} === false))"
671
+ expr = sexp.shift
672
+ [fragment("(#{tmp} = ", sexp), process(expr, :expr), fragment(", (#{tmp} === nil || #{tmp} === false))", sexp)]
590
673
  end
591
674
  end
592
675
 
@@ -600,10 +683,11 @@ module Opal
600
683
 
601
684
  body ||= s(:nil)
602
685
  body = returns body
603
- code = ""
686
+ code = []
604
687
  params = nil
605
688
  scope_name = nil
606
689
  identity = nil
690
+ to_vars = nil
607
691
 
608
692
  args = nil if Fixnum === args # argh
609
693
  args ||= s(:masgn, s(:array))
@@ -623,20 +707,20 @@ module Opal
623
707
  indent do
624
708
  in_scope(:iter) do
625
709
  identity = @scope.identify!
626
- @scope.add_temp "self = #{identity}._s || this"
710
+ @scope.add_temp "#{current_self} = #{identity}._s || this"
627
711
 
628
712
  args[1..-1].each do |arg|
629
- arg = arg[1]
630
- arg = "#{arg}$" if RESERVED.include? arg.to_s
631
- code += "if (#{arg} == null) #{arg} = nil;\n"
713
+ arg = arg[1]
714
+ arg = "#{arg}$" if RESERVED.include? arg.to_s
715
+ code << fragment("if (#{arg} == null) #{arg} = nil;\n", sexp)
632
716
  end
633
717
 
634
718
  params = js_block_args(args[1..-1])
635
- # params.unshift '_$'
636
719
 
637
720
  if splat
721
+ @scope.add_arg splat
638
722
  params << splat
639
- code += "#{splat} = __slice.call(arguments, #{len - 1});"
723
+ code << fragment("#{splat} = __slice.call(arguments, #{len - 1});", sexp)
640
724
  end
641
725
 
642
726
  if block_arg
@@ -644,25 +728,30 @@ module Opal
644
728
  @scope.add_temp block_arg
645
729
  @scope.add_temp '__context'
646
730
  scope_name = @scope.identify!
647
- blk = "\n%s%s = %s._p || nil, __context = %s._s, %s.p = null;\n%s" %
648
- [@indent, block_arg, scope_name, block_arg, scope_name, @indent]
649
731
 
650
- code = blk + code
732
+ blk = []
733
+ blk << fragment("\n#@indent#{block_arg} = #{scope_name}._p || nil, #{scope_name}.p = null;\n#@indent", sexp)
734
+
735
+ code.unshift blk
651
736
  end
652
737
 
653
- code += "\n#@indent" + process(body, :stmt)
738
+ code << fragment("\n#@indent", sexp)
739
+ code << process(body, :stmt)
654
740
 
655
741
  if @scope.defines_defn
656
742
  @scope.add_temp "def = ((typeof(#{current_self}) === 'function') ? #{current_self}.prototype : #{current_self})"
657
743
  end
658
744
 
659
- code = "\n#@indent#{@scope.to_vars}\n#@indent#{code}"
745
+ to_vars = [fragment("\n#@indent", sexp), @scope.to_vars, fragment("\n#@indent", sexp)]
660
746
  end
661
747
  end
662
748
 
663
- itercode = "function(#{params.join ', '}) {\n#{code}\n#@indent}"
664
- call << ("(%s = %s, %s._s = %s, %s)" % [identity, itercode, identity, current_self, identity])
749
+ itercode = [fragment("function(#{params.join ', '}) {\n", sexp), to_vars, code, fragment("\n#@indent}", sexp)]
665
750
 
751
+ itercode.unshift fragment("(#{identity} = ", sexp)
752
+ itercode << fragment(", #{identity}._s = #{current_self}, #{identity})", sexp)
753
+
754
+ call << itercode
666
755
  process call, level
667
756
  end
668
757
 
@@ -701,29 +790,22 @@ module Opal
701
790
  attrs.each do |attr|
702
791
  mid = attr[1]
703
792
  ivar = "@#{mid}".to_sym
704
- pre = @scope.proto
705
793
 
706
794
  unless meth == :attr_writer
795
+ out << fragment(", \n#@indent") unless out.empty?
707
796
  out << process(s(:defn, mid, s(:args), s(:scope, s(:ivar, ivar))), :stmt)
708
797
  end
709
798
 
710
799
  unless meth == :attr_reader
800
+ out << fragment(", \n#@indent") unless out.empty?
711
801
  mid = "#{mid}=".to_sym
712
802
  out << process(s(:defn, mid, s(:args, :val), s(:scope,
713
803
  s(:iasgn, ivar, s(:lvar, :val)))), :stmt)
714
804
  end
715
805
  end
716
806
 
717
- out.join(", \n#@indent") + ', nil'
718
- end
719
-
720
- def handle_alias_native(sexp)
721
- args = sexp[2]
722
- meth = mid_to_jsid args[1][1].to_s
723
- func = args[2][1]
724
-
725
- @scope.methods << meth
726
- "%s%s = %s.%s" % [@scope.proto, meth, @scope.proto, func]
807
+ out << fragment(", nil")
808
+ out
727
809
  end
728
810
 
729
811
  # s(:call, recv, :mid, s(:arglist))
@@ -732,21 +814,27 @@ module Opal
732
814
  recv, meth, arglist, iter = sexp
733
815
  mid = mid_to_jsid meth.to_s
734
816
 
817
+ # we are trying to access a lvar in irb mode
818
+ if @irb_vars and @scope.top? and arglist == s(:arglist) and recv == nil
819
+ return with_temp { |t|
820
+ lvar = meth.intern
821
+ lvar = "#{lvar}$" if RESERVED.include? lvar
822
+ call = s(:call, s(:self), meth.intern, s(:arglist))
823
+ [fragment("((#{t} = Opal.irb_vars.#{lvar}) == null ? ", sexp), process(call, :expr), fragment(" : #{t})", sexp)]
824
+ }
825
+ end
826
+
735
827
  case meth
736
828
  when :attr_reader, :attr_writer, :attr_accessor
737
829
  return handle_attr_optimize(meth, arglist[1..-1]) if @scope.class_scope?
738
830
  when :block_given?
739
831
  return js_block_given(sexp, level)
740
- when :alias_native
741
- return handle_alias_native(sexp) if @scope.class_scope?
742
- when :require
743
- return handle_require arglist[1]
744
832
  end
745
833
 
746
834
  splat = arglist[1..-1].any? { |a| a.first == :splat }
747
835
 
748
836
  if Array === arglist.last and arglist.last.first == :block_pass
749
- block = process s(:js_tmp, process(arglist.pop, :expr)), :expr
837
+ block = process(arglist.pop, :expr)
750
838
  elsif iter
751
839
  block = iter
752
840
  end
@@ -767,17 +855,29 @@ module Opal
767
855
  arglist.insert 1, call_recv unless splat
768
856
  args = process arglist, :expr
769
857
 
770
- dispatch = "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{ meth.to_s }'))"
858
+ dispatch = "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{meth.to_s}'))"
859
+ dispatch = [fragment("((#{tmprecv} = ", sexp), recv_code, fragment(")#{mid} || $mm('#{meth.to_s}'))", sexp)]
771
860
 
772
861
  if tmpfunc
773
- dispatch = "(#{tmpfunc} = #{dispatch}, #{tmpfunc}._p = #{block}, #{tmpfunc})"
862
+ dispatch.unshift fragment("(#{tmpfunc} = ", sexp)
863
+ dispatch << fragment(", #{tmpfunc}._p = ", sexp)
864
+ dispatch << block
865
+ dispatch << fragment(", #{tmpfunc})", sexp)
774
866
  end
775
867
 
776
- result = if splat
777
- "#{dispatch}.apply(#{process call_recv, :expr}, #{args})"
868
+ if splat
869
+ dispatch << fragment(".apply(", sexp)
870
+ dispatch << process(call_recv, :expr)
871
+ dispatch << fragment(", ", sexp)
872
+ dispatch << args
873
+ dispatch << fragment(")", sexp)
778
874
  else
779
- "#{dispatch}.call(#{args})"
875
+ dispatch << fragment(".call(", sexp)
876
+ dispatch.push(*args)
877
+ dispatch << fragment(")", sexp)
780
878
  end
879
+
880
+ result = dispatch
781
881
  else
782
882
  args = process arglist, :expr
783
883
  dispatch = tmprecv ? "(#{tmprecv} = #{recv_code})#{mid}" : "#{recv_code}#{mid}"
@@ -788,86 +888,50 @@ module Opal
788
888
  result
789
889
  end
790
890
 
791
- def handle_require(sexp)
792
- str = handle_require_sexp sexp
793
- @requires << str unless str.nil?
794
- ""
795
- end
796
-
797
- def handle_require_sexp(sexp)
798
- type = sexp.shift
799
-
800
- if type == :str
801
- return sexp[0]
802
- elsif type == :call
803
- recv, meth, args = sexp
804
- parts = args[1..-1].map { |s| handle_require_sexp s }
805
-
806
- if recv == [:const, :File]
807
- if meth == :expand_path
808
- return handle_expand_path(*parts)
809
- elsif meth == :join
810
- return handle_expand_path parts.join("/")
811
- elsif meth == :dirname
812
- return handle_expand_path parts[0].split("/")[0...-1].join("/")
813
- end
814
- end
815
- end
816
-
817
-
818
- case @dynamic_require_severity
819
- when :error
820
- error "Cannot handle dynamic require"
821
- when :warning
822
- warning "Cannot handle dynamic require"
823
- end
824
- end
825
-
826
- def handle_expand_path(path, base = '')
827
- "#{base}/#{path}".split("/").inject([]) do |path, part|
828
- if part == ''
829
- # we had '//', so ignore
830
- elsif part == '..'
831
- path.pop
832
- else
833
- path << part
834
- end
835
-
836
- path
837
- end.join "/"
838
- end
839
-
840
891
  # s(:arglist, [arg [, arg ..]])
841
892
  def process_arglist(sexp, level)
842
- code = ''
893
+ code = []
843
894
  work = []
844
895
 
845
896
  until sexp.empty?
846
- splat = sexp.first.first == :splat
847
- arg = process sexp.shift, :expr
897
+ current = sexp.shift
898
+ splat = current.first == :splat
899
+ arg = process current, :expr
848
900
 
849
901
  if splat
850
902
  if work.empty?
851
903
  if code.empty?
852
- code += "[].concat(#{arg})"
904
+ code << fragment("[].concat(", sexp)
905
+ code << arg
906
+ code << fragment(")", sexp)
853
907
  else
854
908
  code += ".concat(#{arg})"
855
909
  end
856
910
  else
857
- join = "[#{work.join ', '}]"
858
- code += (code.empty? ? join : ".concat(#{join})")
859
- code += ".concat(#{arg})"
911
+ if code.empty?
912
+ code << [fragment("[", sexp), work, fragment("]", sexp)]
913
+ else
914
+ code << [fragment(".concat([", sexp), work, fragment("])", sexp)]
915
+ end
916
+
917
+ code << [fragment(".concat(", sexp), arg, fragment(")", sexp)]
860
918
  end
861
919
 
862
920
  work = []
863
921
  else
864
- work.push arg
922
+ work << fragment(", ", current) unless work.empty?
923
+ work.push(*arg)
865
924
  end
866
925
  end
867
926
 
868
927
  unless work.empty?
869
- join = work.join ', '
870
- code += (code.empty? ? join : ".concat([#{join}])")
928
+ join = work
929
+
930
+ if code.empty?
931
+ code = join
932
+ else
933
+ code << fragment(".concat(", sexp) << join << fragment(")", sexp)
934
+ end
871
935
  end
872
936
 
873
937
  code
@@ -875,9 +939,13 @@ module Opal
875
939
 
876
940
  # s(:splat, sexp)
877
941
  def process_splat(sexp, level)
878
- return "[]" if sexp.first == [:nil]
879
- return "[#{process sexp.first, :expr}]" if sexp.first.first == :lit
880
- process sexp.first, :recv
942
+ if sexp.first == [:nil]
943
+ [fragment("[]", sexp)]
944
+ elsif sexp.first.first == :lit
945
+ [fragment("[", sexp), process(sexp.first, :expr), fragment("]", sexp)]
946
+ else
947
+ process sexp.first, :recv
948
+ end
881
949
  end
882
950
 
883
951
  # s(:class, cid, super, body)
@@ -886,23 +954,23 @@ module Opal
886
954
 
887
955
  body[1] = s(:nil) unless body[1]
888
956
 
889
- code = nil
957
+ code = []
890
958
  @helpers[:klass] = true
891
959
 
892
960
  if Symbol === cid or String === cid
893
- base = current_self
961
+ base = process(s(:self), :expr)
894
962
  name = cid.to_s
895
963
  elsif cid[0] == :colon2
896
964
  base = process(cid[1], :expr)
897
965
  name = cid[2].to_s
898
966
  elsif cid[0] == :colon3
899
- base = 'Opal.Object'
967
+ base = process(s(:js_tmp, 'Opal.Object'), :expr)
900
968
  name = cid[1].to_s
901
969
  else
902
970
  raise "Bad receiver in class"
903
971
  end
904
972
 
905
- sup = sup ? process(sup, :expr) : 'null'
973
+ sup = sup ? process(sup, :expr) : process(s(:js_tmp, 'null'), :expr)
906
974
 
907
975
  indent do
908
976
  in_scope(:class) do
@@ -925,8 +993,13 @@ module Opal
925
993
 
926
994
  body = returns(body)
927
995
  body = process body, :stmt
928
- code = "\n#{@scope.to_donate_methods}"
929
- code += @indent + @scope.to_vars + "\n\n#@indent" + body
996
+ code << fragment("\n", sexp)
997
+ code << @scope.to_donate_methods
998
+
999
+ code << fragment(@indent, sexp)
1000
+ code << @scope.to_vars
1001
+ code << fragment("\n\n#@indent", sexp)
1002
+ code << body
930
1003
  end
931
1004
  end
932
1005
 
@@ -934,43 +1007,46 @@ module Opal
934
1007
  cls = "function #{name}() {};"
935
1008
  boot = "#{name} = __klass(__base, __super, #{name.inspect}, #{name});"
936
1009
 
937
- "(function(__base, __super){#{spacer}#{cls}#{spacer}#{boot}\n#{code}\n#{@indent}})(#{base}, #{sup})"
1010
+ [fragment("(function(__base, __super){#{spacer}#{cls}#{spacer}#{boot}\n", sexp),
1011
+ code, fragment("\n#@indent})", sexp), fragment("(", sexp), base, fragment(", ", sexp), sup, fragment(")", sexp)]
938
1012
  end
939
1013
 
940
1014
  # s(:sclass, recv, body)
941
1015
  def process_sclass(sexp, level)
942
1016
  recv = sexp[0]
943
1017
  body = sexp[1]
944
- code = nil
1018
+ code = []
945
1019
 
946
1020
  in_scope(:sclass) do
947
1021
  @scope.add_temp "__scope = #{current_self}._scope"
948
1022
  @scope.add_temp "def = #{current_self}.prototype"
949
1023
 
950
1024
  body = process body, :stmt
951
- code = @scope.to_vars + body
1025
+ code << @scope.to_vars << body
952
1026
  end
953
1027
 
954
- call = s(:call, recv, :singleton_class, s(:arglist))
955
-
956
- "(function(){#{ code }}).call(#{ process call, :expr })"
1028
+ result = []
1029
+ result << fragment("(function(){", sexp) << code
1030
+ result << fragment("}).call(__opal.singleton(", sexp)
1031
+ result << process(recv, :expr) << fragment("))", sexp)
1032
+ result
957
1033
  end
958
1034
 
959
1035
  # s(:module, cid, body)
960
1036
  def process_module(sexp, level)
961
1037
  cid = sexp[0]
962
1038
  body = sexp[1]
963
- code = nil
1039
+ code = []
964
1040
  @helpers[:module] = true
965
1041
 
966
1042
  if Symbol === cid or String === cid
967
- base = current_self
1043
+ base = process(s(:self), :expr)
968
1044
  name = cid.to_s
969
1045
  elsif cid[0] == :colon2
970
1046
  base = process(cid[1], :expr)
971
1047
  name = cid[2].to_s
972
1048
  elsif cid[0] == :colon3
973
- base = 'Opal.Object'
1049
+ base = fragment('Opal.Object', sexp)
974
1050
  name = cid[1].to_s
975
1051
  else
976
1052
  raise "Bad receiver in class"
@@ -981,7 +1057,13 @@ module Opal
981
1057
  @scope.name = name
982
1058
  @scope.add_temp "#{ @scope.proto } = #{name}.prototype", "__scope = #{name}._scope"
983
1059
  body = process body, :stmt
984
- code = @indent + @scope.to_vars + "\n\n#@indent" + body + "\n#@indent" + @scope.to_donate_methods
1060
+
1061
+ code << fragment(@indent, sexp)
1062
+ code.push(*@scope.to_vars)
1063
+ code << fragment("\n\n#@indent", sexp)
1064
+ code.push(*body)
1065
+ code << fragment("\n#@ident", sexp)
1066
+ code.push(*@scope.to_donate_methods)
985
1067
  end
986
1068
  end
987
1069
 
@@ -989,31 +1071,35 @@ module Opal
989
1071
  cls = "function #{name}() {};"
990
1072
  boot = "#{name} = __module(__base, #{name.inspect}, #{name});"
991
1073
 
992
- "(function(__base){#{spacer}#{cls}#{spacer}#{boot}\n#{code}\n#{@indent}})(#{base})"
993
- end
1074
+ code.unshift fragment("(function(__base){#{spacer}#{cls}#{spacer}#{boot}\n", sexp)
1075
+ code << fragment("\n#@indent})(", sexp)
1076
+ code.push(*base)
1077
+ code << fragment(")", sexp)
994
1078
 
1079
+ code
1080
+ end
995
1081
 
996
1082
  # undef :foo
997
1083
  # => delete MyClass.prototype.$foo
998
1084
  def process_undef(sexp, level)
999
- "delete #{ @scope.proto }#{ mid_to_jsid sexp[0][1].to_s }"
1085
+ fragment("delete #{ @scope.proto }#{ mid_to_jsid sexp[0][1].to_s }", sexp)
1000
1086
  end
1001
1087
 
1002
1088
  # s(:defn, mid, s(:args), s(:scope))
1003
1089
  def process_defn(sexp, level)
1004
1090
  mid, args, stmts = sexp
1005
1091
 
1006
- js_def nil, mid, args, stmts, sexp.line, sexp.end_line
1092
+ js_def nil, mid, args, stmts, sexp.line, sexp.end_line, sexp
1007
1093
  end
1008
1094
 
1009
1095
  # s(:defs, recv, mid, s(:args), s(:scope))
1010
1096
  def process_defs(sexp, level)
1011
1097
  recv, mid, args, stmts = sexp
1012
1098
 
1013
- js_def recv, mid, args, stmts, sexp.line, sexp.end_line
1099
+ js_def recv, mid, args, stmts, sexp.line, sexp.end_line, sexp
1014
1100
  end
1015
1101
 
1016
- def js_def(recvr, mid, args, stmts, line, end_line)
1102
+ def js_def(recvr, mid, args, stmts, line, end_line, sexp)
1017
1103
  jsid = mid_to_jsid mid.to_s
1018
1104
 
1019
1105
  if recvr
@@ -1025,7 +1111,7 @@ module Opal
1025
1111
  recv = current_self
1026
1112
  end
1027
1113
 
1028
- code = ''
1114
+ code = []
1029
1115
  params = nil
1030
1116
  scope_name = nil
1031
1117
  uses_super = nil
@@ -1071,58 +1157,62 @@ module Opal
1071
1157
  @scope.block_name = yielder
1072
1158
 
1073
1159
  params = process args, :expr
1074
- stmt_code = "\n#@indent" + process(stmts, :stmt)
1160
+ stmt_code = [fragment("\n#@indent", stmts), *process(stmts, :stmt)]
1075
1161
 
1076
1162
  opt[1..-1].each do |o|
1077
1163
  next if o[2][2] == :undefined
1078
- id = process s(:lvar, o[1]), :expr
1079
- code += ("if (%s == null) {\n%s%s\n%s}" %
1080
- [id, @indent + INDENT, process(o, :expre), @indent])
1164
+ code << fragment("if (#{o[1]} == null) {\n#{@indent + INDENT}", o)
1165
+ code << process(o, :expr)
1166
+ code << fragment("\n#{@indent}}", o)
1081
1167
  end if opt
1082
1168
 
1083
- code += "#{splat} = __slice.call(arguments, #{argc});" if splat
1169
+ code << fragment("#{splat} = __slice.call(arguments, #{argc});", sexp) if splat
1084
1170
 
1085
1171
  scope_name = @scope.identity
1086
1172
 
1087
1173
  if @scope.uses_block?
1088
1174
  @scope.add_temp yielder
1089
- blk = "\n%s%s = %s._p || nil, %s._p = null;\n%s" % [@indent, yielder, scope_name, scope_name, @indent]
1175
+ blk = fragment(("\n%s%s = %s._p || nil, %s._p = null;\n%s" %
1176
+ [@indent, yielder, scope_name, scope_name, @indent]), sexp)
1090
1177
  end
1091
1178
 
1092
- code += stmt_code
1093
- code = "#{blk}#{code}"
1179
+ code.push(*stmt_code)
1180
+ code.unshift blk if blk
1094
1181
 
1095
1182
  uses_super = @scope.uses_super
1096
1183
 
1097
- code = "#{arity_code}#@indent#{@scope.to_vars}" + code
1184
+ code = [fragment("#{arity_code}#@indent", sexp), @scope.to_vars, code]
1098
1185
  end
1099
1186
  end
1100
1187
 
1101
- defcode = "#{"#{scope_name} = " if scope_name}function(#{params}) {\n#{code}\n#@indent}"
1188
+ result = [fragment("#{"#{scope_name} = " if scope_name}function(", sexp)]
1189
+ result.push(*params)
1190
+ result << fragment(") {\n", sexp)
1191
+ result.push(*code)
1192
+ result << fragment("\n#@indent}", sexp)
1102
1193
 
1103
1194
  if recvr
1104
1195
  if smethod
1105
- "__opal.defs(#{@scope.name}, '$#{mid}', #{defcode})"
1196
+ [fragment("__opal.defs(#{@scope.name}, '$#{mid}', ", sexp), result, fragment(")", sexp)]
1106
1197
  else
1107
- "#{ recv }#{ jsid } = #{ defcode }"
1198
+ [recv, fragment("#{jsid} = ", sexp), result]
1108
1199
  end
1109
1200
  elsif @scope.class? and @scope.name == 'Object'
1110
- "#{current_self}._defn('$#{mid}', #{defcode})"
1201
+ [fragment("#{current_self}._defn('$#{mid}', ", sexp), result, fragment(")", sexp)]
1111
1202
  elsif @scope.class_scope?
1112
1203
  @scope.methods << "$#{mid}"
1113
1204
  if uses_super
1114
1205
  @scope.add_temp uses_super
1115
1206
  uses_super = "#{uses_super} = #{@scope.proto}#{jsid};\n#@indent"
1116
1207
  end
1117
- "#{uses_super}#{ @scope.proto }#{jsid} = #{defcode}"
1118
- # elsif @scope.sclass?
1119
- # "#{ current_self }._defs('$#{mid}', #{defcode})"
1208
+
1209
+ [fragment("#{uses_super}#{@scope.proto}#{jsid} = ", sexp), result]
1120
1210
  elsif @scope.type == :iter
1121
- "def#{jsid} = #{defcode}"
1211
+ [fragment("def#{jsid} = ", sexp), result]
1122
1212
  elsif @scope.type == :top
1123
- "#{ current_self }#{ jsid } = #{ defcode }"
1213
+ [fragment("#{ current_self }#{ jsid } = ", sexp), *result]
1124
1214
  else
1125
- "def#{jsid} = #{defcode}"
1215
+ [fragment("def#{jsid} = ", sexp), result]
1126
1216
  end
1127
1217
  end
1128
1218
 
@@ -1157,12 +1247,12 @@ module Opal
1157
1247
  args << a
1158
1248
  end
1159
1249
 
1160
- args.join ', '
1250
+ [fragment(args.join(', '), exp)]
1161
1251
  end
1162
1252
 
1163
1253
  # s(:self) # => this
1164
1254
  def process_self(sexp, level)
1165
- current_self
1255
+ fragment(current_self, sexp)
1166
1256
  end
1167
1257
 
1168
1258
  # Returns the current value for 'self'. This will be native
@@ -1178,43 +1268,61 @@ module Opal
1178
1268
  end
1179
1269
  end
1180
1270
 
1181
- # s(:true) # => true
1182
- # s(:false) # => false
1183
- # s(:nil) # => nil
1184
- %w(true false nil).each do |name|
1185
- define_method "process_#{name}" do |exp, level|
1186
- name
1187
- end
1271
+ def process_true(sexp, level)
1272
+ fragment("true", sexp)
1273
+ end
1274
+
1275
+ def process_false(sexp, level)
1276
+ fragment("false", sexp)
1277
+ end
1278
+
1279
+ def process_nil(sexp, level)
1280
+ fragment("nil", sexp)
1188
1281
  end
1189
1282
 
1190
1283
  # s(:array [, sexp [, sexp]])
1191
1284
  def process_array(sexp, level)
1192
- return '[]' if sexp.empty?
1285
+ return [fragment("[]", sexp)] if sexp.empty?
1193
1286
 
1194
- code = ''
1287
+ code = []
1195
1288
  work = []
1196
1289
 
1197
1290
  until sexp.empty?
1198
- splat = sexp.first.first == :splat
1199
- part = process sexp.shift, :expr
1291
+ current = sexp.shift
1292
+ splat = current.first == :splat
1293
+ part = process current, :expr
1200
1294
 
1201
1295
  if splat
1202
1296
  if work.empty?
1203
- code += (code.empty? ? part : ".concat(#{part})")
1297
+ if code.empty?
1298
+ code << fragment("[].concat(", sexp) << part << fragment(")", sexp)
1299
+ else
1300
+ code << fragment(".concat(", sexp) << part << fragment(")", sexp)
1301
+ end
1204
1302
  else
1205
- join = "[#{work.join ', '}]"
1206
- code += (code.empty? ? join : ".concat(#{join})")
1207
- code += ".concat(#{part})"
1303
+ if code.empty?
1304
+ code << fragment("[", sexp) << work << fragment("]", sexp)
1305
+ else
1306
+ code << fragment(".concat([", sexp) << work << fragment("])", sexp)
1307
+ end
1308
+
1309
+ code << fragment(".concat(", sexp) << part << fragment(")", sexp)
1208
1310
  end
1209
1311
  work = []
1210
1312
  else
1313
+ work << fragment(", ", current) unless work.empty?
1211
1314
  work << part
1212
1315
  end
1213
1316
  end
1214
1317
 
1215
1318
  unless work.empty?
1216
- join = "[#{work.join ', '}]"
1217
- code += (code.empty? ? join : ".concat(#{join})")
1319
+ join = [fragment("[", sexp), work, fragment("]", sexp)]
1320
+
1321
+ if code.empty?
1322
+ code = join
1323
+ else
1324
+ code.push([fragment(".concat(", sexp), join, fragment(")", sexp)])
1325
+ end
1218
1326
  end
1219
1327
 
1220
1328
  code
@@ -1237,18 +1345,31 @@ module Opal
1237
1345
  hash_obj = {}
1238
1346
  hash_keys = []
1239
1347
  keys.size.times do |i|
1240
- k = process(keys[i], :expr)
1348
+ k = keys[i][1].to_s.inspect
1241
1349
  hash_keys << k unless hash_obj.include? k
1242
1350
  hash_obj[k] = process(vals[i], :expr)
1243
1351
  end
1244
1352
 
1245
- map = hash_keys.map { |k| "#{k}: #{hash_obj[k]}"}
1246
-
1353
+ result = []
1247
1354
  @helpers[:hash2] = true
1248
- "__hash2([#{hash_keys.join ', '}], {#{map.join(', ')}})"
1355
+
1356
+ hash_keys.each do |k|
1357
+ result << fragment(", ", sexp) unless result.empty?
1358
+ result << fragment("#{k}: ", sexp)
1359
+ result << hash_obj[k]
1360
+ end
1361
+
1362
+ [fragment("__hash2([#{hash_keys.join ', '}], {", sexp), result, fragment("})", sexp)]
1249
1363
  else
1250
1364
  @helpers[:hash] = true
1251
- "__hash(#{sexp.map { |p| process p, :expr }.join ', '})"
1365
+ result = []
1366
+
1367
+ sexp.each do |p|
1368
+ result << fragment(", ", p) unless result.empty?
1369
+ result << process(p, :expr)
1370
+ end
1371
+
1372
+ [fragment("__hash(", sexp), result, fragment(")", sexp)]
1252
1373
  end
1253
1374
  end
1254
1375
 
@@ -1256,14 +1377,16 @@ module Opal
1256
1377
  def process_while(sexp, level)
1257
1378
  expr, stmt = sexp
1258
1379
  redo_var = @scope.new_temp
1380
+ code = []
1259
1381
 
1260
1382
  stmt_level = if level == :expr or level == :recv
1261
1383
  :stmt_closure
1262
1384
  else
1263
1385
  :stmt
1264
1386
  end
1387
+
1388
+ code << js_truthy(expr) << fragment("){", sexp)
1265
1389
  pre = "while ("
1266
- code = "#{js_truthy expr}){"
1267
1390
 
1268
1391
  in_while do
1269
1392
  @while_loop[:closure] = true if stmt_level == :stmt_closure
@@ -1272,18 +1395,19 @@ module Opal
1272
1395
 
1273
1396
  if @while_loop[:use_redo]
1274
1397
  pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
1275
- code += "#{redo_var}=false;"
1398
+ code << fragment("#{redo_var}=false;", sexp)
1276
1399
  end
1277
1400
 
1278
- code += body
1401
+ code << body
1279
1402
  end
1280
1403
 
1281
- code += "}"
1282
- code = pre + code
1404
+ code << fragment("}", sexp)
1405
+ code.unshift fragment(pre, sexp)
1283
1406
  @scope.queue_temp redo_var
1284
1407
 
1285
1408
  if stmt_level == :stmt_closure
1286
- code = "(function() {#{code}; return nil;}).call(#{current_self})"
1409
+ code.unshift fragment("(function() {", sexp)
1410
+ code.push fragment("; return nil; }).call(#{current_self})", sexp)
1287
1411
  end
1288
1412
 
1289
1413
  code
@@ -1298,8 +1422,10 @@ module Opal
1298
1422
  else
1299
1423
  :stmt
1300
1424
  end
1425
+
1426
+ code = []
1301
1427
  pre = "while (!("
1302
- code = "#{js_truthy expr})) {"
1428
+ code << js_truthy(expr) << fragment(")) {", exp)
1303
1429
 
1304
1430
  in_while do
1305
1431
  @while_loop[:closure] = true if stmt_level == :stmt_closure
@@ -1308,18 +1434,19 @@ module Opal
1308
1434
 
1309
1435
  if @while_loop[:use_redo]
1310
1436
  pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
1311
- code += "#{redo_var}=false;"
1437
+ code << fragment("#{redo_var}=false;", exp)
1312
1438
  end
1313
1439
 
1314
- code += body
1440
+ code << body
1315
1441
  end
1316
1442
 
1317
- code += "}"
1318
- code = pre + code
1443
+ code << fragment("}", exp)
1444
+ code.unshift fragment(pre, exp)
1319
1445
  @scope.queue_temp redo_var
1320
1446
 
1321
1447
  if stmt_level == :stmt_closure
1322
- code = "(function() {#{code}; return nil;}).call(#{current_self})"
1448
+ code.unshift fragment("(function() {", exp)
1449
+ code << fragment("; return nil; }).call(#{current_self})", exp)
1323
1450
  end
1324
1451
 
1325
1452
  code
@@ -1334,10 +1461,10 @@ module Opal
1334
1461
 
1335
1462
  if [:class, :module].include? @scope.type
1336
1463
  @scope.methods << "$#{exp[0][1].to_s}"
1337
- "%s%s = %s%s" % [@scope.proto, new, @scope.proto, old]
1464
+ fragment("%s%s = %s%s" % [@scope.proto, new, @scope.proto, old], exp)
1338
1465
  else
1339
1466
  current = current_self
1340
- "%s.prototype%s = %s.prototype%s" % [current, new, current, old]
1467
+ fragment("%s.prototype%s = %s.prototype%s" % [current, new, current, old], exp)
1341
1468
  end
1342
1469
  end
1343
1470
 
@@ -1346,21 +1473,25 @@ module Opal
1346
1473
  rhs = sexp[1]
1347
1474
  tmp = @scope.new_temp
1348
1475
  len = 0
1476
+ code = []
1349
1477
 
1350
1478
  # remote :array part
1351
1479
  lhs.shift
1352
1480
  if rhs[0] == :array
1353
1481
  len = rhs.length - 1 # we are guaranteed an array of this length
1354
- code = ["#{tmp} = #{process rhs, :expr}"]
1482
+ code << fragment("#{tmp} = ", sexp) << process(rhs, :expr)
1355
1483
  elsif rhs[0] == :to_ary
1356
- code = ["((#{tmp} = #{process rhs[1], :expr})._isArray ? #{tmp} : (#{tmp} = [#{tmp}]))"]
1484
+ code << fragment("((#{tmp} = ", sexp) << process(rhs[1], :expr)
1485
+ code << fragment(")._isArray ? #{tmp} : (#{tmp} = [#{tmp}]))", sexp)
1357
1486
  elsif rhs[0] == :splat
1358
- code = ["(#{tmp} = #{process(rhs[1], :expr)})['$to_a'] ? (#{tmp} = #{tmp}['$to_a']()) : (#{tmp})._isArray ? #{tmp} : (#{tmp} = [#{tmp}])"]
1487
+ code << fragment("(#{tmp} = ", sexp) << process(rhs[1], :expr)
1488
+ code << fragment(")['$to_a'] ? (#{tmp} = #{tmp}['$to_a']()) : (#{tmp})._isArray ? #{tmp} : (#{tmp} = [#{tmp}])", sexp)
1359
1489
  else
1360
1490
  raise "Unsupported mlhs type"
1361
1491
  end
1362
1492
 
1363
1493
  lhs.each_with_index do |l, idx|
1494
+ code << fragment(", ", sexp) unless code.empty?
1364
1495
 
1365
1496
  if l.first == :splat
1366
1497
  s = l[1]
@@ -1377,7 +1508,7 @@ module Opal
1377
1508
  end
1378
1509
 
1379
1510
  @scope.queue_temp tmp
1380
- code.join ', '
1511
+ code
1381
1512
  end
1382
1513
 
1383
1514
  def process_svalue(sexp, level)
@@ -1389,16 +1520,33 @@ module Opal
1389
1520
  lvar = sexp[0]
1390
1521
  rhs = sexp[1]
1391
1522
  lvar = "#{lvar}$".to_sym if RESERVED.include? lvar.to_s
1392
- @scope.add_local lvar
1393
- res = "#{lvar} = #{process rhs, :expr}"
1394
- level == :recv ? "(#{res})" : res
1523
+
1524
+ if @irb_vars and @scope.top?
1525
+ [fragment("Opal.irb_vars.#{lvar} = ", sexp), process(rhs, :expr)]
1526
+ else
1527
+ @scope.add_local lvar
1528
+ rhs = process(rhs, :expr)
1529
+ result = [fragment(lvar, sexp), fragment(" = ", sexp), rhs]
1530
+
1531
+ if level == :recv
1532
+ result.unshift fragment("(", sexp)
1533
+ result.push fragment(")", sexp)
1534
+ end
1535
+
1536
+ result
1537
+ end
1395
1538
  end
1396
1539
 
1397
1540
  # s(:lvar, :lvar)
1398
- def process_lvar(exp, level)
1399
- lvar = exp.shift.to_s
1541
+ def process_lvar(sexp, level)
1542
+ lvar = sexp.shift.to_s
1400
1543
  lvar = "#{lvar}$" if RESERVED.include? lvar
1401
- lvar
1544
+
1545
+ if @irb_vars and @scope.top?
1546
+ with_temp { |t| fragment("((#{t} = Opal.irb_vars.#{lvar}) == null ? nil : #{t})", sexp) }
1547
+ else
1548
+ fragment(lvar, sexp)
1549
+ end
1402
1550
  end
1403
1551
 
1404
1552
  # s(:iasgn, :ivar, rhs)
@@ -1407,7 +1555,7 @@ module Opal
1407
1555
  rhs = exp[1]
1408
1556
  ivar = ivar.to_s[1..-1]
1409
1557
  lhs = RESERVED.include?(ivar) ? "#{current_self}['#{ivar}']" : "#{current_self}.#{ivar}"
1410
- "#{lhs} = #{process rhs, :expr}"
1558
+ [fragment(lhs, exp), fragment(" = ", exp), process(rhs, :expr)]
1411
1559
  end
1412
1560
 
1413
1561
  # s(:ivar, :ivar)
@@ -1415,18 +1563,18 @@ module Opal
1415
1563
  ivar = exp.shift.to_s[1..-1]
1416
1564
  part = RESERVED.include?(ivar) ? "['#{ivar}']" : ".#{ivar}"
1417
1565
  @scope.add_ivar part
1418
- "#{current_self}#{part}"
1566
+ fragment("#{current_self}#{part}", exp)
1419
1567
  end
1420
1568
 
1421
1569
  # s(:gvar, gvar)
1422
1570
  def process_gvar(sexp, level)
1423
1571
  gvar = sexp.shift.to_s[1..-1]
1424
1572
  @helpers['gvars'] = true
1425
- "__gvars[#{gvar.inspect}]"
1573
+ fragment("__gvars[#{gvar.inspect}]", sexp)
1426
1574
  end
1427
-
1575
+
1428
1576
  def process_nth_ref(sexp, level)
1429
- "nil"
1577
+ fragment("nil", sexp)
1430
1578
  end
1431
1579
 
1432
1580
  # s(:gasgn, :gvar, rhs)
@@ -1434,7 +1582,7 @@ module Opal
1434
1582
  gvar = sexp[0].to_s[1..-1]
1435
1583
  rhs = sexp[1]
1436
1584
  @helpers['gvars'] = true
1437
- "__gvars[#{gvar.to_s.inspect}] = #{process rhs, :expr}"
1585
+ [fragment("__gvars[#{gvar.to_s.inspect}] = ", sexp), process(rhs, :expr)]
1438
1586
  end
1439
1587
 
1440
1588
  # s(:const, :const)
@@ -1443,17 +1591,17 @@ module Opal
1443
1591
 
1444
1592
  if @const_missing
1445
1593
  with_temp do |t|
1446
- "((#{t} = __scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})"
1594
+ fragment("((#{t} = __scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})", sexp)
1447
1595
  end
1448
1596
  else
1449
- "__scope.#{cname}"
1597
+ fragment("__scope.#{cname}", sexp)
1450
1598
  end
1451
1599
  end
1452
1600
 
1453
1601
  # s(:cdecl, :const, rhs)
1454
1602
  def process_cdecl(sexp, level)
1455
1603
  const, rhs = sexp
1456
- "__scope.#{const} = #{process rhs, :expr}"
1604
+ [fragment("__scope.#{const} = ", sexp), process(rhs, :expr)]
1457
1605
  end
1458
1606
 
1459
1607
  # s(:return [val])
@@ -1461,67 +1609,91 @@ module Opal
1461
1609
  val = process(sexp.shift || s(:nil), :expr)
1462
1610
 
1463
1611
  raise SyntaxError, "void value expression: cannot return as an expression" unless level == :stmt
1464
- "return #{val}"
1612
+ [fragment("return ", sexp), val]
1465
1613
  end
1466
1614
 
1467
1615
  # s(:xstr, content)
1468
1616
  def process_xstr(sexp, level)
1469
1617
  code = sexp.first.to_s
1470
1618
  code += ";" if level == :stmt and !code.include?(';')
1471
- level == :recv ? "(#{code})" : code
1619
+
1620
+ result = fragment(code, sexp)
1621
+
1622
+ level == :recv ? [fragment("(", sexp), result, fragment(")", sexp)] : result
1472
1623
  end
1473
1624
 
1474
1625
  # s(:dxstr, parts...)
1475
1626
  def process_dxstr(sexp, level)
1476
- code = sexp.map do |p|
1627
+ result = []
1628
+ needs_sc = false
1629
+
1630
+ sexp.each do |p|
1477
1631
  if String === p
1478
- p.to_s
1632
+ result << fragment(p.to_s, sexp)
1633
+ needs_sc = true if level == :stmt and !p.to_s.include?(';')
1479
1634
  elsif p.first == :evstr
1480
- process p.last, :stmt
1635
+ result.push(*process(p.last, :stmt))
1481
1636
  elsif p.first == :str
1482
- p.last.to_s
1637
+ result << fragment(p.last.to_s, p)
1638
+ needs_sc = true if level == :stmt and !p.last.to_s.include?(';')
1483
1639
  else
1484
1640
  raise "Bad dxstr part"
1485
1641
  end
1486
- end.join
1642
+ end
1487
1643
 
1488
- code += ";" if level == :stmt and !code.include?(';')
1489
- code = "(#{code})" if level == :recv
1490
- code
1644
+ result << fragment(";", sexp) if needs_sc
1645
+
1646
+ if level == :recv
1647
+ [fragment("(", sexp), result, fragment(")", sexp)]
1648
+ else
1649
+ result
1650
+ end
1491
1651
  end
1492
1652
 
1493
1653
  # s(:dstr, parts..)
1494
1654
  def process_dstr(sexp, level)
1495
- parts = sexp.map do |p|
1655
+ result = []
1656
+
1657
+ sexp.each do |p|
1658
+ result << fragment(" + ", sexp) unless result.empty?
1496
1659
  if String === p
1497
- p.inspect
1660
+ result << fragment(p.inspect, sexp)
1498
1661
  elsif p.first == :evstr
1499
- "(" + process(p.last, :expr) + ")"
1662
+ result << fragment("(", p)
1663
+ result << process(p.last, :expr)
1664
+ result << fragment(")", p)
1500
1665
  elsif p.first == :str
1501
- p.last.inspect
1666
+ result << fragment(p.last.inspect, p)
1502
1667
  else
1503
1668
  raise "Bad dstr part"
1504
1669
  end
1505
1670
  end
1506
1671
 
1507
- res = parts.join ' + '
1508
- level == :recv ? "(#{res})" : res
1672
+ if level == :recv
1673
+ [fragment("(", sexp), result, fragment(")", sexp)]
1674
+ else
1675
+ result
1676
+ end
1509
1677
  end
1510
1678
 
1511
1679
  def process_dsym(sexp, level)
1512
- parts = sexp.map do |p|
1680
+ result = []
1681
+
1682
+ sexp.each do |p|
1683
+ result << fragment(" + ", sexp) unless result.empty?
1684
+
1513
1685
  if String === p
1514
- p.inspect
1686
+ result << fragment(p.inspect, sexp)
1515
1687
  elsif p.first == :evstr
1516
- process(s(:call, p.last, :to_s, s(:arglist)), :expr)
1688
+ result << process(s(:call, p.last, :to_s, s(:arglist)), :expr)
1517
1689
  elsif p.first == :str
1518
- p.last.inspect
1690
+ result << fragment(p.last.inspect, sexp)
1519
1691
  else
1520
1692
  raise "Bad dsym part"
1521
1693
  end
1522
1694
  end
1523
1695
 
1524
- "(#{parts.join '+'})"
1696
+ [fragment("(", sexp), result, fragment(")", sexp)]
1525
1697
  end
1526
1698
 
1527
1699
  # s(:if, test, truthy, falsy)
@@ -1543,14 +1715,21 @@ module Opal
1543
1715
  check = js_truthy test
1544
1716
  end
1545
1717
 
1546
- code = "if (#{check}) {\n"
1547
- indent { code += @indent + process(truthy, :stmt) } if truthy
1548
- indent { code += "\n#@indent} else {\n#@indent#{process falsy, :stmt}" } if falsy
1549
- code += "\n#@indent}"
1718
+ result = [fragment("if (", sexp), check, fragment(") {\n", sexp)]
1550
1719
 
1551
- code = "(function() { #{code}; return nil; }).call(#{current_self})" if returnable
1720
+ indent { result.push(fragment(@indent, sexp), process(truthy, :stmt)) } if truthy
1552
1721
 
1553
- code
1722
+ outdent = @indent
1723
+ indent { result.push(fragment("\n#{outdent}} else {\n#@indent", sexp), process(falsy, :stmt)) } if falsy
1724
+
1725
+ result << fragment("\n#@indent}", sexp)
1726
+
1727
+ if returnable
1728
+ result.unshift fragment("(function() { ", sexp)
1729
+ result.push fragment("; return nil; }).call(#{current_self})", sexp)
1730
+ end
1731
+
1732
+ result
1554
1733
  end
1555
1734
 
1556
1735
  def js_truthy_optimize(sexp)
@@ -1564,8 +1743,7 @@ module Opal
1564
1743
  return process sexp, :expr
1565
1744
  end
1566
1745
  elsif [:lvar, :self].include? sexp.first
1567
- name = process sexp, :expr
1568
- "#{name} !== false && #{name} !== nil"
1746
+ [process(sexp.dup, :expr), fragment(" !== false && ", sexp), process(sexp.dup, :expr), fragment(" !== nil", sexp)]
1569
1747
  end
1570
1748
  end
1571
1749
 
@@ -1575,7 +1753,7 @@ module Opal
1575
1753
  end
1576
1754
 
1577
1755
  with_temp do |tmp|
1578
- "(%s = %s) !== false && %s !== nil" % [tmp, process(sexp, :expr), tmp]
1756
+ [fragment("(#{tmp} = ", sexp), process(sexp, :expr), fragment(") !== false && #{tmp} !== nil", sexp)]
1579
1757
  end
1580
1758
  end
1581
1759
 
@@ -1588,7 +1766,11 @@ module Opal
1588
1766
  end
1589
1767
 
1590
1768
  with_temp do |tmp|
1591
- "(%s = %s) === false || %s === nil" % [tmp, process(sexp, :expr), tmp]
1769
+ result = []
1770
+ result << fragment("(#{tmp} = ", sexp)
1771
+ result << process(sexp, :expr)
1772
+ result << fragment(") === false || #{tmp} === nil", sexp)
1773
+ result
1592
1774
  end
1593
1775
  end
1594
1776
 
@@ -1599,26 +1781,30 @@ module Opal
1599
1781
  tmp = @scope.new_temp
1600
1782
 
1601
1783
  if t = js_truthy_optimize(lhs)
1602
- return "((#{tmp} = #{t}) ? #{process rhs, :expr} : #{tmp})".tap {
1603
- @scope.queue_temp tmp
1604
- }
1784
+ result = []
1785
+ result << fragment("((#{tmp} = ", sexp) << t
1786
+ result << fragment(") ? ", sexp) << process(rhs, :expr)
1787
+ result << fragment(" : #{tmp})", sexp)
1788
+ @scope.queue_temp tmp
1789
+
1790
+ return result
1605
1791
  end
1606
1792
 
1607
1793
  @scope.queue_temp tmp
1608
1794
 
1609
- "(%s = %s, %s !== false && %s !== nil ? %s : %s)" %
1610
- [tmp, process(lhs, :expr), tmp, tmp, process(rhs, :expr), tmp]
1795
+ [fragment("(#{tmp} = ", sexp), process(lhs, :expr), fragment(", #{tmp} !== false && #{tmp} !== nil ? ", sexp), process(rhs, :expr), fragment(" : #{tmp})", sexp)]
1796
+
1611
1797
  end
1612
1798
 
1613
1799
  # s(:or, lhs, rhs)
1614
1800
  def process_or(sexp, level)
1615
1801
  lhs = sexp[0]
1616
1802
  rhs = sexp[1]
1617
- t = nil
1618
1803
 
1619
1804
  with_temp do |tmp|
1620
- "((%s = %s), %s !== false && %s !== nil ? %s : %s)" %
1621
- [tmp, process(lhs, :expr), tmp, tmp, tmp, process(rhs, :expr)]
1805
+ lhs = process lhs, :expr
1806
+ rhs = process rhs, :expr
1807
+ [fragment("(#{tmp} = ", sexp), lhs, fragment(", #{tmp} !== false && #{tmp} !== nil ? #{tmp} : ", sexp), rhs, fragment(")", sexp)]
1622
1808
  end
1623
1809
  end
1624
1810
 
@@ -1627,10 +1813,10 @@ module Opal
1627
1813
  call = handle_yield_call sexp, level
1628
1814
 
1629
1815
  if level == :stmt
1630
- "if (#{call} === __breaker) return __breaker.$v"
1816
+ [fragment("if (", sexp), call, fragment(" === __breaker) return __breaker.$v")]
1631
1817
  else
1632
1818
  with_temp do |tmp|
1633
- "(((#{tmp} = #{call}) === __breaker) ? __breaker.$v : #{tmp})"
1819
+ [fragment("(((#{tmp} = ", sexp), call, fragment(") === __breaker) ? __breaker.$v : #{tmp})", sexp)]
1634
1820
  end
1635
1821
  end
1636
1822
  end
@@ -1643,7 +1829,8 @@ module Opal
1643
1829
  # s(:yasgn, :a, s(:yield, arg1, arg2))
1644
1830
  def process_yasgn(sexp, level)
1645
1831
  call = handle_yield_call s(*sexp[1][1..-1]), :stmt
1646
- "if ((%s = %s) === __breaker) return __breaker.$v" % [sexp[0], call]
1832
+
1833
+ [fragment("if ((#{sexp[0]} = ", sexp), call, fragment(") === __breaker) return __breaker.$v", sexp)]
1647
1834
  end
1648
1835
 
1649
1836
  # Created by `#returns()` for when a yield statement should return
@@ -1652,8 +1839,8 @@ module Opal
1652
1839
  call = handle_yield_call sexp, level
1653
1840
 
1654
1841
  with_temp do |tmp|
1655
- "return %s = %s, %s === __breaker ? %s : %s" %
1656
- [tmp, call, tmp, tmp, tmp]
1842
+ [fragment("return #{tmp} = ", sexp), call,
1843
+ fragment(", #{tmp} === __breaker ? #{tmp} : #{tmp}")]
1657
1844
  end
1658
1845
  end
1659
1846
 
@@ -1666,16 +1853,20 @@ module Opal
1666
1853
 
1667
1854
  y = @scope.block_name || '__yield'
1668
1855
 
1669
- splat ? "#{y}.apply(null, #{args})" : "#{y}.call(#{args})"
1856
+ if splat
1857
+ [fragment("#{y}.apply(null, ", sexp), args, fragment(")", sexp)]
1858
+ else
1859
+ [fragment("#{y}.call(", sexp), args, fragment(")", sexp)]
1860
+ end
1670
1861
  end
1671
1862
 
1672
- def process_break(exp, level)
1673
- val = exp.empty? ? 'nil' : process(exp.shift, :expr)
1863
+ def process_break(sexp, level)
1864
+ val = sexp.empty? ? fragment('nil', sexp) : process(sexp.shift, :expr)
1674
1865
  if in_while?
1675
- @while_loop[:closure] ? "return #{ val };" : "break;"
1866
+ @while_loop[:closure] ? [fragment("return ", sexp), val, fragment("", sexp)] : fragment("break;", sexp)
1676
1867
  elsif @scope.iter?
1677
1868
  error "break must be used as a statement" unless level == :stmt
1678
- "return (__breaker.$v = #{ val }, __breaker)"
1869
+ [fragment("return (__breaker.$v = ", sexp), val, fragment(", __breaker)", sexp)]
1679
1870
  else
1680
1871
  error "void value expression: cannot use break outside of iter/while"
1681
1872
  end
@@ -1683,6 +1874,7 @@ module Opal
1683
1874
 
1684
1875
  # s(:case, expr, when1, when2, ..)
1685
1876
  def process_case(exp, level)
1877
+ pre = []
1686
1878
  code = []
1687
1879
  @scope.add_local "$case"
1688
1880
  expr = process exp.shift, :expr
@@ -1690,24 +1882,31 @@ module Opal
1690
1882
  returnable = level != :stmt
1691
1883
  done_else = false
1692
1884
 
1885
+ pre << fragment("$case = ", exp) << expr << fragment(";", exp)
1886
+
1693
1887
  until exp.empty?
1694
1888
  wen = exp.shift
1695
1889
  if wen and wen.first == :when
1696
1890
  returns(wen) if returnable
1697
1891
  wen = process(wen, :stmt)
1698
- wen = "else #{wen}" unless code.empty?
1892
+ code << fragment("else ", exp) unless code.empty?
1699
1893
  code << wen
1700
1894
  elsif wen # s(:else)
1701
1895
  done_else = true
1702
1896
  wen = returns(wen) if returnable
1703
- code << "else {#{process wen, :stmt}}"
1897
+ code << fragment("else {", exp) << process(wen, :stmt) << fragment("}", exp)
1704
1898
  end
1705
1899
  end
1706
1900
 
1707
- code << "else {return nil}" if returnable and !done_else
1901
+ code << fragment("else { return nil }", exp) if returnable and !done_else
1902
+
1903
+ code.unshift pre
1904
+
1905
+ if returnable
1906
+ code.unshift fragment("(function() { ", exp)
1907
+ code << fragment(" }).call(#{current_self})", exp)
1908
+ end
1708
1909
 
1709
- code = "$case = #{expr};#{code.join @space}"
1710
- code = "(function() { #{code} }).call(#{current_self})" if returnable
1711
1910
  code
1712
1911
  end
1713
1912
 
@@ -1717,30 +1916,32 @@ module Opal
1717
1916
  # s(:when, s(:array, foo), bar)
1718
1917
  def process_when(exp, level)
1719
1918
  arg = exp.shift[1..-1]
1720
- body = exp.shift
1721
- body = process body, level if body
1919
+ body = exp.shift || s(:nil)
1920
+ #body = process body, level if body
1921
+ body = process body, level
1722
1922
 
1723
1923
  test = []
1724
1924
  until arg.empty?
1925
+ test << fragment(" || ", exp) unless test.empty?
1725
1926
  a = arg.shift
1726
1927
 
1727
1928
  if a.first == :splat # when inside another when means a splat of values
1728
- call = s(:call, s(:js_tmp, "$splt[i]"), :===, s(:arglist, s(:js_tmp, "$case")))
1729
- splt = "(function($splt) {for(var i = 0; i < $splt.length; i++) {"
1730
- splt += "if (#{process call, :expr}) { return true; }"
1731
- splt += "} return false; }).call(#{current_self}, #{process a[1], :expr})"
1929
+ call = s(:call, s(:js_tmp, "$splt[i]"), :===, s(:arglist, s(:js_tmp, "$case")))
1930
+ splt = [fragment("(function($splt) { for(var i = 0; i < $splt.length; i++) {", exp)]
1931
+ splt << fragment("if (", exp) << process(call, :expr) << fragment(") { return true; }", exp)
1932
+ splt << fragment("} return false; }).call(#{current_self}, ", exp)
1933
+ splt << process(a[1], :expr) << fragment(")", exp)
1732
1934
 
1733
1935
  test << splt
1734
1936
  else
1735
1937
  call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
1736
1938
  call = process call, :expr
1737
- # call = "else " unless test.empty?
1738
1939
 
1739
1940
  test << call
1740
1941
  end
1741
1942
  end
1742
1943
 
1743
- "if (%s) {%s%s%s}" % [test.join(' || '), @space, body, @space]
1944
+ [fragment("if (", exp), test, fragment(") {#@space", exp), body, fragment("#@space}", exp)]
1744
1945
  end
1745
1946
 
1746
1947
  # lhs =~ rhs
@@ -1758,8 +1959,8 @@ module Opal
1758
1959
  # s(:cvar, name)
1759
1960
  def process_cvar(exp, level)
1760
1961
  with_temp do |tmp|
1761
- "((%s = Opal.cvars[%s]) == null ? nil : %s)" %
1762
- [tmp, exp.shift.to_s.inspect, tmp]
1962
+ fragment(("((%s = Opal.cvars[%s]) == null ? nil : %s)" %
1963
+ [tmp, exp.shift.to_s.inspect, tmp]), exp)
1763
1964
  end
1764
1965
  end
1765
1966
 
@@ -1771,7 +1972,7 @@ module Opal
1771
1972
  end
1772
1973
 
1773
1974
  def process_cvdecl(exp, level)
1774
- "(Opal.cvars[#{exp.shift.to_s.inspect}] = #{process exp.shift, :expr})"
1975
+ [fragment("(Opal.cvars[#{exp.shift.to_s.inspect}] = ", exp), process(exp.shift, :expr), fragment(")", exp)]
1775
1976
  end
1776
1977
 
1777
1978
  # BASE::NAME
@@ -1780,22 +1981,28 @@ module Opal
1780
1981
  def process_colon2(sexp, level)
1781
1982
  base = sexp[0]
1782
1983
  cname = sexp[1].to_s
1984
+ result = []
1783
1985
 
1784
1986
  if @const_missing
1785
1987
  with_temp do |t|
1786
- base = process base, :expr
1787
- "((#{t} = (#{base})._scope).#{cname} == null ? #{t}.cm(#{cname.inspect}) : #{t}.#{cname})"
1988
+ base = process base, :expr
1989
+
1990
+ result << fragment("((#{t} = (", sexp) << base << fragment(")._scope).", sexp)
1991
+ result << fragment("#{cname} == null ? #{t}.cm(#{cname.inspect}) : #{t}.#{cname})", sexp)
1788
1992
  end
1789
1993
  else
1790
1994
  base = process base, :expr
1791
- "(#{base})._scope.#{cname}"
1995
+
1996
+ result << fragment("(", sexp) << base << fragment(")._scope.#{cname}", sexp)
1792
1997
  end
1998
+
1999
+ result
1793
2000
  end
1794
2001
 
1795
2002
  def process_colon3(exp, level)
1796
2003
  with_temp do |t|
1797
2004
  cname = exp.shift.to_s
1798
- "((#{t} = __opal.Object._scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})"
2005
+ fragment("((#{t} = __opal.Object._scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})", exp)
1799
2006
  end
1800
2007
  end
1801
2008
 
@@ -1805,42 +2012,45 @@ module Opal
1805
2012
  def process_super(sexp, level)
1806
2013
  args = []
1807
2014
  until sexp.empty?
2015
+ args << fragment(", ", sexp) unless args.empty?
1808
2016
  args << process(sexp.shift, :expr)
1809
2017
  end
1810
2018
 
1811
- js_super "[#{ args.join ', ' }]"
2019
+ js_super [fragment("[", sexp), args, fragment("]", sexp)], sexp
1812
2020
  end
1813
2021
 
1814
2022
  # super
1815
2023
  #
1816
2024
  # s(:zsuper)
1817
2025
  def process_zsuper(exp, level)
1818
- js_super "__slice.call(arguments)"
2026
+ js_super fragment("__slice.call(arguments)", exp), exp
1819
2027
  end
1820
2028
 
1821
- def js_super args
2029
+ def js_super args, sexp
1822
2030
  if @scope.def_in_class?
1823
2031
  mid = @scope.mid.to_s
1824
2032
  sid = "super_#{unique_temp}"
1825
2033
 
1826
2034
  @scope.uses_super = sid
1827
- "#{sid}.apply(#{current_self}, #{ args })"
2035
+
2036
+
2037
+ [fragment("#{sid}.apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
1828
2038
 
1829
2039
  elsif @scope.type == :def
1830
- identity = @scope.identify!
1831
- cls_name = @scope.parent.name || "#{current_self}._klass.prototype"
2040
+ @scope.identify!
2041
+ cls_name = @scope.parent.name || "#{current_self}.constructor.prototype"
1832
2042
  jsid = mid_to_jsid @scope.mid.to_s
1833
2043
 
1834
2044
  if @scope.defs
1835
- "%s._super%s.apply(this, %s)" % [cls_name, jsid, args]
2045
+ [fragment(("%s._super%s.apply(this, " % [cls_name, jsid]), sexp), args, fragment(")", sexp)]
1836
2046
  else
1837
- "#{current_self}._klass._super.prototype%s.apply(#{current_self}, %s)" % [jsid, args]
2047
+ [fragment("#{current_self}.constructor._super.prototype#{jsid}.apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
1838
2048
  end
1839
2049
 
1840
2050
  elsif @scope.type == :iter
1841
2051
  chain, defn, mid = @scope.get_super_chain
1842
2052
  trys = chain.map { |c| "#{c}._sup" }.join ' || '
1843
- "(#{trys} || #{current_self}._klass._super.prototype[#{mid}]).apply(#{current_self}, #{args})"
2053
+ [fragment("(#{trys} || #{current_self}.constructor._super.prototype[#{mid}]).apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
1844
2054
  else
1845
2055
  raise "Cannot call super() from outside a method block"
1846
2056
  end
@@ -1875,7 +2085,11 @@ module Opal
1875
2085
  aset = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs))
1876
2086
  orop = s(:or, aref, aset)
1877
2087
 
1878
- "(#{a} = #{args}, #{r} = #{recv}, #{process orop, :expr})"
2088
+ result = []
2089
+ result << fragment("(#{a} = ", sexp) << args << fragment(", #{r} = ", sexp)
2090
+ result << recv << fragment(", ", sexp) << process(orop, :expr)
2091
+ result << fragment(")", sexp)
2092
+ result
1879
2093
  end
1880
2094
  end
1881
2095
  end
@@ -1883,11 +2097,11 @@ module Opal
1883
2097
  # lhs.b += rhs
1884
2098
  #
1885
2099
  # s(:op_asgn2, lhs, :b=, :+, rhs)
1886
- def process_op_asgn2(exp, level)
1887
- lhs = process exp.shift, :expr
1888
- mid = exp.shift.to_s[0..-2]
1889
- op = exp.shift
1890
- rhs = exp.shift
2100
+ def process_op_asgn2(sexp, level)
2101
+ lhs = process sexp.shift, :expr
2102
+ mid = sexp.shift.to_s[0..-2]
2103
+ op = sexp.shift
2104
+ rhs = sexp.shift
1891
2105
 
1892
2106
  if op.to_s == "||"
1893
2107
  with_temp do |temp|
@@ -1895,7 +2109,7 @@ module Opal
1895
2109
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
1896
2110
  orop = s(:or, getr, asgn)
1897
2111
 
1898
- "(#{temp} = #{lhs}, #{process orop, :expr})"
2112
+ [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(orop, :expr), fragment(")", sexp)]
1899
2113
  end
1900
2114
  elsif op.to_s == '&&'
1901
2115
  with_temp do |temp|
@@ -1903,7 +2117,7 @@ module Opal
1903
2117
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
1904
2118
  andop = s(:and, getr, asgn)
1905
2119
 
1906
- "(#{temp} = #{lhs}, #{process andop, :expr})"
2120
+ [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(andop, :expr), fragment(")", sexp)]
1907
2121
  end
1908
2122
  else
1909
2123
  with_temp do |temp|
@@ -1911,7 +2125,7 @@ module Opal
1911
2125
  oper = s(:call, getr, op, s(:arglist, rhs))
1912
2126
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, oper))
1913
2127
 
1914
- "(#{temp} = #{lhs}, #{process asgn, :expr})"
2128
+ [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(asgn, :expr), fragment(")", sexp)]
1915
2129
  end
1916
2130
  end
1917
2131
  end
@@ -1924,14 +2138,20 @@ module Opal
1924
2138
  begn = returns begn
1925
2139
  end
1926
2140
 
2141
+ result = []
1927
2142
  body = process begn, level
1928
2143
  ensr = exp.shift || s(:nil)
1929
2144
  ensr = process ensr, level
1930
- body = "try {\n#{body}}" unless body =~ /^try \{/
1931
2145
 
1932
- res = "#{body}#{@space}finally {#{@space}#{ensr}}"
1933
- res = "(function() { #{res}; }).call(#{current_self})" if retn
1934
- res
2146
+ body = [fragment("try {\n", exp), body, fragment("}", exp)]
2147
+
2148
+ result << body << fragment("#{@space}finally {#@space", exp) << ensr << fragment("}", exp)
2149
+
2150
+ if retn
2151
+ [fragment("(function() { ", exp), result, fragment("; }).call(#{current_self})", exp)]
2152
+ else
2153
+ result
2154
+ end
1935
2155
  end
1936
2156
 
1937
2157
  def process_rescue(exp, level)
@@ -1943,14 +2163,27 @@ module Opal
1943
2163
  until exp.empty?
1944
2164
  handled_else = true unless exp.first.first == :resbody
1945
2165
  part = indent { process exp.shift, level }
1946
- part = "else " + part unless parts.empty?
2166
+
2167
+ unless parts.empty?
2168
+ parts << fragment("else ", exp)
2169
+ end
2170
+
1947
2171
  parts << part
1948
2172
  end
1949
2173
  # if no rescue statement captures our error, we should rethrow
1950
- parts << indent { "else { throw $err; }" } unless handled_else
2174
+ parts << indent { fragment("else { throw $err; }", exp) } unless handled_else
2175
+
2176
+ code = []
2177
+ code << fragment("try {#@space#{INDENT}", exp)
2178
+ code << body
2179
+ code << fragment("#@space} catch ($err) {#@space", exp)
2180
+ code << parts
2181
+ code << fragment("#@space}", exp)
1951
2182
 
1952
- code = "try {#@space#{INDENT}#{body}#@space} catch ($err) {#@space#{parts.join @space}#{@space}}"
1953
- code = "(function() { #{code} }).call(#{current_self})" if level == :expr
2183
+ if level == :expr
2184
+ code.unshift fragment("(function() { ", exp)
2185
+ code << fragment(" }).call(#{current_self})", exp)
2186
+ end
1954
2187
 
1955
2188
  code
1956
2189
  end
@@ -1963,41 +2196,51 @@ module Opal
1963
2196
  types = args[1..-1]
1964
2197
  types.pop if types.last and types.last.first != :const
1965
2198
 
1966
- err = types.map { |t|
2199
+ err = []
2200
+ types.each do |t|
2201
+ err << fragment(", ", exp) unless err.empty?
1967
2202
  call = s(:call, t, :===, s(:arglist, s(:js_tmp, "$err")))
1968
2203
  a = process call, :expr
1969
- a
1970
- }.join ', '
1971
- err = "true" if err.empty?
2204
+ err << a
2205
+ end
2206
+ err << fragment("true", exp) if err.empty?
1972
2207
 
1973
2208
  if Array === args.last and [:lasgn, :iasgn].include? args.last.first
1974
2209
  val = args.last
1975
2210
  val[2] = s(:js_tmp, "$err")
1976
- val = process(val, :expr) + ";"
2211
+ val = [process(val, :expr) , fragment(";", exp)]
1977
2212
  end
1978
2213
 
1979
- "if (#{err}) {#{@space}#{val}#{body}}"
2214
+ val = [] unless val
2215
+
2216
+ [fragment("if (", exp), err, fragment("){#@space", exp), val, body, fragment("}", exp)]
1980
2217
  end
1981
2218
 
1982
2219
  # FIXME: Hack.. grammar should remove top level begin.
1983
2220
  def process_begin(exp, level)
1984
- process exp[0], level
2221
+ result = process exp[0], level
1985
2222
  end
1986
2223
 
1987
2224
  def process_next(exp, level)
1988
2225
  if in_while?
1989
- "continue;"
2226
+ fragment("continue;", exp)
1990
2227
  else
1991
- "return #{ exp.empty? ? 'nil' : process(exp.shift, :expr) };"
2228
+ result = []
2229
+ result << fragment("return ", exp)
2230
+
2231
+ result << (exp.empty? ? fragment('nil', exp) : process(exp.shift, :expr))
2232
+ result << fragment(";", exp)
2233
+
2234
+ result
1992
2235
  end
1993
2236
  end
1994
2237
 
1995
2238
  def process_redo(exp, level)
1996
2239
  if in_while?
1997
2240
  @while_loop[:use_redo] = true
1998
- "#{@while_loop[:redo_var]} = true"
2241
+ fragment("#{@while_loop[:redo_var]} = true", exp)
1999
2242
  else
2000
- "REDO()"
2243
+ fragment("REDO()", exp)
2001
2244
  end
2002
2245
  end
2003
2246
  end