From da3557df665398a589cf4b3c1a11a79aa590f4da Mon Sep 17 00:00:00 2001 From: Peter Zotov Date: Sat, 14 Apr 2012 10:36:27 +0400 Subject: [PATCH] Implement global variables. --- lib/furnace-avm2/abc/metadata/script_info.rb | 1 + .../source/declaration_tokens/script_token.rb | 2 +- lib/furnace-avm2/source/decompiler.rb | 71 ++++++++++++++----- test/global.as | 11 +++ 4 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 test/global.as diff --git a/lib/furnace-avm2/abc/metadata/script_info.rb b/lib/furnace-avm2/abc/metadata/script_info.rb index c305e69..23a2e88 100644 --- a/lib/furnace-avm2/abc/metadata/script_info.rb +++ b/lib/furnace-avm2/abc/metadata/script_info.rb @@ -1,6 +1,7 @@ module Furnace::AVM2::ABC class ScriptInfo < Record include InitializerBody + include RecordWithTraits root_ref :initializer, :method diff --git a/lib/furnace-avm2/source/declaration_tokens/script_token.rb b/lib/furnace-avm2/source/declaration_tokens/script_token.rb index 15bcb56..4f7eb30 100644 --- a/lib/furnace-avm2/source/declaration_tokens/script_token.rb +++ b/lib/furnace-avm2/source/declaration_tokens/script_token.rb @@ -3,7 +3,7 @@ class ScriptToken < Furnace::Code::NonterminalToken include TokenWithTraits def initialize(origin, options={}) - options = options.merge(environment: :script) + options = options.merge(environment: :script, global_context: origin) super(origin, [ *transform_traits(origin, options.merge(static: false)), diff --git a/lib/furnace-avm2/source/decompiler.rb b/lib/furnace-avm2/source/decompiler.rb index 622fcd1..029a632 100644 --- a/lib/furnace-avm2/source/decompiler.rb +++ b/lib/furnace-avm2/source/decompiler.rb @@ -46,19 +46,13 @@ def decompile @nf = @body.code_to_nf if captures = ActivationPrologue.match(@nf) - @has_closure = true - @activation_local = captures[:activation_local] - - @slots = {} - @body.traits.map do |trait| - @slots[trait.idx] = trait + @closure_slots = {} + @body.slot_traits.each do |trait| + @closure_slots[trait.idx] = trait end @nf.children.slice! 0...4 else - @has_closure = false - @activation_local = nil - if RegularPrologue.match @nf @nf.children.slice! 0...1 else @@ -66,6 +60,13 @@ def decompile end end + if global = @options[:global_context] + @global_slots = {} + global.slot_traits.each do |trait| + @global_slots[trait.idx] = trait + end + end + stmt_block @nf, function: true rescue Exception => e @@ -312,10 +313,24 @@ def expr_get_local(opcode) [:get_scope_object, 1]] end + GlobalGetSlot = Matcher.new do + [:get_slot, + capture(:index), + either[ + [:get_global_scope], # normalized form + [:get_scope_object, 0] # not emitted by ASC + ]] + end + def expr_get_slot(opcode) - if @has_closure && captures = ActivationGetSlot.match(opcode) - index, = captures.values_at(:index) - token(VariableNameToken, @slots[index].name.name) + if @closure_slots && captures = ActivationGetSlot.match(opcode) + # treat as a local variable + slot = @closure_slots[captures[:index]] + token(VariableNameToken) + elsif @global_slots && captures = GlobalGetSlot.match(opcode) + # treat as a global property + slot = @global_slots[captures[:index]] + get_name(nil, slot.name.to_astlet) end end @@ -393,16 +408,38 @@ def expr_set_local(opcode) capture(:value)] end + GlobalSetSlot = Matcher.new do + [:set_slot, + capture(:index), + either[ + [:get_global_scope], # normalized form + [:get_scope_object, 0] # not emitted by ASC + ], + capture(:value)] + end + def expr_set_slot(opcode) - if @has_closure && captures = ActivationSetSlot.match(opcode) + if @closure_slots && captures = ActivationSetSlot.match(opcode) + # treat as a local variable index, value = captures.values_at(:index, :value) + slot = @closure_slots[index] - type = type_token(@slots[index].type.to_astlet) - expr_set_var(@slots[index].name.name, value, type, + type = type_token(slot.type.to_astlet) + expr = expr_set_var(slot.name.name, value, type, !@locals.include?(index)) + @locals.add index + + expr + elsif @global_slots && captures = GlobalSetSlot.match(opcode) + # treat as a global property + index, value = captures.values_at(:index, :value) + slot = @global_slots[index] + + token(AssignmentToken, [ + get_name(nil, slot.name.to_astlet), + expr(value) + ]) end - ensure - @locals.add index if index end ## Arithmetics diff --git a/test/global.as b/test/global.as new file mode 100644 index 0000000..2621f77 --- /dev/null +++ b/test/global.as @@ -0,0 +1,11 @@ +package global { + var a:int = 0; + + function q() { + print("a value is: " + a); + } + + a = 10; + + q(); +} \ No newline at end of file