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.
- data/.gitignore +13 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.md +11 -116
- data/Rakefile +126 -0
- data/bin/opal +1 -2
- data/docs/spec_runner.html +16 -0
- data/index.html +434 -0
- data/lib/opal.rb +14 -15
- data/lib/opal/builder.rb +46 -148
- data/lib/opal/command.rb +45 -115
- data/lib/opal/context.rb +139 -78
- data/lib/opal/dependency_builder.rb +34 -0
- data/lib/opal/environment.rb +92 -0
- data/lib/opal/parser/grammar.rb +4915 -0
- data/lib/opal/{parser.y → parser/grammar.y} +430 -284
- data/lib/opal/parser/lexer.rb +1329 -0
- data/lib/opal/parser/parser.rb +1460 -0
- data/lib/opal/parser/scope.rb +140 -0
- data/lib/opal/parser/sexp.rb +17 -0
- data/lib/opal/version.rb +2 -1
- data/opal.gemspec +23 -0
- data/opal.js +3149 -4162
- data/runtime/README.md +25 -0
- data/runtime/corelib/alpha.rb +10 -0
- data/runtime/corelib/array.rb +962 -0
- data/runtime/corelib/basic_object.rb +66 -0
- data/runtime/corelib/boolean.rb +44 -0
- data/runtime/corelib/class.rb +43 -0
- data/runtime/corelib/comparable.rb +25 -0
- data/runtime/corelib/complex.rb +2 -0
- data/runtime/corelib/dir.rb +29 -0
- data/runtime/corelib/enumerable.rb +316 -0
- data/runtime/corelib/enumerator.rb +80 -0
- data/runtime/corelib/error.rb +25 -0
- data/runtime/corelib/file.rb +80 -0
- data/runtime/corelib/hash.rb +503 -0
- data/runtime/corelib/io.rb +44 -0
- data/runtime/corelib/kernel.rb +237 -0
- data/runtime/corelib/load_order +29 -0
- data/runtime/corelib/match_data.rb +37 -0
- data/runtime/corelib/module.rb +171 -0
- data/runtime/corelib/native.rb +50 -0
- data/runtime/corelib/nil_class.rb +47 -0
- data/runtime/corelib/numeric.rb +219 -0
- data/runtime/corelib/object.rb +21 -0
- data/runtime/corelib/proc.rb +42 -0
- data/runtime/corelib/range.rb +38 -0
- data/runtime/corelib/rational.rb +16 -0
- data/runtime/corelib/regexp.rb +63 -0
- data/runtime/corelib/string.rb +185 -0
- data/runtime/corelib/struct.rb +97 -0
- data/runtime/corelib/time.rb +196 -0
- data/runtime/corelib/top_self.rb +7 -0
- data/runtime/gemlib/alpha.rb +5 -0
- data/runtime/gemlib/kernel.rb +17 -0
- data/runtime/gemlib/load_order +2 -0
- data/runtime/kernel/class.js +256 -0
- data/runtime/kernel/debug.js +42 -0
- data/runtime/kernel/init.js +114 -0
- data/runtime/kernel/load_order +5 -0
- data/runtime/kernel/loader.js +151 -0
- data/runtime/kernel/runtime.js +414 -0
- data/runtime/spec/README.md +34 -0
- data/runtime/spec/core/array/allocate_spec.rb +15 -0
- data/runtime/spec/core/array/append_spec.rb +31 -0
- data/runtime/spec/core/array/assoc_spec.rb +29 -0
- data/runtime/spec/core/array/at_spec.rb +38 -0
- data/runtime/spec/core/array/clear_spec.rb +22 -0
- data/runtime/spec/core/array/collect_spec.rb +3 -0
- data/runtime/spec/core/array/compact_spec.rb +42 -0
- data/runtime/spec/core/array/concat_spec.rb +21 -0
- data/runtime/spec/core/array/constructor_spec.rb +24 -0
- data/runtime/spec/core/array/count_spec.rb +11 -0
- data/runtime/spec/core/array/delete_at_spec.rb +31 -0
- data/runtime/spec/core/array/delete_if_spec.rb +24 -0
- data/runtime/spec/core/array/delete_spec.rb +26 -0
- data/runtime/spec/core/array/each_index_spec.rb +33 -0
- data/runtime/spec/core/array/each_spec.rb +11 -0
- data/runtime/spec/core/array/element_reference_spec.rb +136 -0
- data/runtime/spec/core/array/element_set_spec.rb +7 -0
- data/runtime/spec/core/array/empty_spec.rb +10 -0
- data/runtime/spec/core/array/eql_spec.rb +3 -0
- data/runtime/spec/core/array/equal_value_spec.rb +3 -0
- data/runtime/spec/core/array/fetch_spec.rb +26 -0
- data/runtime/spec/core/array/first_spec.rb +54 -0
- data/runtime/spec/core/array/fixtures/classes.rb +8 -0
- data/runtime/spec/core/array/flatten_spec.rb +41 -0
- data/runtime/spec/core/array/include_spec.rb +20 -0
- data/runtime/spec/core/array/insert_spec.rb +59 -0
- data/runtime/spec/core/array/last_spec.rb +57 -0
- data/runtime/spec/core/array/length_spec.rb +3 -0
- data/runtime/spec/core/array/map_spec.rb +3 -0
- data/runtime/spec/core/array/plus_spec.rb +16 -0
- data/runtime/spec/core/array/pop_spec.rb +79 -0
- data/runtime/spec/core/array/push_spec.rb +19 -0
- data/runtime/spec/core/array/rassoc_spec.rb +12 -0
- data/runtime/spec/core/array/reject_spec.rb +54 -0
- data/runtime/spec/core/array/replace_spec.rb +3 -0
- data/runtime/spec/core/array/reverse_each_spec.rb +18 -0
- data/runtime/spec/core/array/reverse_spec.rb +9 -0
- data/runtime/spec/core/array/shared/collect.rb +53 -0
- data/runtime/spec/core/array/shared/eql.rb +19 -0
- data/runtime/spec/core/array/shared/length.rb +6 -0
- data/runtime/spec/core/array/shared/replace.rb +31 -0
- data/runtime/spec/core/class/new_spec.rb +19 -0
- data/runtime/spec/core/enumerable/all_spec.rb +102 -0
- data/runtime/spec/core/enumerable/any_spec.rb +115 -0
- data/runtime/spec/core/enumerable/collect_spec.rb +3 -0
- data/runtime/spec/core/enumerable/count_spec.rb +29 -0
- data/runtime/spec/core/enumerable/detect_spec.rb +3 -0
- data/runtime/spec/core/enumerable/find_spec.rb +3 -0
- data/runtime/spec/core/enumerable/fixtures/classes.rb +26 -0
- data/runtime/spec/core/enumerable/shared/collect.rb +12 -0
- data/runtime/spec/core/enumerable/shared/entries.rb +7 -0
- data/runtime/spec/core/enumerable/shared/find.rb +49 -0
- data/runtime/spec/core/enumerable/to_a_spec.rb +7 -0
- data/runtime/spec/core/false/and_spec.rb +11 -0
- data/runtime/spec/core/false/inspect_spec.rb +7 -0
- data/runtime/spec/core/false/or_spec.rb +11 -0
- data/runtime/spec/core/false/to_s_spec.rb +7 -0
- data/runtime/spec/core/false/xor_spec.rb +11 -0
- data/runtime/spec/core/hash/allocate_spec.rb +15 -0
- data/runtime/spec/core/hash/assoc_spec.rb +29 -0
- data/runtime/spec/core/hash/clear_spec.rb +21 -0
- data/runtime/spec/core/hash/clone_spec.rb +12 -0
- data/runtime/spec/core/hash/default_spec.rb +6 -0
- data/runtime/spec/core/hash/delete_if_spec.rb +15 -0
- data/runtime/spec/core/hash/element_reference_spec.rb +16 -0
- data/runtime/spec/core/hash/element_set_spec.rb +8 -0
- data/runtime/spec/core/hash/new_spec.rb +13 -0
- data/runtime/spec/core/matchdata/to_a_spec.rb +7 -0
- data/runtime/spec/core/nil/and_spec.rb +12 -0
- data/runtime/spec/core/nil/inspect_spec.rb +8 -0
- data/runtime/spec/core/nil/nil_spec.rb +8 -0
- data/runtime/spec/core/nil/or_spec.rb +12 -0
- data/runtime/spec/core/nil/to_a_spec.rb +8 -0
- data/runtime/spec/core/nil/to_f_spec.rb +12 -0
- data/runtime/spec/core/nil/to_i_spec.rb +12 -0
- data/runtime/spec/core/nil/to_s_spec.rb +8 -0
- data/runtime/spec/core/nil/xor_spec.rb +12 -0
- data/runtime/spec/core/numeric/equal_value_spec.rb +11 -0
- data/runtime/spec/core/object/is_a_spec.rb +2 -0
- data/runtime/spec/core/object/shared/kind_of.rb +0 -0
- data/runtime/spec/core/regexp/match_spec.rb +23 -0
- data/runtime/spec/core/regexp/shared/match.rb +11 -0
- data/runtime/spec/core/symbol/to_proc_spec.rb +8 -0
- data/runtime/spec/core/true/and_spec.rb +11 -0
- data/runtime/spec/core/true/inspect_spec.rb +7 -0
- data/runtime/spec/core/true/or_spec.rb +11 -0
- data/runtime/spec/core/true/to_s_spec.rb +7 -0
- data/runtime/spec/core/true/xor_spec.rb +11 -0
- data/runtime/spec/language/alias_spec.rb +25 -0
- data/runtime/spec/language/and_spec.rb +62 -0
- data/runtime/spec/language/array_spec.rb +68 -0
- data/runtime/spec/language/block_spec.rb +105 -0
- data/runtime/spec/language/break_spec.rb +49 -0
- data/runtime/spec/language/case_spec.rb +165 -0
- data/runtime/spec/language/defined_spec.rb +80 -0
- data/runtime/spec/language/ensure_spec.rb +82 -0
- data/runtime/spec/language/fixtures/block.rb +19 -0
- data/runtime/spec/language/fixtures/break.rb +39 -0
- data/runtime/spec/language/fixtures/defined.rb +9 -0
- data/runtime/spec/language/fixtures/ensure.rb +37 -0
- data/runtime/spec/language/fixtures/next.rb +46 -0
- data/runtime/spec/language/fixtures/send.rb +36 -0
- data/runtime/spec/language/fixtures/super.rb +43 -0
- data/runtime/spec/language/hash_spec.rb +43 -0
- data/runtime/spec/language/if_spec.rb +278 -0
- data/runtime/spec/language/loop_spec.rb +32 -0
- data/runtime/spec/language/next_spec.rb +128 -0
- data/runtime/spec/language/or_spec.rb +65 -0
- data/runtime/spec/language/predefined_spec.rb +21 -0
- data/runtime/spec/language/regexp/interpolation_spec.rb +9 -0
- data/runtime/spec/language/regexp_spec.rb +7 -0
- data/runtime/spec/language/send_spec.rb +105 -0
- data/runtime/spec/language/string_spec.rb +4 -0
- data/runtime/spec/language/super_spec.rb +18 -0
- data/runtime/spec/language/symbol_spec.rb +41 -0
- data/runtime/spec/language/undef_spec.rb +16 -0
- data/runtime/spec/language/unless_spec.rb +44 -0
- data/runtime/spec/language/until_spec.rb +137 -0
- data/runtime/spec/language/variables_spec.rb +28 -0
- data/runtime/spec/language/versions/hash_1.9.rb +20 -0
- data/runtime/spec/language/while_spec.rb +175 -0
- data/runtime/spec/library/stringscanner/scan_spec.rb +36 -0
- data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +49 -0
- data/runtime/spec/opal/opal/defined_spec.rb +15 -0
- data/runtime/spec/opal/opal/function_spec.rb +11 -0
- data/runtime/spec/opal/opal/native_spec.rb +16 -0
- data/runtime/spec/opal/opal/null_spec.rb +10 -0
- data/runtime/spec/opal/opal/number_spec.rb +11 -0
- data/runtime/spec/opal/opal/object_spec.rb +16 -0
- data/runtime/spec/opal/opal/string_spec.rb +11 -0
- data/runtime/spec/opal/opal/typeof_spec.rb +9 -0
- data/runtime/spec/opal/opal/undefined_spec.rb +10 -0
- data/runtime/spec/opal/true/case_compare_spec.rb +12 -0
- data/runtime/spec/opal/true/class_spec.rb +10 -0
- data/runtime/spec/spec_helper.rb +25 -0
- data/runtime/stdlib/base64.rb +91 -0
- data/runtime/stdlib/date.rb +4 -0
- data/{stdlib → runtime/stdlib}/dev.rb +0 -0
- data/runtime/stdlib/forwardable.rb +33 -0
- data/runtime/stdlib/optparse.rb +0 -0
- data/runtime/stdlib/pp.rb +6 -0
- data/{stdlib → runtime/stdlib}/racc/parser.rb +0 -0
- data/runtime/stdlib/rbconfig.rb +0 -0
- data/runtime/stdlib/si.rb +17 -0
- data/runtime/stdlib/strscan.rb +53 -0
- data/runtime/stdlib/uri.rb +111 -0
- data/runtime/stdlib/uri/common.rb +1014 -0
- data/runtime/stdlib/uri/ftp.rb +261 -0
- data/runtime/stdlib/uri/generic.rb +1599 -0
- data/runtime/stdlib/uri/http.rb +106 -0
- data/runtime/stdlib/uri/https.rb +22 -0
- data/runtime/stdlib/uri/ldap.rb +260 -0
- data/runtime/stdlib/uri/ldaps.rb +20 -0
- data/runtime/stdlib/uri/mailto.rb +280 -0
- data/spec/builder/build_source_spec.rb +52 -0
- data/spec/builder/fixtures/build_source/adam.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
- data/spec/builder/fixtures/build_source/beynon.rb +0 -0
- data/spec/builder/fixtures/build_source/charles.js +0 -0
- data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
- data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
- data/spec/builder/fixtures/build_source/foo/x.js +0 -0
- data/spec/builder/fixtures/build_source/foo/y.js +0 -0
- data/spec/builder/output_path_spec.rb +50 -0
- data/spec/grammar/alias_spec.rb +26 -0
- data/spec/grammar/and_spec.rb +13 -0
- data/spec/grammar/array_spec.rb +22 -0
- data/spec/grammar/attrasgn_spec.rb +28 -0
- data/spec/grammar/begin_spec.rb +38 -0
- data/spec/grammar/block_spec.rb +12 -0
- data/spec/grammar/break_spec.rb +17 -0
- data/spec/grammar/call_spec.rb +58 -0
- data/spec/grammar/class_spec.rb +35 -0
- data/spec/grammar/const_spec.rb +13 -0
- data/spec/grammar/cvar_spec.rb +11 -0
- data/spec/grammar/def_spec.rb +60 -0
- data/spec/grammar/false_spec.rb +17 -0
- data/spec/grammar/file_spec.rb +7 -0
- data/spec/grammar/gvar_spec.rb +13 -0
- data/spec/grammar/hash_spec.rb +17 -0
- data/spec/grammar/iasgn_spec.rb +9 -0
- data/spec/grammar/if_spec.rb +26 -0
- data/spec/grammar/iter_spec.rb +59 -0
- data/spec/grammar/ivar_spec.rb +9 -0
- data/spec/grammar/lasgn_spec.rb +8 -0
- data/spec/grammar/line_spec.rb +8 -0
- data/spec/grammar/lvar_spec.rb +38 -0
- data/spec/grammar/module_spec.rb +27 -0
- data/spec/grammar/nil_spec.rb +17 -0
- data/spec/grammar/not_spec.rb +27 -0
- data/spec/grammar/op_asgn1_spec.rb +23 -0
- data/spec/grammar/op_asgn2_spec.rb +23 -0
- data/spec/grammar/or_spec.rb +13 -0
- data/spec/grammar/return_spec.rb +17 -0
- data/spec/grammar/sclass_spec.rb +20 -0
- data/spec/grammar/self_spec.rb +17 -0
- data/spec/grammar/str_spec.rb +96 -0
- data/spec/grammar/super_spec.rb +20 -0
- data/spec/grammar/true_spec.rb +17 -0
- data/spec/grammar/undef_spec.rb +15 -0
- data/spec/grammar/unless_spec.rb +13 -0
- data/spec/grammar/while_spec.rb +15 -0
- data/spec/grammar/xstr_spec.rb +116 -0
- data/spec/grammar/yield_spec.rb +20 -0
- data/spec/spec_helper.rb +9 -0
- metadata +346 -21
- data/lib/opal/bundle.rb +0 -34
- data/lib/opal/lexer.rb +0 -902
- data/lib/opal/nodes.rb +0 -2150
- data/lib/opal/parser.rb +0 -4894
- data/lib/opal/rake/bundle_task.rb +0 -63
- data/opal-parser.js +0 -8343
- data/stdlib/strscan.rb +0 -52
- data/templates/init/Rakefile +0 -7
- data/templates/init/index.html +0 -17
- 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
|
-
|