opal 0.9.4 → 0.10.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.gitignore +2 -3
  4. data/.gitmodules +5 -2
  5. data/.jshintrc +1 -8
  6. data/.rspec +1 -1
  7. data/.travis.yml +15 -23
  8. data/CHANGELOG.md +511 -326
  9. data/CODE_OF_CONDUCT.md +13 -15
  10. data/CONTRIBUTING.md +26 -216
  11. data/Gemfile +20 -12
  12. data/Guardfile +2 -2
  13. data/HACKING.md +230 -0
  14. data/README.md +6 -7
  15. data/bin/opal-mspec +1 -1
  16. data/config.ru +2 -2
  17. data/docs/faq.md +1 -1
  18. data/docs/source_maps.md +1 -1
  19. data/lib/opal.rb +1 -0
  20. data/lib/opal/builder.rb +1 -1
  21. data/lib/opal/cli.rb +30 -28
  22. data/lib/opal/cli_options.rb +3 -0
  23. data/lib/opal/cli_runners.rb +14 -1
  24. data/lib/opal/cli_runners/{apple_script.rb → applescript.rb} +3 -3
  25. data/lib/opal/cli_runners/nashorn.rb +2 -2
  26. data/lib/opal/cli_runners/nodejs.rb +2 -2
  27. data/lib/opal/cli_runners/phantom.js +24 -0
  28. data/lib/opal/cli_runners/phantomjs.rb +10 -10
  29. data/lib/opal/cli_runners/server.rb +3 -3
  30. data/lib/opal/compiler.rb +43 -4
  31. data/lib/opal/config.rb +3 -1
  32. data/lib/opal/errors.rb +13 -0
  33. data/lib/opal/fragment.rb +0 -13
  34. data/lib/opal/nodes.rb +10 -0
  35. data/lib/opal/nodes/args/initialize_kwargs.rb +28 -0
  36. data/lib/opal/nodes/args/kwarg.rb +29 -0
  37. data/lib/opal/nodes/args/kwoptarg.rb +29 -0
  38. data/lib/opal/nodes/args/kwrestarg.rb +39 -0
  39. data/lib/opal/nodes/args/mlhsarg.rb +79 -0
  40. data/lib/opal/nodes/args/normarg.rb +26 -0
  41. data/lib/opal/nodes/args/optarg.rb +27 -0
  42. data/lib/opal/nodes/args/post_args.rb +200 -0
  43. data/lib/opal/nodes/args/post_kwargs.rb +31 -0
  44. data/lib/opal/nodes/args/restarg.rb +33 -0
  45. data/lib/opal/nodes/base.rb +12 -0
  46. data/lib/opal/nodes/call.rb +92 -33
  47. data/lib/opal/nodes/def.rb +26 -169
  48. data/lib/opal/nodes/hash.rb +10 -4
  49. data/lib/opal/nodes/helpers.rb +6 -3
  50. data/lib/opal/nodes/inline_args.rb +61 -0
  51. data/lib/opal/nodes/iter.rb +73 -82
  52. data/lib/opal/nodes/logic.rb +12 -2
  53. data/lib/opal/nodes/masgn.rb +1 -2
  54. data/lib/opal/nodes/node_with_args.rb +141 -0
  55. data/lib/opal/nodes/rescue.rb +121 -43
  56. data/lib/opal/nodes/scope.rb +24 -5
  57. data/lib/opal/nodes/super.rb +122 -54
  58. data/lib/opal/nodes/top.rb +0 -12
  59. data/lib/opal/nodes/yield.rb +2 -13
  60. data/lib/opal/parser.rb +67 -39
  61. data/lib/opal/parser/grammar.rb +3319 -2961
  62. data/lib/opal/parser/grammar.y +234 -46
  63. data/lib/opal/parser/lexer.rb +105 -17
  64. data/lib/opal/parser/sexp.rb +4 -0
  65. data/lib/opal/paths.rb +4 -0
  66. data/lib/opal/regexp_anchors.rb +19 -1
  67. data/lib/opal/sprockets.rb +21 -18
  68. data/lib/opal/sprockets/environment.rb +0 -8
  69. data/lib/opal/sprockets/processor.rb +13 -16
  70. data/lib/opal/sprockets/server.rb +6 -12
  71. data/lib/opal/version.rb +1 -1
  72. data/opal.gemspec +1 -0
  73. data/opal/corelib/array.rb +209 -131
  74. data/opal/corelib/basic_object.rb +7 -3
  75. data/opal/corelib/class.rb +11 -17
  76. data/opal/corelib/constants.rb +2 -2
  77. data/opal/corelib/enumerable.rb +178 -355
  78. data/opal/corelib/enumerator.rb +3 -46
  79. data/opal/corelib/error.rb +2 -2
  80. data/opal/corelib/file.rb +13 -1
  81. data/opal/corelib/hash.rb +26 -56
  82. data/opal/corelib/helpers.rb +10 -0
  83. data/opal/corelib/kernel.rb +6 -3
  84. data/opal/corelib/module.rb +62 -31
  85. data/opal/corelib/number.rb +7 -16
  86. data/opal/corelib/proc.rb +24 -9
  87. data/opal/corelib/range.rb +4 -13
  88. data/opal/corelib/runtime.js +515 -378
  89. data/opal/corelib/string.rb +21 -49
  90. data/opal/corelib/struct.rb +50 -35
  91. data/opal/corelib/unsupported.rb +18 -30
  92. data/opal/opal.rb +0 -1
  93. data/opal/opal/mini.rb +1 -0
  94. data/spec/README.md +6 -4
  95. data/spec/filters/bugs/array.rb +0 -42
  96. data/spec/filters/bugs/basicobject.rb +0 -2
  97. data/spec/filters/bugs/bigdecimal.rb +160 -0
  98. data/spec/filters/bugs/class.rb +0 -5
  99. data/spec/filters/bugs/date.rb +1 -48
  100. data/spec/filters/bugs/enumerable.rb +4 -12
  101. data/spec/filters/bugs/enumerator.rb +0 -1
  102. data/spec/filters/bugs/exception.rb +4 -3
  103. data/spec/filters/bugs/float.rb +4 -2
  104. data/spec/filters/bugs/kernel.rb +25 -10
  105. data/spec/filters/bugs/language.rb +119 -68
  106. data/spec/filters/bugs/method.rb +135 -0
  107. data/spec/filters/bugs/module.rb +13 -28
  108. data/spec/filters/bugs/proc.rb +18 -8
  109. data/spec/filters/bugs/range.rb +0 -3
  110. data/spec/filters/bugs/rational.rb +4 -0
  111. data/spec/filters/bugs/regexp.rb +68 -36
  112. data/spec/filters/bugs/string.rb +1 -1
  113. data/spec/filters/bugs/struct.rb +0 -12
  114. data/spec/filters/bugs/time.rb +1 -0
  115. data/spec/filters/bugs/unboundmethod.rb +2 -1
  116. data/spec/filters/unsupported/freeze.rb +3 -1
  117. data/spec/filters/unsupported/language.rb +0 -7
  118. data/spec/filters/unsupported/privacy.rb +7 -6
  119. data/spec/filters/unsupported/string.rb +10 -0
  120. data/spec/filters/unsupported/struct.rb +3 -0
  121. data/spec/filters/unsupported/symbol.rb +9 -0
  122. data/spec/filters/unsupported/taint.rb +0 -3
  123. data/spec/filters/unsupported/thread.rb +1 -0
  124. data/spec/lib/cli_runners/phantomjs_spec.rb +39 -0
  125. data/spec/lib/cli_spec.rb +42 -1
  126. data/spec/lib/compiler/call_spec.rb +700 -0
  127. data/spec/lib/compiler_spec.rb +46 -28
  128. data/spec/lib/config_spec.rb +13 -0
  129. data/spec/lib/parser/call_spec.rb +18 -0
  130. data/spec/lib/parser/def_spec.rb +29 -0
  131. data/spec/lib/parser/iter_spec.rb +15 -15
  132. data/spec/lib/parser/lambda_spec.rb +153 -12
  133. data/spec/lib/parser/string_spec.rb +5 -0
  134. data/spec/lib/parser/undef_spec.rb +1 -1
  135. data/spec/lib/parser/variables_spec.rb +24 -0
  136. data/spec/lib/paths_spec.rb +12 -5
  137. data/spec/lib/spec_helper.rb +5 -0
  138. data/spec/lib/sprockets/processor_spec.rb +6 -5
  139. data/spec/lib/sprockets_spec.rb +8 -0
  140. data/spec/mspec-opal/formatters.rb +188 -0
  141. data/spec/mspec-opal/runner.rb +193 -0
  142. data/spec/opal/core/enumerator/with_index_spec.rb +6 -0
  143. data/spec/opal/core/kernel/define_singleton_method_spec.rb +1 -1
  144. data/spec/opal/core/kernel/instance_variables_spec.rb +14 -0
  145. data/spec/opal/core/kernel/loop_spec.rb +1 -1
  146. data/spec/opal/core/kernel/raise_spec.rb +1 -1
  147. data/spec/opal/core/language/heredoc_spec.rb +42 -0
  148. data/spec/opal/core/language/rescue_spec.rb +18 -0
  149. data/spec/opal/core/language_spec.rb +22 -0
  150. data/spec/opal/core/module/const_defined_spec.rb +1 -2
  151. data/spec/opal/core/module/name_spec.rb +6 -0
  152. data/spec/opal/core/runtime/bridged_classes_spec.rb +14 -2
  153. data/spec/opal/core/runtime/rescue_spec.rb +12 -2
  154. data/spec/opal/core/runtime/super_spec.rb +1 -0
  155. data/spec/opal/core/string_spec.rb +21 -0
  156. data/spec/opal/stdlib/js_spec.rb +1 -1
  157. data/spec/opal/stdlib/native/hash_spec.rb +7 -0
  158. data/spec/opal/stdlib/promise/always_spec.rb +24 -5
  159. data/spec/opal/stdlib/promise/rescue_spec.rb +15 -6
  160. data/spec/opal/stdlib/promise/then_spec.rb +13 -5
  161. data/spec/opal/stdlib/promise/trace_spec.rb +5 -6
  162. data/spec/opal/stdlib/strscan/scan_spec.rb +1 -1
  163. data/spec/ruby_specs +122 -0
  164. data/spec/spec_helper.rb +3 -15
  165. data/stdlib/base64.rb +51 -121
  166. data/stdlib/bigdecimal.rb +231 -0
  167. data/stdlib/bigdecimal/bignumber.js.rb +11 -0
  168. data/stdlib/bigdecimal/kernel.rb +5 -0
  169. data/stdlib/date.rb +252 -10
  170. data/stdlib/native.rb +38 -38
  171. data/stdlib/nodejs/dir.rb +8 -6
  172. data/stdlib/nodejs/file.rb +28 -3
  173. data/stdlib/nodejs/node_modules/.bin/js-yaml +1 -0
  174. data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esparse +1 -0
  175. data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esvalidate +1 -0
  176. data/stdlib/nodejs/require.rb +1 -1
  177. data/stdlib/nodejs/yaml.rb +3 -2
  178. data/stdlib/opal-parser.rb +7 -2
  179. data/stdlib/pathname.rb +23 -1
  180. data/stdlib/phantomjs.rb +10 -0
  181. data/stdlib/promise.rb +38 -23
  182. data/tasks/building.rake +3 -3
  183. data/tasks/testing.rake +27 -14
  184. data/tasks/testing/mspec_special_calls.rb +1 -1
  185. data/tasks/testing/sprockets-phantomjs.js +4 -0
  186. data/test/opal/test_keyword.rb +110 -110
  187. data/test/opal/unsupported_and_bugs.rb +30 -0
  188. data/vendored-minitest/minitest/assertions.rb +1 -1
  189. metadata +65 -15
  190. data/.spectator +0 -2
  191. data/.spectator-mspec +0 -3
  192. data/opal/corelib/array/inheritance.rb +0 -127
  193. data/spec/rubyspecs +0 -139
