opal 0.3.41 → 0.3.42

Sign up to get free protection for your applications and to get access to all the features.
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