Class: Furnace::AVM2::Transform::NFNormalize

Inherits:
Object
  • Object
show all
Includes:
Visitor
Defined in:
lib/furnace-avm2/transform/nf_normalize.rb

Constant Summary collapse

COERCE_MAP =
{
  :coerce_a => :any,
  :coerce_b => :bool,
  :coerce_s => :string,
}
CONVERT_MAP =
{
  :convert_i => :integer,
  :convert_u => :unsigned,
  :convert_d => :double,
  :convert_s => :string,
  :convert_o => :object,
}
ForInMatcher =
AST::Matcher.new do
  [:while,
    [:has_next2, capture(:object_reg), capture(:index_reg)],
    [:begin,
      [ either_multi[
          [ :set_local, capture(:value_reg) ],
          [ :set_slot, capture(:value_reg), [:get_scope_object, 1] ],
        ],
        [ either[:coerce, :convert], capture(:value_type),
          [ capture(:iterator),
            [:get_local, backref(:object_reg)],
            [:get_local, backref(:index_reg)]]]],
      capture_rest(:body)]]
end
ForInIndexMatcher =
AST::Matcher.new do
  [:set_local, backref(:index_reg), [:integer, 0]]
end
ForInObjectMatcher =
AST::Matcher.new do
  [:set_local, backref(:object_reg),
    [:coerce, :any,
      capture(:root)]]
end
SuperfluousContinueMatcher =
AST::Matcher.new do
  [:continue]
end

Instance Method Summary collapse

Instance Method Details

#on_coerce_imm(node) ⇒ Object Also known as: on_coerce_a, on_coerce_b, on_coerce_s



31
32
33
34
35
36
37
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 31

def on_coerce_imm(node)
  expr, = node.children
  node.update(:coerce, [
    COERCE_MAP[node.type],
    expr
  ])
end

#on_convert_imm(node) ⇒ Object Also known as: on_convert_i, on_convert_u, on_convert_d, on_convert_s, on_convert_o



50
51
52
53
54
55
56
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 50

def on_convert_imm(node)
  expr, = node.children
  node.update(:convert, [
    CONVERT_MAP[node.type],
    expr
  ])
end

#on_nop(node) ⇒ Object



21
22
23
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 21

def on_nop(node)
  node.update(:remove)
end

#on_while(node) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 92

def on_while(node)
  *whatever, code = node.children
  if SuperfluousContinueMatcher.match code.children.last
    code.children.slice! -1
  end

  if captures = ForInMatcher.match(node)
    parent = node.parent

    case captures[:iterator]
    when :next_name
      type = :for_in
    when :next_value
      type = :for_each_in
    else
      return
    end

    index_node = object_node = nil

    loop_index = parent.children.index(node)
    parent.children[0..loop_index].reverse_each do |parent_node|
      if ForInIndexMatcher.match(parent_node, captures)
        index_node  = parent_node
      elsif ForInObjectMatcher.match(parent_node, captures)
        object_node = parent_node
      end

      break if index_node && object_node
    end

    return unless index_node && object_node

    index_node.update(:remove)
    object_node.update(:remove)

    node.update(type, [
      captures[:value_reg],
      captures[:value_type],
      captures[:object_reg],
      AST::Node.new(:begin, captures[:body])
    ])
  end
end

#remove_useless_returnObject



15
16
17
18
19
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 15

def remove_useless_return
  if @nf.children.last.type == :return_void
    @nf.children.slice! -1
  end
end

#transform(nf) ⇒ Object



6
7
8
9
10
11
12
13
# File 'lib/furnace-avm2/transform/nf_normalize.rb', line 6

def transform(nf)
  @nf = nf.normalize_hierarchy!

  remove_useless_return
  visit @nf

  @nf
end