opal 0.3.41 → 0.3.42

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 (285) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +14 -1
  4. data/Gemfile +2 -5
  5. data/Rakefile +41 -3
  6. data/bin/opal +33 -0
  7. data/lib/opal.rb +2 -12
  8. data/lib/opal/core_ext.rb +5 -0
  9. data/lib/opal/grammar.rb +2207 -2138
  10. data/lib/opal/grammar.y +21 -0
  11. data/lib/opal/grammar_helpers.rb +360 -0
  12. data/lib/opal/lexer.rb +55 -401
  13. data/lib/opal/lexer_scope.rb +28 -0
  14. data/lib/opal/parser.rb +155 -171
  15. data/lib/opal/target_scope.rb +257 -0
  16. data/lib/opal/version.rb +1 -1
  17. data/opal.gemspec +6 -2
  18. data/opal/opal-parser.js.erb +3 -2
  19. data/opal/opal.rb +20 -18
  20. data/opal/opal/array.rb +21 -12
  21. data/opal/opal/basic_object.rb +2 -1
  22. data/opal/opal/boolean.rb +3 -0
  23. data/opal/opal/browser_loader.js +57 -0
  24. data/opal/opal/class.rb +51 -13
  25. data/opal/opal/date.rb +1 -20
  26. data/opal/opal/enumerable.rb +66 -33
  27. data/opal/opal/error.rb +2 -0
  28. data/opal/opal/hash.rb +1 -1
  29. data/opal/opal/kernel.rb +14 -3
  30. data/opal/opal/nil_class.rb +4 -0
  31. data/opal/opal/proc.rb +9 -1
  32. data/opal/opal/racc.rb +2 -2
  33. data/opal/opal/regexp.rb +1 -1
  34. data/opal/opal/runtime.js +14 -4
  35. data/opal/opal/string.rb +21 -4
  36. data/opal/opal/time.rb +27 -0
  37. data/spec/core/array/allocate_spec.rb +7 -1
  38. data/spec/core/array/append_spec.rb +18 -3
  39. data/spec/core/array/array_spec.rb +7 -0
  40. data/spec/core/array/assoc_spec.rb +23 -8
  41. data/spec/core/array/at_spec.rb +23 -3
  42. data/spec/core/array/choice_spec.rb +20 -0
  43. data/spec/core/array/clear_spec.rb +45 -4
  44. data/spec/core/array/combination_spec.rb +55 -0
  45. data/spec/core/array/compact_spec.rb +72 -1
  46. data/spec/core/array/constructor_spec.rb +13 -2
  47. data/spec/core/array/count_spec.rb +15 -7
  48. data/spec/core/array/delete_at_spec.rb +44 -1
  49. data/spec/core/array/delete_if_spec.rb +52 -2
  50. data/spec/core/array/delete_spec.rb +83 -2
  51. data/spec/core/array/drop_spec.rb +24 -16
  52. data/spec/core/array/drop_while_spec.rb +17 -0
  53. data/spec/core/array/each_index_spec.rb +11 -1
  54. data/spec/core/array/each_spec.rb +20 -2
  55. data/spec/core/array/empty_spec.rb +4 -1
  56. data/spec/core/array/eql_spec.rb +14 -0
  57. data/spec/core/array/fetch_spec.rb +31 -2
  58. data/spec/core/array/find_index_spec.rb +8 -0
  59. data/spec/core/array/first_spec.rb +45 -8
  60. data/spec/core/array/fixtures/classes.rb +538 -0
  61. data/spec/core/array/flatten_spec.rb +200 -7
  62. data/spec/core/array/frozen_spec.rb +32 -0
  63. data/spec/core/array/include_spec.rb +16 -1
  64. data/spec/core/array/index_spec.rb +5 -25
  65. data/spec/core/array/insert_spec.rb +37 -3
  66. data/spec/core/array/inspect_spec.rb +6 -12
  67. data/spec/core/array/intersection_spec.rb +55 -4
  68. data/spec/core/array/join_spec.rb +29 -4
  69. data/spec/core/array/keep_if_spec.rb +13 -6
  70. data/spec/core/array/last_spec.rb +35 -1
  71. data/spec/core/array/length_spec.rb +7 -4
  72. data/spec/core/array/map_spec.rb +9 -47
  73. data/spec/core/array/minus_spec.rb +68 -4
  74. data/spec/core/array/multiply_spec.rb +138 -6
  75. data/spec/core/array/new_spec.rb +92 -3
  76. data/spec/core/array/ntimes_spec.rb +26 -0
  77. data/spec/core/array/plus_spec.rb +48 -2
  78. data/spec/core/array/pop_spec.rb +159 -39
  79. data/spec/core/array/push_spec.rb +29 -1
  80. data/spec/core/array/rassoc_spec.rb +31 -2
  81. data/spec/core/array/reject_spec.rb +89 -2
  82. data/spec/core/array/replace_spec.rb +7 -29
  83. data/spec/core/array/reverse_each_spec.rb +25 -1
  84. data/spec/core/array/reverse_spec.rb +53 -1
  85. data/spec/core/array/rindex_spec.rb +55 -5
  86. data/spec/core/array/select_spec.rb +35 -8
  87. data/spec/core/array/shared/collect.rb +0 -0
  88. data/spec/core/array/shared/enumeratorize.rb +12 -0
  89. data/spec/core/array/shared/eql.rb +95 -0
  90. data/spec/core/array/shared/index.rb +37 -0
  91. data/spec/core/array/shared/inspect.rb +3 -0
  92. data/spec/core/array/shared/join.rb +7 -0
  93. data/spec/core/array/shared/keep_if.rb +0 -0
  94. data/spec/core/array/shared/length.rb +0 -0
  95. data/spec/core/array/shared/replace.rb +0 -0
  96. data/spec/core/array/shared/slice.rb +0 -0
  97. data/spec/core/array/shift_spec.rb +132 -23
  98. data/spec/core/array/shuffle_spec.rb +82 -6
  99. data/spec/core/array/size_spec.rb +7 -4
  100. data/spec/core/array/slice_spec.rb +132 -1
  101. data/spec/core/array/sort_spec.rb +263 -14
  102. data/spec/core/array/take_spec.rb +24 -16
  103. data/spec/core/array/take_while_spec.rb +14 -10
  104. data/spec/core/array/to_a_spec.rb +18 -1
  105. data/spec/core/array/to_ary_spec.rb +15 -1
  106. data/spec/core/array/try_convert_spec.rb +39 -2
  107. data/spec/core/array/uniq_spec.rb +148 -3
  108. data/spec/core/array/unshift_spec.rb +36 -1
  109. data/spec/core/array/zip_spec.rb +36 -1
  110. data/spec/core/class/new_spec.rb +8 -6
  111. data/spec/core/enumerable/all_spec.rb +37 -9
  112. data/spec/core/enumerable/any_spec.rb +45 -7
  113. data/spec/core/enumerable/collect_spec.rb +4 -1
  114. data/spec/core/enumerable/count_spec.rb +4 -1
  115. data/spec/core/enumerable/detect_spec.rb +2 -2
  116. data/spec/core/enumerable/drop_spec.rb +4 -1
  117. data/spec/core/enumerable/drop_while_spec.rb +4 -1
  118. data/spec/core/enumerable/each_slice_spec.rb +2 -1
  119. data/spec/core/enumerable/each_with_index_spec.rb +4 -1
  120. data/spec/core/enumerable/each_with_object_spec.rb +4 -1
  121. data/spec/core/enumerable/entries_spec.rb +4 -1
  122. data/spec/core/enumerable/find_all_spec.rb +4 -1
  123. data/spec/core/enumerable/find_index_spec.rb +4 -1
  124. data/spec/core/enumerable/find_spec.rb +5 -2
  125. data/spec/core/enumerable/first_spec.rb +4 -1
  126. data/spec/core/enumerable/fixtures/classes.rb +198 -2
  127. data/spec/core/enumerable/grep_spec.rb +4 -1
  128. data/spec/core/enumerable/take_spec.rb +4 -1
  129. data/spec/core/enumerable/to_a_spec.rb +4 -1
  130. data/spec/core/false/and_spec.rb +11 -0
  131. data/spec/core/false/inspect_spec.rb +7 -0
  132. data/spec/core/false/or_spec.rb +11 -0
  133. data/spec/core/false/to_s_spec.rb +7 -0
  134. data/spec/core/false/xor_spec.rb +11 -0
  135. data/spec/core/kernel/rand_spec.rb +5 -5
  136. data/spec/core/module/const_get_spec.rb +4 -4
  137. data/spec/core/module/fixtures/classes.rb +434 -0
  138. data/spec/core/module/method_defined_spec.rb +49 -0
  139. data/spec/core/module/module_function_spec.rb +28 -0
  140. data/spec/core/nil/and_spec.rb +3 -1
  141. data/spec/core/nil/dup_spec.rb +7 -0
  142. data/spec/core/nil/inspect_spec.rb +3 -1
  143. data/spec/core/nil/nil_spec.rb +3 -1
  144. data/spec/core/nil/or_spec.rb +4 -2
  145. data/spec/core/nil/to_a_spec.rb +3 -1
  146. data/spec/core/nil/to_f_spec.rb +3 -1
  147. data/spec/core/nil/to_i_spec.rb +3 -1
  148. data/spec/core/nil/to_s_spec.rb +3 -1
  149. data/spec/core/nil/xor_spec.rb +4 -2
  150. data/spec/core/string/element_reference_spec.rb +14 -1
  151. data/spec/core/string/fixtures/classes.rb +0 -0
  152. data/spec/core/true/and_spec.rb +11 -0
  153. data/spec/core/true/inspect_spec.rb +7 -0
  154. data/spec/core/true/or_spec.rb +11 -0
  155. data/spec/core/true/to_s_spec.rb +7 -0
  156. data/spec/core/true/xor_spec.rb +11 -0
  157. data/spec/{core → core_ext}/array/element_reference_spec.rb +0 -0
  158. data/spec/{core → core_ext}/array/equal_value_spec.rb +0 -0
  159. data/spec/{core → core_ext}/array/fill_spec.rb +0 -0
  160. data/spec/{core → core_ext}/array/reduce_spec.rb +0 -0
  161. data/spec/core_ext/basic_object/send_spec.rb +3 -3
  162. data/spec/{core → core_ext}/boolean/singleton_class_spec.rb +0 -0
  163. data/spec/{core → core_ext}/boolean/to_json_spec.rb +0 -0
  164. data/spec/core_ext/class/_inherited_spec.rb +3 -3
  165. data/spec/core_ext/class/proc_methods_spec.rb +2 -2
  166. data/spec/core_ext/class/singleton_methods_spec.rb +8 -8
  167. data/spec/core_ext/method_missing_spec.rb +3 -3
  168. data/spec/core_ext/native/method_missing_spec.rb +3 -2
  169. data/spec/core_ext/native/to_native_spec.rb +3 -2
  170. data/spec/{core → core_ext}/nil/to_json_spec.rb +0 -0
  171. data/spec/date.rb +0 -0
  172. data/spec/fileutils.rb +0 -0
  173. data/spec/filters/ancestors.rb +4 -0
  174. data/spec/filters/array_delete.rb +3 -0
  175. data/spec/filters/array_fetch.rb +3 -0
  176. data/spec/filters/array_first.rb +3 -0
  177. data/spec/filters/array_flatten.rb +14 -0
  178. data/spec/filters/array_intersection.rb +5 -0
  179. data/spec/filters/array_join.rb +6 -0
  180. data/spec/filters/array_subclasses.rb +4 -0
  181. data/spec/filters/block_args.rb +3 -0
  182. data/spec/filters/coerce_integer.rb +9 -0
  183. data/spec/filters/frozen.rb +4 -0
  184. data/spec/filters/mocks.rb +3 -0
  185. data/spec/filters/should_receive.rb +4 -0
  186. data/spec/filters/tainted.rb +7 -0
  187. data/spec/fixtures/class.rb +124 -0
  188. data/spec/fixtures/class_variables.rb +0 -0
  189. data/spec/fixtures/constants.rb +0 -0
  190. data/spec/grammar/alias_spec.rb +1 -1
  191. data/spec/grammar/def_spec.rb +1 -0
  192. data/spec/grammar/lvar_spec.rb +1 -2
  193. data/spec/grammar/nth_ref_spec.rb +13 -0
  194. data/spec/grammar/sclass_spec.rb +6 -7
  195. data/spec/grammar/str_spec.rb +4 -4
  196. data/spec/grammar/string_spec.rb +8 -0
  197. data/spec/grammar/xstr_spec.rb +4 -4
  198. data/spec/iconv.rb +0 -0
  199. data/spec/language/alias_spec.rb +140 -3
  200. data/spec/language/and_spec.rb +14 -7
  201. data/spec/language/array_spec.rb +57 -5
  202. data/spec/language/block_spec.rb +466 -49
  203. data/spec/language/break_spec.rb +294 -44
  204. data/spec/language/case_spec.rb +151 -3
  205. data/spec/language/class_spec.rb +196 -0
  206. data/spec/language/class_variable_spec.rb +56 -0
  207. data/spec/language/def_spec.rb +507 -4
  208. data/spec/language/defined_spec.rb +19 -7
  209. data/spec/language/ensure_spec.rb +26 -39
  210. data/spec/language/execution_spec.rb +15 -0
  211. data/spec/language/fixtures/array.rb +11 -0
  212. data/spec/language/fixtures/block.rb +57 -0
  213. data/spec/language/fixtures/break.rb +240 -0
  214. data/spec/language/fixtures/ensure.rb +72 -0
  215. data/spec/language/fixtures/literal_lambda.rb +7 -0
  216. data/spec/language/fixtures/metaclass.rb +33 -0
  217. data/spec/language/fixtures/module.rb +24 -0
  218. data/spec/language/fixtures/next.rb +78 -12
  219. data/spec/language/fixtures/return.rb +118 -0
  220. data/spec/language/fixtures/send.rb +110 -0
  221. data/spec/language/fixtures/send_1.9.rb +22 -0
  222. data/spec/language/fixtures/super.rb +308 -0
  223. data/spec/language/fixtures/variables.rb +58 -0
  224. data/spec/language/fixtures/yield.rb +5 -0
  225. data/spec/language/for_spec.rb +192 -0
  226. data/spec/language/hash_spec.rb +29 -5
  227. data/spec/language/if_spec.rb +90 -9
  228. data/spec/language/literal_lambda_spec.rb +1 -47
  229. data/spec/language/loop_spec.rb +39 -2
  230. data/spec/language/metaclass_spec.rb +151 -5
  231. data/spec/language/module_spec.rb +56 -0
  232. data/spec/language/next_spec.rb +370 -12
  233. data/spec/language/not_spec.rb +55 -0
  234. data/spec/language/numbers_spec.rb +56 -0
  235. data/spec/language/or_spec.rb +31 -3
  236. data/spec/language/order_spec.rb +79 -0
  237. data/spec/language/precedence_spec.rb +483 -0
  238. data/spec/language/proc_spec.rb +249 -21
  239. data/spec/language/redo_spec.rb +67 -0
  240. data/spec/language/rescue_spec.rb +121 -0
  241. data/spec/language/retry_spec.rb +56 -0
  242. data/spec/language/return_spec.rb +281 -0
  243. data/spec/language/send_spec.rb +141 -48
  244. data/spec/language/singleton_class_spec.rb +1 -1
  245. data/spec/language/string_spec.rb +11 -0
  246. data/spec/language/super_spec.rb +213 -133
  247. data/spec/language/symbol_spec.rb +2 -1
  248. data/spec/language/undef_spec.rb +3 -1
  249. data/spec/language/unless_spec.rb +6 -2
  250. data/spec/language/until_spec.rb +102 -3
  251. data/spec/language/variables_spec.rb +1212 -16
  252. data/spec/language/versions/array_1.9.rb +39 -0
  253. data/spec/language/versions/case_1.9.rb +20 -0
  254. data/spec/language/versions/hash_1.9.rb +18 -0
  255. data/spec/language/versions/literal_lambda_1.9.rb +143 -0
  256. data/spec/language/versions/not_1.9.rb +22 -0
  257. data/spec/language/versions/send_1.9.rb +241 -0
  258. data/spec/language/versions/symbol_1.9.rb +15 -0
  259. data/spec/language/versions/variables_1.9.rb +8 -0
  260. data/spec/language/while_spec.rb +70 -5
  261. data/spec/language/yield_spec.rb +32 -6
  262. data/spec/mspec/guards/block_device.rb +0 -0
  263. data/spec/mspec/guards/endian.rb +0 -0
  264. data/spec/mspec/helpers/environment.rb +0 -0
  265. data/spec/mspec/helpers/language_version.rb +0 -0
  266. data/spec/mspec/helpers/tmp.rb +0 -0
  267. data/spec/ospec/filter.rb +32 -0
  268. data/spec/ospec/main.rb.erb +18 -0
  269. data/spec/ospec/phantom.rb +97 -0
  270. data/spec/ospec/runner.rb +95 -0
  271. data/spec/ospec/sprockets.js +40 -0
  272. data/spec/pp.rb +3 -0
  273. data/spec/rbconfig.rb +5 -0
  274. data/spec/spec_helper.rb +53 -26
  275. data/spec/yaml.rb +0 -0
  276. metadata +275 -31
  277. data/config.ru +0 -8
  278. data/lib/opal/processor.rb +0 -47
  279. data/lib/opal/scope.rb +0 -236
  280. data/lib/opal/server.rb +0 -94
  281. data/spec/core/boolean/and_spec.rb +0 -17
  282. data/spec/core/boolean/inspect_spec.rb +0 -9
  283. data/spec/core/boolean/or_spec.rb +0 -17
  284. data/spec/core/boolean/to_s_spec.rb +0 -9
  285. data/spec/core/boolean/xor_spec.rb +0 -17
