furnace-avm2 0.0.9 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -3
- data/LICENSE +20 -0
- data/bin/furnace-avm2 +36 -6
- data/bin/furnace-avm2-decompiler +141 -0
- data/furnace-avm2.gemspec +2 -2
- data/lib/furnace-avm2.rb +1 -0
- data/lib/furnace-avm2/abc.rb +24 -7
- data/lib/furnace-avm2/abc/metadata/{option_detail.rb → default_value.rb} +5 -1
- data/lib/furnace-avm2/abc/metadata/initializer_body.rb +8 -0
- data/lib/furnace-avm2/abc/metadata/instance_info.rb +19 -4
- data/lib/furnace-avm2/abc/metadata/klass_info.rb +1 -4
- data/lib/furnace-avm2/abc/metadata/method_body_info.rb +27 -10
- data/lib/furnace-avm2/abc/metadata/method_info.rb +20 -13
- data/lib/furnace-avm2/abc/metadata/multiname_info.rb +6 -0
- data/lib/furnace-avm2/abc/metadata/multiname_kind_genericname.rb +8 -5
- data/lib/furnace-avm2/abc/metadata/multiname_kind_multiname.rb +4 -0
- data/lib/furnace-avm2/abc/metadata/multiname_kind_qname.rb +5 -1
- data/lib/furnace-avm2/abc/metadata/record_with_value.rb +90 -0
- data/lib/furnace-avm2/abc/metadata/script_info.rb +25 -1
- data/lib/furnace-avm2/abc/metadata/trait_class.rb +7 -3
- data/lib/furnace-avm2/abc/metadata/trait_info.rb +8 -4
- data/lib/furnace-avm2/abc/metadata/trait_method.rb +4 -0
- data/lib/furnace-avm2/abc/metadata/trait_slot.rb +5 -51
- data/lib/furnace-avm2/abc/opcodes/bitwise/as3_lshift.rb +1 -1
- data/lib/furnace-avm2/abc/opcodes/bitwise/as3_rshift.rb +1 -1
- data/lib/furnace-avm2/abc/opcodes/bitwise/as3_urshift.rb +1 -1
- data/lib/furnace-avm2/abc/opcodes/debug/as3_debug.rb +15 -0
- data/lib/furnace-avm2/abc/opcodes/debug/as3_debugfile.rb +12 -0
- data/lib/furnace-avm2/abc/opcodes/debug/as3_debugline.rb +12 -0
- data/lib/furnace-avm2/abc/opcodes/function_invocation/as3_callproplex.rb +21 -0
- data/lib/furnace-avm2/abc/opcodes/push_literal/as3_pushbyte.rb +1 -1
- data/lib/furnace-avm2/abc/opcodes/push_literal/as3_pushshort.rb +1 -1
- data/lib/furnace-avm2/binary/record.rb +21 -1
- data/lib/furnace-avm2/source/declaration_tokens/argument_declaration_token.rb +4 -0
- data/lib/furnace-avm2/source/declaration_tokens/arguments_token.rb +15 -0
- data/lib/furnace-avm2/source/declaration_tokens/callee_token.rb +72 -0
- data/lib/furnace-avm2/source/declaration_tokens/class_implementations_token.rb +21 -0
- data/lib/furnace-avm2/source/declaration_tokens/class_inheritance_token.rb +17 -0
- data/lib/furnace-avm2/source/declaration_tokens/class_name_token.rb +21 -0
- data/lib/furnace-avm2/source/declaration_tokens/class_specifiers_token.rb +12 -0
- data/lib/furnace-avm2/source/declaration_tokens/class_token.rb +21 -0
- data/lib/furnace-avm2/source/declaration_tokens/comment_token.rb +22 -0
- data/lib/furnace-avm2/source/declaration_tokens/constructor_specifiers_token.rb +12 -0
- data/lib/furnace-avm2/source/declaration_tokens/constructor_token.rb +15 -0
- data/lib/furnace-avm2/source/declaration_tokens/function_name_token.rb +14 -0
- data/lib/furnace-avm2/source/declaration_tokens/import_token.rb +17 -0
- data/lib/furnace-avm2/source/declaration_tokens/initialization_token.rb +7 -0
- data/lib/furnace-avm2/source/declaration_tokens/method_specifiers_token.rb +13 -0
- data/lib/furnace-avm2/source/declaration_tokens/method_token.rb +15 -0
- data/lib/furnace-avm2/source/declaration_tokens/multiname_token.rb +41 -0
- data/lib/furnace-avm2/source/declaration_tokens/namespace_name_token.rb +16 -0
- data/lib/furnace-avm2/source/declaration_tokens/package_name_token.rb +17 -0
- data/lib/furnace-avm2/source/declaration_tokens/package_token.rb +29 -0
- data/lib/furnace-avm2/source/declaration_tokens/rest_argument_token.rb +12 -0
- data/lib/furnace-avm2/source/declaration_tokens/scope_token.rb +23 -0
- data/lib/furnace-avm2/source/declaration_tokens/script_token.rb +14 -0
- data/lib/furnace-avm2/source/declaration_tokens/slot_name_token.rb +17 -0
- data/lib/furnace-avm2/source/declaration_tokens/slot_token.rb +23 -0
- data/lib/furnace-avm2/source/declaration_tokens/specifiers_token.rb +32 -0
- data/lib/furnace-avm2/source/declaration_tokens/token_with_traits.rb +51 -0
- data/lib/furnace-avm2/source/declaration_tokens/type_token.rb +7 -0
- data/lib/furnace-avm2/source/decompiler.rb +669 -0
- data/lib/furnace-avm2/source/implementation_tokens/access_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/array_token.rb +17 -0
- data/lib/furnace-avm2/source/implementation_tokens/as_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/assignment_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/binary_operator_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/break_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/call_token.rb +5 -0
- data/lib/furnace-avm2/source/implementation_tokens/continue_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/control_flow_token.rb +26 -0
- data/lib/furnace-avm2/source/implementation_tokens/control_transfer_token.rb +20 -0
- data/lib/furnace-avm2/source/implementation_tokens/delete_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/do_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/else_if_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/else_token.rb +22 -0
- data/lib/furnace-avm2/source/implementation_tokens/for_each_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/for_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/generic_specializers_token.rb +17 -0
- data/lib/furnace-avm2/source/implementation_tokens/generic_type_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/if_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/immediate_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/immediate_typename_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/in_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/index_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/is_complex.rb +7 -0
- data/lib/furnace-avm2/source/implementation_tokens/is_simple.rb +7 -0
- data/lib/furnace-avm2/source/implementation_tokens/is_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/label_declaration_token.rb +12 -0
- data/lib/furnace-avm2/source/implementation_tokens/label_token.rb +12 -0
- data/lib/furnace-avm2/source/implementation_tokens/local_variable_token.rb +7 -0
- data/lib/furnace-avm2/source/implementation_tokens/new_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/object_pair_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/object_token.rb +17 -0
- data/lib/furnace-avm2/source/implementation_tokens/parentheses_token.rb +11 -0
- data/lib/furnace-avm2/source/implementation_tokens/property_name_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/return_token.rb +16 -0
- data/lib/furnace-avm2/source/implementation_tokens/rtname_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/statement_token.rb +8 -0
- data/lib/furnace-avm2/source/implementation_tokens/super_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/switch_token.rb +9 -0
- data/lib/furnace-avm2/source/implementation_tokens/ternary_operator_token.rb +13 -0
- data/lib/furnace-avm2/source/implementation_tokens/throw_token.rb +12 -0
- data/lib/furnace-avm2/source/implementation_tokens/typeof_token.rb +13 -0
- data/lib/furnace-avm2/source/implementation_tokens/unary_operator_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/unary_post_operator_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/variable_name_token.rb +14 -0
- data/lib/furnace-avm2/source/implementation_tokens/while_token.rb +9 -0
- data/lib/furnace-avm2/transform.rb +5 -1
- data/lib/furnace-avm2/transform/ast_build.rb +22 -7
- data/lib/furnace-avm2/transform/ast_normalize.rb +61 -20
- data/lib/furnace-avm2/transform/cfg_build.rb +86 -0
- data/lib/furnace-avm2/transform/cfg_reduce.rb +249 -0
- data/lib/furnace-avm2/transform/nf_normalize.rb +130 -0
- data/lib/furnace-avm2/version.rb +4 -2
- data/test/basic.as +239 -0
- metadata +110 -38
- data/lib/furnace-avm2/abc/metadata/option_info.rb +0 -5
- data/test/exception.as +0 -29
- data/test/literal.as +0 -5
- data/test/logic.as +0 -23
- data/test/loops.as +0 -30
- data/test/number.as +0 -14
- data/test/switch.as +0 -38
- data/test/ternary.as +0 -22
@@ -1,5 +1,11 @@
|
|
1
1
|
module Furnace::AVM2::Binary
|
2
2
|
class Record
|
3
|
+
# This jruby compatibility hack allows descendants to use type
|
4
|
+
# as a name for the field.
|
5
|
+
if defined?(type)
|
6
|
+
undef :type
|
7
|
+
end
|
8
|
+
|
3
9
|
class << self
|
4
10
|
attr_reader :format, :codebase
|
5
11
|
|
@@ -180,6 +186,20 @@ module Furnace::AVM2::Binary
|
|
180
186
|
1
|
181
187
|
end
|
182
188
|
|
189
|
+
# int8
|
190
|
+
|
191
|
+
def read_int8(io, options)
|
192
|
+
io.read(1).unpack("c").at(0)
|
193
|
+
end
|
194
|
+
|
195
|
+
def write_int8(io, value, options)
|
196
|
+
io.write([value].pack("c"))
|
197
|
+
end
|
198
|
+
|
199
|
+
def length_int8(value, options)
|
200
|
+
1
|
201
|
+
end
|
202
|
+
|
183
203
|
# uint16
|
184
204
|
|
185
205
|
def read_uint16(io, options)
|
@@ -275,7 +295,7 @@ module Furnace::AVM2::Binary
|
|
275
295
|
|
276
296
|
def read_vstring(io, options)
|
277
297
|
length = read_vuint32(io, {})
|
278
|
-
io.read(length)
|
298
|
+
io.read(length).force_encoding('UTF-8')
|
279
299
|
end
|
280
300
|
|
281
301
|
def write_vstring(io, value, options)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class CalleeToken < Furnace::Code::SurroundedToken
|
3
|
+
def initialize(origin, header, method, body, options={})
|
4
|
+
@method, @body = method, body
|
5
|
+
|
6
|
+
super(origin, [
|
7
|
+
*header,
|
8
|
+
*declaration(origin, options),
|
9
|
+
(Furnace::AVM2::Decompiler.new(@body, options).decompile if @body),
|
10
|
+
Furnace::Code::NewlineToken.new(origin, options)
|
11
|
+
], options)
|
12
|
+
|
13
|
+
if options[:debug_funids]
|
14
|
+
@children.unshift \
|
15
|
+
CommentToken.new(origin,
|
16
|
+
"Function ##{options[:index]}",
|
17
|
+
options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def text_after
|
22
|
+
if @body.nil?
|
23
|
+
";\n" # no bodies
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def declaration(origin, options)
|
28
|
+
if @method.has_defaults?
|
29
|
+
defaults = [nil] * (@method.param_count - @method.default_count) + @method.defaults
|
30
|
+
end
|
31
|
+
|
32
|
+
args = @method.param_count.times.map do |num|
|
33
|
+
if @method.has_param_names?
|
34
|
+
name = @method.param_names[num]
|
35
|
+
else
|
36
|
+
name = "param#{num}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if defaults
|
40
|
+
default = defaults[num]
|
41
|
+
end
|
42
|
+
|
43
|
+
ArgumentDeclarationToken.new(@origin, [
|
44
|
+
VariableNameToken.new(origin, name, options),
|
45
|
+
(TypeToken.new(origin, [
|
46
|
+
MultinameToken.new(origin, @method.param_types[num], options)
|
47
|
+
], options) if @method.param_types[num]),
|
48
|
+
(InitializationToken.new(origin, [
|
49
|
+
ImmediateToken.new(origin, default.printable_value, options)
|
50
|
+
], options) if default && default.printable_value)
|
51
|
+
], options)
|
52
|
+
end
|
53
|
+
|
54
|
+
if @method.needs_rest?
|
55
|
+
args << ArgumentDeclarationToken.new(origin, [
|
56
|
+
RestArgumentToken.new(origin, "rest", options)
|
57
|
+
], options)
|
58
|
+
end
|
59
|
+
|
60
|
+
tokens = []
|
61
|
+
|
62
|
+
tokens << ArgumentsToken.new(origin, args, options)
|
63
|
+
if @method.return_type
|
64
|
+
tokens << TypeToken.new(origin, [
|
65
|
+
MultinameToken.new(origin, @method.return_type, options)
|
66
|
+
], options)
|
67
|
+
end
|
68
|
+
|
69
|
+
tokens
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class ClassImplementationsToken < Furnace::Code::SeparatedToken
|
3
|
+
def initialize(origin, options={})
|
4
|
+
super(origin, origin.interfaces.map { |iface|
|
5
|
+
MultinameToken.new(origin, iface, options)
|
6
|
+
}, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def text_before
|
10
|
+
"implements "
|
11
|
+
end
|
12
|
+
|
13
|
+
def text_between
|
14
|
+
", "
|
15
|
+
end
|
16
|
+
|
17
|
+
def text_after
|
18
|
+
" "
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class ClassInheritanceToken < Furnace::Code::SurroundedToken
|
3
|
+
def initialize(origin, options={})
|
4
|
+
super(origin, [
|
5
|
+
MultinameToken.new(origin, origin.super_name, options)
|
6
|
+
], options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def text_before
|
10
|
+
"extends "
|
11
|
+
end
|
12
|
+
|
13
|
+
def text_after
|
14
|
+
" "
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class ClassNameToken < Furnace::Code::SurroundedToken
|
3
|
+
def initialize(origin, options={})
|
4
|
+
super(origin, [
|
5
|
+
MultinameToken.new(origin, origin.name, options)
|
6
|
+
], options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def text_before
|
10
|
+
if origin.interface?
|
11
|
+
"interface "
|
12
|
+
else
|
13
|
+
"class "
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def text_after
|
18
|
+
" "
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class ClassToken < Furnace::Code::NonterminalToken
|
3
|
+
include TokenWithTraits
|
4
|
+
|
5
|
+
def initialize(origin, options={})
|
6
|
+
options = options.merge(environment: :class)
|
7
|
+
|
8
|
+
super(origin, [
|
9
|
+
ClassSpecifiersToken.new(origin, options),
|
10
|
+
ClassNameToken.new(origin, options),
|
11
|
+
(ClassInheritanceToken.new(origin, options) if origin.super_name),
|
12
|
+
(ClassImplementationsToken.new(origin, options) if origin.interfaces.any?),
|
13
|
+
ScopeToken.new(origin, [
|
14
|
+
*transform_traits(origin.klass, options.merge(static: true, instance: origin)),
|
15
|
+
(Furnace::Code::NewlineToken.new(origin, options) if origin.klass.traits.any?),
|
16
|
+
*transform_traits(origin, options.merge(static: false, instance: origin)),
|
17
|
+
], options)
|
18
|
+
], options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class CommentToken < Furnace::Code::TerminalToken
|
3
|
+
def initialize(origin, content, options={})
|
4
|
+
super(origin, options)
|
5
|
+
@content = content
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_text
|
9
|
+
if @options[:commented]
|
10
|
+
" #{@content}\n"
|
11
|
+
elsif @content.is_a? Furnace::Code::Token
|
12
|
+
"/*\n#{@content.to_text.rstrip}\n */\n\n"
|
13
|
+
else
|
14
|
+
"/* #{@content} */\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_structure(options={})
|
19
|
+
structurize "/* ... */", options
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'callee_token'
|
2
|
+
|
3
|
+
module Furnace::AVM2::Tokens
|
4
|
+
class ConstructorToken < CalleeToken
|
5
|
+
def initialize(origin, options={})
|
6
|
+
super(origin, [
|
7
|
+
ConstructorSpecifiersToken.new(origin, options),
|
8
|
+
FunctionNameToken.new(origin, [
|
9
|
+
MultinameToken.new(origin, options[:instance].name, options.merge(omit_ns: true))
|
10
|
+
], options),
|
11
|
+
], origin.initializer, origin.initializer_body,
|
12
|
+
options.merge({ index: origin.initializer_idx }))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class ImportToken < Furnace::Code::SurroundedToken
|
3
|
+
def initialize(origin, name, options={})
|
4
|
+
super(origin, [
|
5
|
+
NamespaceNameToken.new(origin, name, options)
|
6
|
+
], options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def text_before
|
10
|
+
"import "
|
11
|
+
end
|
12
|
+
|
13
|
+
def text_after
|
14
|
+
".*;\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'specifiers_token'
|
2
|
+
|
3
|
+
module Furnace::AVM2::Tokens
|
4
|
+
class MethodSpecifiersToken < SpecifiersToken
|
5
|
+
def specifiers
|
6
|
+
list = []
|
7
|
+
list << "final" if @origin.final? && !@options[:static]
|
8
|
+
list << "override" if @origin.override?
|
9
|
+
list.concat super
|
10
|
+
list
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'callee_token'
|
2
|
+
|
3
|
+
module Furnace::AVM2::Tokens
|
4
|
+
class MethodToken < CalleeToken
|
5
|
+
def initialize(origin, options={})
|
6
|
+
super(origin, [
|
7
|
+
MethodSpecifiersToken.new(origin, options),
|
8
|
+
FunctionNameToken.new(origin, [
|
9
|
+
MultinameToken.new(origin, origin.name, options.merge(omit_ns: true))
|
10
|
+
], options),
|
11
|
+
], origin.data.method, origin.body,
|
12
|
+
options.merge({ index: origin.data.method_idx }))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class MultinameToken < Furnace::Code::TerminalToken
|
3
|
+
def initialize(origin, multiname, options={})
|
4
|
+
super(origin, options)
|
5
|
+
@multiname = multiname
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_text
|
9
|
+
if @multiname
|
10
|
+
if @options[:debug_names]
|
11
|
+
debug = "/* #{@multiname.to_astlet.to_sexp} */ "
|
12
|
+
end
|
13
|
+
|
14
|
+
qualified_name = ->(ns) {
|
15
|
+
if @options[:ns].include?(ns) || ["*", ""].include?(ns.name.to_s) || @options[:omit_ns]
|
16
|
+
"#{debug}#{@multiname.name}"
|
17
|
+
else
|
18
|
+
"#{debug}#{ns.name}.#{@multiname.name}"
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
case @multiname.kind
|
23
|
+
when :QName, :QNameA
|
24
|
+
qualified_name.(@multiname.ns)
|
25
|
+
when :GenericName
|
26
|
+
"#{debug}#{@multiname.name.name}.<#{@multiname.parameters.map(&:name).join}>"
|
27
|
+
when :Multiname
|
28
|
+
if @multiname.ns_set.ns.count == 1
|
29
|
+
qualified_name.(@multiname.ns_set.ns[0])
|
30
|
+
else
|
31
|
+
"#{debug}%%Multiname"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
"#{debug}%%#{@multiname.kind}"
|
35
|
+
end
|
36
|
+
else
|
37
|
+
"%%nil"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Furnace::AVM2::Tokens
|
2
|
+
class NamespaceNameToken < Furnace::Code::TerminalToken
|
3
|
+
def initialize(origin, name, options={})
|
4
|
+
super(origin, options)
|
5
|
+
@name = name
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_text
|
9
|
+
if @name == "*"
|
10
|
+
nil
|
11
|
+
else
|
12
|
+
@name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|