@@ -5,11 +5,17 @@ module Opal
5
5
  class HashNode < Base
6
6
  handle :hash
7
7
 
8
- def keys_and_values
8
+ def extract_keys_and_values(pairs)
9
9
  keys, values = [], []
10
10
 
11
- children.each_with_index do |obj, idx|
12
- if idx.even?
11
+ pairs.each_with_index do |obj, idx|
12
+ if obj.type == :kwsplat
13
+ # obj is (:kwsplat, (:hash, (:key, value), ...))
14
+ kwsplat_pairs = obj[1].children
15
+ kwsplat_keys, kwsplat_values = extract_keys_and_values(kwsplat_pairs)
16
+ keys.concat(kwsplat_keys)
17
+ values.concat(kwsplat_values)
18
+ elsif idx.even?
13
19
  keys << obj
14
20
  else
15
21
  values << obj
@@ -24,7 +30,7 @@ module Opal
24
30
  end
25
31
 
26
32
  def compile
27
- keys, values = keys_and_values
33
+ keys, values = extract_keys_and_values(children)
28
34
 
29
35
  if simple_keys? keys
30
36
  compile_hash2 keys, values
@@ -23,6 +23,9 @@ module Opal
23
23
  # Doesn't take in account utf8
24
24
  BASIC_IDENTIFIER_RULES = /#{REGEXP_START}[$_a-z][$_a-z\d]*#{REGEXP_END}/i