@@ -0,0 +1,28 @@
1
+ module Opal
2
+ # LexerScope is used during lexing to keep track of local variables
3
+ # created inside a scope. A lexer scope can be asked if it has a local
4
+ # variable defined, and it can also check its parent scope if applicable.
5
+ #
6
+ # A LexerScope is created automatically as a new scope is entered during
7
+ # the lexing stage.
8
+ class LexerScope
9
+ attr_reader :locals
10
+ attr_accessor :parent
11
+
12
+ def initialize(type)
13
+ @block = type == :block
14
+ @locals = []
15
+ @parent = nil
16
+ end
17
+
18
+ def add_local(local)
19
+ @locals << local
20
+ end
21
+
22
+ def has_local?(local)
23
+ return true if @locals.include? local
24
+ return @parent.has_local?(local) if @parent and @block
25
+ false
26
+ end
27
+ end
28
+ end
data/lib/opal/parser.rb CHANGED
@@ -1,45 +1,10 @@
1
1
  require 'opal/lexer'
2
2
  require 'opal/grammar'
3
- require 'opal/scope'
3
+ require 'opal/target_scope'
4
4
 
5
5
  module Opal
6
- # This class is used to generate the javascript code from the given
7
- # ruby code. First, this class will use an instance of `Opal::Grammar`
8
- # to lex and then build up a tree of sexp statements. Once done, the
9
- # top level sexp is passed into `#top` which recursively generates
10
- # javascript for each sexp inside, and the result is returned as a
11
- # string.
12
- #
13
- # p = Opal::Parser.new
14
- # p.parse "puts 42"
15
- # # => "(function() { ... })()"
16
- #
17
- # ## Sexps
18
- #
19
- # A sexp, in opal, is an array where the first value is a symbol
20
- # identifying the type of sexp. A simple ruby string "hello" would
21
- # be represented by the sexp:
22
- #
23
- # s(:str, "hello")
24
- #
25
- # Once that sexp is encounterd by the parser, it is handled by
26
- # `#process` which removes the sexp type from the array, and checks
27
- # for a method "process_str", which is used to handle specific sexps.
28
- # Once found, that method is called with the sexp and level as
29
- # arguments, and the returned string is the javascript to be used in
30
- # the resulting file.
31
- #
32
- # ## Levels
33
- #
34
- # A level inside the parser is just a symbol representing what type
35
- # of destination the code to be generated is for. For example, the
36
- # main two levels are `:stmt` and `:expr`. Most sexps generate the
37
- # same code for every level, but an `if` statement for example
38
- # will change when written as an expression. Javascript cannot have
39
- # if statements as expressions, so that sexp would wrap its result
40
- # inside an anonymous function so the if statement can compile as
41
- # expected.
42
6
  class Parser
