1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252 |
- # 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
- "<variable #{name} at #{codeOriginString}>"
- end
- end
- class Address < Node
- attr_reader :base, :offset
-
- def initialize(codeOrigin, base, offset)
- super(codeOrigin)
- @base = base
- @offset = offset
- raise "Bad base for address #{base.inspect} at #{codeOriginString}" unless base.is_a? Variable or base.register?
- raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
- end
-
- def withOffset(extraOffset)
- Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset))
- end
-
- def children
- [@base, @offset]
- end
-
- def mapChildren
- Address.new(codeOrigin, (yield @base), (yield @offset))
- end
-
- def dump
- "#{offset.dump}[#{base.dump}]"
- end
-
- def address?
- true
- end
-
- def label?
- false
- end
-
- def immediate?
- false
- end
-
- def register?
- false
- end
- end
- class BaseIndex < Node
- attr_reader :base, :index, :scale, :offset
-
- def initialize(codeOrigin, base, index, scale, offset)
- super(codeOrigin)
- @base = base
- @index = index
- @scale = scale
- raise unless [1, 2, 4, 8].member? @scale
- @offset = offset
- end
-
- def scaleShift
- case scale
- when 1
- 0
- when 2
- 1
- when 4
- 2
- when 8
- 3
- else
- raise "Bad scale at #{codeOriginString}"
- end
- end
-
- def withOffset(extraOffset)
- BaseIndex.new(codeOrigin, @base, @index, @scale, Immediate.new(codeOrigin, @offset.value + extraOffset))
- end
-
- def children
- [@base, @index, @offset]
- end
-
- def mapChildren
- BaseIndex.new(codeOrigin, (yield @base), (yield @index), @scale, (yield @offset))
- end
-
- def dump
- "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
- end
-
- def address?
- true
- end
-
- def label?
- false
- end
-
- def immediate?
- false
- end
-
- def register?
- false
- end
- end
- class AbsoluteAddress < NoChildren
- attr_reader :address
-
- def initialize(codeOrigin, address)
- super(codeOrigin)
- @address = address
- end
-
- def withOffset(extraOffset)
- AbsoluteAddress.new(codeOrigin, Immediate.new(codeOrigin, @address.value + extraOffset))
- end
-
- def dump
- "#{address.dump}[]"
- end
-
- def address?
- true
- end
-
- def label?
- false
- end
-
- def immediate?
- false
- end
-
- def register?
- false
- end
- end
- class Instruction < Node
- attr_reader :opcode, :operands, :annotation
-
- def initialize(codeOrigin, opcode, operands, annotation=nil)
- super(codeOrigin)
- @opcode = opcode
- @operands = operands
- @annotation = annotation
- end
-
- def children
- operands
- end
-
- def mapChildren(&proc)
- Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation)
- end
-
- def dump
- "\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
- end
- def lowerDefault
- case opcode
- when "localAnnotation"
- $asm.putLocalAnnotation
- when "globalAnnotation"
- $asm.putGlobalAnnotation
- else
- raise "Unhandled opcode #{opcode} at #{codeOriginString}"
- end
- end
- end
- class Error < NoChildren
- def initialize(codeOrigin)
- super(codeOrigin)
- end
-
- def dump
- "\terror"
- end
- end
- class ConstDecl < Node
- attr_reader :variable, :value
-
- def initialize(codeOrigin, variable, value)
- super(codeOrigin)
- @variable = variable
- @value = value
- end
-
- def children
- [@variable, @value]
- end
-
- def mapChildren
- ConstDecl.new(codeOrigin, (yield @variable), (yield @value))
- end
-
- def dump
- "const #{@variable.dump} = #{@value.dump}"
- end
- end
- $labelMapping = {}
- class Label < NoChildren
- attr_reader :name
-
- def initialize(codeOrigin, name)
- super(codeOrigin)
- @name = name
- end
-
- def self.forName(codeOrigin, name)
- if $labelMapping[name]
- raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
- else
- $labelMapping[name] = Label.new(codeOrigin, name)
- end
- $labelMapping[name]
- end
-
- def dump
- "#{name}:"
- end
- end
- class LocalLabel < NoChildren
- attr_reader :name
-
- def initialize(codeOrigin, name)
- super(codeOrigin)
- @name = name
- end
- @@uniqueNameCounter = 0
-
- def self.forName(codeOrigin, name)
- if $labelMapping[name]
- raise "Label name collision: #{name}" unless $labelMapping[name].is_a? LocalLabel
- else
- $labelMapping[name] = LocalLabel.new(codeOrigin, name)
- end
- $labelMapping[name]
- end
-
- def self.unique(comment)
- newName = "_#{comment}"
- if $labelMapping[newName]
- while $labelMapping[newName = "_#{@@uniqueNameCounter}_#{comment}"]
- @@uniqueNameCounter += 1
- end
- end
- forName(nil, newName)
- end
-
- def cleanName
- if name =~ /^\./
- "_" + name[1..-1]
- else
- name
- end
- end
-
- def dump
- "#{name}:"
- end
- end
- class LabelReference < Node
- attr_reader :label
-
- def initialize(codeOrigin, label)
- super(codeOrigin)
- @label = label
- end
-
- def children
- [@label]
- end
-
- def mapChildren
- LabelReference.new(codeOrigin, (yield @label))
- end
-
- def name
- label.name
- end
-
- def dump
- label.name
- end
-
- def address?
- false
- end
-
- def label?
- true
- end
-
- def immediate?
- false
- end
- end
- class LocalLabelReference < NoChildren
- attr_reader :label
-
- def initialize(codeOrigin, label)
- super(codeOrigin)
- @label = label
- end
-
- def children
- [@label]
- end
-
- def mapChildren
- LocalLabelReference.new(codeOrigin, (yield @label))
- end
-
- def name
- label.name
- end
-
- def dump
- label.name
- end
-
- def address?
- false
- end
-
- def label?
- true
- end
-
- def immediate?
- false
- end
- end
- class Sequence < Node
- attr_reader :list
-
- def initialize(codeOrigin, list)
- super(codeOrigin)
- @list = list
- end
-
- def children
- list
- end
-
- def mapChildren(&proc)
- Sequence.new(codeOrigin, @list.map(&proc))
- end
-
- def dump
- list.collect{|v| v.dump}.join("\n")
- end
- end
- class True < NoChildren
- def initialize
- super(nil)
- end
-
- @@instance = True.new
-
- def self.instance
- @@instance
- end
-
- def value
- true
- end
-
- def dump
- "true"
- end
- end
- class False < NoChildren
- def initialize
- super(nil)
- end
-
- @@instance = False.new
-
- def self.instance
- @@instance
- end
-
- def value
- false
- end
-
- def dump
- "false"
- end
- end
- class TrueClass
- def asNode
- True.instance
- end
- end
- class FalseClass
- def asNode
- False.instance
- end
- end
- class Setting < NoChildren
- attr_reader :name
-
- def initialize(codeOrigin, name)
- super(codeOrigin)
- @name = name
- end
-
- @@mapping = {}
-
- def self.forName(codeOrigin, name)
- unless @@mapping[name]
- @@mapping[name] = Setting.new(codeOrigin, name)
- end
- @@mapping[name]
- end
-
- def dump
- name
- end
- end
- class And < Node
- attr_reader :left, :right
-
- def initialize(codeOrigin, left, right)
- super(codeOrigin)
- @left = left
- @right = right
- end
-
- def children
- [@left, @right]
- end
-
- def mapChildren
- And.new(codeOrigin, (yield @left), (yield @right))
- end
-
- def dump
- "(#{left.dump} and #{right.dump})"
- end
- end
- class Or < Node
- attr_reader :left, :right
-
- def initialize(codeOrigin, left, right)
- super(codeOrigin)
- @left = left
- @right = right
- end
-
- def children
- [@left, @right]
- end
-
- def mapChildren
- Or.new(codeOrigin, (yield @left), (yield @right))
- end
-
- def dump
- "(#{left.dump} or #{right.dump})"
- end
- end
- class Not < Node
- attr_reader :child
-
- def initialize(codeOrigin, child)
- super(codeOrigin)
- @child = child
- end
-
- def children
- [@child]
- end
-
- def mapChildren
- Not.new(codeOrigin, (yield @child))
- end
-
- def dump
- "(not #{child.dump})"
- end
- end
- class Skip < NoChildren
- def initialize(codeOrigin)
- super(codeOrigin)
- end
-
- def dump
- "\tskip"
- end
- end
- class IfThenElse < Node
- attr_reader :predicate, :thenCase
- attr_accessor :elseCase
-
- def initialize(codeOrigin, predicate, thenCase)
- super(codeOrigin)
- @predicate = predicate
- @thenCase = thenCase
- @elseCase = Skip.new(codeOrigin)
- end
-
- def children
- if @elseCase
- [@predicate, @thenCase, @elseCase]
- else
- [@predicate, @thenCase]
- end
- end
-
- def mapChildren
- IfThenElse.new(codeOrigin, (yield @predicate), (yield @thenCase), (yield @elseCase))
- end
-
- def dump
- "if #{predicate.dump}\n" + thenCase.dump + "\nelse\n" + elseCase.dump + "\nend"
- end
- end
- class Macro < Node
- attr_reader :name, :variables, :body
- def initialize(codeOrigin, name, variables, body)
- super(codeOrigin)
- @name = name
- @variables = variables
- @body = body
- end
-
- def children
- @variables + [@body]
- end
-
- def mapChildren
- Macro.new(codeOrigin, @name, @variables.map{|v| yield v}, (yield @body))
- end
-
- def dump
- "macro #{name}(" + variables.collect{|v| v.dump}.join(", ") + ")\n" + body.dump + "\nend"
- end
- end
- class MacroCall < Node
- attr_reader :name, :operands, :annotation
-
- def initialize(codeOrigin, name, operands, annotation)
- super(codeOrigin)
- @name = name
- @operands = operands
- raise unless @operands
- @operands.each{|v| raise unless v}
- @annotation = annotation
- end
-
- def children
- @operands
- end
-
- def mapChildren(&proc)
- MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation)
- end
-
- def dump
- "\t#{name}(" + operands.collect{|v| v.dump}.join(", ") + ")"
- end
- end
|