move compiler into virtual

and associated changes in code, requires tests etc
This commit is contained in:
Torsten Ruger 2015-05-08 15:10:30 +03:00
parent a1b9acce3d
commit de8fe46fe0
17 changed files with 195 additions and 174 deletions

View File

@ -1,42 +0,0 @@
module Compiler
# Compiling is the conversion of the AST into 2 things:
# - code (ie sequences of Instructions inside Blocks) carried by CompiledMethods
# - an object graph containing all the Methods, their classes and Constants
#
# Some compile methods just add code, some may add structure (ie Blocks) while
# others instantiate Class and Method objects
#
# Everything in ruby is an expression, ie returns a value. So the effect of every compile
# is that a value is put into the ReturnSlot of the current Message.
# The compile method (so every compile method) returns the value that it deposits which
# may be unknown Mystery value.
#
# The Compiler.compile uses a visitor patter to dispatch according to the class name of
# the expression. So a NameExpression is delegated to compile_name etc.
# This makes the dispatch extensible, ie Expressions may be added by external code,
# as long as matching compile methods are supplied too.
#
def self.compile expression , method
exp_name = expression.class.name.split("::").last.sub("Expression","").downcase
#puts "Expression #{exp_name}"
begin
self.send "compile_#{exp_name}".to_sym , expression, method
rescue NoMethodError => e
puts "No compile method found for " + exp_name
raise e
end
end
end
require_relative "compiler/basic_expressions"
require_relative "compiler/callsite_expression"
require_relative "compiler/compound_expressions"
require_relative "compiler/if_expression"
require_relative "compiler/function_expression"
require_relative "compiler/module_expression"
require_relative "compiler/operator_expressions"
require_relative "compiler/return_expression"
require_relative "compiler/while_expression"
require_relative "compiler/expression_list"

View File

@ -1,99 +0,0 @@
# collection of the simple ones, int and strings and such
module Compiler
# Constant expressions can by definition be evaluated at compile time.
# But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_
# So we view ConstantExpressions like functions that return the value of the constant.
# In other words, their storage is the return slot as it would be for a method
# The current approach moves the constant into a variable before using it
# But in the future (in the one that holds great things) we optimize those unneccesay moves away
# attr_reader :value
def self.compile_integer expression , method
int = Virtual::IntegerConstant.new(expression.value)
to = Virtual::Return.new(Virtual::Integer , int)
method.add_code Virtual::Set.new( to , int)
to
end
def self.compile_true expression , method
value = Virtual::TrueConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
def self.compile_false expression , method
value = Virtual::FalseConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
def self.compile_nil expression , method
value = Virtual::NilConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
# attr_reader :name
# compiling name needs to check if it's a variable and if so resolve it
# otherwise it's a method without args and a send is issued.
# whichever way this goes the result is stored in the return slot (as all compiles)
def self.compile_name expression , method
return Virtual::Self.new( Virtual::Mystery ) if expression.name == :self
name = expression.name
if method.has_var(expression.name)
# either an argument, so it's stored in message
if( index = method.has_arg(name))
method.add_code MessageGet.new(name , index)
else # or a local so it is in the frame
method.add_code FrameGet.new(name , index)
end
else
call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit
Compiler.compile(call, method)
end
end
def self.compile_module expression , method
clazz = Virtual::BootSpace.space.get_or_create_class name
raise "uups #{clazz}.#{name}" unless clazz
to = Virtual::Return.new(Virtual::Reference , clazz )
method.add_code Virtual::Set.new( to , clazz )
to
end
# attr_reader :string
def self.compile_string expression , method
value = Virtual::StringConstant.new(expression.string)
to = Virtual::Return.new(Virtual::Reference , value)
Virtual::BootSpace.space.add_object value
method.add_code Virtual::Set.new( to , value )
to
end
#attr_reader :left, :right
def self.compile_assignment expression , method
raise "must assign to NameExpression , not #{expression.left}" unless expression.left.instance_of? Ast::NameExpression
r = Compiler.compile(expression.right , method )
raise "oh noo, nil from where #{expression.right.inspect}" unless r
index = method.has_arg(name)
if index
method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::MessageSlot.new(index , r,type , r ))
else
index = method.ensure_local(expression.left.name)
method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::FrameSlot.new(index , r.type , r ))
end
r
end
def self.compile_variable expression, method
method.add_code Virtual::InstanceGet.new(expression.name)
Virtual::Return.new( Virtual::Mystery )
end
end