25
25
 
26
+ # Defining a local function like Array may break everything
27
+ RESERVED_FUNCTION_NAMES = /#{REGEXP_START}(?:Array)#{REGEXP_END}/
28
+
26
29
 
27
30
  def property(name)
28
31
  valid_name?(name) ? ".#{name}" : "[#{name.inspect}]"
@@ -114,15 +117,15 @@ module Opal
114
117
  if sexp.type == :call
115
118
  mid = sexp[2]
116
119
  receiver_handler_class = (receiver = sexp[1]) && compiler.handlers[receiver.type]
117
-
120
+
118
121
  # Only operator calls on the truthy_optimize? node classes should be optimized.
119
122
  # Monkey patch method calls might return 'self'/aka a bridged instance and need
120
123
  # the nil check - see discussion at https://github.com/opal/opal/pull/1097
121
124
  allow_optimization_on_type = Compiler::COMPARE.include?(mid.to_s) &&
122
125
  receiver_handler_class &&
123
126
  receiver_handler_class.truthy_optimize?
124
-
125
- if allow_optimization_on_type ||
127
+
128
+ if allow_optimization_on_type ||
126
129
  mid == :block_given? ||
127
130
  mid == :"=="
128
131
  expr(sexp)
@@ -0,0 +1,61 @@
1
+ require 'opal/nodes/base'
2
+
3
+ module Opal
4
+ module Nodes
5
+ # def args list
6
+ class InlineArgs < Base
7
+ handle :inline_args
8
+
9
+ def compile
10
+ push(arg_names.join(', '))
11
+ end
12
+
13
+ def arg_names
14
+ done_kwargs = false
15
+
16
+ children.inject([]) do |result, child|
17
+ case child.type
18
+ when :kwarg, :kwoptarg, :kwrestarg
19
+ unless done_kwargs
20
+ done_kwargs = true
21
+ result << '$kwargs'
22
+ end
23
+ add_arg(child)
24
+ when :mlhs
25
+ tmp = scope.next_temp
26
+ result << tmp
27
+ scope.mlhs_mapping[child] = tmp
28
+ when :arg, :optarg
29
+ arg_name = variable(child[1]).to_s
30
+ if !child.meta[:inline] && arg_name[0] != '$'
31
+ arg_name = "$#{arg_name}"
32
+ end
33
+ result << arg_name
34
+ add_arg(child)
35
+ when :restarg
36
+ # To make function.length working
37
+ # in cases like def m(*rest)
38
+ tmp_arg_name = scope.next_temp + "_rest"
39
+ result << tmp_arg_name
40
+ add_arg(child)
41
+ else
42
+ raise "Unknown argument type #{child.inspect}"
43
+ end
44
+
45
+ result
46
+ end
47
+ end
48
+
49
+ # If the argument has a name,
50
+ # we should mark it as an argument for current scope
51
+ # Otherwise, these args will be interpreted
52
+ # in the child scope as local variables
53
+ def add_arg(arg)
54
+ if arg[1]
55
+ arg_name = variable(arg[1].to_sym)
56
+ scope.add_arg(arg_name)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,46 +1,37 @@
1
- require 'opal/nodes/scope'
1
+ require 'opal/nodes/node_with_args'
2
2
 
