opal 0.3.11 → 0.3.15

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 (282) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE +20 -0
  4. data/README.md +11 -116
  5. data/Rakefile +126 -0
  6. data/bin/opal +1 -2
  7. data/docs/spec_runner.html +16 -0
  8. data/index.html +434 -0
  9. data/lib/opal.rb +14 -15
  10. data/lib/opal/builder.rb +46 -148
  11. data/lib/opal/command.rb +45 -115
  12. data/lib/opal/context.rb +139 -78
  13. data/lib/opal/dependency_builder.rb +34 -0
  14. data/lib/opal/environment.rb +92 -0
  15. data/lib/opal/parser/grammar.rb +4915 -0
  16. data/lib/opal/{parser.y → parser/grammar.y} +430 -284
  17. data/lib/opal/parser/lexer.rb +1329 -0
  18. data/lib/opal/parser/parser.rb +1460 -0
  19. data/lib/opal/parser/scope.rb +140 -0
  20. data/lib/opal/parser/sexp.rb +17 -0
  21. data/lib/opal/version.rb +2 -1
  22. data/opal.gemspec +23 -0
  23. data/opal.js +3149 -4162
  24. data/runtime/README.md +25 -0
  25. data/runtime/corelib/alpha.rb +10 -0
  26. data/runtime/corelib/array.rb +962 -0
  27. data/runtime/corelib/basic_object.rb +66 -0
  28. data/runtime/corelib/boolean.rb +44 -0
  29. data/runtime/corelib/class.rb +43 -0
  30. data/runtime/corelib/comparable.rb +25 -0
  31. data/runtime/corelib/complex.rb +2 -0
  32. data/runtime/corelib/dir.rb +29 -0
  33. data/runtime/corelib/enumerable.rb +316 -0
  34. data/runtime/corelib/enumerator.rb +80 -0
  35. data/runtime/corelib/error.rb +25 -0
  36. data/runtime/corelib/file.rb +80 -0
  37. data/runtime/corelib/hash.rb +503 -0
  38. data/runtime/corelib/io.rb +44 -0
  39. data/runtime/corelib/kernel.rb +237 -0
  40. data/runtime/corelib/load_order +29 -0
  41. data/runtime/corelib/match_data.rb +37 -0
  42. data/runtime/corelib/module.rb +171 -0
  43. data/runtime/corelib/native.rb +50 -0
  44. data/runtime/corelib/nil_class.rb +47 -0
  45. data/runtime/corelib/numeric.rb +219 -0
  46. data/runtime/corelib/object.rb +21 -0
  47. data/runtime/corelib/proc.rb +42 -0
  48. data/runtime/corelib/range.rb +38 -0
  49. data/runtime/corelib/rational.rb +16 -0
  50. data/runtime/corelib/regexp.rb +63 -0
  51. data/runtime/corelib/string.rb +185 -0
  52. data/runtime/corelib/struct.rb +97 -0
  53. data/runtime/corelib/time.rb +196 -0
  54. data/runtime/corelib/top_self.rb +7 -0
  55. data/runtime/gemlib/alpha.rb +5 -0
  56. data/runtime/gemlib/kernel.rb +17 -0
  57. data/runtime/gemlib/load_order +2 -0
  58. data/runtime/kernel/class.js +256 -0
  59. data/runtime/kernel/debug.js +42 -0
  60. data/runtime/kernel/init.js +114 -0
  61. data/runtime/kernel/load_order +5 -0
  62. data/runtime/kernel/loader.js +151 -0
  63. data/runtime/kernel/runtime.js +414 -0
  64. data/runtime/spec/README.md +34 -0
  65. data/runtime/spec/core/array/allocate_spec.rb +15 -0
  66. data/runtime/spec/core/array/append_spec.rb +31 -0
  67. data/runtime/spec/core/array/assoc_spec.rb +29 -0
  68. data/runtime/spec/core/array/at_spec.rb +38 -0
  69. data/runtime/spec/core/array/clear_spec.rb +22 -0
  70. data/runtime/spec/core/array/collect_spec.rb +3 -0
  71. data/runtime/spec/core/array/compact_spec.rb +42 -0
  72. data/runtime/spec/core/array/concat_spec.rb +21 -0
  73. data/runtime/spec/core/array/constructor_spec.rb +24 -0
  74. data/runtime/spec/core/array/count_spec.rb +11 -0
  75. data/runtime/spec/core/array/delete_at_spec.rb +31 -0
  76. data/runtime/spec/core/array/delete_if_spec.rb +24 -0
  77. data/runtime/spec/core/array/delete_spec.rb +26 -0
  78. data/runtime/spec/core/array/each_index_spec.rb +33 -0
  79. data/runtime/spec/core/array/each_spec.rb +11 -0
  80. data/runtime/spec/core/array/element_reference_spec.rb +136 -0
  81. data/runtime/spec/core/array/element_set_spec.rb +7 -0
  82. data/runtime/spec/core/array/empty_spec.rb +10 -0
  83. data/runtime/spec/core/array/eql_spec.rb +3 -0
  84. data/runtime/spec/core/array/equal_value_spec.rb +3 -0
  85. data/runtime/spec/core/array/fetch_spec.rb +26 -0
  86. data/runtime/spec/core/array/first_spec.rb +54 -0
  87. data/runtime/spec/core/array/fixtures/classes.rb +8 -0
  88. data/runtime/spec/core/array/flatten_spec.rb +41 -0
  89. data/runtime/spec/core/array/include_spec.rb +20 -0
  90. data/runtime/spec/core/array/insert_spec.rb +59 -0
  91. data/runtime/spec/core/array/last_spec.rb +57 -0
  92. data/runtime/spec/core/array/length_spec.rb +3 -0
  93. data/runtime/spec/core/array/map_spec.rb +3 -0
  94. data/runtime/spec/core/array/plus_spec.rb +16 -0
  95. data/runtime/spec/core/array/pop_spec.rb +79 -0
  96. data/runtime/spec/core/array/push_spec.rb +19 -0
  97. data/runtime/spec/core/array/rassoc_spec.rb +12 -0
  98. data/runtime/spec/core/array/reject_spec.rb +54 -0
  99. data/runtime/spec/core/array/replace_spec.rb +3 -0
  100. data/runtime/spec/core/array/reverse_each_spec.rb +18 -0
  101. data/runtime/spec/core/array/reverse_spec.rb +9 -0
  102. data/runtime/spec/core/array/shared/collect.rb +53 -0
  103. data/runtime/spec/core/array/shared/eql.rb +19 -0
  104. data/runtime/spec/core/array/shared/length.rb +6 -0
  105. data/runtime/spec/core/array/shared/replace.rb +31 -0
  106. data/runtime/spec/core/class/new_spec.rb +19 -0
  107. data/runtime/spec/core/enumerable/all_spec.rb +102 -0
  108. data/runtime/spec/core/enumerable/any_spec.rb +115 -0
  109. data/runtime/spec/core/enumerable/collect_spec.rb +3 -0
  110. data/runtime/spec/core/enumerable/count_spec.rb +29 -0
  111. data/runtime/spec/core/enumerable/detect_spec.rb +3 -0
  112. data/runtime/spec/core/enumerable/find_spec.rb +3 -0
  113. data/runtime/spec/core/enumerable/fixtures/classes.rb +26 -0
  114. data/runtime/spec/core/enumerable/shared/collect.rb +12 -0
  115. data/runtime/spec/core/enumerable/shared/entries.rb +7 -0
  116. data/runtime/spec/core/enumerable/shared/find.rb +49 -0
  117. data/runtime/spec/core/enumerable/to_a_spec.rb +7 -0
  118. data/runtime/spec/core/false/and_spec.rb +11 -0
  119. data/runtime/spec/core/false/inspect_spec.rb +7 -0
  120. data/runtime/spec/core/false/or_spec.rb +11 -0
  121. data/runtime/spec/core/false/to_s_spec.rb +7 -0
  122. data/runtime/spec/core/false/xor_spec.rb +11 -0
  123. data/runtime/spec/core/hash/allocate_spec.rb +15 -0
  124. data/runtime/spec/core/hash/assoc_spec.rb +29 -0
  125. data/runtime/spec/core/hash/clear_spec.rb +21 -0
  126. data/runtime/spec/core/hash/clone_spec.rb +12 -0
  127. data/runtime/spec/core/hash/default_spec.rb +6 -0
  128. data/runtime/spec/core/hash/delete_if_spec.rb +15 -0
  129. data/runtime/spec/core/hash/element_reference_spec.rb +16 -0
  130. data/runtime/spec/core/hash/element_set_spec.rb +8 -0
  131. data/runtime/spec/core/hash/new_spec.rb +13 -0
  132. data/runtime/spec/core/matchdata/to_a_spec.rb +7 -0
  133. data/runtime/spec/core/nil/and_spec.rb +12 -0
  134. data/runtime/spec/core/nil/inspect_spec.rb +8 -0
  135. data/runtime/spec/core/nil/nil_spec.rb +8 -0
  136. data/runtime/spec/core/nil/or_spec.rb +12 -0
  137. data/runtime/spec/core/nil/to_a_spec.rb +8 -0
  138. data/runtime/spec/core/nil/to_f_spec.rb +12 -0
  139. data/runtime/spec/core/nil/to_i_spec.rb +12 -0
  140. data/runtime/spec/core/nil/to_s_spec.rb +8 -0
  141. data/runtime/spec/core/nil/xor_spec.rb +12 -0
  142. data/runtime/spec/core/numeric/equal_value_spec.rb +11 -0
  143. data/runtime/spec/core/object/is_a_spec.rb +2 -0
  144. data/runtime/spec/core/object/shared/kind_of.rb +0 -0
  145. data/runtime/spec/core/regexp/match_spec.rb +23 -0
  146. data/runtime/spec/core/regexp/shared/match.rb +11 -0
  147. data/runtime/spec/core/symbol/to_proc_spec.rb +8 -0
  148. data/runtime/spec/core/true/and_spec.rb +11 -0
  149. data/runtime/spec/core/true/inspect_spec.rb +7 -0
  150. data/runtime/spec/core/true/or_spec.rb +11 -0
  151. data/runtime/spec/core/true/to_s_spec.rb +7 -0
  152. data/runtime/spec/core/true/xor_spec.rb +11 -0
  153. data/runtime/spec/language/alias_spec.rb +25 -0
  154. data/runtime/spec/language/and_spec.rb +62 -0
  155. data/runtime/spec/language/array_spec.rb +68 -0
  156. data/runtime/spec/language/block_spec.rb +105 -0
  157. data/runtime/spec/language/break_spec.rb +49 -0
  158. data/runtime/spec/language/case_spec.rb +165 -0
  159. data/runtime/spec/language/defined_spec.rb +80 -0
  160. data/runtime/spec/language/ensure_spec.rb +82 -0
  161. data/runtime/spec/language/fixtures/block.rb +19 -0
  162. data/runtime/spec/language/fixtures/break.rb +39 -0
  163. data/runtime/spec/language/fixtures/defined.rb +9 -0
  164. data/runtime/spec/language/fixtures/ensure.rb +37 -0
  165. data/runtime/spec/language/fixtures/next.rb +46 -0
  166. data/runtime/spec/language/fixtures/send.rb +36 -0
  167. data/runtime/spec/language/fixtures/super.rb +43 -0
  168. data/runtime/spec/language/hash_spec.rb +43 -0
  169. data/runtime/spec/language/if_spec.rb +278 -0
  170. data/runtime/spec/language/loop_spec.rb +32 -0
  171. data/runtime/spec/language/next_spec.rb +128 -0
  172. data/runtime/spec/language/or_spec.rb +65 -0
  173. data/runtime/spec/language/predefined_spec.rb +21 -0
  174. data/runtime/spec/language/regexp/interpolation_spec.rb +9 -0
  175. data/runtime/spec/language/regexp_spec.rb +7 -0
  176. data/runtime/spec/language/send_spec.rb +105 -0
  177. data/runtime/spec/language/string_spec.rb +4 -0
  178. data/runtime/spec/language/super_spec.rb +18 -0
  179. data/runtime/spec/language/symbol_spec.rb +41 -0
  180. data/runtime/spec/language/undef_spec.rb +16 -0
  181. data/runtime/spec/language/unless_spec.rb +44 -0
  182. data/runtime/spec/language/until_spec.rb +137 -0
  183. data/runtime/spec/language/variables_spec.rb +28 -0
  184. data/runtime/spec/language/versions/hash_1.9.rb +20 -0
  185. data/runtime/spec/language/while_spec.rb +175 -0
  186. data/runtime/spec/library/stringscanner/scan_spec.rb +36 -0
  187. data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +49 -0
  188. data/runtime/spec/opal/opal/defined_spec.rb +15 -0
  189. data/runtime/spec/opal/opal/function_spec.rb +11 -0
  190. data/runtime/spec/opal/opal/native_spec.rb +16 -0
  191. data/runtime/spec/opal/opal/null_spec.rb +10 -0
  192. data/runtime/spec/opal/opal/number_spec.rb +11 -0
  193. data/runtime/spec/opal/opal/object_spec.rb +16 -0
  194. data/runtime/spec/opal/opal/string_spec.rb +11 -0
  195. data/runtime/spec/opal/opal/typeof_spec.rb +9 -0
  196. data/runtime/spec/opal/opal/undefined_spec.rb +10 -0
  197. data/runtime/spec/opal/true/case_compare_spec.rb +12 -0
  198. data/runtime/spec/opal/true/class_spec.rb +10 -0
  199. data/runtime/spec/spec_helper.rb +25 -0
  200. data/runtime/stdlib/base64.rb +91 -0
  201. data/runtime/stdlib/date.rb +4 -0
  202. data/{stdlib → runtime/stdlib}/dev.rb +0 -0
  203. data/runtime/stdlib/forwardable.rb +33 -0
  204. data/runtime/stdlib/optparse.rb +0 -0
  205. data/runtime/stdlib/pp.rb +6 -0
  206. data/{stdlib → runtime/stdlib}/racc/parser.rb +0 -0
  207. data/runtime/stdlib/rbconfig.rb +0 -0
  208. data/runtime/stdlib/si.rb +17 -0
  209. data/runtime/stdlib/strscan.rb +53 -0
  210. data/runtime/stdlib/uri.rb +111 -0
  211. data/runtime/stdlib/uri/common.rb +1014 -0
  212. data/runtime/stdlib/uri/ftp.rb +261 -0
  213. data/runtime/stdlib/uri/generic.rb +1599 -0
  214. data/runtime/stdlib/uri/http.rb +106 -0
  215. data/runtime/stdlib/uri/https.rb +22 -0
  216. data/runtime/stdlib/uri/ldap.rb +260 -0
  217. data/runtime/stdlib/uri/ldaps.rb +20 -0
  218. data/runtime/stdlib/uri/mailto.rb +280 -0
  219. data/spec/builder/build_source_spec.rb +52 -0
  220. data/spec/builder/fixtures/build_source/adam.rb +0 -0
  221. data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
  222. data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
  223. data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
  224. data/spec/builder/fixtures/build_source/beynon.rb +0 -0
  225. data/spec/builder/fixtures/build_source/charles.js +0 -0
  226. data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
  227. data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
  228. data/spec/builder/fixtures/build_source/foo/x.js +0 -0
  229. data/spec/builder/fixtures/build_source/foo/y.js +0 -0
  230. data/spec/builder/output_path_spec.rb +50 -0
  231. data/spec/grammar/alias_spec.rb +26 -0
  232. data/spec/grammar/and_spec.rb +13 -0
  233. data/spec/grammar/array_spec.rb +22 -0
  234. data/spec/grammar/attrasgn_spec.rb +28 -0
  235. data/spec/grammar/begin_spec.rb +38 -0
  236. data/spec/grammar/block_spec.rb +12 -0
  237. data/spec/grammar/break_spec.rb +17 -0
  238. data/spec/grammar/call_spec.rb +58 -0
  239. data/spec/grammar/class_spec.rb +35 -0
  240. data/spec/grammar/const_spec.rb +13 -0
  241. data/spec/grammar/cvar_spec.rb +11 -0
  242. data/spec/grammar/def_spec.rb +60 -0
  243. data/spec/grammar/false_spec.rb +17 -0
  244. data/spec/grammar/file_spec.rb +7 -0
  245. data/spec/grammar/gvar_spec.rb +13 -0
  246. data/spec/grammar/hash_spec.rb +17 -0
  247. data/spec/grammar/iasgn_spec.rb +9 -0
  248. data/spec/grammar/if_spec.rb +26 -0
  249. data/spec/grammar/iter_spec.rb +59 -0
  250. data/spec/grammar/ivar_spec.rb +9 -0
  251. data/spec/grammar/lasgn_spec.rb +8 -0
  252. data/spec/grammar/line_spec.rb +8 -0
  253. data/spec/grammar/lvar_spec.rb +38 -0
  254. data/spec/grammar/module_spec.rb +27 -0
  255. data/spec/grammar/nil_spec.rb +17 -0
  256. data/spec/grammar/not_spec.rb +27 -0
  257. data/spec/grammar/op_asgn1_spec.rb +23 -0
  258. data/spec/grammar/op_asgn2_spec.rb +23 -0
  259. data/spec/grammar/or_spec.rb +13 -0
  260. data/spec/grammar/return_spec.rb +17 -0
  261. data/spec/grammar/sclass_spec.rb +20 -0
  262. data/spec/grammar/self_spec.rb +17 -0
  263. data/spec/grammar/str_spec.rb +96 -0
  264. data/spec/grammar/super_spec.rb +20 -0
  265. data/spec/grammar/true_spec.rb +17 -0
  266. data/spec/grammar/undef_spec.rb +15 -0
  267. data/spec/grammar/unless_spec.rb +13 -0
  268. data/spec/grammar/while_spec.rb +15 -0
  269. data/spec/grammar/xstr_spec.rb +116 -0
  270. data/spec/grammar/yield_spec.rb +20 -0
  271. data/spec/spec_helper.rb +9 -0
  272. metadata +346 -21
  273. data/lib/opal/bundle.rb +0 -34
  274. data/lib/opal/lexer.rb +0 -902
  275. data/lib/opal/nodes.rb +0 -2150
  276. data/lib/opal/parser.rb +0 -4894
  277. data/lib/opal/rake/bundle_task.rb +0 -63
  278. data/opal-parser.js +0 -8343
  279. data/stdlib/strscan.rb +0 -52
  280. data/templates/init/Rakefile +0 -7
  281. data/templates/init/index.html +0 -17
  282. data/templates/init/lib/__NAME__.rb +0 -2
