move compiler to bosl and get first test working (adjusting syntax as i go)

This commit is contained in:
Torsten Ruger 2015-09-19 16:28:41 +03:00
parent ab8bb55789
commit 2061097e88
18 changed files with 107 additions and 111 deletions

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
module Compiler
# Compiling is the conversion of the AST into 2 things:
@ -14,19 +14,14 @@ module Virtual
# may be unknown Unknown 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.
# the expression. So a NameExpression is delegated to Virtual::Set.new 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 + " #{e}"
raise e
end
exp_name = expression.type
puts "Expression #{expression.to_sexp}"
self.send "compile_#{exp_name}".to_sym , expression, method
end
end

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
# collection of the simple ones, int and strings and such
module Compiler
@ -12,36 +12,36 @@ module Virtual
# 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 = expression.value
to = Return.new(Integer , int)
method.source.add_code Set.new( int , to )
def self.compile_int expression , method
int = *expression
to = Virtual::Return.new(Integer , int)
method.source.add_code Virtual::Set.new( int , to )
to
end
def self.compile_true expression , method
to = Return.new(Reference , true )
method.source.add_code Set.new( true , to )
to = Virtual::Return.new(Reference , true )
method.source.add_code Virtual::Set.new( true , to )
to
end
def self.compile_false expression , method
to = Return.new(Reference , false)
method.source.add_code Set.new( false , to )
to = Virtual::Return.new(Reference , false)
method.source.add_code Virtual::Set.new( false , to )
to
end
def self.compile_nil expression , method
to = Return.new(Reference , nil)
method.source.add_code Set.new( nil , to )
to = Virtual::Return.new(Reference , nil)
method.source.add_code Virtual::Set.new( nil , to )
to
end
def self.compile_modulename expression , method
clazz = Parfait::Space.object_space.get_class_by_name expression.name
raise "compile_modulename #{clazz}.#{name}" unless clazz
to = Return.new(Reference , clazz )
method.source.add_code Set.new( clazz , to )
to = Virtual::Return.new(Reference , clazz )
method.source.add_code Virtual::Set.new( clazz , to )
to
end
@ -49,9 +49,9 @@ module Virtual
def self.compile_string expression , method
# Clearly a TODO here to implement strings rather than reusing symbols
value = expression.string.to_sym
to = Return.new(Reference , value)
to = Virtual::Return.new(Reference , value)
method.source.constants << value
method.source.add_code Set.new( value , to )
method.source.add_code Virtual::Set.new( value , to )
to
end
@ -64,17 +64,17 @@ module Virtual
raise "oh noo, nil from where #{expression.right.inspect}" unless r
index = method.has_arg(expression.left.name.to_sym)
if index
method.source.add_code Set.new(ArgSlot.new(index , r.type , r ) , Return.new)
method.source.add_code Virtual::Set.new(ArgSlot.new(index , r.type , r ) , Virtual::Return.new)
else
index = method.ensure_local(expression.left.name.to_sym)
method.source.add_code Set.new(FrameSlot.new(index , r.type , r ) , Return.new)
method.source.add_code Virtual::Set.new(FrameSlot.new(index , r.type , r ) , Virtual::Return.new)
end
r
end
def self.compile_variable expression, method
method.source.add_code InstanceGet.new(expression.name)
Return.new( Unknown )
Virtual::Return.new( Unknown )
end
end
end

View File

@ -1,33 +1,36 @@
module Virtual
module Bosl
module Compiler
# operators are really function calls
# call_site - attr_reader :name, :args , :receiver
def self.compile_callsite expession , method
me = Compiler.compile( expession.receiver , method )
def self.compile_call expession , method
name , arguments , receiver = *expession
name = name.to_a.first
me = Compiler.compile( receiver.to_a.first , method )
## need two step process, compile and save to frame
# then move from frame to new message
method.source.add_code NewMessage.new
method.source.add_code Set.new( me , NewSelf.new(me.type))
method.source.add_code Set.new( expession.name.to_sym , NewMessageName.new())
method.source.add_code Virtual::NewMessage.new
method.source.add_code Virtual::Set.new( me , Virtual::NewSelf.new(me.type))
method.source.add_code Virtual::Set.new( name.to_sym , Virtual::NewMessageName.new())
compiled_args = []
expession.args.each_with_index do |arg , i|
arguments.to_a.each_with_index do |arg , i|
#compile in the running method, ie before passing control
val = Compiler.compile( arg , method)
# move the compiled value to it's slot in the new message
# + 1 as this is a ruby 0-start , but 0 is the last message ivar.
# so the next free is +1
to = NewArgSlot.new(i + 1 ,val.type , val)
to = Virtual::NewArgSlot.new(i + 1 ,val.type , val)
# (doing this immediately, not after the loop, so if it's a return it won't get overwritten)
method.source.add_code Set.new( val , to )
method.source.add_code Virtual::Set.new( val , to )
compiled_args << to
end
method.source.add_code MessageSend.new(expession.name , me , compiled_args) #and pass control
method.source.add_code Virtual::MessageSend.new(name , me , compiled_args) #and pass control
# the effect of the method is that the NewMessage Return slot will be filled, return it
# (this is what is moved _inside_ above loop for such expressions that are calls (or constants))
Return.new( method.source.return_type )
Virtual::Return.new( method.source.return_type )
end
end
end

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
module Compiler
# attr_reader :values

View File

