Permalink
Browse files

Refactored *Scope classes into separate files

  • Loading branch information...
vidarh committed Sep 16, 2014
1 parent 72d255e commit 00846430aa22c4567d2e65302430af2a73203aa6
Showing with 346 additions and 338 deletions.
  1. +136 −0 classcope.rb
  2. +38 −0 funcscope.rb
  3. +45 −0 globalscope.rb
  4. +29 −0 localvarscope.rb
  5. +5 −338 scope.rb
  6. +34 −0 sexpscope.rb
  7. +59 −0 vtableoffsets.rb
View
@@ -0,0 +1,136 @@
require 'vtableoffsets'
# Class scope.
# Holds name of class, vtable for methods defined within the class
# as well as all defined instance & class variables.
class ClassScope < Scope
# class name,
# method v-table,
# instance variables
# and class variables
attr_reader :name, :vtable, :instance_vars, :class_vars
# This is the number of instance variables allowed for the class
# Class, and is used for bootstrapping. Note that it could be
# determined by the compiler checking the actual class implementation,
# so this is a bit of a copout.
#
# slot 0 is reserved for the vtable pointer for _all_ classes.
# slot 1 is reserved for @instance_size for objects of class Class
# slot 2 is reserved for @name
# slot 3 is reserved for the superclass pointer
CLASS_IVAR_NUM = 4
def initialize(next_scope, name, offsets, superclass)
@next = next_scope
@superclass = superclass
@name = name
@vtable = {}
@vtableoffsets = offsets
@ivaroff = @superclass ? @superclass.instance_size : 0
@instance_vars = !@superclass ? [:@__class__] : [] # FIXME: Do this properly
@class_vars = {}
end
def class_scope
self
end
def rest?
false
end
def add_ivar(a)
@instance_vars << a.to_sym if !@instance_vars.include?(a.to_sym)
end
def instance_size
@instance_vars.size + @ivaroff
end
# Returns an argument within a class scope.
# First, check if argument is class or instance variable.
# If argument is not defined within class scope, check next (outer) scope.
# If both fails, the argument is an adress (<tt>:addr</tt>).
def get_arg(a)
# Handle self
if a.to_sym == :self
return [:global,@name]
end
# class variables.
# if it starts with "@@" it's a classvariable.
if a.to_s[0..1] == "@@" or @class_vars.include?(a)
@class_vars[a] ||= a.to_s[2..-1].to_sym # save without "@@"
instance_var = @class_vars[a]
cvar = "__classvar__#{@name}__#{instance_var}"
return [:cvar, cvar.to_sym] # -> e.g. __classvar__Foo__varname
end
# instance variables.
# if it starts with a single "@", it's a instance variable.
if a.to_s[0] == ?@ or @instance_vars.include?(a)
offset = @instance_vars.index(a)
add_ivar(a) if !offset
offset = @instance_vars.index(a)
# This will show the name of the current class, the superclass name, the instance variable
# name, the offset of the instance variable relative to the current class "base", and the
# instance variable offset for the current class which comes in quite handy when debugging
# object layout:
#
# STDERR.puts [:ivar, @name, @superclass ? @superclass.name : "",a, offset, @ivaroff].inspect
return [:ivar, offset + @ivaroff]
end
# if not in class scope, check next (outer) scope.
n = @next.get_arg(a) if @next
return n if n[0] == :global # Prevent e.g. "true" from being treated as method call
return [:possible_callm, n[1]] if n && !(?A..?Z).member?(a.to_s[0]) # Hacky way of excluding constants
return n if n
# if none works up to here, it must be an adress.
return [:addr, a]
end
# Returns the size of a class object.
# This is a multiple of @vtableoffsets.max, but this
# is deceiving as the offsets starts at a value that
# is based on the amount of data needed at the start of
# the class object as instance variables for the class
# object.
def klass_size
@vtableoffsets.max * Emitter::PTR_SIZE
end
# Adds a given name / identifier to the classes vtable, if not yet added.
def add_vtable_entry(name)
# FIXME: If "name" is an array, the first element specified the
# class object to add the vtable entry to. If it is "self"
# it means adding the entry to the meta class (and possibly creating
# the meta class). If it is not "self" we need to generate code
# for adding this method, as the class object may be dynamically
# determined. The vtable offset would be determined based on name[1] in
# this case.
@vtable[name] ||= VTableEntry.new
v = @vtable[name]
v.name = name.to_s
v.offset = @vtableoffsets.alloc_offset(name) if !v.offset
return v
end
# Sets a given vtable entry (identified by <tt>name</tt>)
# with the given <tt>realname</tt> and function <tt>f</tt>
def set_vtable_entry(name, realname, f)
v = add_vtable_entry(name)
v.realname = realname
v.function = f
end
end
View
@@ -0,0 +1,38 @@
# Function Scope.
# Holds variables defined within function, as well as all arguments
# part of the function.
class FuncScope < Scope
attr_reader :func
def initialize(func)
@func = func
end
def rest?
@func ? @func.rest? : false
end
def lvaroffset
@func.lvaroffset
end
# Returns an argument within the function scope, if defined here.
# A function holds it's own scope chain, so if the function doens't
# return anything, we fall back to just an addr.
def get_arg(a)
a = a.to_sym
if @func
arg = @func.get_arg(a)
return arg if arg
end
return [:addr, a]
end
def method
@func
end
end
View
@@ -0,0 +1,45 @@
# 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 < Scope
attr_accessor :globals
attr_reader :class_scope
def initialize(offsets)
@vtableoffsets = offsets
@globals = Set.new
@class_scope = ClassScope.new(self,"Object",@vtableoffsets,nil)
# Despite not following "$name" syntax, these are really global constants.
@globals << :false
@globals << :true
@globals << :nil
end
def rest?
false
end
# Returns an argument within the global scope, if defined here.
# Otherwise returns it as an address (<tt>:addr</tt>)
def get_arg(a)
return [:global, a] if @globals.member?(a)
return [:possible_callm, a] if a && !(?A..?Z).member?(a.to_s[0]) # Hacky way of excluding constants
return [:addr, a]
end
def name
""
end
def instance_size
0
end
def lvaroffset
0
end
end
View
@@ -0,0 +1,29 @@
# Local scope.
# Is used when local variables are defined via <tt>:let</tt> expression.
class LocalVarScope < Scope
def initialize(locals, next_scope)
@next = next_scope
@locals = locals
end
def method
@next ? @next.method : nil
end
def rest?
@next ? @next.rest? : false
end
# Returns an argument within the current local scope.
# If the passed argument isn't defined in this local scope,
# check the next (outer) scope.
# Finally, return it as an adress, if both doesn't work.
def get_arg(a)
a = a.to_sym
return [:lvar, @locals[a] + (rest? ? 1 : 0) + @next.lvaroffset] if @locals.include?(a)
return @next.get_arg(a) if @next
return [:addr, a] # Shouldn't get here normally
end
end
Oops, something went wrong.

0 comments on commit 0084643

Please sign in to comment.