7
+
43
8
  # Generated code gets indented with two spaces on each scope
44
9
  INDENT = ' '
45
10
 
@@ -63,28 +28,14 @@ module Opal
63
28
  # Statements which should not have ';' added to them.
64
29
  STATEMENTS = [:xstr, :dxstr]
65
30
 
66
- # The grammar (tree of sexps) representing this compiled code
67
- # @return [Opal::Grammar]
68
- attr_reader :grammar
69
-
70
31
  # Holds an array of paths which this file "requires".
71
32
  # @return [Array<String>]
72
33
  attr_reader :requires
73
34
 
74
- # This does the actual parsing. The ruby code given is first
75
- # run through a `Grammar` instance which returns a sexp to
76
- # process. This is then handled recursively, resulting in a
77
- # string of javascript being returned.
78
- #
79
- # p = Opal::Parser.new
80
- # p.parse "puts 'hey'"
81
- # # => "(function() { .... })()"
82
- #
83
- # @param [String] source the ruby code to parse
84
- # @param [String] file the filename representing this code
85
- # @return [String] string of javascript code
35
+ attr_reader :result
36
+
86
37
  def parse(source, options = {})
87
- @grammar = Grammar.new
38
+ @sexp = Grammar.new.parse(source, options[:file])
88
39
  @requires = []