3
3
  module Opal
4
4
  module Nodes
5
- class IterNode < ScopeNode
5
+ class IterNode < NodeWithArgs
6
6
  handle :iter
7
7
 
8
8
  children :args_sexp, :body_sexp
9
9
 
10
+ attr_accessor :block_arg, :shadow_args
11
+
10
12
  def compile
11
- opt_args = extract_opt_args
12
- block_arg = extract_block_arg
13
-
14
- # find any splat args
15
- if args.last.is_a?(Sexp) and args.last.type == :splat
16
- splat = args.last[1][1]
17
- args.pop
18
- len = args.length
19
- end
13
+ inline_params = nil
14
+ extract_block_arg
15
+ extract_shadow_args
16
+ split_args
20
17
 
21
- params = args_to_params(args[1..-1])
22
- params << splat if splat
18
+ # require 'pry'; binding.pry
23
19
 
24
20
  to_vars = identity = body_code = nil
25
21
 
26
22
  in_scope do
23
+ inline_params = process(inline_args_sexp)
24
+
27
25
  identity = scope.identify!
28
26
  add_temp "self = #{identity}.$$s || this"
29
27
 
30
- compile_args(args[1..-1], opt_args, params)
28
+ compile_shadow_args
31
29
 
32
- if splat
33
- scope.add_arg splat
34
- push "#{splat} = $slice.call(arguments, #{len - 1});"
35
- end
30
+ compile_inline_args
31
+ compile_post_args
36
32
 
