opal 0.3.11 → 0.3.15

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/opal/nodes.rb DELETED
@@ -1,2150 +0,0 @@
1
- module Opal
2
- class Parser < Racc::Parser
3
-
4
- # Indent for generated code scopes; 2 spaces, never use tabs
5
- INDENT = ' '
6
-
7
- LEVEL_TOP = 0 # normal top level statements
8
- LEVEL_TOP_CLOSURE = 1 # normal top level, but wrapped in js closure
9
- LEVEL_LIST = 2
10
- LEVEL_EXPR = 3
11
- LEVEL_COMPARE = 4 # comparison of if statement etc
12
-
13
- # Base node for generators. All other nodes inherit from this
14
- class BaseNode
15
-
16
- attr_reader :line
17
-
18
- # Generate the code for this node. This MUST be overriden in subclasses.
19
- def generate(opts, level)
20
- ''
21
- end
22
-
23
- # Makes the node return its value. Overriden by various subclasses. This is
24
- # not for use with the ruby return statement, this just means that the
25
- # generated scope requires us to return within a javascript function. The
26
- # return statement in ruby uses another method for returning.
27
- def returns
28
- FuncReturnNode.new self
29
- end
30
-
31
- # By default, all nodes are expressions (';' to finish them). Statements
32
- # override this to be false.
33
- def expression?
34
- true
35
- end
36
-
37
- # Processes the node, which generates it. By default, process will also fix
38
- # the line number etc. Some nodes override this as they need a slightly
39
- # different approach. This will also set the level for indentation?? To
40
- # generate, but not indent or fix the line number, you may call {#generate}
41
- # directly. Note that this relies on level. If the level is {LEVEL_LIST},
42
- # for example, then a node will not correct its line number or indentation.
43
- def process(opts, level)
44
- if level <= LEVEL_LIST
45
- fix_line_number(opts) + generate(opts, level)
46
- else
47
- generate opts, level
48
- end
49
- end
50
-
51
- # Fix line numbers for nodes that need to. This returns code that is used
52
- # inside {#process}. Basically, this returns a string of new line chars
53
- # which will be prepended to the generated code for this node. This will
54
- # use the {@line} local ivar, if present, or you may pass a direct line
55
- # number into the {line} parameter.
56
- def fix_line_number(opts, line = nil)
57
- code = ''
58
- # make sure we are on the right line
59
- target = line || @line
60
- current = opts[:top].line
61
-
62
- if current < target
63
- (target - current).times {
64
- opts[:top].line += 1
65
- code += "\n"
66
- }
67
-
68
- code += opts[:indent]
69
- end
70
-
71
- code
72
- end
73
-
74
- # Reserved js words - we cannot just generate properties with these names
75
- # as they will cause a parse error, so we need to wrap them in brackets.
76
- def js_reserved_words
77
- %w[break case catch continue debugger default delete do else finally
78
- for function if in instanceof new return switch this throw try typeof
79
- var void while with class enum export extends import super true false]
80
- end
81
-
82
- def generate_truthy_test(expr, opts)
83
- if expr.is_a?(EqualNode) || expr.is_a?(ComparisonNode)
84
- expr.generate opts, LEVEL_EXPR
85
- else
86
- tmp = opts[:scope].temp_local
87
- code = expr.generate opts, LEVEL_EXPR
88
- res = "(#{tmp} = #{code}, #{tmp} !== false && #{tmp} !== nil)"
89
- opts[:scope].queue_temp tmp
90
- res
91
- end
92
- end
93
-
94
- end
95
-
96
- # Scope nodes. All scope nodes inherit from this node, including: method,
97
- # class, def, etc.
98
- class ScopeNode < BaseNode
99
-
100
- attr_reader :variables
101
-
102
- attr_reader :parent
103
-
104
- def initialize(parent, statements)
105
- @parent = parent
106
- @statements = statements
107
- # all variables - arg, tempts, params etc
108
- @variables = []
109
- # all vars for scope and temp
110
- @scope_vars = []
111
- # temps
112
- @temp_current = 'a'
113
- @temp_queue = []
114
- # ivars..we need to make sure these exist (make sure they are nil if new)
115
- @ivars = []
116
-
117
- # keep tabs on whether in while loop or not
118
- @while_scope = 0
119
- @while_scope_stack = []
120
- end
121
-
122
- def push_while_scope(while_scope)
123
- @while_scope_stack << while_scope
124
- @while_scope += 1
125
- end
126
-
127
- def pop_while_scope
128
- @while_scope_stack.pop
129
- @while_scope -= 1
130
- end
131
-
132
- def in_while_scope?
133
- @while_scope > 0
134
- end
135
-
136
- def while_scope
137
- @while_scope_stack.last
138
- end
139
-
140
- def ensure_ivar(name)
141
- @ivars << name unless @ivars.include? name
142
- end
143
-
144
- def param_variable(name)
145
- @variables << name
146
- end
147
-
148
- def ensure_variable(name)
149
- variable = find_variable name
150
- return variable if variable
151
-
152
- # does not exist in scope
153
- @scope_vars << name
154
- @variables << name
155
- end
156
-
157
- def find_variable(name)
158
- scope = self
159
-
160
- while scope
161
- return name if scope.variables.include? name
162
-
163
- if scope.is_a?(BlockNode) && scope.parent
164
- scope = scope.parent
165
- else
166
- break
167
- end
168
- end
169
-
170
- nil
171
- end
172
-
173
- def temp_local
174
- return @temp_queue.pop if @temp_queue.last
175
-
176
- name = '__' + @temp_current
177
- @scope_vars << name
178
- @temp_current = @temp_current.succ
179
- name
180
- end
181
-
182
- def queue_temp(temp)
183
- @temp_queue << temp
184
- end
185
-
186
- def set_uses_block
187
- return @block_arg_name if @block_arg_name
188
-
189
- @block_arg_name = '__block__'
190
- end
191
-
192
- def generate(opts, level)
193
- stmts = @statements.generate opts, level
194
- vars = ''
195
-
196
- vars + stmts
197
- end
198
- end
199
-
200
- # Top level scope. This also manages things like line numbers etc. All opts
201
- # will be passed a :top key, that references this root scope (instead of
202
- # needing to manually traverse it each time).
203
- class TopScopeNode < ScopeNode
204
-
205
- # helpers we need to add to top of file
206
- attr_reader :file_helpers
207
-
208
- # keep track of the current line number in the generator
209
- attr_accessor :line
210
-
211
- # expose top level options... useful for certain nodes to know if we are
212
- # debug mode etc
213
- attr_reader :opts
214
-
215
- def initialize(statements)
216
- super nil, statements
217
- @file_helpers = []
218
- @line = 1
219
- end
220
-
221
- # [Parser] options
222
- def options=(opts)
223
- @overload_arithmetic = opts[:overload_arithmetic] || false
224
- @overload_comparison = opts[:overload_comparison] || false
225
- @overload_bitwise = opts[:overload_bitwise] || false
226
- @overload_shift = opts[:overload_shift] || true
227
- @overload_equal = opts[:overload_equal] || false
228
- @method_missing = opts[:method_missing] || false
229
- end
230
-
231
- def overload_arithmetic?; @overload_arithmetic; end
232
-
233
- def overload_comparison?; @overload_comparison; end
234
-
235
- def overload_bitwise?; @overload_bitwise; end
236
-
237
- def overload_shift?; @overload_shift; end
238
-
239
- def overload_equal?; @overload_equal; end
240
-
241
- def method_missing?; @method_missing; end
242
-
243
- def generate(opts, level)
244
- @opts = opts
245
- code = []
246
- @statements.returns
247
- # code << super(opts, level)
248
- code << @statements.generate(opts, level)
249
-
250
- pre = "function($rb, self, __FILE__) {"
251
- pre += 'function $$(){'
252
- post = "\n}\n"
253
-
254
- unless @scope_vars.empty?
255
- post += "var #{@scope_vars.join ', '};"
256
- end
257
-
258
- post += 'var nil = $rb.Qnil, $super = $rb.S, $break = $rb.B, '
259
- post += '$class = $rb.dc, $defn = $rb.dm, $defs = $rb.ds, $cg = $rb.cg, '
260
- post += '$range = $rb.G, $hash = $rb.H, $B = $rb.P, $rb_send = $rb.sm'
261
-
262
- post += ';'
263
-
264
- # ivars
265
- @ivars.each do |ivar|
266
- if js_reserved_words.include? ivar
267
- ivar_name = "self['#{ivar}']"
268
- else
269
- ivar_name = "self.#{ivar}"
270
- end
271
-
272
- post += "#{ivar_name}===undefined&&(#{ivar_name}=nil);"
273
- end
274
-
275
- post += "return $$();\n"
276
- post += "}"
277
-
278
- pre + code.join('') + post
279
- end
280
- end
281
-
282
- # Statements - represents any chain of statements
283
- class StatementsNode < BaseNode
284
-
285
- attr_reader :nodes
286
-
287
- def initialize(nodes = [])
288
- @line = 0
289
- @nodes = nodes
290
- end
291
-
292
- def returns
293
- if @nodes.length > 0
294
- @nodes[-1] = @nodes[-1].returns
295
- else
296
- @nodes << FuncReturnNode.new(NilNode.new)
297
- end
298
- end
299
-
300
- def generate(opts, level)
301
- code = []
302
-
303
- return NilNode.new.generate(opts, level) if @nodes.empty?
304
-
305
- @nodes.each do |node|
306
- node_code = node.process opts, level
307
-
308
- if level <= LEVEL_TOP_CLOSURE
309
- # to prevent lots of trailing whitespace when we generate statements
310
- # on new lines, we only insert indent if we dont have a newline
311
- # marker straight away
312
- if node_code[0] == "\n"
313
- code << node_code
314
- else
315
- code << (opts[:indent] + node_code)
316
- end
317
-
318
- # if expression, add ';' .. statements don't need ';'. We MUST call
319
- # this after we generate it, as some statements may determine
320
- # themselves during compilation. For example, IfNode does this
321
- # depending on whether it needs to generate as a LEVEL_TOP, or as a
322
- # LEVEL_TOP_CLOSURE.
323
- code << ';' if node.expression?
324
-
325
- else
326
- code << node_code
327
- end
328
- end
329
-
330
- code.join ''
331
- end
332
-
333
- # Push more statements onto end.
334
- def <<(node)
335
- @nodes << node
336
- self
337
- end
338
-
339
- # Generate statements for top level. Generally used for files
340
- def generate_top(parser_options = {})
341
- scope = TopScopeNode.new self
342
- opts = {}
343
-
344
- scope.options = parser_options
345
-
346
- opts[:scope] = scope
347
- opts[:indent] = ''
348
- opts[:top] = scope
349
-
350
- return scope.generate opts, LEVEL_TOP
351
- end
352
- end
353
-
354
- class NumericNode < BaseNode
355
-
356
- attr_accessor :value
357
-
358
- def initialize(val)
359
- @line = val[:line]
360
- @value = val[:value]
361
- end
362
-
363
- def generate(opts, level)
364
- @value.to_s
365
- end
366
- end
367
-
368
- class SymbolNode < BaseNode
369
-
370
- def initialize(val)
371
- @line = val[:line]
372
- @value = val[:value]
373
- end
374
-
375
- def generate(opts, level)
376
- "'#{@value}'"
377
- end
378
- end
379
-
380
- class CallNode < BaseNode
381
-
382
- # any call may have a block assigned to it
383
- attr_writer :block
384
-
385
- attr_reader :recv
386
-
387
- attr_reader :mid
388
-
389
- def initialize(recv, mid, args)
390
- @recv = recv
391
- @mid = mid[:value]
392
- @args = args
393
- @line = recv ? recv.line : mid[:line]
394
- end
395
-
396
- def mid_to_jsid(id)
397
- return "['#{id}']" if /[\!\=\?\+\-\*\/\^\&\%\@\|\[\]\<\>\~]/ =~ id
398
-
399
- # default we just do .method_name
400
- '.' + id
401
- end
402
-
403
- def generate(opts, level)
404
- # Special handlers
405
- if @recv.is_a? NumericNode and @mid == '-@'
406
- @recv.value = "-#{@recv.value}"
407
- return @recv.generate opts, level
408
-
409
- elsif @mid == "block_given?"
410
- # name = opts[:scope].set_uses_block
411
- return "($yy !== $y.y)"
412
- end
413
-
414
- code = ''
415
- arg_res = []
416
- recv = nil
417
- mid = 'm$' + @mid
418
-
419
- # receiver
420
- if @recv.is_a? NumericNode
421
- recv = "(#{@recv.process opts, LEVEL_EXPR})"
422
- elsif @recv
423
- recv = @recv.process opts, LEVEL_EXPR
424
- else
425
- recv = "self"
426
- end
427
-
428
- # dispatch is true if we use the dispatch method (i.e. we want
429
- # to support method missing).
430
- dispatch = opts[:top].method_missing?
431
-
432
- unless dispatch
433
- mid = mid_to_jsid mid
434
- end
435
-
436
- args = @args
437
-
438
- # normal args
439
- if args[0]
440
- args[0].each do |arg|
441
- arg_res << arg.generate(opts, LEVEL_EXPR)
442
- end
443
- end
444
-
445
- # hash assoc args
446
- if args[2]
447
- arg_res << HashNode.new(args[2], { :line => 0 }, { :line => 0 }).generate(opts, LEVEL_EXPR)
448
- end
449
-
450
- if @block
451
- tmp_recv = opts[:scope].temp_local
452
- block = @block.generate opts, LEVEL_TOP
453
- arg_res.unshift tmp_recv
454
-
455
- code = "(#{tmp_recv} = #{recv}, $B.f = #{tmp_recv}#{mid}, ($B.p ="
456
- code += "#{block}).$self=self, $B.f).call(#{arg_res.join ', '})"
457
-
458
- opts[:scope].queue_temp tmp_recv
459
- code
460
-
461
- # &to_proc. Note, this must not reassign the $self for the proc.. we are
462
- # just passing on an existing block.
463
- #
464
- # FIXME need to actually call to_proc.
465
- elsif args[3]
466
- tmp_recv = opts[:scope].temp_local
467
- arg_res.unshift tmp_recv
468
-
469
- code = "($B.p = #{args[3].process opts, LEVEL_LIST}, "
470
- code += "$B.f = (#{tmp_recv} = #{recv})#{mid}).call(#{arg_res.join ', '})"
471
-
472
- opts[:scope].queue_temp tmp_recv
473
-
474
- code
475
-
476
- # no block
477
- else
478
- # splat args
479
- if args[1]
480
- splat = args[1].generate(opts, LEVEL_EXPR)
481
-
482
- if dispatch
483
- arg_res.unshift recv, "'#{mid}'"
484
- splat_args = "[#{arg_res.join ', '}].concat(#{splat})"
485
-
486
- return "$rb_send.apply(null, #{splat_args})"
487
- end
488
-
489
- # non-disptach
490
- tmp_recv = opts[:scope].temp_local
491
- splat_args = arg_res.empty? ? "#{splat}" :
492
- "[#{arg_res.join ', '}].concat(#{splat})"
493
-
494
- result = "(#{tmp_recv} = #{recv})" + mid + ".apply("
495
- result += "#{tmp_recv}, #{splat_args})"
496
- opts[:scope].queue_temp tmp_recv
497
-
498
- return result
499
-
500
- # not a block call, and not a &to_proc call
501
- else
502
- if dispatch
503
- arg_res.unshift recv, "'#{mid}'"
504
- "$rb_send(#{arg_res.join ', '})"
505
- else
506
- "#{recv}#{mid}(#{arg_res.join(', ')})"
507
- end
508
- end
509
- end
510
- end
511
- end
512
-
513
- class SelfNode < BaseNode
514
- # We often use a fake SelfNode for filling in gaps, so it takes a default
515
- # hash to save us manually making one every time.
516
- def initialize(val = { :line => 0 })
517
- @line = val[:line]
518
- end
519
-
520
- def generate(opts, level)
521
- 'self'
522
- end
523
- end
524
-
525
- class NilNode < BaseNode
526
- # Default val hash to save us passing them into fake nodes
527
- def initialize(val = { :line => 0 })
528
- @line = val[:line]
529
- end
530
-
531
- def generate(opts, level)
532
- 'nil'
533
- end
534
- end
535
-
536
- class UndefinedNode < BaseNode
537
-
538
- def initialize(val)
539
- @line = val[:line]
540
- end
541
-
542
- def generate(opts, level)
543
- 'undefined'
544
- end
545
- end
546
-
547
- class NullNode < BaseNode
548
-
549
- def initialize(val)
550
- @line = val[:line]
551
- end
552
-
553
- def generate(opts, level)
554
- 'null'
555
- end
556
- end
557
-
558
- class ModuleNode < ScopeNode
559
-
560
- def initialize(mod, path, body, _end)
561
- super nil, body
562
- @line = mod[:line]
563
- @base = path[0]
564
- @class_name = path[1][:value]
565
- @end_line = _end[:line]
566
- end
567
-
568
- def generate(opts, level)
569
- code = '$class('
570
-
571
- # base
572
- if @base.nil?
573
- code += SelfNode.new.generate(opts, level)
574
- else
575
- code += @base.generate(opts, level)
576
- end
577
-
578
- code += ', '
579
-
580
- # superclass
581
- code += (NilNode.new.generate(opts, level) + ', ')
582
-
583
- # module name
584
- code += "'#{@class_name}', "
585
-
586
- # scope
587
- scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
588
- @statements.returns
589
- stmt = @statements.generate scope, LEVEL_TOP
590
-
591
- if @scope_vars.empty?
592
- code += ('function(self) { ' + stmt)
593
- else
594
- code += "function(self) {var #{@scope_vars.join ', '};#{stmt}"
595
- end
596
-
597
- # fix line ending
598
- code += fix_line_number opts, @end_line
599
- code += '}, 2)'
600
-
601
- code
602
- end
603
- end
604
-
605
- class ClassNode < ScopeNode
606
-
607
- def initialize(cls, path, sup, body, _end)
608
- super nil, body
609
- @line = cls[:line]
610
- @base = path[0]
611
- @cls_name = path[1]
612
- @super = sup
613
- @end_line = _end[:line]
614
- end
615
-
616
- def generate(opts, level)
617
- code = '$class('
618
-
619
- # base
620
- code += (@base.nil? ? SelfNode.new.generate(opts, level) : @base.generate(opts, level))
621
- code += ', '
622
-
623
- # superclass
624
- code += (@super ? @super.generate(opts, level) : NilNode.new.generate(opts, level))
625
- code += ', '
626
-
627
- # class name
628
- code += "'#{@cls_name[:value]}', "
629
-
630
- # scope
631
- scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
632
- @statements.returns
633
- stmt = @statements.generate scope, level
634
-
635
- if @scope_vars.empty?
636
- code += "function(self) {#{stmt}"
637
- else
638
- code += "function(self) { var #{@scope_vars.join ', '};#{stmt}"
639
- end
640
-
641
- # fix trailing line number
642
- code += fix_line_number opts, @end_line
643
-
644
- code += opts[:indent] + '}, 0)'
645
- code
646
- end
647
- end
648
-
649
- class ClassShiftNode < ScopeNode
650
-
651
- def initialize(cls, expr, body, endn)
652
- super nil, body
653
- @line = cls[:line]
654
- @expr = expr
655
- @end_line = endn[:line]
656
- end
657
-
658
- def generate(opts, level)
659
- code = '$class('
660
-
661
- # base
662
- code += @expr.generate(opts, level)
663
- code += ', nil, nil, '
664
-
665
- # scope
666
- scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
667
- @statements.returns
668
- stmt = @statements.generate scope, level
669
-
670
- if @scope_vars.empty?
671
- code += "function(self) {#{stmt}"
672
- else
673
- code += "function(self) { var #{@scope_vars.join ', '};#{stmt}"
674
- end
675
-
676
- # fix trailing line number
677
- code += fix_line_number opts, @end_line
678
-
679
- code += opts[:indent] + '}, 1)'
680
- code
681
- end
682
- end
683
-
684
- class DefNode < ScopeNode
685
-
686
- def initialize(defn, singleton, fname, args, body, endn)
687
- super nil, body
688
- # do this early
689
- @line = defn[:line]
690
- @singleton = singleton
691
- @fname = fname
692
- @args = args
693
- @body = body
694
- @end_line = endn[:line]
695
- end
696
-
697
- def generate(opts, level)
698
- if @singleton
699
- code = "$defs(#{@singleton.generate opts, level}, "
700
- else
701
- code = "$defn(self, "
702
- end
703
-
704
- # method id
705
- code += "'#{@fname[:value]}', "
706
-
707
- # all method arg names need to be places in function arg list
708
- method_args = []
709
-
710
- pre_code = ''
711
-
712
- # scope
713
- scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
714
-
715
- args = @args
716
-
717
- # normal args
718
- if args[0]
719
- args[0].each do |arg|
720
- param_variable arg[:value]
721
- method_args << arg[:value]
722
- end
723
- end
724
-
725
- arity = method_args.length
726
-
727
- # optional args
728
- if args[1]
729
- args[1].each do |arg|
730
- param_variable arg[0][:value]
731
- method_args << arg[0][:value]
732
-
733
- # undefined is a special case... we use it to make core libs have
734
- # right arity, but we dont want overhead of checking for no arg.
735
- # i.e. non given arg will be undefined, not nil..
736
- unless arg[1].is_a? UndefinedNode
737
- pre_code += "if (#{arg[0][:value]} == undefined) {#{arg[0][:value]} = #{arg[1].generate(opts, LEVEL_EXPR)};}"
738
- end
739
- end
740
- end
741
-
742
- # rest args
743
- if args[2]
744
- if args[2][:value] != "*"
745
- param_variable args[2][:value]
746
- method_args << args[2][:value]
747
- pre_code += "#{args[2][:value]} = [].slice.call(arguments, #{method_args.length - 1});"
748
- end
749
- end
750
-
751
- # arity not currently used..could use it for debug mode?
752
- arity = (-arity) - 1 if args[1] or args[2]
753
-
754
- # block arg
755
- if args[3]
756
- param_variable args[3][:value]
757
- @block_arg_name = args[3][:value]
758
- pre_code += "var #{args[3][:value]} = (($yy == $y.y) ? nil: $yy);"
759
- end
760
-
761
- @body.returns
762
- stmt = @body.generate scope, LEVEL_TOP
763
-
764
- code += "function(#{method_args.join ', '}) { var self = this;"
765
-
766
- # local vars... only if we used any..
767
- unless @scope_vars.empty?
768
- pre_code = "var #{@scope_vars.join ', '};" + pre_code
769
- end
770
-
771
- # ivars
772
- @ivars.each do |ivar|
773
- if js_reserved_words.include? ivar
774
- ivar_name = "self['#{ivar}']"
775
- else
776
- ivar_name = "self.#{ivar}"
777
- end
778
-
779
- pre_code += "if (#{ivar_name} == undefined) { #{ivar_name} = nil; }"
780
- end
781
-
782
- # block support
783
- if @block_arg_name
784
-
785
- block_code = "var $y = $B, $yy, $ys, $yb = $y.b;"
786
- block_code += "if ($y.f == arguments.callee) { $yy = $y.p; }"
787
- block_code += "else { $yy = $y.y; }"
788
- block_code += "$y.f = nil ;$ys = $yy.$self;"
789
- pre_code = block_code + pre_code
790
- end
791
-
792
- code += (pre_code + stmt)
793
-
794
- # fix trailing end and 0/1 for normal/singleton
795
- code += (fix_line_number(opts, @end_line) + "})")
796
-
797
- code
798
- end
799
- end
800
-
801
- class BodyStatementsNode < BaseNode
802
-
803
- attr_reader :opt_rescue
804
- attr_reader :opt_ensure
805
-
806
- def initialize(stmt, optrescue, optelse, optensure)
807
- @statements = stmt
808
- @opt_rescue = optrescue
809
- @opt_else = optelse
810
- @opt_ensure = optensure
811
- @line = stmt.line
812
- end
813
-
814
- def returns
815
- @statements.returns
816
- end
817
-
818
- def generate(opts, level)
819
- @statements.generate opts, level
820
- end
821
- end
822
-
823
- class OrNode < BaseNode
824
-
825
- def initialize(node, lhs, rhs)
826
- @line = node[:line]
827
- @lhs = lhs
828
- @rhs = rhs
829
- end
830
-
831
- def generate(opts, level)
832
- res = '(('
833
- tmp = opts[:scope].temp_local
834
- res += "(#{tmp} = #{@lhs.generate opts, LEVEL_LIST}), #{tmp} != false && #{tmp} != nil) ? "
835
- res += "#{tmp} : #{@rhs.generate opts, LEVEL_LIST})"
836
- opts[:scope].queue_temp tmp
837
- res
838
- end
839
- end
840
-
841
- class AndNode < BaseNode
842
-
843
- def initialize(node, lhs, rhs)
844
- @line = node[:line]
845
- @lhs = lhs
846
- @rhs = rhs
847
- end
848
-
849
- def generate(opts, level)
850
- res = '(('
851
- tmp = opts[:scope].temp_local
852
- res += "(#{tmp} = #{@lhs.generate opts, LEVEL_LIST}), #{tmp} != false && #{tmp} != nil) ? "
853
- res += "#{@rhs.generate opts, LEVEL_LIST} : #{tmp})"
854
- opts[:scope].queue_temp tmp
855
- res
856
- end
857
- end
858
-
859
- class ArrayNode < BaseNode
860
-
861
- def initialize(parts, begn, endn)
862
- @line = begn[:line] || 0
863
- @end_line = endn[:line] || 0
864
- @args = parts
865
- end
866
-
867
- # We should really alter opts[:indent] to temp increase it so that args
868
- # on a new line are indented to that of the array beg/end
869
- def generate(opts, level)
870
- parts = @args[0].map { |arg| arg.process opts, LEVEL_LIST }
871
- code = "[#{parts.join ', '}#{fix_line_number opts, @end_line}]"
872
-
873
- if @args[1]
874
- res = "#{code}.concat(#{@args[1].generate opts, LEVEL_EXPR})"
875
- else
876
- res = code
877
- end
878
-
879
- "#{res}"
880
- end
881
- end
882
-
883
- class HashNode < BaseNode
884
-
885
- def initialize(parts, begn, endn)
886
- @line = begn[:line] || 0
887
- @end_line = endn[:line] || 0
888
- @parts = parts
889
- end
890
-
891
- def generate(opts, level)
892
- parts = @parts.flatten.map { |part| part.process opts, LEVEL_LIST }
893
- "$hash(#{parts.join ', '}#{fix_line_number opts, @end_line})"
894
- end
895
- end
896
-
897
- class IfNode < BaseNode
898
-
899
- def initialize(begn, expr, stmt, tail, endn)
900
- @type = begn[:value]
901
- @line = begn[:line]
902
- @end_line = endn[:line]
903
- @expr = expr
904
- @stmt = stmt
905
- @tail = tail
906
- end
907
-
908
- def returns
909
- @stmt.returns
910
- # need to apply to each tail item
911
- @tail.each do |tail|
912
- if tail[0][:value] == 'elsif'
913
- tail[2].returns
914
- else
915
- tail[1].returns
916
- end
917
- end
918
- self
919
- end
920
-
921
- def expression?
922
- @expr_level
923
- end
924
-
925
- def generate(opts, level)
926
- code = ''
927
- done_else = false
928
- tail = nil
929
- old_indent = opts[:indent]
930
-
931
- opts[:indent] = opts[:indent] + INDENT
932
-
933
- # stmt_level is level_top, unless we are an expression.. then it is level_top_closure..
934
- stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
935
-
936
- if stmt_level == LEVEL_TOP_CLOSURE
937
- returns
938
- @level_expr = true
939
- end
940
-
941
- expr = generate_truthy_test @expr, opts
942
- # code += "if ((#{@expr.generate opts, LEVEL_EXPR}).$r) {#{@stmt.process opts, stmt_level}"
943
- code += "if (#{@type == 'if' ? '' : '!'}#{expr}) {#{@stmt.process opts, stmt_level}"
944
-
945
- @tail.each do |tail|
946
- opts[:indent] = old_indent
947
- code = code + fix_line_number(opts, tail[0][:line])
948
-
949
- if tail[0][:value] == 'elsif'
950
- expr = generate_truthy_test tail[1], opts
951
-
952
- code += "} else if (#{expr}) {"
953
- # code += "} else if ((#{tail[1].generate opts, LEVEL_EXPR}).$r) {"
954
- opts[:indent] = opts[:indent] + INDENT
955
- code = code + tail[2].process(opts, stmt_level)
956
- else
957
- done_else = true
958
- code += '} else {'
959
- opts[:indent] = opts[:indent] + INDENT
960
- code += tail[1].process(opts, stmt_level)
961
- end
962
- end
963
-
964
- if @force_else
965
- # generate an else statement if we MUST have one. If, for example, we
966
- # set the result of ourself as a variable, we must have an else part
967
- # which simply returns nil.
968
- end
969
-
970
- opts[:indent] = old_indent
971
- code += (fix_line_number(opts, @end_line) + '}')
972
-
973
- # if we were an expression, we need to wrap ourself as closure
974
- code = "(function() {#{code}})()" if level == LEVEL_EXPR
975
- code
976
- end
977
- end
978
-
979
- class CaseNode < BaseNode
980
-
981
- def initialize(begn, expr, body, endn)
982
- @line = begn[:line]
983
- @expr = expr
984
- @body = body
985
- @end_line = endn[:line]
986
- end
987
-
988
- def returns
989
- @body.each do |part|
990
- if part[0][:value] == 'when'
991
- part[2].returns
992
- else
993
- part[1].returns
994
- end
995
- end
996
- self
997
- end
998
-
999
- def generate(opts, level)
1000
- code = ''
1001
- done_else = false
1002
- tail = nil
1003
- old_indent = opts[:indent]
1004
-
1005
- opts[:indent] = opts[:indent] + INDENT
1006
-
1007
- stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
1008
-
1009
- if stmt_level == LEVEL_TOP_CLOSURE
1010
- returns
1011
- @level_expr = true
1012
- end
1013
-
1014
- expr = @expr.generate opts, LEVEL_EXPR
1015
- case_ref = opts[:scope].temp_local
1016
-
1017
- code += "#{case_ref} = #{expr};"
1018
-
1019
- @body.each_with_index do |part, idx|
1020
- opts[:indent] = old_indent
1021
- code += fix_line_number opts, part[0][:line]
1022
-
1023
- if part[0][:value] == 'when'
1024
- code += (idx == 0 ? "if" : "} else if")
1025
- parts = part[1].map do |expr|
1026
- generate_truthy_test CallNode.new(expr,
1027
- {:value => '===' },
1028
- [[TempNode.new(case_ref)]]
1029
- ), opts
1030
- end
1031
- opts[:indent] = opts[:indent] + INDENT
1032
- code += " (#{parts.join ' || '}) {#{part[2].process opts, stmt_level}"
1033
- else
1034
- code += "} else {#{part[1].process opts, stmt_level}"
1035
- end
1036
- end
1037
-
1038
- opts[:indent] = old_indent
1039
-
1040
- opts[:scope].queue_temp case_ref
1041
- code += (fix_line_number(opts, @end_line) + '}')
1042
-
1043
- code = "(function() {#{code}})()" if level == LEVEL_EXPR
1044
- code
1045
- end
1046
- end
1047
-
1048
- class TempNode < BaseNode
1049
-
1050
- def initialize(val)
1051
- @val = val
1052
- @line = 0
1053
- end
1054
-
1055
- def generate(opts, level)
1056
- @val
1057
- end
1058
- end
1059
-
1060
- class ConstantNode < BaseNode
1061
-
1062
- def initialize(name)
1063
- @line = name[:line]
1064
- @name = name[:value]
1065
- end
1066
-
1067
- def value
1068
- @name
1069
- end
1070
-
1071
- def generate(opts, level)
1072
- "$cg(#{SelfNode.new.generate opts, level}, '#{@name}')"
1073
- end
1074
- end
1075
-
1076
- class Colon2Node < BaseNode
1077
-
1078
- def initialize(lhs, name)
1079
- @lhs = lhs
1080
- @line = name[:line]
1081
- @name = name[:value]
1082
- end
1083
-
1084
- def generate(opts, level)
1085
- # FIXME This should really be 'const at'.. const_get will relook all the way up chain
1086
- "$cg(#{@lhs.generate opts, level}, '#{@name}')"
1087
- end
1088
- end
1089
-
1090
- class Colon3Node < BaseNode
1091
-
1092
- def initialize(name)
1093
- @line = name[:line]
1094
- @name = name[:value]
1095
- end
1096
-
1097
- def generate(opts, level)
1098
- "rm_vm_cg($opal.Object, '#{@name}')"
1099
- end
1100
- end
1101
-
1102
- class AssignNode < BaseNode
1103
-
1104
- def initialize(lhs, rhs, assign = {})
1105
- @line = lhs.line
1106
- @lhs = lhs
1107
- @rhs = rhs
1108
- end
1109
-
1110
- def generate(opts, level)
1111
- if @lhs.is_a? IvarNode
1112
- ivar_name = @lhs.value.slice 1, @lhs.value.length
1113
- ivar_rhs = @rhs.generate opts, LEVEL_EXPR
1114
-
1115
- return "self['#{ivar_name}'] = #{ivar_rhs}" if js_reserved_words.include? ivar_name
1116
- return "self.#{ivar_name} = #{ivar_rhs}"
1117
-
1118
- elsif @lhs.is_a? CvarNode
1119
- return "$rb.cvs('#{@lhs.value}', #{@rhs.generate opts, LEVEL_EXPR})"
1120
-
1121
- elsif @lhs.is_a? GvarNode
1122
- return "$rb.gs('#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
1123
-
1124
- elsif @lhs.is_a? IdentifierNode
1125
- opts[:scope].ensure_variable @lhs.value
1126
-
1127
- # optimize yield assigning
1128
- if @rhs.is_a?(YieldNode) and level == LEVEL_TOP
1129
- return @rhs.generate_assign(opts, @lhs)
1130
- end
1131
- return @lhs.value + " = " + @rhs.generate(opts, LEVEL_EXPR)
1132
-
1133
- elsif @lhs.is_a? ArefNode
1134
- return AsetNode.new(@lhs.recv, @lhs.arefs, @rhs).process(opts, level)
1135
-
1136
- elsif @lhs.is_a? ConstantNode
1137
- return "$rb.cs(self, '#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
1138
-
1139
- elsif @lhs.is_a? CallNode
1140
- return CallNode.new(@lhs.recv, { :value => @lhs.mid + '=', :line => @line }, [[@rhs]]).generate(opts, level);
1141
-
1142
- else
1143
- raise "Bad lhs for assign on #{@line}"
1144
- end
1145
- end
1146
- end
1147
-
1148
- class MlhsAssignNode < BaseNode
1149
-
1150
- def initialize(node, lhs, rhs)
1151
- @line = node[:line]
1152
- @lhs = lhs
1153
- @rhs = rhs
1154
- end
1155
-
1156
- def generate(opts, level)
1157
- @lhs.inspect
1158
- @generator_opts = opts
1159
- '(' + generate_mlhs_context(@lhs, @rhs) + ')'
1160
- end
1161
-
1162
- def generate_mlhs_context(arr, rhs)
1163
- puts "mlhs node at #@line"
1164
- parts = []
1165
-
1166
- tmp_recv = @generator_opts[:scope].temp_local
1167
- tmp_len = @generator_opts[:scope].temp_local
1168
- rhs_code = rhs.generate @generator_opts, LEVEL_EXPR
1169
-
1170
- parts << "#{tmp_recv} = #{rhs_code}"
1171
- parts << "(#{tmp_recv}.$flags & $rb.T_ARRAY) || (#{tmp_recv} = [#{tmp_recv}])"
1172
- parts << "#{tmp_len} = #{tmp_recv}.length"
1173
-
1174
- if arr[0]
1175
- arr[0].each_with_index do |part, idx|
1176
- if part.is_a? Array
1177
- parts.push generate_mlhs_context part, rhs
1178
- else
1179
- assign = AssignNode.new part, TempNode.new("#{tmp_recv}[#{idx}]")
1180
- code = assign.generate @generator_opts, LEVEL_EXPR
1181
- parts.push "#{idx} < #{tmp_len} ? #{code} : nil"
1182
- # parts.push assign.generate @generator_opts, LEVE<D-/>L_EXPR
1183
- end
1184
- end
1185
- end
1186
-
1187
- parts << tmp_recv
1188
-
1189
- @generator_opts[:scope].queue_temp tmp_recv
1190
- @generator_opts[:scope].queue_temp tmp_len
1191
-
1192
- parts.join ', '
1193
- end
1194
- end
1195
-
1196
- class OpAsgnNode < BaseNode
1197
-
1198
- def initialize(asgn, lhs, rhs)
1199
- @line = asgn[:line]
1200
- @lhs = lhs
1201
- @rhs = rhs
1202
- @asgn = asgn[:value]
1203
- end
1204
-
1205
- def generate(opts, level)
1206
- assign = nil
1207
-
1208
- if @asgn == '||'
1209
- assign = OrNode.new({:value => '||', :line => @line }, @lhs, AssignNode.new(@lhs, @rhs))
1210
- elsif %w[+ - / *].include? @asgn
1211
- assign = AssignNode.new @lhs, CallNode.new(@lhs, {:value => @asgn, :line => @line}, [[@rhs]])
1212
- else
1213
- raise "Bas op asgn type: #{@asgn}"
1214
- end
1215
- assign.generate(opts, level)
1216
- end
1217
- end
1218
-
1219
- class IvarNode < BaseNode
1220
-
1221
- attr_reader :value
1222
-
1223
- def initialize(val)
1224
- @line = val[:line]
1225
- @value = val[:value]
1226
- end
1227
-
1228
- def generate(opts, level)
1229
- var_name = @value.slice 1, @value.length
1230
- opts[:scope].ensure_ivar var_name
1231
-
1232
- return "self['#{var_name}']" if js_reserved_words.include? var_name
1233
- "self.#{var_name}"
1234
- end
1235
- end
1236
-
1237
- class CvarNode < BaseNode
1238
-
1239
- attr_reader :value
1240
-
1241
- def initialize(val)
1242
- @line = val[:line]
1243
- @value = val[:value]
1244
- end
1245
-
1246
- def generate(opts, level)
1247
- "$rb.cvg('#{@value}')"
1248
- end
1249
- end
1250
-
1251
- class IdentifierNode < BaseNode
1252
- attr_reader :value
1253
-
1254
- def initialize(val)
1255
- @line = val[:line]
1256
- @value = val[:value]
1257
- end
1258
-
1259
- def local_variable?(opts)
1260
- opts[:scope].find_variable(@value) ? true : false
1261
- end
1262
-
1263
- def generate(opts, level)
1264
- if opts[:scope].find_variable @value
1265
- @value
1266
- else
1267
- CallNode.new(nil, { :value => @value, :line => @line }, [[]]).generate(opts, level)
1268
- end
1269
- end
1270
- end
1271
-
1272
- class FuncReturnNode < BaseNode
1273
-
1274
- def initialize(val)
1275
- @value = val
1276
- @line = val.line
1277
- end
1278
-
1279
- def generate(opts, level)
1280
- "return #{@value.generate opts, level}"
1281
- end
1282
- end
1283
-
1284
- class StringNode < BaseNode
1285
-
1286
- def initialize(parts, endn)
1287
- @line = endn[:line]
1288
- @parts = parts
1289
- @join = endn[:value]
1290
- end
1291
-
1292
- def generate(opts, level)
1293
- if @parts.length == 0
1294
- "''"
1295
- elsif @parts.length == 1
1296
- if @parts[0][0] == 'string_content'
1297
- @join + @parts[0][1][:value] + @join
1298
- elsif @parts[0][0] == 'string_dbegin'
1299
- CallNode.new(@parts[0][1], { :value => 'to_s', :line => 0 }, [[]]).generate(opts, level)
1300
- end
1301
-
1302
- else
1303
- parts = @parts.map do |part|
1304
- if part[0] == 'string_content'
1305
- @join + part[1][:value] + @join
1306
- elsif part[0] == 'string_dbegin'
1307
- "(" + part[1].generate(opts, LEVEL_EXPR) + ").m$to_s()"
1308
- # CallNode.new(part[1], { :value => 'to_s', :line => 0 }, [[]]).generate(opts, level)
1309
- end
1310
- end
1311
-
1312
- '(' + parts.join(' + ') + ')'
1313
- end
1314
- end
1315
- end
1316
-
1317
- class ArithmeticNode < BaseNode
1318
- def initialize(lhs, op, rhs)
1319
- @lhs = lhs
1320
- @op = op[:value]
1321
- @line = op[:line]
1322
- @rhs = rhs
1323
- end
1324
-
1325
- def generate(opts, level)
1326
- lhs = @lhs.generate opts, LEVEL_EXPR
1327
- rhs = @rhs.generate opts, LEVEL_EXPR
1328
-
1329
- if opts[:top].overload_arithmetic?
1330
- if opts[:top].method_missing?
1331
- return "$rb_send(#{lhs}, 'm$#{@op}', #{rhs})"
1332
- else
1333
- lhs = "(#{lhs})" if @lhs.is_a? NumericNode
1334
- return "#{lhs}['m$#{@op}'](#{rhs})"
1335
- end
1336
- else
1337
- return "#{lhs} #{@op} #{rhs}"
1338
- end
1339
- end
1340
- end
1341
-
1342
- class EqualNode < BaseNode
1343
- def initialize(lhs, op, rhs)
1344
- @line = op[:line]
1345
- @op = op[:value]
1346
- @lhs = lhs
1347
- @rhs = rhs
1348
- end
1349
-
1350
- def generate(opts, level)
1351
- lhs = @lhs.generate opts, LEVEL_EXPR
1352
- rhs = @rhs.generate opts, LEVEL_EXPR
1353
-
1354
- if opts[:top].overload_equal?
1355
- if opts[:top].method_missing?
1356
- return "$rb_send(#{lhs}, 'm$#{@op}', #{rhs})"
1357
- else
1358
- lhs = "(#{lhs})" if @lhs.is_a? NumericNode
1359
- return "#{lhs}['m$#{@op}'](#{rhs})"
1360
- end
1361
- else
1362
- op = "#{@op}="
1363
- lhs = "(#{lhs})" if @lhs.is_a? NumericNode
1364
- rhs = "(#{rhs})" if @rhs.is_a? NumericNode
1365
- return "#{lhs}.valueOf() #{op} #{rhs}.valueOf()"
1366
- end
1367
- end
1368
- end
1369
-
1370
- class ComparisonNode < BaseNode
1371
-
1372
- def initialize(op, lhs, rhs)
1373
- @line = op[:line]
1374
- @op = op[:value]
1375
- @lhs = lhs
1376
- @rhs = rhs
1377
- end
1378
-
1379
- def generate(opts, level)
1380
- lhs = @lhs.generate opts, LEVEL_EXPR
1381
- lhs = "(#{lhs})" if @lhs.is_a? NumericNode
1382
- rhs = @rhs.generate opts, LEVEL_EXPR
1383
-
1384
- if opts[:top].overload_equal?
1385
- if @op == '!='
1386
- "!#{lhs}['m$=='](#{rhs})"
1387
- else
1388
- "#{lhs}['m$#{@op}'](#{rhs})"
1389
- end
1390
- else
1391
- if @op == '!='
1392
- rhs = "(#{rhs})" if @rhs.is_a? NumericNode
1393
- "#{lhs}.valueOf() !== #{rhs}.valueOf()"
1394
- elsif @op == '=='
1395
- rhs = "(#{rhs})" if @rhs.is_a? NumericNode
1396
- "#{lhs}.valueOf() === #{rhs}.valueOf()"
1397
- else
1398
- "#{lhs} #{@op} #{rhs}"
1399
- end
1400
- end
1401
- end
1402
- end
1403
-
1404
- class UnaryNode < BaseNode
1405
-
1406
- def initialize(op, val)
1407
- @line = op[:line]
1408
- @op = op[:value]
1409
- @val = val
1410
- end
1411
-
1412
- def generate(opts, level)
1413
- if @op == '!'
1414
- tmp = opts[:scope].temp_local
1415
- expr = @val.generate opts, LEVEL_EXPR
1416
- res = "(#{tmp} = #{expr}, #{tmp} === false || #{tmp} === nil)"
1417
- opts[:scope].queue_temp tmp
1418
- res
1419
- else
1420
- "#{@op}#{@val.generate opts, level}"
1421
- end
1422
- end
1423
- end
1424
-
1425
- class TrueNode < BaseNode
1426
-
1427
- def initialize(val)
1428
- @line = val[:line]
1429
- end
1430
-
1431
- def generate(opts, level)
1432
- "true"
1433
- end
1434
- end
1435
-
1436
- class FalseNode < BaseNode
1437
-
1438
- def initialize(val)
1439
- @line = val[:line]
1440
- end
1441
-
1442
- def generate(opts, level)
1443
- "false"
1444
- end
1445
- end
1446
-
1447
- class BlockNode < ScopeNode
1448
-
1449
- def initialize(start, vars, stmt, endn)
1450
- super nil, stmt
1451
- @line = start[:line]
1452
- @args = vars
1453
- @stmt = stmt
1454
- @end_line = endn[:line]
1455
- end
1456
-
1457
- def generate(opts, level)
1458
- @parent = opts[:scope]
1459
- pre_code = ''
1460
- code = ''
1461
-
1462
- scope = { :scope => self, :top => opts[:top], :indent => opts[:indent] + INDENT }
1463
- args = @args[0]
1464
- method_args = []
1465
-
1466
- if args
1467
- # normal args
1468
- if args[0]
1469
- args[0].each do |arg|
1470
- param_variable arg[:value]
1471
- method_args << arg[:value]
1472
-
1473
- # Argument checking.. If normal args are required but not passed
1474
- # they just default to nil. Lambdas have the same effect as
1475
- # methods, so we check this by wrapping lambdas in an anon
1476
- # function that knows the arity of this block. So here, make all
1477
- # norm args nil if not present.
1478
- #
1479
- # Also, this is optional, and can be turned on/off for
1480
- # performance gains.
1481
- if false
1482
- pre_code += "if (#{arg[:value]} === undefined) { #{arg[:value]} = nil; }"
1483
- end
1484
- end
1485
- end
1486
-
1487
- # optional args
1488
- if args[1]
1489
- args[1].each do |arg|
1490
- opt_arg_name = arg[0][:value]
1491
- param_variable opt_arg_name
1492
- method_args << arg[0][:value]
1493
- pre_code += "if (#{opt_arg_name} === undefined) { #{opt_arg_name} = #{arg[1].generate(opts, level)};}"
1494
- end
1495
- end
1496
-
1497
- # rest args
1498
- if args[2]
1499
- # ignore rest arg if it is anonymous
1500
- unless args[2][:value] == '*'
1501
- rest_arg_name = args[2][:value]
1502
- # FIXME if we just pass '*', then we make a tmp variable name for it..
1503
- param_variable rest_arg_name
1504
- method_args << rest_arg_name
1505
- pre_code += "#{rest_arg_name} = [].slice.call(arguments, #{method_args.length - 1});"
1506
- end
1507
- end
1508
-
1509
- # block arg
1510
- if args[3]
1511
- param_variable args[3][:value]
1512
- @block_arg_name = args[3][:value]
1513
- pre_code += "var #{args[3][:value]} = (($yy == $y.y) ? nil: $yy);"
1514
- end
1515
- end
1516
-
1517
- @stmt.returns
1518
- stmt = @stmt.process scope, LEVEL_TOP
1519
-
1520
- block_var = opts[:scope].temp_local
1521
- # code += "(#{block_var} = "
1522
-
1523
- code += "function(#{method_args.join ', '}) { var self = this;"
1524
-
1525
- unless @scope_vars.empty?
1526
- code += " var #{@scope_vars.join ', '};"
1527
- end
1528
-
1529
- # block arg
1530
- if @block_arg_name
1531
- block_code = "var $y = $B, $yy, $ys, $yb = $y.b;"
1532
- block_code += "if ($y.f == arguments.callee) { $yy = $y.p; }"
1533
- block_code += "else { $yy = $y.y; }"
1534
- block_code += "$y.f = nil ;$ys = $yy.o$s;"
1535
- pre_code = block_code + pre_code
1536
- end
1537
-
1538
- code += (pre_code + stmt + fix_line_number(opts, @end_line) + "}")
1539
-
1540
- # code += ", #{block_var}.$arity = 0, #{block_var}.$meth = null"
1541
- # code += ", #{block_var})"
1542
- opts[:scope].queue_temp block_var
1543
- code
1544
- end
1545
- end
1546
-
1547
- class XStringNode < BaseNode
1548
-
1549
- def initialize(begn, parts, endn)
1550
- @line = begn[:line]
1551
- @parts = parts
1552
- @end_line = endn[:line]
1553
- end
1554
-
1555
- # we dont want return for xstring.. or do we? no..
1556
- def returns
1557
- self
1558
- end
1559
-
1560
- # Treat ourself like an expression. All xstrings should add their own
1561
- # semi-colons etc, so we can allow if, return, etc.
1562
- def expression?
1563
- false
1564
- end
1565
-
1566
- def generate(opts, level)
1567
- parts = @parts.map do |part|
1568
- if part[0] == 'string_content'
1569
- part[1][:value]
1570
- elsif part[0] == 'string_dbegin'
1571
- part[1].generate opts, LEVEL_EXPR
1572
- end
1573
- end
1574
-
1575
- parts.join ''
1576
- end
1577
- end
1578
-
1579
- class ParenNode < BaseNode
1580
-
1581
- def initialize(opening, parts, closing)
1582
- @line = opening[:line]
1583
- @parts = parts
1584
- @end_line = closing[:line]
1585
- end
1586
-
1587
- def generate(opts, level)
1588
- parts = @parts.nodes.map do |part|
1589
- part.generate opts, LEVEL_EXPR
1590
- end
1591
-
1592
- # if no parens, then we need to eval to nil
1593
- parts << 'nil' if parts.empty?
1594
-
1595
- "(#{parts.join ', '})"
1596
- end
1597
- end
1598
-
1599
- class ArefNode < BaseNode
1600
-
1601
- attr_reader :recv
1602
-
1603
- attr_reader :arefs
1604
-
1605
- def initialize(recv, arefs)
1606
- @line = recv.line
1607
- @recv = recv
1608
- @arefs = arefs
1609
- end
1610
-
1611
- def generate(opts, level)
1612
- CallNode.new(@recv, { :line => @line, :value => '[]'}, @arefs).generate opts, level
1613
- end
1614
- end
1615
-
1616
- class AsetNode < BaseNode
1617
-
1618
- def initialize(recv, arefs, val)
1619
- @line = recv.line
1620
- @recv = recv
1621
- @arefs = arefs
1622
- @val = val
1623
- end
1624
-
1625
- def generate(opts, level)
1626
- @arefs[0] || (@arefs[0] = [])
1627
- @arefs[0] << @val
1628
- CallNode.new(@recv, { :line => @line, :value => '[]='}, @arefs ).generate(opts, level)
1629
- end
1630
- end
1631
-
1632
- # Used for post form of IF and UNLESS statements
1633
- class IfModNode < BaseNode
1634
-
1635
- def initialize(type, expr, stmt)
1636
- @line = type[:line]
1637
- @type = type[:value]
1638
- @expr = expr
1639
- @stmt = stmt
1640
- end
1641
-
1642
- # If we return, that means our "else" result - which is not generated by
1643
- # default, needs to return nil (as it might be needed if our if statement
1644
- # does not evaluate truthy
1645
- def returns
1646
- @returns = true
1647
- @stmt = @stmt.returns
1648
- self
1649
- end
1650
-
1651
- def generate(opts, level)
1652
- # if we return, make sure our stmt does
1653
- @stmt.returns if @returns
1654
-
1655
- expr = generate_truthy_test @expr, opts
1656
-
1657
- r = "if(#{@type == 'if' ? '' : '!'}(#{expr}"
1658
- r += ")) {#{@stmt.process(opts, LEVEL_TOP)}}"
1659
-
1660
- # also, if we return, we need to ensure we have an else conditional
1661
- r += " else { return nil; }" if @returns
1662
- r
1663
- end
1664
- end
1665
-
1666
- class YieldNode < BaseNode
1667
-
1668
- def initialize(start, args)
1669
- @line = start[:line]
1670
- @args = args
1671
- end
1672
-
1673
- # Get basic yielding code yield(yself,...)
1674
- def yield_code(opts)
1675
- block_code = "$yy"
1676
-
1677
- parts = []
1678
-
1679
- if @args[0]
1680
- @args[0].each { |arg| parts << arg.generate(opts, LEVEL_EXPR) }
1681
- end
1682
-
1683
- if @args[1]
1684
- parts.unshift '$ys'
1685
- code = "#{block_code}.apply($ys, [#{parts.join ', '}].concat(#{@args[1].generate(opts, LEVEL_EXPR)}))"
1686
- else
1687
- parts.unshift '$ys'
1688
- code = "#{block_code}.call(#{parts.join ', '})"
1689
- end
1690
-
1691
- code
1692
- end
1693
-
1694
- def generate(opts, level)
1695
- # need to get block from nearest method
1696
- block = opts[:scope].set_uses_block
1697
- code = yield_code opts
1698
-
1699
- if level == LEVEL_TOP
1700
- "if (#{code} == $yb) { return $yb.$value; }"
1701
- else
1702
- # basically we need to return out of this method and we are not
1703
- # top level so we will need to throw and error which is caught
1704
- # directly inside this method which just returns the break
1705
- # value. We should warn that the given code is going to cause
1706
- # a try/catch statement to be added to check for this. i.e. this
1707
- # can/should be optimized out in the source code
1708
- tmp = opts[:scope].temp_local
1709
- "((#{tmp} = #{code}) == $yb ? $break() : #{tmp})"
1710
- end
1711
- end
1712
-
1713
- # special generator for assigning to variable. We know we will be
1714
- # top level if this is called.
1715
- def generate_assign(opts, lhs)
1716
- "if ((#{lhs.value} = #{yield_code opts}) == $yb) { return $yb.$value; }"
1717
- end
1718
- end
1719
-
1720
- class BreakNode < BaseNode
1721
-
1722
- def initialize(start, args)
1723
- @line = start[:line]
1724
- @args = args
1725
- end
1726
-
1727
- # as we either throw or return ourself we can ignore the
1728
- # request to return ourself if last statement
1729
- def returns
1730
- self
1731
- end
1732
-
1733
- def generate(opts, level)
1734
- code = []
1735
-
1736
- if @args[0]
1737
- @args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1738
- end
1739
-
1740
- case code.length
1741
- when 0
1742
- code = "nil"
1743
- when 1
1744
- code = code[0]
1745
- else
1746
- code = '[' + code.join(', ') + ']'
1747
- end
1748
-
1749
- if opts[:scope].in_while_scope?
1750
- while_scope = opts[:scope].while_scope
1751
- tmp_break_val = while_scope.set_captures_break
1752
- "#{tmp_break_val} = #{code}; break"
1753
- elsif opts[:scope].is_a? BlockNode
1754
- if level == LEVEL_TOP
1755
- "return ($B.b.$value = #{code}, $B.b)"
1756
- else
1757
- # block must have a try/catch wrapper inside to detect
1758
- # breaks and return the break value if a break is fired.
1759
- # We should also warn that the ruby code is not optimized
1760
- # and suggest it is reconfigured to avoid the (possibly)
1761
- # expensive try/catch block.
1762
- "$break(#{code})"
1763
- end
1764
- else
1765
- "$break(#{code})"
1766
- end
1767
- end
1768
- end
1769
-
1770
- class NextNode < BaseNode
1771
-
1772
- def initialize(start, args)
1773
- @line = start[:line]
1774
- @args = args
1775
- end
1776
-
1777
- def returns
1778
- self
1779
- end
1780
-
1781
- def generate(opts, level)
1782
- code = []
1783
-
1784
- if @args[0]
1785
- @args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1786
- end
1787
-
1788
- case code.length
1789
- when 0
1790
- code = "nil"
1791
- when 1
1792
- code = code[0]
1793
- else
1794
- code = '[' + code.join(', ') + ']'
1795
- end
1796
-
1797
- if opts[:scope].in_while_scope?
1798
- "continue"
1799
- else
1800
- # if in block
1801
- "return #{code}"
1802
- # else if in while/until loop
1803
-
1804
- end
1805
- end
1806
- end
1807
-
1808
- class RedoNode < BaseNode
1809
-
1810
- def initialize(start)
1811
- @line = start[:line]
1812
- end
1813
-
1814
- def generate(opts, level)
1815
- if opts[:scope].in_while_scope?
1816
- "#{opts[:scope].while_scope.redo_var} = true"
1817
- else
1818
- "REDO()"
1819
- end
1820
- end
1821
- end
1822
-
1823
- class WhileNode < BaseNode
1824
-
1825
- attr_reader :redo_var
1826
-
1827
- def initialize(begn, exp, stmt, endn)
1828
- @line = begn[:line]
1829
- @type = begn[:value]
1830
- @expr = exp
1831
- @stmt = stmt
1832
- @end_line = endn[:line]
1833
- end
1834
-
1835
- def returns
1836
- @returns = true
1837
- self
1838
- end
1839
-
1840
- def set_captures_break
1841
- tmp = @current_scope.temp_local
1842
- @captures_break = tmp
1843
- end
1844
-
1845
- def generate(opts, level)
1846
- @current_scope = opts[:scope]
1847
- stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
1848
- truthy = @type == 'while' ? '' : '!'
1849
-
1850
- if stmt_level == LEVEL_TOP_CLOSURE
1851
- returns
1852
- @level_expr = true
1853
- end
1854
-
1855
- @redo_var = eval_expr = opts[:scope].temp_local
1856
- code = "#{eval_expr} = false; while (#{eval_expr} || #{truthy}("
1857
- code += generate_truthy_test @expr, opts
1858
- code += ")) {#{eval_expr} = false;"
1859
-
1860
- opts[:scope].push_while_scope self
1861
-
1862
- code += @stmt.process opts, LEVEL_TOP
1863
-
1864
- opts[:scope].pop_while_scope
1865
-
1866
- code += fix_line_number opts, @end_line
1867
- code += "}"
1868
-
1869
- opts[:scope].queue_temp eval_expr
1870
-
1871
- return_value = "nil"
1872
-
1873
- if @captures_break
1874
- code = "#@captures_break = nil; #{code}"
1875
- opts[:scope].queue_temp @captures_break
1876
- return_value = @captures_break
1877
- end
1878
-
1879
- code = "(function() {#{code} return #{return_value};})()" if stmt_level == LEVEL_TOP_CLOSURE
1880
- code
1881
- end
1882
- end
1883
-
1884
- class ForNode < BaseNode
1885
-
1886
- def initialize(begn, vars, expr, compstmt, endn)
1887
- @line = begn[:line]
1888
- @vars = vars
1889
- @expr = expr
1890
- @stmt = compstmt
1891
- @end_line = endn[:line]
1892
- end
1893
-
1894
- def returns
1895
- @returns = true
1896
- self
1897
- end
1898
-
1899
- def generate(opts, level)
1900
- @current_scope = opts[:scope]
1901
- stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
1902
-
1903
- if stmt_level == LEVEL_TOP_CLOSURE
1904
- returns
1905
- @level_expr = true
1906
- end
1907
-
1908
- idx = opts[:scope].temp_local
1909
- ref = opts[:scope].temp_local
1910
- len = opts[:scope].temp_local
1911
- code = "for (#{idx} = 0, #{ref} = #{@expr.generate opts, LEVEL_EXPR}"
1912
- code += ", #{len} = #{ref}.length; #{idx} < #{len}; #{idx}++) {"
1913
-
1914
- code += @stmt.process opts, LEVEL_TOP
1915
-
1916
- code += fix_line_number opts, @end_line
1917
- code += "}"
1918
- end
1919
- end
1920
-
1921
- class SuperNode < BaseNode
1922
-
1923
- def initialize(start, args)
1924
- @line = start[:line]
1925
- @args = args
1926
- end
1927
-
1928
- def generate(opts, level)
1929
- parts = []
1930
-
1931
- if @args[0]
1932
- @args[0].each { |arg| parts << arg.generate(opts, LEVEL_EXPR) }
1933
- end
1934
-
1935
- "$super(arguments.callee, self, [#{parts.join ', '}])"
1936
- end
1937
- end
1938
-
1939
- class ReturnNode < BaseNode
1940
-
1941
- def initialize(ret, val)
1942
- @line = ret[:line]
1943
- @args = val
1944
- end
1945
-
1946
- def returns
1947
- self
1948
- end
1949
-
1950
- def generate(opts, level)
1951
- args = @args
1952
-
1953
- if args[0].nil?
1954
- code = NilNode.new.generate opts, level
1955
- elsif args[0].length == 1
1956
- code = args[0][0].generate opts, level
1957
- else
1958
- # this really should return array of return vals
1959
- code = NilNode.new.generate opts, level
1960
- code = []
1961
- args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1962
- code = code = '[' + code.join(', ') + ']'
1963
- end
1964
-
1965
- # if we are in a block, we need to throw return to nearest mthod
1966
- if !opts[:scope].is_a?(DefNode)
1967
- return_func = '__return_func'
1968
- return "$return(#{code}, #{return_func})"
1969
-
1970
- # level top, we are running full stmts, so just return normally
1971
- elsif level == LEVEL_TOP
1972
- return "return #{code}"
1973
- else
1974
- "$return(#{code})"
1975
- end
1976
- end
1977
- end
1978
-
1979
- class BeginNode < BaseNode
1980
-
1981
- def initialize(beginn, body, endn)
1982
- @line = beginn[:line]
1983
- @body = body
1984
- @end_line = endn[:line]
1985
- end
1986
-
1987
- def generate(opts, level)
1988
- code = "try {"
1989
- old_indent = opts[:indent]
1990
- opts[:indent] = opts[:indent] + INDENT
1991
-
1992
- code += @body.process opts, LEVEL_TOP
1993
- code += "} catch (__err__) {"
1994
-
1995
- @body.opt_rescue.each do |res|
1996
- code += "#{fix_line_number opts, res[0][:line]}if (true){"
1997
- opts[:indent] = opts[:indent] + INDENT
1998
- opts[:scope].ensure_variable res[2].value if res[2]
1999
- code += (res[2].value + " = __err__;") if res[2]
2000
- code += "#{res[3].process opts, LEVEL_TOP}}"
2001
- opts[:indent] = old_indent + INDENT
2002
- end
2003
-
2004
- if opt_ensure = @body.opt_ensure
2005
- # puts "optional ensure!"
2006
- code += "} finally {"
2007
- code += opt_ensure.process opts, LEVEL_TOP
2008
- end
2009
-
2010
-
2011
- opts[:indent] = old_indent
2012
- code += (fix_line_number(opts, @end_line) + "}")
2013
- code
2014
- end
2015
- end
2016
-
2017
- class TernaryNode < BaseNode
2018
-
2019
- def initialize(expr, truthy, falsy)
2020
- @line = expr.line
2021
- @expr = expr
2022
- @true = truthy
2023
- @false = falsy
2024
- end
2025
-
2026
- def generate(opts, level)
2027
- test = generate_truthy_test @expr, opts
2028
- "(#{test} ? #{@true.generate opts, LEVEL_EXPR} : #{@false.generate opts, LEVEL_EXPR})"
2029
- end
2030
- end
2031
-
2032
- class GvarNode < BaseNode
2033
-
2034
- attr_reader :value
2035
-
2036
- def initialize(val)
2037
- @line = val[:line]
2038
- @value = val[:value]
2039
- end
2040
-
2041
- def generate(opts, level)
2042
- "$rb.gg('#{@value}')"
2043
- end
2044
- end
2045
-
2046
- class FileNode < BaseNode
2047
-
2048
- def initialize(val)
2049
- @line = val[:line]
2050
- end
2051
-
2052
- def generate(opts, level)
2053
- "__FILE__"
2054
- end
2055
- end
2056
-
2057
- class LineNode < BaseNode
2058
-
2059
- def initialize(val)
2060
- @line = val[:line]
2061
- @val = val[:value]
2062
- end
2063
-
2064
- def generate(opts, level)
2065
- "(#{@val})"
2066
- end
2067
- end
2068
-
2069
- class RegexpNode < BaseNode
2070
-
2071
- def initialize(begn, parts)
2072
- @line = begn[:line]
2073
- @parts = parts
2074
- end
2075
-
2076
- def generate(opts, level)
2077
- parts = @parts.map do |part|
2078
- if part[0] == 'string_content'
2079
- part[1][:value]
2080
- elsif part[0] == 'string_dbegin'
2081
- part[1].generate opts, LEVEL_EXPR
2082
- end
2083
- end
2084
-
2085
- "/#{parts.join ''}/"
2086
- end
2087
- end
2088
-
2089
- class WordsNode < BaseNode
2090
-
2091
- def initialize(begn, parts, endn)
2092
- @line = begn[:line]
2093
- @parts = parts
2094
- @end_line = endn[:line]
2095
- end
2096
-
2097
- def generate(opts, level)
2098
- parts = @parts.map do |part|
2099
- if part[0] == 'string_content'
2100
- part[1][:value].inspect
2101
- else
2102
- CallNode.new(part[1], {:value => 'to_s', :line => @line }, []).generate(opts, LEVEL_EXPR)
2103
- end
2104
- end
2105
-
2106
- '[' + parts.join(', ') + ']'
2107
- end
2108
- end
2109
-
2110
- class RangeNode < BaseNode
2111
-
2112
- def initialize(range, beg, last)
2113
- @line = beg.line
2114
- @beg = beg
2115
- @last = last
2116
- @range = range[:value]
2117
- @end_line = last.line
2118
- end
2119
-
2120
- def generate(opts, level)
2121
- beg = @beg.generate opts, LEVEL_EXPR
2122
- last = @last.generate opts, LEVEL_EXPR
2123
- excl = @range == '...'
2124
- "$range(#{beg}, #{last}, #{excl})"
2125
- end
2126
- end
2127
-
2128
- class UndefNode < BaseNode
2129
-
2130
- def initialize(start, parts)
2131
- @line = start[:line]
2132
- @parts = parts
2133
- end
2134
-
2135
- def generate(opts, level)
2136
- parts = @parts.map do |a|
2137
- if a.is_a? SymbolNode
2138
- a.generate opts, level
2139
- else
2140
- '"' + a[:value] + '"'
2141
- end
2142
- end
2143
- parts.unshift 'self'
2144
- "$rb.um(#{parts.join ', '})"
2145
- end
2146
- end
2147
- end
2148
- end
2149
-
2150
-