View File

@ -4,12 +4,11 @@ module Parfait
eval(File.open("./lib/parfait/hash.rb").read)
end
require "compiler"
require "stream_reader"
require "elf/object_writer"
require 'salama-reader'
require 'parser/transform'
require "salama-object-file"
require "virtual/machine"
require "virtual"
require "register/register_machine"
require "arm/arm_machine"

18
lib/virtual.rb Normal file
View File

@ -0,0 +1,18 @@
require "virtual/machine"
require "virtual/compiler"
require "virtual/instruction"
require "virtual/compiled_method"
require "virtual/slots/slot"
require "virtual/type"
require "virtual/object"
require "virtual/constants"
require "virtual/boot_space"
# the passes _are_ order dependant
require "virtual/passes/send_implementation"
require "virtual/passes/get_implementation"
require "virtual/passes/enter_implementation"
require "virtual/passes/frame_implementation"
Sof::Volotile.add(Virtual::Block , [:method])
Sof::Volotile.add(Virtual::CompiledMethod , [:current])

44
lib/virtual/compiler.rb Normal file
View File

@ -0,0 +1,44 @@
module Virtual
module Compiler
# Compiling is the conversion of the AST into 2 things:
# - code (ie sequences of Instructions inside Blocks) carried by CompiledMethods
# - an object graph containing all the Methods, their classes and Constants
#
# Some compile methods just add code, some may add structure (ie Blocks) while
# others instantiate Class and Method objects
#
# Everything in ruby is an expression, ie returns a value. So the effect of every compile
# is that a value is put into the ReturnSlot of the current Message.
# The compile method (so every compile method) returns the value that it deposits which
# may be unknown Mystery value.
#
# The Compiler.compile uses a visitor patter to dispatch according to the class name of
# the expression. So a NameExpression is delegated to compile_name etc.
# This makes the dispatch extensible, ie Expressions may be added by external code,
# as long as matching compile methods are supplied too.
#
def self.compile expression , method
exp_name = expression.class.name.split("::").last.sub("Expression","").downcase
#puts "Expression #{exp_name}"
begin
self.send "compile_#{exp_name}".to_sym , expression, method
rescue NoMethodError => e
puts "No compile method found for " + exp_name
raise e
end
end
end
end
require_relative "compiler/basic_expressions"
require_relative "compiler/callsite_expression"
require_relative "compiler/compound_expressions"
require_relative "compiler/if_expression"
require_relative "compiler/function_expression"
require_relative "compiler/module_expression"
require_relative "compiler/operator_expressions"
require_relative "compiler/return_expression"
require_relative "compiler/while_expression"
require_relative "compiler/expression_list"

View File

