# Copyright (C) 2011 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
require "config"
#
# Base utility types for the AST.
#
# Valid methods for Node:
#
# node.children -> Returns an array of immediate children.
#
# node.descendents -> Returns an array of all strict descendants (children
# and children of children, transitively).
#
# node.flatten -> Returns an array containing the strict descendants and
# the node itself.
#
# node.filter(type) -> Returns an array containing those elements in
# node.flatten that are of the given type (is_a? type returns true).
#
# node.mapChildren{|v| ...} -> Returns a new node with all children
# replaced according to the given block.
#
# Examples:
#
# node.filter(Setting).uniq -> Returns all of the settings that the AST's
# IfThenElse blocks depend on.
#
# node.filter(StructOffset).uniq -> Returns all of the structure offsets
# that the AST depends on.
class Node
attr_reader :codeOrigin
def initialize(codeOrigin)
@codeOrigin = codeOrigin
end
def codeOriginString
@codeOrigin.to_s
end
def descendants
children.collect{|v| v.flatten}.flatten
end
def flatten
[self] + descendants
end
def filter(type)
flatten.select{|v| v.is_a? type}
end
end
class NoChildren < Node
def initialize(codeOrigin)
super(codeOrigin)
end
def children
[]
end
def mapChildren
self
end
end
class StructOffsetKey
attr_reader :struct, :field
def initialize(struct, field)
@struct = struct
@field = field
end
def hash
@struct.hash + @field.hash * 3
end
def eql?(other)
@struct == other.struct and @field == other.field
end
end
#
# AST nodes.
#
class StructOffset < NoChildren
attr_reader :struct, :field
def initialize(codeOrigin, struct, field)
super(codeOrigin)
@struct = struct
@field = field
end
@@mapping = {}
def self.forField(codeOrigin, struct, field)
key = StructOffsetKey.new(struct, field)
unless @@mapping[key]
@@mapping[key] = StructOffset.new(codeOrigin, struct, field)
end
@@mapping[key]
end
def dump
"#{struct}::#{field}"
end
def <=>(other)
if @struct != other.struct
return @struct <=> other.struct
end
@field <=> other.field
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class Sizeof < NoChildren
attr_reader :struct
def initialize(codeOrigin, struct)
super(codeOrigin)
@struct = struct
end
@@mapping = {}
def self.forName(codeOrigin, struct)
unless @@mapping[struct]
@@mapping[struct] = Sizeof.new(codeOrigin, struct)
end
@@mapping[struct]
end
def dump
"sizeof #{@struct}"
end
def <=>(other)
@struct <=> other.struct
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class Immediate < NoChildren
attr_reader :value
def initialize(codeOrigin, value)
super(codeOrigin)
@value = value
raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value.is_a? Integer
end
def dump
"#{value}"
end
def ==(other)
other.is_a? Immediate and other.value == @value
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class AddImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
AddImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} + #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class SubImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
SubImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} - #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class MulImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
MulImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} * #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class NegImmediate < Node
attr_reader :child
def initialize(codeOrigin, child)
super(codeOrigin)
@child = child
end
def children
[@child]
end
def mapChildren
NegImmediate.new(codeOrigin, (yield @child))
end
def dump
"(-#{@child.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class OrImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
OrImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} | #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class AndImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
AndImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} & #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class XorImmediates < Node
attr_reader :left, :right
def initialize(codeOrigin, left, right)
super(codeOrigin)
@left = left
@right = right
end
def children
[@left, @right]
end
def mapChildren
XorImmediates.new(codeOrigin, (yield @left), (yield @right))
end
def dump
"(#{left.dump} ^ #{right.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class BitnotImmediate < Node
attr_reader :child
def initialize(codeOrigin, child)
super(codeOrigin)
@child = child
end
def children
[@child]
end
def mapChildren
BitnotImmediate.new(codeOrigin, (yield @child))
end
def dump
"(~#{@child.dump})"
end
def address?
false
end
def label?
false
end
def immediate?
true
end
def register?
false
end
end
class RegisterID < NoChildren
attr_reader :name
def initialize(codeOrigin, name)
super(codeOrigin)
@name = name
end
@@mapping = {}
def self.forName(codeOrigin, name)
unless @@mapping[name]
@@mapping[name] = RegisterID.new(codeOrigin, name)
end
@@mapping[name]
end
def dump
name
end
def address?
false
end
def label?
false
end
def immediate?
false
end
def register?
true
end
end
class FPRegisterID < NoChildren
attr_reader :name
def initialize(codeOrigin, name)
super(codeOrigin)
@name = name
end
@@mapping = {}
def self.forName(codeOrigin, name)
unless @@mapping[name]
@@mapping[name] = FPRegisterID.new(codeOrigin, name)
end
@@mapping[name]
end
def dump
name
end
def address?
false
end
def label?
false
end
def immediate?
false
end
def register?
true
end
end
class SpecialRegister < NoChildren
def initialize(name)
@name = name
end
def address?
false
end
def label?
false
end
def immediate?
false
end
def register?
true
end
end
class Variable < NoChildren
attr_reader :name
def initialize(codeOrigin, name)
super(codeOrigin)
@name = name
end
@@mapping = {}
def self.forName(codeOrigin, name)
unless @@mapping[name]
@@mapping[name] = Variable.new(codeOrigin, name)
end
@@mapping[name]
end
def dump
name
end
def inspect
"