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
|
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
|
@ -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
|
@ -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
|
@ -1,4 +1,4 @@
|
|||||||
module Virtual
|
module Bosl
|
||||||
module Compiler
|
module Compiler
|
||||||
|
|
||||||
# attr_reader :values
|
# attr_reader :values
|
@ -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
|
@ -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
|
@ -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
|
||||||
|
|
@ -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
|
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
|
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
|
@ -1,4 +1,4 @@
|
|||||||
module Virtual
|
module Bosl
|
||||||
module Compiler
|
module Compiler
|
||||||
|
|
||||||
# while- attr_reader :condition, :body
|
# while- attr_reader :condition, :body
|
@ -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"
|
||||||
|
@ -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)
|
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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user