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
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
-