opal 0.3.44 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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