@@ -0,0 +1,1460 @@
1
+ require 'opal/parser/lexer'
2
+ require 'opal/parser/grammar'
3
+ require 'opal/parser/scope'
4
+
5
+ module Opal
6
+ class OpalParseError < Exception; end
7
+
8
+ class Parser
9
+ def self.to_syms(ary)
10
+ ary.map &:to_sym
11
+ end
12
+
13
+ INDENT = ' '
14
+
15
+ LEVEL = to_syms(%w[statement statement_closure list expression receiver])
16
+
17
+ # Maths operators
18
+ MATH = %w(+ - / * %)
19
+
20
+ # Comparison operators
21
+ COMPARE = %w(< <= > >=)
22
+
23
+ # All operators that can be optimized in method calls
24
+ CALL_OPERATORS = MATH + COMPARE
25
+
26
+ # Reserved javascript keywords - we cannot create variables with the
27
+ # same name
28
+ RESERVED = %w(
29
+ break case catch continue debugger default delete do else finally for
30
+ function if in instanceof new return switch this throw try typeof var let
31
+ void while with class enum export extends import super true false native
32
+ const
33
+ )
34
+
35
+ METHOD_NAMES = {
36
+ :== => 'eq',
37
+ :=== => 'eqq',
38
+ :[] => 'aref',
39
+ :[]= => 'aset',
40
+ :~ => 'tild',
41
+ :<=> => 'cmp',
42
+ :=~ => 'match',
43
+ :+ => 'plus',
44
+ :- => 'minus',
45
+ :/ => 'div',
46
+ :* => 'mul',
47
+ :< => 'lt',
48
+ :<= => 'le',
49
+ :> => 'gt',
50
+ :>= => 'ge',
51
+ :<< => 'lshft',
52
+ :>> => 'rshft',
53
+ :| => 'or',
54
+ :& => 'and',
55
+ :^ => 'xor',
56
+ :+@ => 'uplus',
57
+ :-@ => 'uminus',
58
+ :% => 'mod',
59
+ :** => 'pow'
60
+ }
61
+
62
+ # Type info for flags of objects. This helps identify the type of object
63
+ # being dealt with
64
+ TYPES = {
65
+ class: 0x0001,
66
+ module: 0x0002,
67
+ object: 0x0004,
68
+ boolean: 0x0008,
69
+ string: 0x0010,
70
+ array: 0x0020,
71
+ number: 0x0040,
72
+ proc: 0x0080,
73
+ hash: 0x0100,
74
+ range: 0x0200,
75
+ iclass: 0x0400,
76
+ singleton: 0x0800
77
+ }
78
+
79
+ STATEMENTS = to_syms(%w[xstr dxstr])
80
+
81
+ def initialize(opts = {})
82
+ @debug = opts[:debug] or false
83
+ end
84
+
85
+ def parse(source, file = '(file)')
86
+ @file = file
87
+ @helpers = {
88
+ :breaker => true, :no_proc => true, :klass => true, :defn => true, :defs => true, :const_get => true,
89
+ :slice => true
90
+ }
91
+
92
+ parser = Grammar.new
93
+ reset
94
+
95
+ begin
96
+ top parser.parse(source, file)
97
+ rescue Exception => e
98
+ raise OpalParseError.new("#{e.message}\nfrom parsing #{file}:#{parser.line}")
99
+ end
100
+ end
101
+
102
+ def s(*parts)
103
+ sexp = Sexp.new *parts
104
+ sexp.line = @line
105
+ sexp
106
+ end
107
+
108
+ def reset
109
+ @line = 1
110
+ @indent = ''
111
+ @unique = 0
112
+ end
113
+
114
+ def mid_to_jsid(mid)
115
+ 'm$' + if name = METHOD_NAMES[mid.to_sym]
116
+ name + '$'
117
+ else
118
+ mid.sub('!', '$b').sub('?', '$p').sub('=', '$e')
119
+ end
120
+ end
121
+
122
+ # guaranteed unique id per file..
123
+ def unique_temp
124
+ "$TMP_#{@unique += 1}"
125
+ end
126
+
127
+ def top(sexp, options = {})
128
+ code = nil
129
+ vars = []
130
+
131
+ in_scope(:top) do
132
+ code = process s(:scope, sexp), :statement
133
+
134
+ vars << "FILE = $opal.FILE" if @uses_file
135
+ vars << "nil = $opal.nil"
136
+ vars << "$const = $opal.constants"
137
+ vars.concat @scope.locals.map { |t| "#{t}" }
138
+ vars.concat @scope.temps.map { |t| t }
139
+ vars.concat @helpers.keys.map { |h| "$#{h} = $opal.#{h}" }
140
+
141
+ code = "var #{vars.join ', '};" + code unless vars.empty?
142
+ end
143
+
144
+ pre = "(function($opal) {"
145
+ post = ""
146
+
147
+ uniques = []
148
+
149
+ @unique.times { |i| uniques << "$TMP_#{i+1}" }
150
+
151
+ unless uniques.empty?
152
+ post += ";var #{uniques.join ', '};"
153
+ end
154
+
155
+ post += "\n}).call(opal.top, opal);"
156
+
157
+ pre + code + post
158
+ end
159
+
160
+ def in_scope(type)
161
+ return unless block_given?
162
+
163
+ parent = @scope
164
+ @scope = Scope.new(type).tap { |s| s.parent = parent }
165
+ yield @scope
166
+
167
+ @scope = parent
168
+ end
169
+
170
+ def indent(&block)
171
+ indent = @indent
172
+ @indent += INDENT
173
+ res = yield
174
+ @indent = indent
175
+ res
176
+ end
177
+
178
+ # Used when we enter a while statement. This pushes onto the current
179
+ # scope's while stack so we know how to handle break, next etc.
180
+ #
181
+ # Usage:
182
+ #
183
+ # in_while do
184
+ # # generate while body here.
185
+ # end
186
+ def in_while
187
+ return unless block_given?
188
+ @while_loop = @scope.push_while
189
+ result = yield
190
+ @scope.pop_while
191
+
192
+ result
193
+ end
194
+
195
+ def in_while?
196
+ @scope.in_while?
197
+ end
198
+
199
+ def process(sexp, level)
200
+ type = sexp.shift
201
+
202
+ raise "Unsupported sexp: #{type}" unless respond_to? type
203
+
204
+ line = fix_line sexp.line
205
+ code = __send__ type, sexp, level
206
+ line + code
207
+ end
208
+
209
+ def fix_line(line)
210
+ res = ""
211
+
212
+ if @line < line
213
+ res = "\n" * (line - @line)
214
+ res += @indent
215
+ @line = line
216
+ end
217
+ res
218
+ end
219
+
220
+ def returns(sexp)
221
+ return returns s(:nil) unless sexp
222
+
223
+ case sexp.first
224
+ when :break, :next
225
+ sexp
226
+ when :scope
227
+ sexp
228
+ when :block
229
+ if sexp.length > 1
230
+ sexp[-1] = returns sexp[-1]
231
+ else
232
+ sexp << returns(s(:nil))
233
+ end
234
+ sexp
235
+ when :when
236
+ sexp[2] = returns(sexp[2])
237
+ sexp
238
+ when :ensure
239
+ sexp[1] = returns sexp[1]
240
+ sexp
241
+ when :while
242
+ sexp[2] = returns(sexp[2])
243
+ sexp
244
+ when :return
245
+ sexp
246
+ when :xstr
247
+ sexp[1] = "return #{sexp[1]};" unless /return|;/ =~ sexp[1]
248
+ sexp
249
+ when :dxstr
250
+ sexp[1] = "return #{sexp[1]}" unless /return|;|\n/ =~ sexp[1]
251
+ sexp
252
+ when :if
253
+ sexp[2] = returns(sexp[2] || s(:nil))
254
+ sexp[3] = returns(sexp[3] || s(:nil))
255
+ sexp
256
+ else
257
+ s(:js_return, sexp).tap { |s|
258
+ s.line = sexp.line
259
+ }
260
+ end
261
+ end
262
+
263
+ def expression?(sexp)
264
+ !STATEMENTS.include?(sexp.first)
265
+ end
266
+
267
+ def block(sexp, level)
268
+ result = []
269
+ sexp << s(:nil) if sexp.empty?
270
+
271
+ until sexp.empty?
272
+ stmt = sexp.shift
273
+ expr = expression?(stmt) and LEVEL.index(level) < LEVEL.index(:list)
274
+ result << process(stmt, level)
275
+ result << ";" if expr
276
+ end
277
+
278
+ result.join
279
+ end
280
+
281
+ def scope(sexp, level)
282
+ stmt = sexp.shift
283
+ stmt = returns stmt unless @scope.donates_methods
284
+ code = process stmt, :statement
285
+
286
+ code
287
+ end
288
+
289
+ # s(:js_return, sexp)
290
+ def js_return(sexp, level)
291
+ "return #{process sexp.shift, :expression}"
292
+ end
293
+
294
+ # s(:js_tmp, str)
295
+ def js_tmp(sexp, level)
296
+ sexp.shift.to_s
297
+ end
298
+
299
+ # s(:js_block_given)
300
+ def js_block_given(sexp, level)
301
+ @scope.uses_block!
302
+ "$block_given"
303
+ end
304
+
305
+ def js_operator_call(sexp, level)
306
+ recv = sexp[0]
307
+ meth = sexp[1]
308
+ arglist = sexp[2]
309
+ mid = mid_to_jsid meth.to_s
310
+
311
+ a = @scope.new_temp
312
+ b = @scope.new_temp
313
+ l = process recv, :expression
314
+ r = process arglist[1], :expression
315
+
316
+ res = "(#{a} = #{l}, #{b} = #{r}, typeof(#{a}) === "
317
+ res += "'number' ? #{a} #{meth} #{b} : #{a}.#{mid}"
318
+ res += "(null, #{b}))"
319
+
320
+ @scope.queue_temp a
321
+ @scope.queue_temp b
322
+
323
+ res
324
+ end
325
+
326
+ def js_compile_time_helpers(exp, level)
327
+ recv = exp[0]
328
+ meth = exp[1]
329
+ args = exp[2]
330
+
331
+ arg = args[1] || raise("No argument given to compile helper: #{meth}")
332
+ arg = process arg, :expression
333
+ tmp = @scope.new_temp
334
+
335
+ res = case meth
336
+ when :object?
337
+ "(!!(#{tmp} = #{arg}, #{tmp} != null && #{tmp}.$klass))"
338
+ when :native?
339
+ "(!!(#{tmp} = #{arg}, #{tmp} == null || !#{tmp}.$klass))"
340
+ when :string?
341
+ "(typeof #{arg} === 'string')"
342
+ when :number?
343
+ "(typeof #{arg} === 'number')"
344
+ when :function?
345
+ "(typeof #{arg} === 'function')"
346
+ when :defined?
347
+ "((#{tmp} = typeof(#{arg})) === 'undefined' ? nil : #{tmp})"
348
+ when :undefined?
349
+ "(typeof(#{arg}) === 'undefined')"
350
+ when :null?
351
+ "(#{arg} === null)"
352
+ when :typeof
353
+ "(typeof(#{arg}))"
354
+ else
355
+ raise "Bad compile time helper: #{meth}"
356
+ end
357
+
358
+ @scope.queue_temp tmp
359
+
360
+ res
361
+ end
362
+
363
+ # s(:lit, 1)
364
+ # s(:lit, :foo)
365
+ def lit(sexp, level)
366
+ val = sexp.shift
367
+ case val
368
+ when Numeric
369
+ level == :receiver ? "(#{val.inspect})" : val.inspect
370
+ when Symbol
371
+ val.to_s.inspect
372
+ when Regexp
373
+ val == // ? /^/.inspect : val.inspect
374
+ when Range
375
+ "$opal.range(#{val.begin}, #{val.end}, #{val.exclude_end?})"
376
+ else
377
+ raise "Bad lit: #{val.inspect}"
378
+ end
379
+ end
380
+
381
+ def dregx(sexp, level)
382
+ parts = sexp.map do |part|
383
+ if String === part
384
+ part.inspect
385
+ elsif part[0] == :str
386
+ process part, :expression
387
+ else
388
+ process part[1], :expression
389
+ end
390
+ end
391
+
392
+ "(new RegExp(#{parts.join ' + '}))"
393
+ end
394
+
395
+ def dot2 exp, level
396
+ "$opal.range(#{process exp[0], :expression}, #{process exp[1], :expression}, false)"
397
+ end
398
+
399
+ # s(:str, "string")
400
+ def str(sexp, level)
401
+ str = sexp.shift
402
+ if str == @file
403
+ @uses_file = true
404
+ "FILE"
405
+ else
406
+ str.inspect
407
+ end
408
+ end
409
+
410
+ def defined(sexp, level)
411
+ part = sexp[0]
412
+ case part[0]
413
+ when :self
414
+ "self".inspect
415
+ when :nil
416
+ "nil".inspect
417
+ when :true
418
+ "true".inspect
419
+ when :false
420
+ "false".inspect
421
+ when :call
422
+ mid = mid_to_jsid part[2].to_s
423
+ recv = part[1] ? process(part[1], :expression) : 'this'
424
+ "(#{recv}.#{mid} ? 'method' : nil)"
425
+ else
426
+ raise "bad defined? part: #{part[0]}"
427
+ end
428
+ end
429
+
430
+ # s(:not, sexp)
431
+ def not(sexp, level)
432
+ tmp = @scope.new_temp
433
+ code = "((#{tmp} = #{process sexp.shift, :expression}) === false || #{tmp} === nil)"
434
+ @scope.queue_temp tmp
435
+ code
436
+ end
437
+
438
+ def block_pass(exp, level)
439
+ pass = process exp.shift, level
440
+
441
+ tmp = @scope.new_temp
442
+
443
+ to_proc = process(s(:call, s(:js_tmp, tmp), :to_proc, s(:arglist)), :expression)
444
+
445
+ code = "(#{tmp} = #{pass}, (typeof(#{tmp}) === 'function' || #{tmp} == nil ? #{tmp} : #{to_proc}))"
446
+
447
+ @scope.queue_temp tmp
448
+
449
+ code
450
+ end
451
+
452
+ # s(:iter, call, block_args [, body)
453
+ def iter(sexp, level)
454
+ call = sexp[0]
455
+ args = sexp[1]
456
+ body = sexp[2]
457
+
458
+ body ||= s(:nil)
459
+ body = returns body
460
+ code = ""
461
+ params = nil
462
+
463
+ args = nil if Fixnum === args # argh
464
+ args ||= s(:masgn, s(:array))
465
+ args = args.first == :lasgn ? s(:array, args) : args[1]
466
+
467
+ if args.last[0] == :splat
468
+ splat = args[-1][1][1]
469
+ args[-1] = s(:lasgn, splat)
470
+ len = args.length
471
+ end
472
+
473
+ indent do
474
+ in_scope(:iter) do
475
+ args[1..-1].each do |arg|
476
+ arg = arg[1]
477
+ arg = "#{arg}$" if RESERVED.include? arg.to_s
478
+ code += "if (#{arg} === undefined) {#{arg} = nil; }"
479
+ end
480
+
481
+ params = js_block_args(args[1..-1])
482
+ params.unshift '_$'
483
+ code += "#{splat} = $slice.call(arguments, #{len - 1});" if splat
484
+ code += process body, :statement
485
+
486
+ code = @scope.to_vars + code
487
+ end
488
+ end
489
+
490
+ call << "function(#{params.join ', '}) {#{code}#{fix_line sexp.end_line}}"
491
+ process call, level
492
+ end
493
+
494
+ def js_block_args(sexp)
495
+ sexp.map do |arg|
496
+ a = arg[1].intern
497
+ a = "#{a}$".intern if RESERVED.include? a.to_s
498
+ @scope.add_arg a
499
+ a
500
+ end
501
+ end
502
+
503
+ ##
504
+ # recv.mid = rhs
505
+ #
506
+ # s(recv, :mid=, s(:arglist, rhs))
507
+
508
+ def attrasgn(exp, level)
509
+ recv = exp[0]
510
+ mid = exp[1]
511
+ arglist = exp[2]
512
+
513
+ return process(s(:call, recv, mid, arglist), level)
514
+ end
515
+
516
+ # s(:call, recv, :mid, s(:arglist))
517
+ # s(:call, nil, :mid, s(:arglist))
518
+ def call(sexp, level)
519
+ recv = sexp[0]
520
+ meth = sexp[1]
521
+ arglist = sexp[2]
522
+ iter = sexp[3]
523
+
524
+ mid = mid_to_jsid meth.to_s
525
+
526
+ return js_operator_call(sexp, level) if CALL_OPERATORS.include? meth.to_s
527
+ return js_compile_time_helpers(sexp, level) if recv && recv == [:const, :Opal]
528
+ return js_block_given(sexp, level) if meth == :block_given?
529
+ return "undefined" if meth == :undefined
530
+
531
+ splat = arglist[1..-1].any? { |a| a.first == :splat }
532
+
533
+ if Sexp === arglist.last and arglist.last.first == :block_pass
534
+ tmpproc = @scope.new_temp
535
+ arglist.insert 1, s(:js_tmp, process(arglist.pop, :expression))
536
+ elsif iter
537
+ tmpproc = @scope.new_temp
538
+ arglist.insert 1, s(:js_tmp, "(#{tmpproc}=#{iter},#{tmpproc}.$S=this,#{tmpproc})")
539
+ else
540
+ arglist.insert 1, s(:js_tmp, 'null') unless arglist.length == 1
541
+ end
542
+
543
+ tmprecv = @scope.new_temp if splat or @debug
544
+ args = ""
545
+
546
+ recv_code = recv.nil? ? 'this' : process(recv, :receiver)
547
+
548
+ args = process arglist, :expression
549
+
550
+ @scope.queue_temp tmprecv if tmprecv
551
+ @scope.queue_temp tmpproc if tmpproc
552
+
553
+ if @debug
554
+ pre = "((#{tmprecv}=#{recv_code}).#{mid} || $opal.mm('#{mid}'))."
555
+ splat ? "#{pre}apply(#{tmprecv}, #{args})" : "#{pre}call(#{tmprecv}#{args == '' ? '' : ", #{args}"})"
556
+ else
557
+ splat ? "(#{tmprecv}=#{recv_code}).#{mid}.apply(#{tmprecv}, #{args})" : "#{recv_code}.#{mid}(#{args})"
558
+ end
559
+ end
560
+
561
+ # s(:arglist, [arg [, arg ..]])
562
+ def arglist(sexp, level)
563
+ code = ''
564
+ work = []
565
+
566
+ until sexp.empty?
567
+ splat = sexp.first.first == :splat
568
+ arg = process sexp.shift, :expression
569
+
570
+ if splat
571
+ if work.empty?
572
+ if code.empty?
573
+ code += arg
574
+ else
575
+ code += ".concat(#{arg})"
576
+ end
577
+ else
578
+ join = "[#{work.join ', '}]"
579
+ code += (code.empty? ? join : ".concat(#{join})")
580
+ code += ".concat(#{arg})"
581
+ end
582
+
583
+ work = []
584
+ else
585
+ work.push arg
586
+ end
587
+ end
588
+
589
+ unless work.empty?
590
+ join = work.join ', '
591
+ code += (code.empty? ? join : ".concat([#{work}])")
592
+ end
593
+
594
+ code
595
+ end
596
+
597
+ # s(:splat, sexp)
598
+ def splat(sexp, level)
599
+ return "[]" if sexp.first == [:nil]
600
+ return "[#{process sexp.first, :expression}]" if sexp.first.first == :lit
601
+ process sexp.first, :receiver
602
+ end
603
+
604
+ # s(:class, cid, super, body)
605
+ def class(sexp, level)
606
+ cid = sexp[0]
607
+ sup = sexp[1]
608
+ body = sexp[2]
609
+ code = nil
610
+
611
+ if Symbol === cid or String === cid
612
+ donates_methods = (cid === :Object || cid === :BasicObject)
613
+ base = 'this'
614
+ name = cid.to_s.inspect
615
+ elsif cid[0] == :colon2
616
+ base = process(cid[1], :expression)
617
+ name = cid[2].to_s.inspect
618
+ elsif cid[0] == :colon3
619
+ donates_methods = (cid[1] === :Object || cid[1] === :BasicObject)
620
+ base = '$opal.Object'
621
+ name = cid[1].to_s.inspect
622
+ else
623
+ raise "Bad receiver in class"
624
+ end
625
+
626
+ sup = sup ? process(sup, :expression) : 'nil'
627
+
628
+ indent do
629
+ in_scope(:class) do
630
+ @scope.donates_methods = donates_methods
631
+ code = @scope.to_vars + process(body, :statement)
632
+ code += @scope.to_donate_methods if @scope.donates_methods
633
+ end
634
+ end
635
+
636
+ "$klass(#{base}, #{sup}, #{name}, function() {#{code}#{fix_line sexp.end_line}}, 0)"
637
+ end
638
+
639
+ # s(:sclass, recv, body)
640
+ def sclass(sexp, level)
641
+ recv = sexp[0]
642
+ body = sexp[1]
643
+ code = nil
644
+ base = process recv, :expression
645
+
646
+ in_scope(:sclass) do
647
+ code = @scope.to_vars + process(body, :statement)
648
+ end
649
+
650
+ "$klass(#{base}, nil, nil, function() {#{code}}, 2)"
651
+ end
652
+
653
+ # s(:module, cid, body)
654
+ def module(sexp, level)
655
+ cid = sexp[0]
656
+ body = sexp[1]
657
+ code = nil
658
+
659
+ if Symbol === cid or String === cid
660
+ base = 'this'
661
+ name = cid.to_s.inspect
662
+ elsif cid[0] == :colon2
663
+ base = process(cid[1], :expression)
664
+ name = cid[2].to_s.inspect
665
+ elsif cid[0] == :colon3
666
+ base = '$opal.Object'
667
+ name = cid[1].to_s.inspect
668
+ else
669
+ raise "Bad receiver in class"
670
+ end
671
+
672
+ indent do
673
+ in_scope(:module) do
674
+ @scope.donates_methods = true
675
+ code = @scope.to_vars + process(body, :statement) + @scope.to_donate_methods
676
+ end
677
+ end
678
+
679
+ "$klass(#{base}, nil, #{name}, function() {#{code}#{fix_line sexp.end_line}}, 1)"
680
+ end
681
+
682
+ def undef(exp, level)
683
+ "$opal.undef(this, #{process exp.shift, :expression})"
684
+ end
685
+
686
+ # s(:defn, mid, s(:args), s(:scope))
687
+ def defn(sexp, level)
688
+ mid = sexp[0]
689
+ args = sexp[1]
690
+ stmts = sexp[2]
691
+ js_def nil, mid, args, stmts, sexp.line, sexp.end_line
692
+ end
693
+
694
+ # s(:defs, recv, mid, s(:args), s(:scope))
695
+ def defs(sexp, level)
696
+ recv = sexp[0]
697
+ mid = sexp[1]
698
+ args = sexp[2]
699
+ stmts = sexp[3]
700
+ js_def recv, mid, args, stmts, sexp.line, sexp.end_line
701
+ end
702
+
703
+ def js_def(recvr, mid, args, stmts, line, end_line)
704
+ mid = mid_to_jsid mid.to_s
705
+
706
+ if recvr
707
+ type = '$defs'
708
+ recv = process(recvr, :expression)
709
+ else
710
+ type = '$defn'
711
+ recv = 'this'
712
+ end
713
+
714
+ code = ''
715
+ params = nil
716
+ scope_name = @scope.name
717
+
718
+ # opt args if last arg is sexp
719
+ opt = args.pop if Sexp === args.last
720
+
721
+ # block name &block
722
+ if args.last.to_s[0] == '&'
723
+ block_name = args.pop[1..-1].intern
724
+ end
725
+
726
+ # splat args *splat
727
+ if args.last.to_s[0] == '*'
728
+ if args.last == :*
729
+ args.pop
730
+ else
731
+ splat = args[-1].to_s[1..-1].intern
732
+ args[-1] = splat
733
+ len = args.length - 2
734
+ end
735
+ end
736
+
737
+ aritycode = arity_check(args, opt, splat) if @debug
738
+
739
+ indent do
740
+ in_scope(:def) do
741
+ args.insert 1, '$yield'
742
+ params = process args, :expression
743
+
744
+ if block_name
745
+ @scope.add_arg block_name
746
+ @scope.uses_block!
747
+ end
748
+
749
+ opt[1..-1].each do |o|
750
+ id = process s(:lvar, o[1]), :expression
751
+ code += "if (#{id} === undefined) { #{process o, :expression}; }"
752
+ end if opt
753
+
754
+ code += "#{splat} = $slice.call(arguments, #{len + 1});" if splat
755
+ code += process(stmts, :statement)
756
+
757
+ if @scope.uses_block?
758
+ blk = "$yield || ($yield = $no_proc);"
759
+ blk = "var #{block_name} = $yield || ($yield = $no_proc, nil);" if block_name
760
+ blk += "var $context = $yield.$S;"
761
+ blk = "var $block_given = ($yield != null); #{blk}"
762
+ code = blk + code
763
+ end
764
+
765
+ code = aritycode.to_s + code
766
+
767
+ if @scope.catches_break?
768
+ code = "try {#{code}} catch (e) { if (e === $breaker) { return e.$v; }; throw e;}"
769
+ end
770
+
771
+ code = @scope.to_vars + code
772
+ end
773
+ end
774
+
775
+ defcode = "#{"#{scope_name} = " if scope_name}function(#{params}) {#{code}#{fix_line end_line}}"
776
+
777
+ if recvr
778
+ "#{type}(#{recv}, '#{mid}', #{defcode})"
779
+ elsif @scope.type == :class
780
+ @scope.methods << mid if @scope.donates_methods
781
+ "$proto.#{mid} = #{defcode}"
782
+ elsif @scope.type == :module
783
+ @scope.methods << mid
784
+ "$proto.#{mid} = #{defcode}"
785
+ else
786
+ "#{type}(#{recv}, '#{mid}', #{defcode})"
787
+ end
788
+ end
789
+
790
+ ##
791
+ # Returns code used in debug mode to check arity of method call
792
+ def arity_check(args, opt, splat)
793
+ arity = args.size - 1
794
+ arity -= (opt.size - 1) if opt
795
+ arity -= 1 if splat
796
+ arity = -arity - 1 if opt or splat
797
+
798
+ aritycode = "var $arity = arguments.length; if ($arity !== 0) { $arity -= 1; }"
799
+ if arity < 0 # splat or opt args
800
+ aritycode + "if ($arity < #{-(arity + 1)}) { $opal.arg_error($arity, #{arity}); }"
801
+ else
802
+ aritycode + "if ($arity !== #{arity}) { $opal.arg_error($arity, #{arity}); }"
803
+ end
804
+ end
805
+
806
+ def args(exp, level)
807
+ args = []
808
+
809
+ until exp.empty?
810
+ a = exp.shift.intern
811
+ a = "#{a}$".intern if RESERVED.include? a.to_s
812
+ @scope.add_arg a
813
+ args << a
814
+ end
815
+
816
+ args.join ', '
817
+ end
818
+
819
+ # s(:self) # => this
820
+ def self(sexp, level)
821
+ 'this'
822
+ end
823
+
824
+ # s(:true) # => true
825
+ # s(:false) # => false
826
+ # s(:nil) # => nil
827
+ %w(true false nil).each do |name|
828
+ define_method name do |exp, level|
829
+ name
830
+ end
831
+ end
832
+
833
+ # s(:array [, sexp [, sexp]])
834
+ def array(sexp, level)
835
+ return '[]' if sexp.empty?
836
+
837
+ code = ''
838
+ work = []
839
+
840
+ until sexp.empty?
841
+ splat = sexp.first.first == :splat
842
+ part = process sexp.shift, :expression
843
+
844
+ if splat
845
+ if work.empty?
846
+ code += (code.empty? ? part : ".concat(#{part})")
847
+ else
848
+ join = "[#{work.join ', '}]"
849
+ code += (code.empty? ? join : ".concat(#{join})")
850
+ code += ".concat(#{part})"
851
+ end
852
+ work = []
853
+ else
854
+ work << part
855
+ end
856
+ end
857
+
858
+ unless work.empty?
859
+ join = "[#{work.join ', '}]"
860
+ code += (code.empty? ? join : ".concat(#{join})")
861
+ end
862
+
863
+ code
864
+ end
865
+
866
+ # s(:hash, key1, val1, key2, val2...)
867
+ def hash(sexp, level)
868
+ "(new $opal.hash(#{sexp.map { |p| process p, :expression }.join ', '}))"
869
+ end
870
+
871
+ # s(:while, exp, block, true)
872
+ def while(sexp, level)
873
+ expr = sexp[0]
874
+ stmt = sexp[1]
875
+ redo_var = @scope.new_temp
876
+ stmt_level = if level == :expression or level == :receiver
877
+ :statement_closure
878
+ else
879
+ :statement
880
+ end
881
+ pre = "while ("
882
+ code = "#{js_truthy expr}){"
883
+
884
+ in_while do
885
+ @while_loop[:closure] = true if stmt_level == :statement_closure
886
+ @while_loop[:redo_var] = redo_var
887
+ body = process(stmt, :statement)
888
+
889
+ if @while_loop[:use_redo]
890
+ pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
891
+ code += "#{redo_var}=false;"
892
+ end
893
+
894
+ code += body
895
+ end
896
+
897
+ code += "}"
898
+ code = pre + code
899
+ @scope.queue_temp redo_var
900
+
901
+ if stmt_level == :statement_closure
902
+ code = "(function() {#{code}; return nil;}).call(this)"
903
+ end
904
+
905
+ code
906
+ end
907
+
908
+ def until(exp, level)
909
+ expr = exp[0]
910
+ stmt = exp[1]
911
+ redo_var = @scope.new_temp
912
+ stmt_level = if level == :expression or level == :receiver
913
+ :statement_closure
914
+ else
915
+ :statement
916
+ end
917
+ pre = "while (!("
918
+ code = "#{js_truthy expr})) {"
919
+
920
+ in_while do
921
+ @while_loop[:closure] = true if stmt_level == :statement_closure
922
+ @while_loop[:redo_var] = redo_var
923
+ body = process(stmt, :statement)
924
+
925
+ if @while_loop[:use_redo]
926
+ pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
927
+ code += "#{redo_var}=false;"
928
+ end
929
+
930
+ code += body
931
+ end
932
+
933
+ code += "}"
934
+ code = pre + code
935
+ @scope.queue_temp redo_var
936
+
937
+ if stmt_level == :statement_closure
938
+ code = "(function() {#{code}; return nil;}).call(this)"
939
+ end
940
+
941
+ code
942
+ end
943
+
944
+ ##
945
+ # alias foo bar
946
+ #
947
+ # s(:alias, s(:lit, :foo), s(:lit, :bar))
948
+ def alias(exp, level)
949
+ new = exp[0]
950
+ old = exp[1]
951
+ "$opal.alias(this, #{process new, :expression}, #{process old, :expression})"
952
+ end
953
+
954
+ def svalue(sexp, level)
955
+ process sexp.shift, level
956
+ end
957
+
958
+ # s(:lasgn, :lvar, rhs)
959
+ def lasgn(sexp, level)
960
+ lvar = sexp[0]
961
+ rhs = sexp[1]
962
+ lvar = "#{lvar}$".intern if RESERVED.include? lvar.to_s
963
+ @scope.add_local lvar
964
+ "#{lvar} = #{process rhs, :expression}"
965
+ end
966
+
967
+ # s(:lvar, :lvar)
968
+ def lvar(exp, level)
969
+ lvar = exp.shift.to_s
970
+ lvar = "#{lvar}$" if RESERVED.include? lvar
971
+ lvar
972
+ end
973
+
974
+ # s(:iasgn, :ivar, rhs)
975
+ def iasgn(exp, level)
976
+ ivar = exp[0]
977
+ rhs = exp[1]
978
+ ivar = ivar.to_s[1..-1]
979
+ lhs = RESERVED.include?(ivar) ? "this['#{ivar}']" : "this.#{ivar}"
980
+ "#{lhs} = #{process rhs, :expression}"
981
+ end
982
+
983
+ # s(:ivar, :ivar)
984
+ def ivar(exp, level)
985
+ ivar = exp.shift.to_s[1..-1]
986
+ part = RESERVED.include?(ivar) ? "['#{ivar}']" : ".#{ivar}"
987
+ @scope.add_ivar part
988
+ "this#{part}"
989
+ end
990
+
991
+ # s(:gvar, gvar)
992
+ def gvar(sexp, level)
993
+ gvar = sexp.shift.to_s
994
+ tmp = @scope.new_temp
995
+ code = "((#{tmp} = $opal.gvars[#{gvar.inspect}]) == null ? nil : #{tmp})"
996
+ @scope.queue_temp tmp
997
+ code
998
+ end
999
+
1000
+ # s(:gasgn, :gvar, rhs)
1001
+ def gasgn(sexp, level)
1002
+ gvar = sexp[0]
1003
+ rhs = sexp[1]
1004
+ "($opal.gvars[#{gvar.to_s.inspect}] = #{process rhs, :expression})"
1005
+ end
1006
+
1007
+ # s(:const, :const)
1008
+ def const(sexp, level)
1009
+ if @debug
1010
+ "$opal.const_get($const, #{sexp.shift.to_s.inspect})"
1011
+ else
1012
+ "$const.#{sexp.shift}"
1013
+ end
1014
+ end
1015
+
1016
+ # s(:cdecl, :const, rhs)
1017
+ def cdecl(sexp, level)
1018
+ const = sexp[0]
1019
+ rhs = sexp[1]
1020
+ "$const.#{const} = #{process rhs, :expression}"
1021
+ end
1022
+
1023
+ # s(:return [val])
1024
+ def return(sexp, level)
1025
+ val = process(sexp.shift || s(:nil), :expression)
1026
+
1027
+ if level == :statement
1028
+ "return #{val}"
1029
+ else
1030
+ "$return(#{val})"
1031
+ end
1032
+ end
1033
+
1034
+ # s(:xstr, content)
1035
+ def xstr(sexp, level)
1036
+ code = sexp.first.to_s
1037
+ code += ";" if level == :statement and !code.include?(';')
1038
+ code = "(#{code})" if level == :receiver
1039
+
1040
+ code
1041
+ end
1042
+
1043
+ # s(:dxstr, parts...)
1044
+ def dxstr(sexp, level)
1045
+ code = sexp.map do |p|
1046
+ if String === p
1047
+ p.to_s
1048
+ elsif p.first == :evstr
1049
+ process p.last, :expression
1050
+ elsif p.first == :str
1051
+ p.last.to_s
1052
+ else
1053
+ raise "Bad dxstr part"
1054
+ end
1055
+ end.join
1056
+
1057
+ code += ";" if level == :statement and !code.include?(';')
1058
+ code = "(#{code})" if level == :receiver
1059
+ code
1060
+ end
1061
+
1062
+ # s(:dstr, parts..)
1063
+ def dstr(sexp, level)
1064
+ parts = sexp.map do |p|
1065
+ if String === p
1066
+ p.inspect
1067
+ elsif p.first == :evstr
1068
+ process(s(:call, p.last, :to_s, s(:arglist)), :expression)
1069
+ elsif p.first == :str
1070
+ p.last.inspect
1071
+ else
1072
+ raise "Bad dstr part"
1073
+ end
1074
+ end
1075
+
1076
+ "(#{parts.join ' + '})"
1077
+ end
1078
+
1079
+ def dsym(sexp, level)
1080
+ parts = sexp.map do |p|
1081
+ if String === p
1082
+ p.inspect
1083
+ elsif p.first == :evstr
1084
+ process(s(:call, p.last, :to_s, s(:arglist)), :expression)
1085
+ elsif p.first == :str
1086
+ p.last.inspect
1087
+ else
1088
+ raise "Bad dsym part"
1089
+ end
1090
+ end
1091
+
1092
+ "(#{parts.join '+'})"
1093
+ end
1094
+
1095
+ # s(:if, test, truthy, falsy)
1096
+ def if(sexp, level)
1097
+ test = sexp[0]
1098
+ truthy = sexp[1]
1099
+ falsy = sexp[2]
1100
+
1101
+ if level == :expression or level == :receiver
1102
+ truthy = returns(truthy || s(:nil))
1103
+ falsy = returns(falsy || s(:nil))
1104
+ end
1105
+
1106
+ code = "if (#{js_truthy test}) {"
1107
+ indent { code += process(truthy, :statement) } if truthy
1108
+ indent { code += "} else {#{process falsy, :statement}" } if falsy
1109
+ code += "#{fix_line sexp.end_line}}"
1110
+
1111
+ code = "(function() { #{code}; return nil; }).call(this)" if level == :expression or level == :receiver
1112
+
1113
+ code
1114
+ end
1115
+
1116
+ def js_truthy_optimize(sexp)
1117
+ if sexp.first == :call
1118
+ mid = sexp[2]
1119
+ if mid == :block_given?
1120
+ return process sexp, :expression
1121
+ elsif COMPARE.include? mid.to_s
1122
+ return process sexp, :expression
1123
+ end
1124
+ end
1125
+ end
1126
+
1127
+ def js_truthy(sexp)
1128
+ if optimized = js_truthy_optimize(sexp)
1129
+ return optimized
1130
+ end
1131
+
1132
+ tmp = @scope.new_temp
1133
+ code = "(#{tmp} = #{process sexp, :expression}) !== false && #{tmp} !== nil"
1134
+ @scope.queue_temp tmp
1135
+
1136
+ code
1137
+ end
1138
+
1139
+ # s(:and, lhs, rhs)
1140
+ def and(sexp, level)
1141
+ lhs = sexp[0]
1142
+ rhs = sexp[1]
1143
+ t = nil
1144
+ tmp = @scope.new_temp
1145
+
1146
+ if t = js_truthy_optimize(lhs)
1147
+ return "(#{tmp} = #{t} ? #{process rhs, :expression} : #{tmp})".tap {
1148
+ @scope.queue_temp tmp
1149
+ }
1150
+ end
1151
+
1152
+ code = "(#{tmp} = #{process lhs, :expression}, #{tmp} !== false && "
1153
+ code += "#{tmp} != nil ? #{process rhs, :expression} : #{tmp})"
1154
+ @scope.queue_temp tmp
1155
+
1156
+ code
1157
+ end
1158
+
1159
+ # s(:or, lhs, rhs)
1160
+ def or(sexp, level)
1161
+ lhs = sexp[0]
1162
+ rhs = sexp[1]
1163
+ t = nil
1164
+ tmp = @scope.new_temp
1165
+
1166
+ if t = js_truthy_optimize(lhs)
1167
+ return "(#{tmp} = #{t} ? #{tmp} : #{process rhs, :expression})".tap {
1168
+ @scope.queue_temp tmp
1169
+ }
1170
+ end
1171
+
1172
+ code = "(#{tmp} = #{process lhs, :expression}, #{tmp} !== false && "
1173
+ code += "#{tmp} != nil ? #{tmp} : #{process rhs, :expression})"
1174
+ @scope.queue_temp tmp
1175
+
1176
+ code
1177
+ end
1178
+
1179
+ # s(:yield, arg1, arg2)
1180
+ def yield(sexp, level)
1181
+ @scope.uses_block!
1182
+ splat = sexp.any? { |s| s.first == :splat }
1183
+ sexp.unshift s(:js_tmp, 'null')
1184
+ sexp.unshift s(:js_tmp, '$context') unless splat
1185
+ args = arglist(sexp, level)
1186
+
1187
+ call = if splat
1188
+ "$yield.apply($context, #{args})"
1189
+ else
1190
+ "$yield.call(#{args})"
1191
+ end
1192
+
1193
+ if level == :receiver or level == :expression
1194
+ tmp = @scope.new_temp
1195
+ @scope.catches_break!
1196
+ code = "((#{tmp} = #{call}) === $breaker ? #{tmp}.$t() : #{tmp})"
1197
+ @scope.queue_temp tmp
1198
+ else
1199
+ code = call
1200
+ end
1201
+
1202
+ code
1203
+ end
1204
+
1205
+ def break(exp, level)
1206
+ val = exp.empty? ? 'nil' : process(exp.shift, :expression)
1207
+ if in_while?
1208
+ if @while_loop[:closure]
1209
+ "return #{val};"
1210
+ else
1211
+ "break;"
1212
+ end
1213
+ else
1214
+ "return ($breaker.$v = #{val}, $breaker)"
1215
+ end
1216
+ end
1217
+
1218
+ # s(:case, expr, when1, when2, ..)
1219
+ def case(exp, level)
1220
+ code = []
1221
+ @scope.add_local "$case"
1222
+ expr = process exp.shift, :expression
1223
+ # are we inside a statement_closure
1224
+ returnable = level != :statement
1225
+ done_else = false
1226
+
1227
+ until exp.empty?
1228
+ wen = exp.shift
1229
+ if wen and wen.first == :when
1230
+ returns(wen) if returnable
1231
+ wen = process(wen, :statement)
1232
+ wen = "else #{wen}" unless code.empty?
1233
+ code << wen
1234
+ elsif wen # s(:else)
1235
+ done_else = true
1236
+ wen = returns(wen) if returnable
1237
+ code << "else {#{process wen, :statement}}"
1238
+ end
1239
+ end
1240
+
1241
+ code << "else {return nil}" if returnable and !done_else
1242
+
1243
+ code = "$case = #{expr};#{code.join "\n"}"
1244
+ code = "(function() { #{code} }).call(this)" if returnable
1245
+ code
1246
+ end
1247
+
1248
+ # when foo
1249
+ # bar
1250
+ #
1251
+ # s(:when, s(:array, foo), bar)
1252
+ def when(exp, level)
1253
+ arg = exp.shift[1..-1]
1254
+ body = exp.shift
1255
+ body = process body, level if body
1256
+
1257
+ test = []
1258
+ until arg.empty?
1259
+ a = arg.shift
1260
+
1261
+ if a.first == :when # when inside another when means a splat of values
1262
+ call = s(:call, s(:js_tmp, "$splt[i]"), :===, s(:arglist, s(:js_tmp, "$case")))
1263
+ splt = "(function($splt) {for(var i = 0; i < $splt.length; i++) {"
1264
+ splt += "if (#{process call, :expression}) { return true; }"
1265
+ splt += "} return false; }).call(this, #{process a[1], :expression})"
1266
+
1267
+ test << splt
1268
+ else
1269
+ call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
1270
+ call = process call, :expression
1271
+ # call = "else " unless test.empty?
1272
+
1273
+ test << call
1274
+ end
1275
+ end
1276
+
1277
+ "if (#{test.join " || "}) {\n#{body}\n}"
1278
+ end
1279
+
1280
+ # lhs =~ rhs
1281
+ #
1282
+ # s(:match3, lhs, rhs)
1283
+ def match3(sexp, level)
1284
+ lhs = sexp[0]
1285
+ rhs = sexp[1]
1286
+ call = s(:call, lhs, :=~, s(:arglist, rhs))
1287
+ process call, level
1288
+ end
1289
+
1290
+ # @@class_variable
1291
+ #
1292
+ # s(:cvar, name)
1293
+ def cvar(exp, level)
1294
+ tmp = @scope.new_temp
1295
+ code = "((#{tmp} = $opal.cvars[#{exp.shift.to_s.inspect}]) == null ? nil : #{tmp})"
1296
+ @scope.queue_temp tmp
1297
+ code
1298
+ end
1299
+
1300
+ # @@name = rhs
1301
+ #
1302
+ # s(:cvasgn, :@@name, rhs)
1303
+ def cvasgn(exp, level)
1304
+ "($opal.cvars[#{exp.shift.to_s.inspect}] = #{process exp.shift, :expression})"
1305
+ end
1306
+
1307
+ def cvdecl(exp, level)
1308
+ "($opal.cvars[#{exp.shift.to_s.inspect}] = #{process exp.shift, :expression})"
1309
+ end
1310
+
1311
+ # BASE::NAME
1312
+ #
1313
+ # s(:colon2, base, :NAME)
1314
+ def colon2(sexp, level)
1315
+ base = sexp[0]
1316
+ name = sexp[1]
1317
+ "$opal.const_get((#{process base, :expression}).$const, #{name.to_s.inspect})"
1318
+ end
1319
+
1320
+ def colon3(exp, level)
1321
+ "$opal.const_get($opal.Object, #{exp.shift.to_s.inspect})"
1322
+ end
1323
+
1324
+ # super a, b, c
1325
+ #
1326
+ # s(:super, arg1, arg2, ...)
1327
+ def super(sexp, level)
1328
+ args = []
1329
+ until sexp.empty?
1330
+ args << process(sexp.shift, :expression)
1331
+ end
1332
+ "$opal.zuper(arguments.callee, this, [#{args.join ', '}])"
1333
+ end
1334
+
1335
+ # super
1336
+ #
1337
+ # s(:zsuper)
1338
+ def zsuper(exp, level)
1339
+ "$opal.zuper(arguments.callee, this, [])"
1340
+ end
1341
+
1342
+ # a ||= rhs
1343
+ #
1344
+ # s(:op_asgn_or, s(:lvar, :a), s(:lasgn, :a, rhs))
1345
+ def op_asgn_or(exp, level)
1346
+ process s(:or, exp.shift, exp.shift), :expression
1347
+ end
1348
+
1349
+ def op_asgn1(sexp, level)
1350
+ "'FIXME(op_asgn1)'"
1351
+ end
1352
+
1353
+ # lhs.b += rhs
1354
+ #
1355
+ # s(:op_asgn2, lhs, :b=, :+, rhs)
1356
+ def op_asgn2(exp, level)
1357
+ lhs = process exp.shift, :expression
1358
+ mid = exp.shift.to_s[0..-2]
1359
+ op = exp.shift
1360
+ rhs = exp.shift
1361
+
1362
+ if op.to_s == "||"
1363
+ raise "op_asgn2 for ||"
1364
+ else
1365
+ temp = @scope.new_temp
1366
+ getr = s(:call, s(:js_tmp, temp), mid, s(:arglist))
1367
+ oper = s(:call, getr, op, s(:arglist, rhs))
1368
+ asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, oper))
1369
+
1370
+ "(#{temp} = #{lhs}, #{process asgn, :expression})".tap {
1371
+ @scope.queue_temp temp
1372
+ }
1373
+ end
1374
+ end
1375
+
1376
+ # s(:ensure, body, ensure)
1377
+ def ensure(exp, level)
1378
+ begn = exp.shift
1379
+ if level == :receiver || level == :expression
1380
+ retn = true
1381
+ begn = returns begn
1382
+ end
1383
+
1384
+ body = process begn, level
1385
+ ensr = exp.shift || s(:nil)
1386
+ ensr = process ensr, level
1387
+ body = "try {\n#{body}}" unless body =~ /^try \{/
1388
+
1389
+ res = "#{body}\n finally {\n#{ensr}}"
1390
+ res = "(function() { #{res}; }).call(this)" if retn
1391
+ res
1392
+ end
1393
+
1394
+ def rescue(exp, level)
1395
+ body = exp.first.first == :resbody ? s(:nil) : exp.shift
1396
+ body = process body, level
1397
+
1398
+ parts = []
1399
+ until exp.empty?
1400
+ part = process exp.shift, level
1401
+ part = "else " + part unless parts.empty?
1402
+ parts << part
1403
+ end
1404
+ # if no rescue statement captures our error, we should rethrow
1405
+ parts << "else { throw $err; }"
1406
+
1407
+ code = "try {\n#{body}\n} catch ($err) {\n#{parts.join "\n"}\n}"
1408
+ code = "(function() { #{code} }).call(this)" if level == :expression
1409
+
1410
+ code
1411
+ end
1412
+
1413
+ def resbody(exp, level)
1414
+ args = exp[0]
1415
+ body = exp[1]
1416
+ body = process(body || s(:nil), level)
1417
+ types = args[1..-2]
1418
+
1419
+ err = types.map { |t|
1420
+ call = s(:call, t, :===, s(:arglist, s(:js_tmp, "$err")))
1421
+ a = process call, :expression
1422
+ #puts a
1423
+ a
1424
+ }.join ', '
1425
+ err = "true" if err.empty?
1426
+
1427
+ if Sexp === args.last and [:lasgn, :iasgn].include? args.last.first
1428
+ val = args.last
1429
+ val[2] = s(:js_tmp, "$err")
1430
+ val = process(val, :expression) + ";"
1431
+ end
1432
+
1433
+ "if (#{err}) {\n#{val}#{body}}"
1434
+ # raise exp.inspect
1435
+ end
1436
+
1437
+ # FIXME: Hack.. grammar should remove top level begin.
1438
+ def begin(exp, level)
1439
+ process exp[0], level
1440
+ end
1441
+
1442
+ def next(exp, level)
1443
+ val = exp.empty? ? 'nil' : process(exp.shift, :expression)
1444
+ if in_while?
1445
+ "continue;"
1446
+ else
1447
+ "return #{val};"
1448
+ end
1449
+ end
1450
+
1451
+ def redo(exp, level)
1452
+ if in_while?
1453
+ @while_loop[:use_redo] = true
1454
+ "#{@while_loop[:redo_var]} = true"
1455
+ else
1456
+ "REDO()"
1457
+ end
1458
+ end
1459
+ end
1460
+ end