37
- if block_arg
38
- scope.block_name = block_arg
39
- scope.add_temp block_arg
40
- scope_name = scope.identify!
41
-
42
- line "#{block_arg} = #{scope_name}.$$p || nil, #{scope_name}.$$p = null;"
43
- end
33
+ compile_block_arg
34
+ compile_norm_args
44
35
 
45
36
  body_code = stmt(body)
46
37
  to_vars = scope.to_vars
@@ -50,86 +41,86 @@ module Opal
50
41
 
51
42
  unshift to_vars
52
43
 
53
- unshift "(#{identity} = function(#{params.join ', '}){"
54
- push "}, #{identity}.$$s = self, #{identity})"
44
+ unshift "(#{identity} = function(", inline_params, "){"
45
+ push "}, #{identity}.$$s = self,"
46
+ push " #{identity}.$$brk = $brk," if compiler.has_break?
47
+ push " #{identity})"
55
48
  end
56
49
 
57
- def compile_args(args, opt_args, params)
58
- args.each_with_index do |arg, idx|
59
- if arg.type == :lasgn
60
- arg = variable(arg[1])
50
+ def norm_args
51
+ @norm_args ||= args[1..-1].select { |arg| arg.type == :arg }
52
+ end
61
53
 
62
- if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
63
- push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
64
- else
65
- push "if (#{arg} == null) #{arg} = nil;"
66
- end
67
- elsif arg.type == :array
68
- vars = {}
69
- arg[1..-1].each_with_index do |_arg, _idx|
70
- _arg = variable(_arg[1])
71
- unless vars.has_key?(_arg) || params.include?(_arg)
72
- vars[_arg] = "#{params[idx]}[#{_idx}]"
73
- end
74
- end
75
- push "var #{ vars.map{|k, v| "#{k} = #{v}"}.join(', ') };"
76
- else
77
- raise "Bad block arg type"
78
- end
54
+ def compile_norm_args
55
+ norm_args.each do |arg|
56
+ arg = variable(arg[1])
57
+ push "if (#{arg} == null) #{arg} = nil;"
79
58
  end
80
59
  end
81
60
 
82
- # opt args are last (if present) and are a s(:block)
83
- def extract_opt_args
84
- if args.last.is_a?(Sexp) and args.last.type == :block
85
- opt_args = args.pop
86
- opt_args.shift
87
- opt_args
61
+ def compile_block_arg
62
+ if block_arg
63
+ scope.block_name = block_arg
64
+ scope.add_temp block_arg
65
+ scope_name = scope.identify!
66
+
67
+ line "#{block_arg} = #{scope_name}.$$p || nil, #{scope_name}.$$p = null;"
88
68
  end
89
69
  end
90
70
 
