move compiler to bosl and get first test working (adjusting syntax as i go)
This commit is contained in:
parent
ab8bb55789
commit
2061097e88
@ -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
|
@ -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
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Bosl
|
||||
module Compiler
|
||||
|
||||
# attr_reader :values
|
@ -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
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Bosl
|
||||
module Compiler
|
||||
# if - attr_reader :cond, :if_true, :if_false
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Bosl
|
||||
module Compiler
|
||||
# module attr_reader :name ,:expressions
|
||||
def self.compile_module expression , context
|
23
lib/bosl/compiler/name_expression.rb
Normal file
23
lib/bosl/compiler/name_expression.rb
Normal 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
|
20
lib/bosl/compiler/operator_expressions.rb
Normal file
20
lib/bosl/compiler/operator_expressions.rb
Normal 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
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Bosl
|
||||
module Compiler
|
||||
|
||||
# while- attr_reader :condition, :body
|
@ -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"
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user