89
40
  @line = 1
90
41
  @indent = ''
@@ -100,8 +51,9 @@ module Opal
100
51
  @method_missing = (options[:method_missing] != false)
101
52
  @optimized_operators = (options[:optimized_operators] != false)
102
53
  @arity_check = options[:arity_check]
54
+ @const_missing = (options[:const_missing] != false)
103
55
 
104
- top @grammar.parse(source, @file)
56
+ @result = top(@sexp)
105
57
  end
106
58
 
107
59
  # This is called when a parsing/processing error occurs. This
@@ -113,7 +65,7 @@ module Opal
113
65
  #
114
66
  # @param [String] msg error message to raise
115
67
  def error(msg)
116
- raise "#{msg} :#{@file}:#{@line}"
68
+ raise SyntaxError, "#{msg} :#{@file}:#{@line}"
117
69
  end
118
70
 
119
71
  # Instances of `Scope` can use this to determine the current
@@ -177,7 +129,6 @@ module Opal
177
129
  # @return [String]
178
130
  def top(sexp, options = {})
179
131
  code = nil
180
- vars = []
181
132
 
182
133
  in_scope(:top) do
183
134
  indent {
@@ -221,7 +172,7 @@ module Opal
221
172
  return unless block_given?
222
173
 
223
174
  parent = @scope
224
- @scope = Scope.new(type, self).tap { |s| s.parent = parent }
175
+ @scope = TargetScope.new(type, self).tap { |s| s.parent = parent }
225
176
  yield @scope
226
177
 
227
178
  @scope = parent
@@ -608,8 +559,13 @@ module Opal
608
559
  "(#{recv}#{mid} ? 'method' : nil)"
609
560
  when :xstr
610
561
  "(typeof(#{process part, :expression}) !== 'undefined')"
562
+ when :const
563
+ "(__scope.#{part[1].to_s} != null)"
611
564
  when :colon2
612
565
  "false"
566
+ when :ivar
567
+ ivar_name = part[1].to_s[1..-1]
568
+ "(#{current_self}[#{ivar_name.inspect}] != null ? 'instance-variable' : 'nil')"
613
569
  else
614
570
  raise "bad defined? part: #{part[0]}"
615
571
  end
@@ -676,8 +632,6 @@ module Opal
676
632
  @scope.add_temp block_arg
677
633
  @scope.add_temp '__context'
678
634
  scope_name = @scope.identify!
679
- # @scope.add_arg block_arg
680
- # code += "var #{block_arg} = _$ || nil, $context = #{block_arg}.$S;"
681
635
  blk = "\n%s%s = %s._p || nil, __context = %s._s, %s.p = null;\n%s" %
682
636
  [@indent, block_arg, scope_name, block_arg, scope_name, @indent]
683
637
 
@@ -695,7 +649,7 @@ module Opal
695
649
  end
696
650
 
697
651
  itercode = "function(#{params.join ', '}) {\n#{code}\n#@indent}"
698
- call[3] << s(:js_tmp, "(%s = %s, %s._s = %s, %s)" % [identity, itercode, identity, current_self, identity])
652
+ call << ("(%s = %s, %s._s = %s, %s)" % [identity, itercode, identity, current_self, identity])
699
653
 
700
654
  process call, level
701
655
  end
@@ -714,11 +668,8 @@ module Opal
714
668
  #
715
669
  # s(recv, :mid=, s(:arglist, rhs))
716
670
  def process_attrasgn(exp, level)
717
- recv = exp[0]
718
- mid = exp[1]
719
- arglist = exp[2]
720
-
721
- return process(s(:call, recv, mid, arglist), level)
671
+ recv, mid, arglist = exp
672
+ process s(:call, recv, mid, arglist), level
722
673
  end
723
674
 
724
675
  # Used to generate optimized attr_reader, attr_writer and
@@ -784,13 +735,7 @@ module Opal
784
735
  when :alias_native
785
736
  return handle_alias_native(sexp) if @scope.class_scope?
786
737
  when :require
787
- path = arglist[1]
788
-
789
- if path and path[0] == :str
790
- @requires << path[1]
791
- end
792
-
793
- return ""
738
+ return handle_require arglist[1]
794
739
  when :respond_to?
795
740
  return handle_respond_to(sexp, level)
796
741
  end
@@ -798,21 +743,18 @@ module Opal
798
743
  splat = arglist[1..-1].any? { |a| a.first == :splat }
799
744
 
800
745
  if Array === arglist.last and arglist.last.first == :block_pass
801
- arglist << s(:js_tmp, process(arglist.pop, :expr))
746
+ block = process s(:js_tmp, process(arglist.pop, :expr)), :expr
802
747
  elsif iter
803
- block = iter
748
+ block = iter
804
749
  end
805
750
 
806
751
  recv ||= s(:self)
807
752
 
808
753
  if block
809
- tmprecv = @scope.new_temp
810
- elsif splat and recv != [:self] and recv[0] != :lvar
811
- tmprecv = @scope.new_temp
812
- else # method_missing
813
- tmprecv = @scope.new_temp
754
+ tmpfunc = @scope.new_temp
814
755
  end
815
756
 
757
+ tmprecv = @scope.new_temp
816
758
  args = ""
817
759
 
818
760
  recv_code = process recv, :recv
@@ -822,10 +764,10 @@ module Opal
822
764
  arglist.insert 1, call_recv unless splat
823
765
  args = process arglist, :expr
824
766
 
825
- dispatch = if tmprecv
826
- "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{ meth.to_s }'))"
827
- else
828
- "(#{recv_code}#{mid} || $mm('#{ meth.to_s }'))"
767
+ dispatch = "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{ meth.to_s }'))"
768
+
769
+ if tmpfunc
770
+ dispatch = "(#{tmpfunc} = #{dispatch}, #{tmpfunc}._p = #{block}, #{tmpfunc})"
829
771
  end
830
772
 
831
773
  result = if splat
@@ -839,10 +781,53 @@ module Opal
839
781
  result = splat ? "#{dispatch}.apply(#{tmprecv || recv_code}, #{args})" : "#{dispatch}(#{args})"
840
782
  end
841
783
 
842
- @scope.queue_temp tmprecv if tmprecv
784
+ @scope.queue_temp tmpfunc if tmpfunc
843
785
  result
844
786
  end
845
787
 
788
+ def handle_require(sexp)
789
+ str = handle_require_sexp sexp
790
+ @requires << str
791
+ ""
792
+ end
793
+
794
+ def handle_require_sexp(sexp)
795
+ type = sexp.shift
796
+
797
+ if type == :str
798
+ return sexp[0]
799
+ elsif type == :call
800
+ recv, meth, args = sexp
801
+ parts = args[1..-1].map { |s| handle_require_sexp s }
802
+
803
+ if recv == [:const, :File]
804
+ if meth == :expand_path
805
+ return handle_expand_path(*parts)
806
+ elsif meth == :join
807
+ return handle_expand_path parts.join("/")
808
+ elsif meth == :dirname
809
+ return handle_expand_path parts[0].split("/")[0...-1].join("/")
810
+ end
811
+ end
812
+ end
813
+
814
+ error "Cannot handle dynamic require"
815
+ end
816
+
817
+ def handle_expand_path(path, base = '')
818
+ "#{base}/#{path}".split("/").inject([]) do |path, part|
819
+ if part == ''
820
+ # we had '//', so ignore
821
+ elsif part == '..'
822
+ path.pop
823
+ else
824
+ path << part
825
+ end
826
+
827
+ path
828
+ end.join "/"
829
+ end
830
+
846
831
  # s(:arglist, [arg [, arg ..]])
847
832
  def process_arglist(sexp, level)
848
833
  code = ''
@@ -997,31 +982,24 @@ module Opal
997
982
  "(function(__base){#{spacer}#{cls}#{spacer}#{boot}\n#{code}\n#{@indent}})(#{base})"
998
983
  end
999
984
 
1000
- def process_undef(exp, level)
1001
- @helpers[:undef] = true
1002
- jsid = mid_to_jsid exp[0][1].to_s
1003
985
 
1004
- # "__undef(this, #{jsid.inspect})"
1005
- # FIXME: maybe add this to donate(). it will be undefined, so
1006
- # when added to includees it will actually undefine methods there
1007
- # too.
1008
- "delete #{ @scope.proto }#{jsid}"
986
+ # undef :foo
987
+ # => delete MyClass.prototype.$foo
988
+ def process_undef(sexp, level)
989
+ "delete #{ @scope.proto }#{ mid_to_jsid sexp[0][1].to_s }"
1009
990
  end
1010
991
 
1011
992
  # s(:defn, mid, s(:args), s(:scope))
1012
993
  def process_defn(sexp, level)
1013
- mid = sexp[0]
1014
- args = sexp[1]
1015
- stmts = sexp[2]
994
+ mid, args, stmts = sexp
995
+
1016
996
  js_def nil, mid, args, stmts, sexp.line, sexp.end_line
1017
997
  end
1018
998
 
1019
999
  # s(:defs, recv, mid, s(:args), s(:scope))
1020
1000
  def process_defs(sexp, level)
1021
- recv = sexp[0]
1022
- mid = sexp[1]
1023
- args = sexp[2]
1024
- stmts = sexp[3]
1001
+ recv, mid, args, stmts = sexp
1002
+
1025
1003
  js_def recv, mid, args, stmts, sexp.line, sexp.end_line
1026
1004
  end
1027
1005
 
@@ -1058,7 +1036,6 @@ module Opal
1058
1036
  if args.last.to_s.start_with? '*'
1059
1037
  uses_splat = true
1060
1038
  if args.last == :*
1061
- #args[-1] = splat
1062
1039
  argc -= 1
1063
1040
  else
1064
1041
  splat = args[-1].to_s[1..-1].to_sym
@@ -1067,8 +1044,6 @@ module Opal
1067
1044
  end
1068
1045
  end
1069
1046
 
1070
- args << block_name if block_name # have to re-add incase there was a splat arg
1071
-
1072
1047
  if @arity_check
1073
1048
  arity_code = arity_check(args, opt, uses_splat, block_name, mid) + "\n#{INDENT}"
1074
1049
  end
@@ -1088,55 +1063,24 @@ module Opal
1088
1063
  params = process args, :expr
1089
1064
  stmt_code = "\n#@indent" + process(stmts, :stmt)
1090
1065
 
1091
- if @scope.uses_block?
1092
- # CASE 1: no args - only the block
1093
- if argc == 0 and !splat
1094
- # add param name as a function param, to make it cleaner
1095
- # params = yielder
1096
- code += "if (typeof(#{yielder}) !== 'function') { #{yielder} = nil }"
1097
- # CASE 2: we have a splat - use argc to get splat args, then check last one
1098
- elsif splat
1099
- @scope.add_temp yielder
1100
- code += "#{splat} = __slice.call(arguments, #{argc});\n#{@indent}"
1101
- code += "if (typeof(#{splat}[#{splat}.length - 1]) === 'function') { #{yielder} = #{splat}.pop(); } else { #{yielder} = nil; }\n#{@indent}"
1102
- # CASE 3: we have some opt args
1103
- elsif opt
1104
- code += "var BLOCK_IDX = arguments.length - 1;\n#{@indent}"
1105
- code += "if (typeof(arguments[BLOCK_IDX]) === 'function' && arguments[BLOCK_IDX]._s !== undefined) { #{yielder} = arguments[BLOCK_IDX] } else { #{yielder} = nil }"
1106
- lastopt = opt[-1][1]
1107
- opt[1..-1].each do |o|
1108
- id = process s(:lvar, o[1]), :expr
1109
- if o[2][2] == :undefined
1110
- code += ("if (%s === %s && typeof(%s) === 'function') { %s = undefined; }" % [id, yielder, id, id])
1111
- else
1112
- code += ("if (%s == null || %s === %s) {\n%s%s\n%s}" %
1113
- [id, id, yielder, @indent + INDENT, process(o, :expre), @indent])
1114
- end
1115
- end
1116
-
1117
- # CASE 4: normal args and block
1118
- else
1119
- code += "if (typeof(#{yielder}) !== 'function') { #{yielder} = nil }"
1120
- end
1121
- else
1122
- opt[1..-1].each do |o|
1123
- next if o[2][2] == :undefined
1124
- id = process s(:lvar, o[1]), :expr
1125
- code += ("if (%s == null) {\n%s%s\n%s}" %
1066
+ opt[1..-1].each do |o|
1067
+ next if o[2][2] == :undefined
1068
+ id = process s(:lvar, o[1]), :expr
1069
+ code += ("if (%s == null) {\n%s%s\n%s}" %
1126
1070
  [id, @indent + INDENT, process(o, :expre), @indent])
1127
- end if opt
1071
+ end if opt
1128
1072
 
1129
- code += "#{splat} = __slice.call(arguments, #{argc});" if splat
1130
- end
1073
+ code += "#{splat} = __slice.call(arguments, #{argc});" if splat
1131
1074
 
1132
- code += stmt_code
1075
+ scope_name = @scope.identity
1133
1076
 
1134
- if @scope.uses_block? and !block_name
1135
- params = params.empty? ? yielder : "#{params}, #{yielder}"
1077
+ if @scope.uses_block?
1078
+ @scope.add_temp yielder
1079
+ blk = "\n%s%s = %s._p || nil, %s._p = null;\n%s" % [@indent, yielder, scope_name, scope_name, @indent]
1136
1080
  end
1137
1081
 
1138
- # Returns the identity name if identified, nil otherwise
1139
- scope_name = @scope.identity
1082
+ code += stmt_code
1083
+ code = "#{blk}#{code}"
1140
1084
 
1141
1085
  uses_super = @scope.uses_super
1142
1086
 
@@ -1152,6 +1096,8 @@ module Opal
1152
1096
  else
1153
1097
  "#{ recv }#{ jsid } = #{ defcode }"
1154
1098
  end
1099
+ elsif @scope.class? and @scope.name == 'Object'
1100
+ "#{current_self}._defn('$#{mid}', #{defcode})"
1155
1101
  elsif @scope.class_scope?
1156
1102
  @scope.methods << "$#{mid}"
1157
1103
  if uses_super
@@ -1159,6 +1105,8 @@ module Opal
1159
1105
  uses_super = "#{uses_super} = #{@scope.proto}#{jsid};\n#@indent"
1160
1106
  end
1161
1107
  "#{uses_super}#{ @scope.proto }#{jsid} = #{defcode}"
1108
+ # elsif @scope.sclass?
1109
+ # "#{ current_self }._defs('$#{mid}', #{defcode})"
1162
1110
  elsif @scope.type == :iter
1163
1111
  "def#{jsid} = #{defcode}"
1164
1112
  elsif @scope.type == :top
@@ -1176,7 +1124,6 @@ module Opal
1176
1124
  arity = args.size - 1
1177
1125
  arity -= (opt.size - 1) if opt
1178
1126
  arity -= 1 if splat
1179
- arity -= 1 if block_name
1180
1127
  arity = -arity - 1 if opt or splat
1181
1128
 
1182
1129
  # $arity will point to our received arguments count
@@ -1185,7 +1132,7 @@ module Opal
1185
1132
  if arity < 0 # splat or opt args
1186
1133
  aritycode + "if ($arity < #{-(arity + 1)}) { __opal.ac($arity, #{arity}, this, #{meth}); }"
1187
1134
  else
1188
- aritycode + "if ($arity !== #{arity} && (typeof(arguments[$arity - 1]) !== 'function' || ($arity - 1) !== #{arity})) { __opal.ac($arity, #{arity}, this, #{meth}); }"
1135
+ aritycode + "if ($arity !== #{arity}) { __opal.ac($arity, #{arity}, this, #{meth}); }"
1189
1136
  end
1190
1137
  end
1191
1138
 
@@ -1214,13 +1161,9 @@ module Opal
1214
1161
  def current_self
1215
1162
  if @scope.class_scope?
1216
1163
  @scope.name
1217
- elsif @scope.top?
1164
+ elsif @scope.top? or @scope.iter?
1218
1165
  'self'
1219
- elsif @scope.top?
1220
- 'self'
1221
- elsif @scope.iter?
1222
- 'self'
1223
- else # def
1166
+ else # defn, defs
1224
1167
  'this'
1225
1168
  end
1226
1169
  end
@@ -1301,9 +1244,9 @@ module Opal
1301
1244
 
1302
1245
  # s(:while, exp, block, true)
1303
1246
  def process_while(sexp, level)
1304
- expr = sexp[0]
1305
- stmt = sexp[1]
1247
+ expr, stmt = sexp
1306
1248
  redo_var = @scope.new_temp
1249
+
1307
1250
  stmt_level = if level == :expr or level == :recv
1308
1251
  :stmt_closure
1309
1252
  else
@@ -1471,6 +1414,10 @@ module Opal
1471
1414
  @helpers['gvars'] = true
1472
1415
  "__gvars[#{gvar.inspect}]"
1473
1416
  end
1417
+
1418
+ def process_nth_ref(sexp, level)
1419
+ "nil"
1420
+ end
1474
1421
 
1475
1422
  # s(:gasgn, :gvar, rhs)
1476
1423
  def process_gasgn(sexp, level)
@@ -1491,8 +1438,7 @@ module Opal
1491
1438
 
1492
1439
  # s(:cdecl, :const, rhs)
1493
1440
  def process_cdecl(sexp, level)
1494
- const = sexp[0]
1495
- rhs = sexp[1]
1441
+ const, rhs = sexp
1496
1442
  "__scope.#{const} = #{process rhs, :expr}"
1497
1443
  end
1498
1444
 
@@ -1500,7 +1446,7 @@ module Opal
1500
1446
  def process_return(sexp, level)
1501
1447
  val = process(sexp.shift || s(:nil), :expr)
1502
1448
 
1503
- raise "Cannot return as an expression" unless level == :stmt
1449
+ raise SyntaxError, "void value expression: cannot return as an expression" unless level == :stmt
1504
1450
  "return #{val}"
1505
1451
  end
1506
1452
 
@@ -1634,8 +1580,7 @@ module Opal
1634
1580
 
1635
1581
  # s(:and, lhs, rhs)
1636
1582
  def process_and(sexp, level)
1637
- lhs = sexp[0]
1638
- rhs = sexp[1]
1583
+ lhs, rhs = sexp
1639
1584
  t = nil
1640
1585
  tmp = @scope.new_temp
1641
1586
 
@@ -1702,12 +1647,12 @@ module Opal
1702
1647
  @scope.uses_block!
1703
1648
 
1704
1649
  splat = sexp.any? { |s| s.first == :splat }
1705
- # sexp.unshift s(:js_tmp, '__context') unless splat # self
1650
+ sexp.unshift s(:js_tmp, 'null') unless splat # self
1706
1651
  args = process_arglist sexp, level
1707
1652
 
1708
1653
  y = @scope.block_name || '__yield'
1709
1654
 
1710
- splat ? "#{y}.apply(null, #{args})" : "#{y}(#{args})"
1655
+ splat ? "#{y}.apply(null, #{args})" : "#{y}.call(#{args})"
1711
1656
  end
1712
1657
 
1713
1658
  def process_break(exp, level)
@@ -1718,7 +1663,7 @@ module Opal
1718
1663
  error "break must be used as a statement" unless level == :stmt
1719
1664
  "return (__breaker.$v = #{ val }, __breaker)"
1720
1665
  else
1721
- error "cannot use break outside of iter/while"
1666
+ error "void value expression: cannot use break outside of iter/while"
1722
1667
  end
1723
1668
  end
1724
1669
 
@@ -1864,7 +1809,7 @@ module Opal
1864
1809
 
1865
1810
  elsif @scope.type == :def
1866
1811
  identity = @scope.identify!
1867
- cls_name = @scope.parent.name
1812
+ cls_name = @scope.parent.name || "#{current_self}._klass.prototype"
1868
1813
  jsid = mid_to_jsid @scope.mid.to_s
1869
1814
 
1870
1815
  if @scope.defs
@@ -1889,8 +1834,31 @@ module Opal
1889
1834
  process s(:or, exp.shift, exp.shift), :expr
1890
1835
  end
1891
1836
 
1837
+ # a &&= rhs
1838
+ #
1839
+ # s(:op_asgn_and, s(:lvar, :a), s(:lasgn, :a, rhs))
1840
+ def process_op_asgn_and(sexp, level)
1841
+ process s(:and, sexp.shift, sexp.shift), :expr
1842
+ end
1843
+
1844
+ # lhs[args] ||= rhs
1845
+ #
1846
+ # s(:op_asgn1, lhs, args, :||, rhs)
1892
1847
  def process_op_asgn1(sexp, level)
1893
- "'FIXME(op_asgn1)'"
1848
+ lhs, arglist, op, rhs = sexp
1849
+
1850
+ with_temp do |a| # args
1851
+ with_temp do |r| # recv
1852
+ args = process arglist[1], :expr
1853
+ recv = process lhs, :expr
1854
+
1855
+ aref = s(:call, s(:js_tmp, r), :[], s(:arglist, s(:js_tmp, a)))
1856
+ aset = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs))
1857
+ orop = s(:or, aref, aset)
1858
+
1859
+ "(#{a} = #{args}, #{r} = #{recv}, #{process orop, :expr})"
1860
+ end
1861
+ end
1894
1862
  end
