# Holds globals, and (for now at least), global constants. # Note that Ruby-like "constants" aren't really - they are "assign-once" # variables. As such, some of them can be treated as true constants # (because their value is known at compile time), but some of them are # not. For now, we'll treat all of them as global variables. class GlobalScope attr_accessor :globals def initialize @globals = Set.new end def get_arg a return [:global,a] if @globals.member?(a) return [:addr,a] end end class FuncScope def initialize func, next_scope = nil @func = func @next = next_scope end def rest? @func ? @func.rest? : false end def get_arg a a = a.to_sym if @func arg = @func.get_arg(a) return arg if arg end return @next.get_arg(a) if @next return [:addr,a] end end class LocalVarScope def initialize locals, next_scope @next = next_scope @locals = locals end def rest? @next ? @next.rest? : false end def get_arg a a = a.to_sym return [:lvar,@locals[a] + (rest? ? 1 : 0)] if @locals.include?(a) return @next.get_arg(a) if @next return [:addr,a] # Shouldn't get here normally end end VTableEntry = Struct.new(:name,:realname,:offset,:function) # Need a global list of vtable offsets since # we can't usually statically determine what class # an object belongs to. class VTableOffsets def initialize @vtable = {} @vtable_max = 1 # Start at 1 since offset 0 is reserved for the vtable pointer for the Class object # Then we insert the "new" method. get_offset(:new) end def get_offset(name) name = name.to_sym if !@vtable[name] @vtable[name] = @vtable_max @vtable_max += 1 end return @vtable[name] end def max @vtable_max end end class ClassScope attr_reader :name,:vtable def initialize next_scope,name,offsets @next = next_scope @name = name @vtable = {} @vtableoffsets = offsets end def rest? false end def get_arg a return @next.get_arg(a) if @next return [:addr,a] end def klass_size @vtableoffsets.max * Emitter::PTR_SIZE end def add_vtable_entry(name) @vtable[name] ||= VTableEntry.new v = @vtable[name] v.name = name.to_s v.offset = @vtableoffsets.get_offset(name) if !v.offset return v end def set_vtable_entry(name,realname,f) v = add_vtable_entry(name) v.realname = realname v.function = f end end