@ -1,8 +1,8 @@
module Virtual
module Bosl
module Compiler
# list - attr_reader :expressions
def self.compile_list expession , method
expession.expressions.collect do |part|
def self.compile_expressions expession , method
expession.children.collect do |part|
Compiler.compile( part , method )
end
end

View File

@ -1,12 +1,15 @@
module Virtual
module Bosl
module Compiler
# function attr_reader :name, :params, :body , :receiver
def self.compile_function expression, method
args = expression.params.collect do |p|
raise "error, argument must be a identifier, not #{p}" unless p.is_a? Ast::NameExpression
p.name
return_type , name , parameters, kids = *expression
name = name.to_a.first
args = parameters.to_a.collect do |p|
raise "error, argument must be a identifier, not #{p}" unless p.type == :field
p[2]
end
if expression.receiver
if expression[:receiver]
# compiler will always return slot. with known value or not
r = Compiler.compile(expression.receiver, method )
if( r.value.is_a? Parfait::Class )
@ -15,21 +18,20 @@ module Virtual
raise "unimplemented case in function #{r}"
end
else
r = Self.new()
r = Virtual::Self.new()
class_name = method.for_class.name
end
new_method = MethodSource.create_method(class_name, expression.name , args )
new_method = Virtual::MethodSource.create_method(class_name, name , args )
new_method.source.receiver = r
new_method.for_class.add_instance_method new_method
#frame = frame.new_frame
return_type = nil
expression.body.each do |ex|
kids.to_a.each do |ex|
return_type = Compiler.compile(ex,new_method )
raise return_type.inspect if return_type.is_a? Instruction
raise return_type.inspect if return_type.is_a? Virtual::Instruction
end
new_method.source.return_type = return_type
Return.new(return_type)
Virtual::Return.new(return_type)
end
end
end

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
module Compiler
# if - attr_reader :cond, :if_true, :if_false

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
module Compiler
# module attr_reader :name ,:expressions
def self.compile_module expression , context

View File

@ -0,0 +1,23 @@
module Bosl
module Compiler
# 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
name = expression.to_a.first
return Virtual::Self.new( Reference.new(method.for_class)) if name == :self
# either an argument, so it's stored in message
ret = Virtual::Return.new
if( index = method.has_arg(name))
method.source.add_code Virtual::Set.new( Virtual::ArgSlot.new(index ) , ret)
else # or a local so it is in the frame
index = method.ensure_local( name )
method.source.add_code Virtual::Set.new(Virtual::FrameSlot.new(index ) , ret )
end
return ret
end
end #module
end

View File

@ -0,0 +1,20 @@
module Bosl
module Compiler
# operator attr_reader :operator, :left, :right
def self.compile_operator expression, method
call = Ast::CallSiteExpression.new(expression.operator , [expression.right] , expression.left )
Compiler.compile(call, method)
end
def self.compile_assign expression, method
puts "assign"
puts expression.inspect
name , value = *expression
name = name.to_a.first
v = self.compile(value , method )
index = method.ensure_local( name )
method.source.add_code Virtual::Set.new(Virtual::FrameSlot.new(index ) , v )
end
end
end

View File

@ -1,9 +1,9 @@
module Virtual
module Bosl
module Compiler
# return attr_reader :expression
def self.compile_return expression, method
return Compiler.compile(expression.expression , method)
return Compiler.compile(expression.to_a.first , method)
end
end
end

View File

@ -1,4 +1,4 @@
module Virtual
module Bosl
module Compiler
# while- attr_reader :condition, :body

View File

@ -5,7 +5,7 @@ require "virtual/positioned"
require "virtual/padding"
require "virtual/parfait_adapter"
require "virtual/compiler"
require "bosl/compiler"
require "virtual/instruction"
require "virtual/method_source"
require "virtual/slots/slot"

View File

@ -1,28 +0,0 @@
module Virtual
module Compiler
# 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 Self.new( Reference.new(method.for_class)) if expression.name == :self
name = expression.name.to_sym
if method.has_var(name)
# either an argument, so it's stored in message
ret = Return.new
if( index = method.has_arg(name))
method.source.add_code Set.new( ArgSlot.new(index ) , ret)
else # or a local so it is in the frame
index = method.ensure_local( name )
method.source.add_code Set.new(FrameSlot.new(index ) , ret )
end
return ret
else
call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit
Compiler.compile(call, method)
end
end
end #module
end

View File

@ -1,9 +0,0 @@
module Virtual
module Compiler
# operator attr_reader :operator, :left, :right
def self.compile_operator expression, method
call = Ast::CallSiteExpression.new(expression.operator , [expression.right] , expression.left )
Compiler.compile(call, method)
end
end
end

View File

@ -135,7 +135,7 @@ module Virtual
syntax = @parser.parse_with_debug(bytes)
parts = Parser::Transform.new.apply(syntax)
#puts parts.to_s
Compiler.compile( parts , @space.get_main )
Bosl::Compiler.compile( parts , @space.get_main )
end
private

View File

@ -5,8 +5,9 @@ class TestFoo < MiniTest::Test
def test_foo2
@string_input = <<HERE
def foo2(x)
a = 5
int foo(int x)
int a = 5
return a
end
3.foo( 4 )
HERE
@ -14,16 +15,5 @@ HERE
check
end
def test_foo
@string_input = "3.foo( 4 )"
@expect = [Virtual::Return ]
check
end
def test_add
@string_input = "2 + 5"
@expect = [Virtual::Return ]
check
end
end