91
- # does this iter define a block_pass
92
71
  def extract_block_arg
93
- if args.last.is_a?(Sexp) and args.last.type == :block_pass
94
- block_arg = args.pop
95
- block_arg = block_arg[1][1].to_sym
72
+ if args.is_a?(Sexp) && args.last.is_a?(Sexp) and args.last.type == :block_pass
73
+ self.block_arg = args.pop[1][1].to_sym
74
+ end
75
+ end
76
+
77
+ def compile_shadow_args
78
+ shadow_args.each do |shadow_arg|
79
+ scope.add_local(shadow_arg.last)
80
+ end
81
+ end
82
+
83
+ def extract_shadow_args
84
+ if args.is_a?(Sexp)
85
+ @shadow_args = []
86
+ args.children.each_with_index do |arg, idx|
87
+ if arg.type == :shadowarg
88
+ @shadow_args << args.delete(arg)
89
+ end
90
+ end
96
91
  end
97
92
  end
98
93
 
99
94
  def args
100
- if Fixnum === args_sexp or args_sexp.nil?
101
- s(:array)
102
- elsif args_sexp.type == :lasgn
103
- s(:array, args_sexp)
95
+ sexp = if Fixnum === args_sexp or args_sexp.nil?
96
+ s(:args)
97
+ elsif args_sexp.is_a?(Sexp) && args_sexp.type == :lasgn
98
+ s(:args, s(:arg, *args_sexp[1]))
104
99
  else
105
100
  args_sexp[1]
106
101
  end
102
+
103
+ # compacting _ arguments into a single one (only the first one leaves in the sexp)
104
+ caught_blank_argument = false
105
+
106
+ sexp.each_with_index do |part, idx|
107
+ if part.is_a?(Sexp) && part.last == :_
108
+ if caught_blank_argument
109
+ sexp.delete_at(idx)
110
+ end
111
+ caught_blank_argument = true
112
+ end
113
+ end
114
+
115
+ sexp
107
116
  end
108
117
 
109
118
  def body
110
119
  compiler.returns(body_sexp || s(:nil))
111
120
  end
112
121
 
113
- # Maps block args into array of jsid. Adds $ suffix to invalid js
114
- # identifiers.
115
- #
116
- # s(:args, parts...) => ["a", "b", "break$"]
117
- def args_to_params(sexp)
118
- result = []
119
- sexp.each do |arg|
120
- if arg[0] == :lasgn
121
- ref = variable(arg[1])
122
- next if ref == :_ && result.include?(ref)
123
- self.add_arg ref
124
- result << ref
125
- elsif arg[0] == :array
126
- result << scope.next_temp
127
- else
128
- raise "Bad js_block_arg: #{arg[0]}"
129
- end
130
- end
131
-
132
- result
122
+ def mlhs_args
123
+ scope.mlhs_mapping.keys
133
124
  end
134
125
  end
135
126
  end
@@ -40,8 +40,18 @@ module Opal
40
40
 
41
41
  def compile_iter
42
42
  error "break must be used as a statement" unless stmt?
43
- push expr_or_nil(value)
44
- wrap "return ($breaker.$v = ", ", $breaker)"
43
+ compiler.has_break!
44
+ line 'Opal.brk(', break_val, ', $brk)'
45
+ end
46
+
47
+ def break_val
48
+ if value.nil?
49
+ expr(s(:nil))
50
+ elsif children.size > 1
51
+ expr(s(:array, *children))
52
+ else
53
+ expr(value)
54
+ end
45
55
  end
46
56
  end
47
57
 
@@ -3,8 +3,7 @@ require 'opal/nodes/base'
3
3
  module Opal
4
4
  module Nodes
5
5
  class MassAssignNode < Base
6
- # TODO: does this work for cvars?? constants??
7
- SIMPLE_ASSIGNMENT = [:lasgn, :iasgn, :lvar, :gasgn]
6
+ SIMPLE_ASSIGNMENT = [:lasgn, :iasgn, :lvar, :gasgn, :cdecl]
8
7
 
9
8
  handle :masgn
10
9
  children :lhs, :rhs
