diff --git a/lib/rubyx.rb b/lib/rubyx.rb index 3f738ea3..d160d88b 100644 --- a/lib/rubyx.rb +++ b/lib/rubyx.rb @@ -4,7 +4,6 @@ require_relative "util" require_relative "elf/object_writer" require_relative "risc" require_relative "slot_machine/slot_machine" -require_relative "slot_language/slot_compiler" require_relative "arm/arm_machine" require_relative "arm/arm_platform" require_relative "sol/statement" diff --git a/lib/slot_language/README.md b/lib/slot_language/README.md deleted file mode 100644 index 9116ea1a..00000000 --- a/lib/slot_language/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Slot Language - -This is a new layer / approach to create code for the next level, the slot_machine. - -In essence the slot_language lets us code the slot_machine. - -## Problem - -The Problem with the current way is that some of the slot_machine instructions are -really quite complex. They are really more functions than instructions. - -This is especially true for everything around the dynamic call. Dynamic call itself -is still ok, but resolve_method is too much. And it even uses method_missing, another -instruction that is too much, which in turn should use raise and now we really see -the point. - -I thought about making those "super" instruction real methods and just calling them, -but the calling overhead is just too much, and really it is the wrong tool for the -job. Calling implies switching of context, while resolve_method and raise and mm -really all operate on the same context. - -## The Slot Machine - -The Slot Machine is a kind of memory based, oo abstraction of the risc machine, that in -turn mirrors a cpu relatively closely. The machine "knows" the message in the way a -cpu knows its registers. And the oo part means it also knows the parfait object -model. - -While Ruby/Sol code only ever assumes the type of self, the Slot Machine assumes types -of the whole of Parfait. The main instruction after which the machine is named is -the SlotLoad, which moves one instance variable to another. - -## Code for the Machine - -Since the Slot and SlotMachine have proven useful abstractions, this introduces the -SlotLanguage as a way to create code for the SlotMachine. - -The SlotMachine defines no methods on objects and passes no objects. While it has call -and return, these are defined in terms of jumps and use, like all Slot instructions, -the message. - -## Syntax (projection) - -Since we are not defining methods, there is no separate scope. We create objects that -will transform to SlotMachine Instructions _in_ the scope of the current method. -In other words they will have access to the compiler and the callable, when transforming -to SlotMachine (similar to Sol in that way). This means at compile time we -can use the frame type and constants, while we can always assume the Message (and not -much else) at runtime. - -As the scope is "fixed", we will use the file scope, ie one file defines one -instruction/macro, by convention of the same name. - -For starters we will use ruby syntax, with these semantics: -- only globals and message (the literal) are valid variable names -- dot will mean pointer traversal, sort of like c (no calling) -- names on right hand of dot must be instance variables of left -- equal will mean assignment in the SlotLoad kind of sense -- some macro mechanism is called for (tbd) -- maybe labels have to be created (sort of like the risc dsl) - -The result of a compilation will be a SlotMachine Macro diff --git a/lib/slot_language/assignment.rb b/lib/slot_language/assignment.rb deleted file mode 100644 index b5969f26..00000000 --- a/lib/slot_language/assignment.rb +++ /dev/null @@ -1,25 +0,0 @@ -module SlotLanguage - # A Assignment makes SlotLoad. That means it stores the information - # to be able to create a SlotLoad - # - # Just like the SlotLoad stores two Slots, here we store two Variables - # - class Assignment - # The two Variables that become Slots in to_slot - attr_reader :left , :right - - def initialize(left , right) - @left = left - @right = right - raise "No Slot #{left}" unless left.is_a?(Variable) - raise "No Slot #{right}" unless right.is_a?(Variable) - end - - # create the SlotLoad, by creating the two Slots from the Variables - def to_slot(compiler) - left_d = @left.to_slot(compiler) - right_d = @right.to_slot(compiler) - SlotMachine::SlotLoad.new("source" , left_d , right_d) - end - end -end diff --git a/lib/slot_language/code/resolve_method.slot b/lib/slot_language/code/resolve_method.slot deleted file mode 100644 index 77d8ece0..00000000 --- a/lib/slot_language/code/resolve_method.slot +++ /dev/null @@ -1,22 +0,0 @@ -# passed in? name and cache_entry -word! = name_ -cache_entry! = cache_entry_ -# local var assignment -callable_method! = cache_entry.cached_type.methods - -while_start_label - -goto(exit_label) if( nil == callable_method) - -goto(ok_label) if(callable_method.name == word) - -callable_method = callable_method.next_callable - -goto(while_start_label) - -exit_label - -MethodMissing.new(compiler.source_name , word.symbol).to_risc(compiler) - -ok_label -cache_entry.cached_method = callable_method diff --git a/lib/slot_language/equal_goto.rb b/lib/slot_language/equal_goto.rb deleted file mode 100644 index 26b5c8c3..00000000 --- a/lib/slot_language/equal_goto.rb +++ /dev/null @@ -1,13 +0,0 @@ -module SlotLanguage - class EqualGoto - attr_reader :left , :right, :goto - - def initialize( left , right) - @left = left - @right = right - end - def set_goto(go) - @goto = go - end - end -end diff --git a/lib/slot_language/goto.rb b/lib/slot_language/goto.rb deleted file mode 100644 index 80d33314..00000000 --- a/lib/slot_language/goto.rb +++ /dev/null @@ -1,10 +0,0 @@ -module SlotLanguage - class Goto - attr_reader :label - - def initialize(label) - @label = label - end - - end -end diff --git a/lib/slot_language/macro_maker.rb b/lib/slot_language/macro_maker.rb deleted file mode 100644 index 0ac4242f..00000000 --- a/lib/slot_language/macro_maker.rb +++ /dev/null @@ -1,65 +0,0 @@ - -module SlotLanguage - # MacroMaker instances represent Macros at the Slot level - # - # Macros are like SlotInstruction instances in that they transform to Risc - # But all SlotInstructions form a whole that lets us reduce Sol to Slot to risc. - # Each Macro on the other hand represents a functionality (kind of method) - # that can not be coded in sol. It transforms to a sequence of risc Instructions - # that can not be coded any other way. They are not Methods, as they have no - # scope, hence the name Macro. - # - # This MacroMaker is an attempt to code these kind of sequences in SlotLanguage - # The SlotCompiler is used to transform a file of SlotLanguage code into and - # array of SlotLanguage constructs, which in turn can be transformed into - # SlotInstructions. - # To start with we work backwards from existing large SlotInstructions, to - # get a list of constructs that will transform to the same SlotInstructions - # that transform to the same risc as the current large instruction (+ some redundandency) - class MacroMaker - # an array of Makers - attr_reader :source - - # load slot code from a file, in a subdir code/ + filename - # use load_string to compile the content - def self.load_file(relative_name) - path = File.expand_path( "../code/#{relative_name}" , __FILE__) - load_string( File.read(path)) - end - - # compile the given SlotLanguage source - # the compiler returns an array of Makers which a new MacroMaker - # instance stores - # return the MacroMaker that represents the source - def self.load_string(source_code) - MacroMaker.new( SlotCompiler.compile(source_code) ) - end - - # must initialize with an array of Makers, which is stored - def initialize( source ) - @source = source - raise "undefined source #{source}" unless source.is_a?(Array) - end - - # Basically calls to_slot on each Element of the source array - # - # Thus transforming an array of Makers into a linked list of - # SlotInstructions. - # Return the head of the linked list. - def to_slot(compiler) - chain = do_link( @source.first , compiler) - rest = @source.dup - rest.shift - rest.each do |link| - chain << do_link(link , compiler) - end - chain - end - - private - def do_link(link,compiler) - return link if link.is_a?(SlotMachine::Instruction) - link.to_slot(compiler) - end - end -end diff --git a/lib/slot_language/slot_compiler.rb b/lib/slot_language/slot_compiler.rb deleted file mode 100644 index dee609ac..00000000 --- a/lib/slot_language/slot_compiler.rb +++ /dev/null @@ -1,127 +0,0 @@ -require "parser/current" -require "ast" - -module SlotLanguage - class SlotCompiler < AST::Processor - DEBUG = false - - # conditionals supported, currently only equal - def self.checks - [:==] - end - - def self.compile(input) - ast = Parser::CurrentRuby.parse( input ) - self.new.process(ast) - end - attr_reader :labels - def initialize - @labels = {} - end - - def not_implemented(node) - raise "Not implemented #{node.type}" - end - # default to error, so non implemented stuff shows early - def handler_missing(node) - not_implemented(node) - end - def on_send(statement) - kids = statement.children.dup - receiver = kids.shift - name = kids.shift - return label(name) if(name.to_s.end_with?("_label")) - return goto(name,kids) if(name == :goto) - return check(name,receiver, kids) if SlotCompiler.checks.include?(name) - return assign(receiver, name , kids) if(name.to_s.end_with?("=")) - puts "Send: #{statement} " if DEBUG - var = Variable.new( name ) - if(receiver) - puts "receiver at #{name} #{receiver}" if DEBUG - process(receiver).chained(var) - else - var - end - end - def on_lvar(lvar) - puts "lvar #{lvar}" if DEBUG - Variable.new(lvar.children.first ) - end - def on_lvasgn( expression) - puts "i/lvasgn #{expression}" if DEBUG - var = var_for(expression.children[0]) - value = process(expression.children[1]) - Assignment.new(var , value) - end - alias :on_ivasgn :on_lvasgn - - def on_if(expression) - puts "if #{expression}" if DEBUG - condition = process(expression.children[0]) - condition.set_goto( process(expression.children[1]) ) - condition - end - def on_begin(exp) - if( exp.children.length == 1) - process(exp.first) - else - process_all(exp) - end - end - def on_ivar(expression) - puts "ivar #{expression}" if DEBUG - var_for(expression.children.first) - end - - private - - def var_for( name ) - name = name.to_s - if(name[0] == "@") - MessageVariable.new(name.to_s[1 .. -1].to_sym) - else - Variable.new(name.to_sym) - end - end - def label(name) - raise "no label #{name}" unless(name.to_s.end_with?("_label")) - if @labels.has_key?(name) - return @labels[name] - else - @labels[name] = SlotMachine::Label.new(name.to_s , name) - end - end - def goto(name , args) - # error handling would not hurt - puts "goto #{name} , #{args}" if DEBUG - label = process(args.first) - Goto.new( label ) - end - def check(name , receiver , kids) - raise "Familiy too large #{kids}" if kids.length > 1 - puts "Kids " + kids.to_s if DEBUG - right = process(kids.first) - case name - when :== - return EqualGoto.new(process(receiver) , right) - else - raise "Only ==, not #{name}" unless name == :== - end - end - - def assign(receiver , name , kids) - receiver = process(receiver) - puts "Assign #{name} , #{receiver}" if DEBUG - raise "Only one arg #{kids}" unless kids.length == 1 - right = process kids.shift - name = name.to_s[0...-1].to_sym - receiver.chained(Variable.new(name)) - Assignment.new(receiver,right) - end - end -end -require_relative "variable" -require_relative "assignment" -require_relative "macro_maker" -require_relative "goto" -require_relative "equal_goto" diff --git a/lib/slot_language/variable.rb b/lib/slot_language/variable.rb deleted file mode 100644 index b92a4d5f..00000000 --- a/lib/slot_language/variable.rb +++ /dev/null @@ -1,43 +0,0 @@ -module SlotLanguage - # A Variable makes Slots. A Slot is the central SlotMachines description of a - # variable in an object. At the Language level this holds the information - # (names of variables) to be able to create the Slot instance - # - # In the SlotLanguage this is used in the Assignment. Just as a Slotload stores - # two slots to define what is loaded where, the Assignment, that creates a SlotLoad, - # uses two Variables. - class Variable - # stores the (instance) names that allow us to create a Slot - attr_reader :name , :chain - - def initialize(name) - @name = name - raise "No name given #{name}" unless name.is_a?(Symbol) - end - - def chained(to) - raise "Must chain to variable #{to}" unless to.is_a?(Variable) - if(@chain) - @chain.chained(to) - else - @chain = to - end - self - end - - def to_slot(compiler) - SlotMachine::Slotted.for(:message , [name]) - end - - def to_s - str = "message.#{name}" - str += chain.to_s if @chain - str - end - end - - class MessageVariable < Variable - end - class Constant < Variable - end -end diff --git a/test/slot_language/helper.rb b/test/slot_language/helper.rb deleted file mode 100644 index 1abb8a0c..00000000 --- a/test/slot_language/helper.rb +++ /dev/null @@ -1,18 +0,0 @@ -require_relative "../helper" - -module SlotLanguage - module SlotHelper - def compile(input) - SlotCompiler.compile(input) - end - def compile_class(input) - compile(input).class - end - end - module SlotToHelper - def setup - Parfait.boot!({}) - @compiler = SlotMachine::SlotCollection.compiler_for( :Space , :main,{},{}) - end - end -end diff --git a/test/slot_language/mini.slot b/test/slot_language/mini.slot deleted file mode 100644 index e1e25e32..00000000 --- a/test/slot_language/mini.slot +++ /dev/null @@ -1,2 +0,0 @@ -start_label -a = b diff --git a/test/slot_language/test_assignment.rb b/test/slot_language/test_assignment.rb deleted file mode 100644 index 85e956c5..00000000 --- a/test/slot_language/test_assignment.rb +++ /dev/null @@ -1,64 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestAssignment < MiniTest::Test - include SlotHelper - def compile_assign(str) - assign = compile(str) - assert_equal Assignment , assign.class - assert_equal :a , assign.left.name - assert_equal :b , assign.right.name - assign - end - def test_slot_load_rinst - assign = compile_assign("a = @b") - end - def test_slot_load_linst - assign = compile_assign("@a = b") - end - def test_slot_load_lrinst - compile_assign("@a = @b") - end - def test_assign - assign = compile_assign("a = b") - assert_equal Assignment , assign.class - end - end - class TestAssignment2 < MiniTest::Test - include SlotHelper - - def test_slot_load_linst_trav - assert_equal Assignment , compile_class("@a = b.c") - end - def test_assign1 - assign = compile("c = c.next") - assert_equal Assignment , assign.class - end - def test_shift - load = compile("a = b.c") - assert_equal Assignment , load.class - assert_equal :a , load.left.name - assert_equal Variable , load.right.class - end - end - class TestAssignment3 < MiniTest::Test - include SlotHelper - - def test_inst_ass - assign = compile("@a.b = c") - assert_equal Assignment , assign.class - assert_equal MessageVariable , assign.left.class - assert_equal :a , assign.left.name - assert_equal Variable , assign.left.chain.class - assert_equal :b , assign.left.chain.name - end - def test_local_ass - assign = compile("a.b = c") - assert_equal Assignment , assign.class - assert_equal Variable , assign.left.class - assert_equal :a , assign.left.name - assert_equal Variable , assign.left.chain.class - assert_equal :b , assign.left.chain.name - end - end -end diff --git a/test/slot_language/test_equal_goto.rb b/test/slot_language/test_equal_goto.rb deleted file mode 100644 index 92b63f0d..00000000 --- a/test/slot_language/test_equal_goto.rb +++ /dev/null @@ -1,92 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestEqualGoto < MiniTest::Test - include SlotHelper - - def do_check(check) - assert_equal EqualGoto , check.class - assert_equal Goto , check.goto.class - assert check.left.is_a?(Variable) - assert check.right.is_a?(Variable) - assert_equal :a , check.left.name - assert_equal :b , check.right.name - end - def test_equal_local - check = compile("goto(exit_label) if(a == b)") - do_check(check) - end - def test_equal_inst_left - check = compile("goto(exit_label) if(@a == b)") - do_check(check) - end - def test_equal_inst_right - check = compile("goto(exit_label) if(a == @b)") - do_check(check) - end - end - - class TestEqualGotoFull < MiniTest::Test - include SlotHelper - def setup - @expr = compile("start_label;goto(start_label) if( b == c)") - end - def test_2 - assert_equal Array , @expr.class - assert_equal 2 , @expr.length - end - def test_label - assert_equal SlotMachine::Label , @expr.first.class - assert_equal :start_label , @expr.first.name - end - def test_conditional - assert_equal EqualGoto , @expr.last.class - assert_equal :start_label , @expr.last.goto.label.name - end - def test_same_label - assert_equal @expr.first.object_id , @expr.last.goto.label.object_id - end - def test_expression_left - assert_equal Variable , @expr.last.left.class - assert_equal :b , @expr.last.left.name - end - def test_expression_right - assert_equal Variable , @expr.last.right.class - assert_equal :c , @expr.last.right.name - end - end - class TestEqualGotoChain < MiniTest::Test - include SlotHelper - def setup - @expr = compile("goto(start_label) if( a.b == c)") - end - def test_eq - assert_equal EqualGoto , @expr.class - end - def test_left - assert_equal Variable , @expr.left.class - assert_equal :a , @expr.left.name - end - def test_left_chain - assert_equal Variable , @expr.left.chain.class - assert_equal :b , @expr.left.chain.name - end - end - class TestEqualGotoChain2 < MiniTest::Test - include SlotHelper - def setup - @expr = compile("goto(start_label) if( a == @b.c)") - end - def test_eq - assert_equal EqualGoto , @expr.class - end - def test_left - assert_equal MessageVariable , @expr.right.class - assert_equal :b , @expr.right.name - end - def test_left_chain - assert_equal Variable , @expr.right.chain.class - assert_equal :c , @expr.right.chain.name - end - end -end diff --git a/test/slot_language/test_goto.rb b/test/slot_language/test_goto.rb deleted file mode 100644 index a18cb769..00000000 --- a/test/slot_language/test_goto.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestGoto < MiniTest::Test - include SlotHelper - - def test_goto_class - assert_equal Goto , compile_class("goto(exit_label)") - end - def test_goto_label - goto = compile("goto(exit_label)") - assert_equal SlotMachine::Label , goto.label.class - assert_equal :exit_label , goto.label.name - end - - def test_label - label = compile("while_label") - assert_equal SlotMachine::Label , label.class - assert_equal :while_label , label.name - end - - def test_2_label - labels = compile("exit_label;exit_label") - assert_equal :exit_label , labels[0].name - assert_equal :exit_label , labels[1].name - assert_equal labels[0].object_id , labels[1].object_id - end - - def test_goto_with_label - gotos = compile("exit_label;goto(exit_label)") - assert_equal :exit_label , gotos[0].name - assert_equal :exit_label , gotos[1].label.name - assert_equal gotos[0].object_id , gotos[1].label.object_id - end - end -end diff --git a/test/slot_language/test_macro_maker.rb b/test/slot_language/test_macro_maker.rb deleted file mode 100644 index 79f5ca6e..00000000 --- a/test/slot_language/test_macro_maker.rb +++ /dev/null @@ -1,45 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestMacroMakerLoad < MiniTest::Test - include SlotToHelper - def setup - super - @slot = MacroMaker.load_string( mini_file ).to_slot(@compiler) - end - def test_label - assert_equal SlotMachine::Label , @slot.class - end - def test_assign - assert_equal SlotMachine::SlotLoad , @slot.next.class - assert_equal "message.a" , @slot.next.left.to_s - assert_equal "message.b" , @slot.next.right.to_s - end - def test_length - assert_equal 2 , @slot.length - end - end - - class TestMacroMakerLoad < MiniTest::Test - include SlotHelper - - def check_mini(maker) - assert_equal MacroMaker , maker.class - assert_equal Array , maker.source.class - assert_equal SlotMachine::Label , maker.source.first.class - assert_equal 2 , maker.source.length - end - def mini_file - File.read(File.expand_path( "../mini.slot" , __FILE__)) - end - def test_mini_file - check_mini MacroMaker.load_file("../../../test/slot_language/mini.slot") - end - def test_mini_string - check_mini MacroMaker.load_string( mini_file ) - end - def test_mini_source - check_mini MacroMaker.new( SlotCompiler.compile(mini_file)) - end - end -end diff --git a/test/slot_language/test_slot_compiler.rb b/test/slot_language/test_slot_compiler.rb deleted file mode 100644 index 11cf6e15..00000000 --- a/test/slot_language/test_slot_compiler.rb +++ /dev/null @@ -1,17 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestSlotCompiler < MiniTest::Test - include SlotHelper - - def test_init - assert SlotCompiler.new - end - def test_labels - assert SlotCompiler.new.labels.empty? - end - def test_basic_compile - assert_equal Variable , compile("a").class - end - end -end diff --git a/test/slot_language/test_variable.rb b/test/slot_language/test_variable.rb deleted file mode 100644 index 2669a9c9..00000000 --- a/test/slot_language/test_variable.rb +++ /dev/null @@ -1,35 +0,0 @@ -require_relative "helper" - -module SlotLanguage - class TestVariable < MiniTest::Test - include SlotHelper - def compile_var(str) - var = compile(str) - assert var.is_a?(Variable) - assert_equal :a , var.name - var - end - def test_local - assert_equal Variable , compile_var("a").class - end - def test_inst - assert_equal MessageVariable , compile_var("@a").class - end - def test_local_chain - chain = compile_var("a.b") - assert_equal Variable , chain.chain.class - assert_equal :b , chain.chain.name - end - def test_local_chain2 - chain = compile_var("a.b.c") - assert_equal Variable , chain.chain.chain.class - assert_equal :c , chain.chain.chain.name - end - def test_inst_chain - chain = compile_var("@a.b") - assert_equal MessageVariable , chain.class - assert_equal Variable , chain.chain.class - assert_equal :b , chain.chain.name - end - end -end