@ -0,0 +1,101 @@
module Virtual
# collection of the simple ones, int and strings and such
module Compiler
# Constant expressions can by definition be evaluated at compile time.
# But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_
# So we view ConstantExpressions like functions that return the value of the constant.
# In other words, their storage is the return slot as it would be for a method
# The current approach moves the constant into a variable before using it
# But in the future (in the one that holds great things) we optimize those unneccesay moves away
# attr_reader :value
def self.compile_integer expression , method
int = Virtual::IntegerConstant.new(expression.value)
to = Virtual::Return.new(Virtual::Integer , int)
method.add_code Virtual::Set.new( to , int)
to
end
def self.compile_true expression , method
value = Virtual::TrueConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
def self.compile_false expression , method
value = Virtual::FalseConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
def self.compile_nil expression , method
value = Virtual::NilConstant.new
to = Virtual::Return.new(Virtual::Reference , value)
method.add_code Virtual::Set.new( to , value )
to
end
# attr_reader :name
# compiling name needs to check if it's a variable and if so resolve it
# otherwise it's a method without args and a send is issued.
# whichever way this goes the result is stored in the return slot (as all compiles)
def self.compile_name expression , method
return Virtual::Self.new( Virtual::Mystery ) if expression.name == :self
name = expression.name
if method.has_var(expression.name)
# either an argument, so it's stored in message
if( index = method.has_arg(name))
method.add_code MessageGet.new(name , index)
else # or a local so it is in the frame
method.add_code FrameGet.new(name , index)
end
else
call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit
Compiler.compile(call, method)
end
end
def self.compile_module expression , method
clazz = Virtual::BootSpace.space.get_or_create_class name
raise "uups #{clazz}.#{name}" unless clazz
to = Virtual::Return.new(Virtual::Reference , clazz )
method.add_code Virtual::Set.new( to , clazz )
to
end
# attr_reader :string
def self.compile_string expression , method
value = Virtual::StringConstant.new(expression.string)
to = Virtual::Return.new(Virtual::Reference , value)
Virtual::BootSpace.space.add_object value
method.add_code Virtual::Set.new( to , value )
to
end
#attr_reader :left, :right
def self.compile_assignment expression , method
raise "must assign to NameExpression , not #{expression.left}" unless expression.left.instance_of? Ast::NameExpression
r = Compiler.compile(expression.right , method )
raise "oh noo, nil from where #{expression.right.inspect}" unless r
index = method.has_arg(name)
if index
method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::MessageSlot.new(index , r,type , r ))
else
index = method.ensure_local(expression.left.name)
method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::FrameSlot.new(index , r.type , r ))
end
r
end
def self.compile_variable expression, method
method.add_code Virtual::InstanceGet.new(expression.name)
Virtual::Return.new( Virtual::Mystery )
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# operators are really function calls
@ -24,3 +25,4 @@ module Compiler
Virtual::Return.new( method.return_type )
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# attr_reader :values
@ -12,3 +13,4 @@ module Compiler
to.do
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# list - attr_reader :expressions
def self.compile_list expession , method
@ -6,3 +7,4 @@ module Compiler
end
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# function attr_reader :name, :params, :body , :receiver
def self.compile_function expression, method
@ -67,3 +68,4 @@ module Compiler
function
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# if - attr_reader :cond, :if_true, :if_false
@ -38,3 +39,4 @@ module Compiler
last
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# module attr_reader :name ,:expressions
def self.compile_module expression , context
@ -20,3 +21,4 @@ module Compiler
return clazz
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# operator attr_reader :operator, :left, :right
def self.compile_operator expression, method
@ -5,3 +6,4 @@ module Compiler
Compiler.compile(call, method)
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# return attr_reader :expression
@ -20,3 +21,4 @@ module Compiler
return return_reg
end
end
end

View File

@ -1,3 +1,4 @@
module Virtual
module Compiler
# while- attr_reader :condition, :body
@ -23,3 +24,4 @@ module Compiler
last
end
end
end

View File

@ -35,7 +35,7 @@ module Virtual
def initialize
@parser = Parser::Salama.new
the_end = Halt.new
@message = Message.new(the_end , the_end , :Object)
# @message = Message.new(the_end , the_end , :Object)
end
attr_reader :message
@ -62,24 +62,6 @@ module Virtual
main = Virtual::CompiledMethod.main
Compiler.compile( parts , main )
end
end
end
require_relative "instruction"
require_relative "compiled_method"
require_relative "frame"
require_relative "message"
require_relative "slots/slot"
require_relative "type"
require_relative "object"
require_relative "constants"
require_relative "boot_space"
# the passes _are_ order dependant
require_relative "passes/send_implementation"
require_relative "passes/get_implementation"
require_relative "passes/enter_implementation"
require_relative "passes/frame_implementation"
Sof::Volotile.add(Virtual::Block , [:method])
Sof::Volotile.add(Virtual::CompiledMethod , [:current])
end