1895
1863
 
1896
1864
  # lhs.b += rhs
@@ -1903,7 +1871,21 @@ module Opal
1903
1871
  rhs = exp.shift
1904
1872
 
1905
1873
  if op.to_s == "||"
1906
- raise "op_asgn2 for ||"
1874
+ with_temp do |temp|
1875
+ getr = s(:call, s(:js_tmp, temp), mid, s(:arglist))
1876
+ asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
1877
+ orop = s(:or, getr, asgn)
1878
+
1879
+ "(#{temp} = #{lhs}, #{process orop, :expr})"
1880
+ end
1881
+ elsif op.to_s == '&&'
1882
+ with_temp do |temp|
1883
+ getr = s(:call, s(:js_tmp, temp), mid, s(:arglist))
1884
+ asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
1885
+ andop = s(:and, getr, asgn)
1886
+
1887
+ "(#{temp} = #{lhs}, #{process andop, :expr})"
1888
+ end
1907
1889
  else
1908
1890
  with_temp do |temp|
1909
1891
  getr = s(:call, s(:js_tmp, temp), mid, s(:arglist))
@@ -1936,15 +1918,17 @@ module Opal
1936
1918
  def process_rescue(exp, level)
1937
1919
  body = exp.first.first == :resbody ? s(:nil) : exp.shift