@@ -0,0 +1,141 @@
1
+ require 'opal/nodes/scope'
2
+
3
+ module Opal
4
+ module Nodes
5
+ class NodeWithArgs < ScopeNode
6
+ attr_accessor :mlhs_args
7
+ attr_accessor :used_kwargs
8
+ attr_accessor :mlhs_mapping
9
+ attr_accessor :working_arguments
10
+ attr_writer :inline_args
11
+ attr_accessor :kwargs_initialized
12
+
13
+ attr_reader :inline_args, :post_args
14
+
15
+ def initialize(*)
16
+ super
17
+
18
+ @mlhs_args = {}
19
+ @used_kwargs = []
20
+ @mlhs_mapping = {}
21
+ @working_arguments = nil
22
+ @in_mlhs = false
23
+ @kwargs_initialized = false
24
+
25
+ @inline_args = []
26
+ @post_args = []
27
+
28
+ @post_args_started = false
29
+ end
30
+
31
+ def split_args
32
+ args = self.args[1..-1]
33
+ args.each_with_index do |arg, idx|
34
+ last_argument = (idx == args.length - 1)
35
+ case arg.type
36
+ when :arg, :mlhs, :kwarg, :kwoptarg, :kwrestarg
37
+ if @post_args_started
38
+ @post_args << arg
39
+ else
40
+ @inline_args << arg
41
+ end
42
+ when :restarg
43
+ @post_args_started = true
44
+ @post_args << arg
45
+ when :optarg
46
+ if args[idx, args.length].any? { |next_arg| next_arg.type != :optarg && next_arg.type != :restarg }
47
+ @post_args_started = true
48
+ end
49
+ # otherwise we have:
50
+ # a. ... + optarg + [optargs]
51
+ # b. ... + optarg + [optargs] + restarg
52
+ # and these cases are simple, we can handle args in inline mode
53
+
54
+ if @post_args_started
55
+ @post_args << arg
56
+ else
57
+ @inline_args << arg
58
+ end
59
+ end
60
+ end
61
+
62
+ inline_args.each do |inline_arg|
63
+ inline_arg.meta[:inline] = true
64
+ end
65
+
66
+ optimize_args!
67
+ end
68
+
69
+ def opt_args
70
+ @opt_args ||= args[1..-1].select { |arg| arg.first == :optarg }
71
+ end
72
+
73
+ def rest_arg
74
+ @rest_arg ||= args[1..-1].find { |arg| arg.first == :restarg }
75
+ end
76
+
77
+ def keyword_args
78
+ @keyword_args ||= args[1..-1].select do |arg|
79
+ [:kwarg, :kwoptarg, :kwrestarg].include? arg.first
80
+ end
81
+ end
82
+
83
+ def inline_args_sexp
84
+ s(:inline_args, *args[1..-1])
85
+ end
86
+
87
+ def post_args_sexp
88
+ s(:post_args, *post_args)
89
+ end
90
+
91
+ def compile_inline_args
92
+ inline_args.each do |inline_arg|
93
+ push process(inline_arg)
94
+ end
95
+ end
96
+
97
+ def compile_post_args
98
+ push process(post_args_sexp)
99
+ end
100
+
101
+ def compile_block_arg
102
+ if scope.uses_block?
103
+ scope_name = scope.identity
104
+ yielder = scope.block_name
105
+
106
+ add_temp "$iter = #{scope_name}.$$p"
107
+ add_temp "#{yielder} = $iter || nil"
108
+
109
+ line "#{scope_name}.$$p = null;"
110
+ end
111
+ end
112
+
113
+ def with_inline_args(args)
114
+ old_inline_args = inline_args
115
+ self.inline_args = args
116
+ yield
117
+ self.inline_args = old_inline_args
118
+ end
119
+
120
+ def in_mlhs
121
+ old_mlhs = @in_mlhs
122
+ @in_mlhs = true
123
+ yield
124
+ @in_mlhs = old_mlhs
125
+ end
126
+
127
+ def in_mlhs?
128
+ @in_mlhs
129
+ end
130
+
131
+ def optimize_args!
132
+ # Simple cases like def m(a,b,*rest) can be processed inline
133
+ if post_args.length == 1 && post_args.first.type == :restarg
134
+ rest_arg = post_args.pop
135
+ rest_arg.meta[:offset] = inline_args.length
136
+ inline_args << rest_arg
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end