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 module Compiler
# Compiling is the conversion of the AST into 2 things: # Compiling is the conversion of the AST into 2 things:
@ -14,19 +14,14 @@ module Virtual
# may be unknown Unknown value. # may be unknown Unknown value.
# #
# The Compiler.compile uses a visitor patter to dispatch according to the class name of # 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, # This makes the dispatch extensible, ie Expressions may be added by external code,
# as long as matching compile methods are supplied too. # as long as matching compile methods are supplied too.
# #
def self.compile expression , method def self.compile expression , method
exp_name = expression.class.name.split("::").last.sub("Expression","").downcase exp_name = expression.type
#puts "Expression #{exp_name}" puts "Expression #{expression.to_sexp}"
begin
self.send "compile_#{exp_name}".to_sym , expression, method self.send "compile_#{exp_name}".to_sym , expression, method
rescue NoMethodError => e
puts "No compile method found for " + exp_name + " #{e}"
raise e
end
end end
end end

View File

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

View File

@ -1,33 +1,36 @@
module Virtual module Bosl
module Compiler module Compiler
# operators are really function calls # operators are really function calls
# call_site - attr_reader :name, :args , :receiver # call_site - attr_reader :name, :args , :receiver
def self.compile_callsite expession , method def self.compile_call expession , method
me = Compiler.compile( expession.receiver , 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 ## need two step process, compile and save to frame
# then move from frame to new message # then move from frame to new message
method.source.add_code NewMessage.new method.source.add_code Virtual::NewMessage.new
method.source.add_code Set.new( me , NewSelf.new(me.type)) method.source.add_code Virtual::Set.new( me , Virtual::NewSelf.new(me.type))
method.source.add_code Set.new( expession.name.to_sym , NewMessageName.new()) method.source.add_code Virtual::Set.new( name.to_sym , Virtual::NewMessageName.new())
compiled_args = [] 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 #compile in the running method, ie before passing control
val = Compiler.compile( arg , method) val = Compiler.compile( arg , method)
# move the compiled value to it's slot in the new message # 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. # + 1 as this is a ruby 0-start , but 0 is the last message ivar.
# so the next free is +1 # 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) # (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 compiled_args << to
end 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 # 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)) # (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 end
end end

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
module Virtual module Bosl
module Compiler module Compiler
# module attr_reader :name ,:expressions # module attr_reader :name ,:expressions
def self.compile_module expression , context 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 module Compiler
# return attr_reader :expression # return attr_reader :expression
def self.compile_return expression, method def self.compile_return expression, method
return Compiler.compile(expression.expression , method) return Compiler.compile(expression.to_a.first , method)
end end
end end
end end

View File

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

View File

@ -5,7 +5,7 @@ require "virtual/positioned"
require "virtual/padding" require "virtual/padding"
require "virtual/parfait_adapter" require "virtual/parfait_adapter"
require "virtual/compiler" require "bosl/compiler"
require "virtual/instruction" require "virtual/instruction"
require "virtual/method_source" require "virtual/method_source"
require "virtual/slots/slot" 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) syntax = @parser.parse_with_debug(bytes)
parts = Parser::Transform.new.apply(syntax) parts = Parser::Transform.new.apply(syntax)
#puts parts.to_s #puts parts.to_s
Compiler.compile( parts , @space.get_main ) Bosl::Compiler.compile( parts , @space.get_main )
end end
private private

View File

@ -5,8 +5,9 @@ class TestFoo < MiniTest::Test
def test_foo2 def test_foo2
@string_input = <<HERE @string_input = <<HERE
def foo2(x) int foo(int x)
a = 5 int a = 5
return a
end end
3.foo( 4 ) 3.foo( 4 )
HERE HERE
@ -14,16 +15,5 @@ HERE
check check
end 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 end