1938
1920
  body = indent { process body, level }
1921
+ handled_else = false
1939
1922
 
1940
1923
  parts = []
1941
1924
  until exp.empty?
1925
+ handled_else = true unless exp.first.first == :resbody
1942
1926
  part = indent { process exp.shift, level }
1943
1927
  part = "else " + part unless parts.empty?
1944
1928
  parts << part
1945
1929
  end
1946
1930
  # if no rescue statement captures our error, we should rethrow
1947
- parts << indent { "else { throw $err; }" }
1931
+ parts << indent { "else { throw $err; }" } unless handled_else
1948
1932
 
1949
1933
  code = "try {#@space#{INDENT}#{body}#@space} catch ($err) {#@space#{parts.join @space}#{@space}}"
1950
1934
  code = "(function() { #{code} }).call(#{current_self})" if level == :expr
@@ -1957,7 +1941,8 @@ module Opal
1957
1941
  body = exp[1]
1958
1942
 
1959
1943
  body = process(body || s(:nil), level)
1960
- types = args[1..-2]
1944
+ types = args[1..-1]
1945
+ types.pop if types.last and types.last.first != :const
1961
1946
 
1962
1947
  err = types.map { |t|
1963
1948
  call = s(:call, t, :===, s(:arglist, s(:js_tmp, "$err")))
@@ -1981,11 +1966,10 @@ module Opal
1981
1966
  end
1982
1967
 
1983
1968
  def process_next(exp, level)
1984
- val = exp.empty? ? 'nil' : process(exp.shift, :expr)
1985
1969
  if in_while?
1986
1970
  "continue;"
1987
1971
  else
1988
- "return #{val};"
1972
+ "return #{ exp.empty? ? 'nil' : process(exp.shift, :expr) };"
1989
1973
  end
1990
1974
  end
1991
1975