diff --git a/lib/compiler.rb b/lib/compiler.rb deleted file mode 100644 index 4aac9936..00000000 --- a/lib/compiler.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Compiler - - # Compiling is the conversion of the AST into 2 things: - # - code (ie sequences of Instructions inside Blocks) carried by CompiledMethods - # - an object graph containing all the Methods, their classes and Constants - # - # Some compile methods just add code, some may add structure (ie Blocks) while - # others instantiate Class and Method objects - # - # Everything in ruby is an expression, ie returns a value. So the effect of every compile - # is that a value is put into the ReturnSlot of the current Message. - # The compile method (so every compile method) returns the value that it deposits which - # may be unknown Mystery 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. - # 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 - raise e - end - end - -end - -require_relative "compiler/basic_expressions" -require_relative "compiler/callsite_expression" -require_relative "compiler/compound_expressions" -require_relative "compiler/if_expression" -require_relative "compiler/function_expression" -require_relative "compiler/module_expression" -require_relative "compiler/operator_expressions" -require_relative "compiler/return_expression" -require_relative "compiler/while_expression" -require_relative "compiler/expression_list" diff --git a/lib/compiler/basic_expressions.rb b/lib/compiler/basic_expressions.rb deleted file mode 100644 index 309ca9b7..00000000 --- a/lib/compiler/basic_expressions.rb +++ /dev/null @@ -1,99 +0,0 @@ -# collection of the simple ones, int and strings and such - -module Compiler - - # Constant expressions can by definition be evaluated at compile time. - # But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_ - # So we view ConstantExpressions like functions that return the value of the constant. - # In other words, their storage is the return slot as it would be for a method - - # The current approach moves the constant into a variable before using it - # 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 = Virtual::IntegerConstant.new(expression.value) - to = Virtual::Return.new(Virtual::Integer , int) - method.add_code Virtual::Set.new( to , int) - to - end - - def self.compile_true expression , method - value = Virtual::TrueConstant.new - to = Virtual::Return.new(Virtual::Reference , value) - method.add_code Virtual::Set.new( to , value ) - to - end - - def self.compile_false expression , method - value = Virtual::FalseConstant.new - to = Virtual::Return.new(Virtual::Reference , value) - method.add_code Virtual::Set.new( to , value ) - to - end - - def self.compile_nil expression , method - value = Virtual::NilConstant.new - to = Virtual::Return.new(Virtual::Reference , value) - method.add_code Virtual::Set.new( to , value ) - to - end - - # 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 Virtual::Self.new( Virtual::Mystery ) if expression.name == :self - name = expression.name - if method.has_var(expression.name) - # either an argument, so it's stored in message - if( index = method.has_arg(name)) - method.add_code MessageGet.new(name , index) - else # or a local so it is in the frame - method.add_code FrameGet.new(name , index) - end - else - call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit - Compiler.compile(call, method) - end - end - - - def self.compile_module expression , method - clazz = Virtual::BootSpace.space.get_or_create_class name - raise "uups #{clazz}.#{name}" unless clazz - to = Virtual::Return.new(Virtual::Reference , clazz ) - method.add_code Virtual::Set.new( to , clazz ) - to - end - -# attr_reader :string - def self.compile_string expression , method - value = Virtual::StringConstant.new(expression.string) - to = Virtual::Return.new(Virtual::Reference , value) - Virtual::BootSpace.space.add_object value - method.add_code Virtual::Set.new( to , value ) - to - end - - #attr_reader :left, :right - def self.compile_assignment expression , method - raise "must assign to NameExpression , not #{expression.left}" unless expression.left.instance_of? Ast::NameExpression - r = Compiler.compile(expression.right , method ) - raise "oh noo, nil from where #{expression.right.inspect}" unless r - index = method.has_arg(name) - if index - method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::MessageSlot.new(index , r,type , r )) - else - index = method.ensure_local(expression.left.name) - method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::FrameSlot.new(index , r.type , r )) - end - r - end - - def self.compile_variable expression, method - method.add_code Virtual::InstanceGet.new(expression.name) - Virtual::Return.new( Virtual::Mystery ) - end -end diff --git a/lib/salama.rb b/lib/salama.rb index 291fcefa..6241b3dd 100644 --- a/lib/salama.rb +++ b/lib/salama.rb @@ -4,12 +4,11 @@ module Parfait eval(File.open("./lib/parfait/hash.rb").read) end -require "compiler" require "stream_reader" require "elf/object_writer" require 'salama-reader' require 'parser/transform' require "salama-object-file" -require "virtual/machine" +require "virtual" require "register/register_machine" require "arm/arm_machine" diff --git a/lib/virtual.rb b/lib/virtual.rb new file mode 100644 index 00000000..b046bea5 --- /dev/null +++ b/lib/virtual.rb @@ -0,0 +1,18 @@ +require "virtual/machine" + +require "virtual/compiler" +require "virtual/instruction" +require "virtual/compiled_method" +require "virtual/slots/slot" +require "virtual/type" +require "virtual/object" +require "virtual/constants" +require "virtual/boot_space" +# the passes _are_ order dependant +require "virtual/passes/send_implementation" +require "virtual/passes/get_implementation" +require "virtual/passes/enter_implementation" +require "virtual/passes/frame_implementation" + +Sof::Volotile.add(Virtual::Block , [:method]) +Sof::Volotile.add(Virtual::CompiledMethod , [:current]) diff --git a/lib/virtual/compiler.rb b/lib/virtual/compiler.rb new file mode 100644 index 00000000..f6d49483 --- /dev/null +++ b/lib/virtual/compiler.rb @@ -0,0 +1,44 @@ +module Virtual + module Compiler + + # Compiling is the conversion of the AST into 2 things: + # - code (ie sequences of Instructions inside Blocks) carried by CompiledMethods + # - an object graph containing all the Methods, their classes and Constants + # + # Some compile methods just add code, some may add structure (ie Blocks) while + # others instantiate Class and Method objects + # + # Everything in ruby is an expression, ie returns a value. So the effect of every compile + # is that a value is put into the ReturnSlot of the current Message. + # The compile method (so every compile method) returns the value that it deposits which + # may be unknown Mystery 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. + # 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 + raise e + end + end + + end +end + +require_relative "compiler/basic_expressions" +require_relative "compiler/callsite_expression" +require_relative "compiler/compound_expressions" +require_relative "compiler/if_expression" +require_relative "compiler/function_expression" +require_relative "compiler/module_expression" +require_relative "compiler/operator_expressions" +require_relative "compiler/return_expression" +require_relative "compiler/while_expression" +require_relative "compiler/expression_list" diff --git a/lib/compiler/README.md b/lib/virtual/compiler/README.md similarity index 100% rename from lib/compiler/README.md rename to lib/virtual/compiler/README.md diff --git a/lib/virtual/compiler/basic_expressions.rb b/lib/virtual/compiler/basic_expressions.rb new file mode 100644 index 00000000..9ecbdfe8 --- /dev/null +++ b/lib/virtual/compiler/basic_expressions.rb @@ -0,0 +1,101 @@ +module Virtual + # collection of the simple ones, int and strings and such + + module Compiler + + # Constant expressions can by definition be evaluated at compile time. + # But that does not solve their storage, ie they need to be accessible at runtime from _somewhere_ + # So we view ConstantExpressions like functions that return the value of the constant. + # In other words, their storage is the return slot as it would be for a method + + # The current approach moves the constant into a variable before using it + # 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 = Virtual::IntegerConstant.new(expression.value) + to = Virtual::Return.new(Virtual::Integer , int) + method.add_code Virtual::Set.new( to , int) + to + end + + def self.compile_true expression , method + value = Virtual::TrueConstant.new + to = Virtual::Return.new(Virtual::Reference , value) + method.add_code Virtual::Set.new( to , value ) + to + end + + def self.compile_false expression , method + value = Virtual::FalseConstant.new + to = Virtual::Return.new(Virtual::Reference , value) + method.add_code Virtual::Set.new( to , value ) + to + end + + def self.compile_nil expression , method + value = Virtual::NilConstant.new + to = Virtual::Return.new(Virtual::Reference , value) + method.add_code Virtual::Set.new( to , value ) + to + end + + # 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 Virtual::Self.new( Virtual::Mystery ) if expression.name == :self + name = expression.name + if method.has_var(expression.name) + # either an argument, so it's stored in message + if( index = method.has_arg(name)) + method.add_code MessageGet.new(name , index) + else # or a local so it is in the frame + method.add_code FrameGet.new(name , index) + end + else + call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit + Compiler.compile(call, method) + end + end + + + def self.compile_module expression , method + clazz = Virtual::BootSpace.space.get_or_create_class name + raise "uups #{clazz}.#{name}" unless clazz + to = Virtual::Return.new(Virtual::Reference , clazz ) + method.add_code Virtual::Set.new( to , clazz ) + to + end + + # attr_reader :string + def self.compile_string expression , method + value = Virtual::StringConstant.new(expression.string) + to = Virtual::Return.new(Virtual::Reference , value) + Virtual::BootSpace.space.add_object value + method.add_code Virtual::Set.new( to , value ) + to + end + + #attr_reader :left, :right + def self.compile_assignment expression , method + raise "must assign to NameExpression , not #{expression.left}" unless expression.left.instance_of? Ast::NameExpression + r = Compiler.compile(expression.right , method ) + raise "oh noo, nil from where #{expression.right.inspect}" unless r + index = method.has_arg(name) + if index + method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::MessageSlot.new(index , r,type , r )) + else + index = method.ensure_local(expression.left.name) + method.add_code Virtual::Set.new(Virtual::Return.new , Virtual::FrameSlot.new(index , r.type , r )) + end + r + end + + def self.compile_variable expression, method + method.add_code Virtual::InstanceGet.new(expression.name) + Virtual::Return.new( Virtual::Mystery ) + end + end +end diff --git a/lib/compiler/callsite_expression.rb b/lib/virtual/compiler/callsite_expression.rb similarity index 97% rename from lib/compiler/callsite_expression.rb rename to lib/virtual/compiler/callsite_expression.rb index 02eddd24..da746725 100644 --- a/lib/compiler/callsite_expression.rb +++ b/lib/virtual/compiler/callsite_expression.rb @@ -1,4 +1,5 @@ -module Compiler +module Virtual + module Compiler # operators are really function calls # call_site - attr_reader :name, :args , :receiver @@ -23,4 +24,5 @@ module Compiler # (this is what is moved _inside_ above loop for such expressions that are calls (or constants)) Virtual::Return.new( method.return_type ) end + end end diff --git a/lib/compiler/compound_expressions.rb b/lib/virtual/compiler/compound_expressions.rb similarity index 86% rename from lib/compiler/compound_expressions.rb rename to lib/virtual/compiler/compound_expressions.rb index 02c6f147..21d1dacf 100644 --- a/lib/compiler/compound_expressions.rb +++ b/lib/virtual/compiler/compound_expressions.rb @@ -1,4 +1,5 @@ -module Compiler +module Virtual + module Compiler # attr_reader :values def self.compile_array expession, context @@ -11,4 +12,5 @@ module Compiler def self.compile_hash context to.do end + end end diff --git a/lib/compiler/expression_list.rb b/lib/virtual/compiler/expression_list.rb similarity index 83% rename from lib/compiler/expression_list.rb rename to lib/virtual/compiler/expression_list.rb index 3f50ef9a..12b0d7ac 100644 --- a/lib/compiler/expression_list.rb +++ b/lib/virtual/compiler/expression_list.rb @@ -1,8 +1,10 @@ -module Compiler +module Virtual + module Compiler # list - attr_reader :expressions def self.compile_list expession , method expession.expressions.collect do |part| Compiler.compile( part , method ) end end + end end diff --git a/lib/compiler/function_expression.rb b/lib/virtual/compiler/function_expression.rb similarity index 98% rename from lib/compiler/function_expression.rb rename to lib/virtual/compiler/function_expression.rb index 7a52efed..91d0e2bb 100644 --- a/lib/compiler/function_expression.rb +++ b/lib/virtual/compiler/function_expression.rb @@ -1,4 +1,5 @@ -module Compiler +module Virtual + module Compiler # function attr_reader :name, :params, :body , :receiver def self.compile_function expression, method args = expression.params.collect do |p| @@ -66,4 +67,5 @@ module Compiler context.function = parent_function function end + end end diff --git a/lib/compiler/if_expression.rb b/lib/virtual/compiler/if_expression.rb similarity index 97% rename from lib/compiler/if_expression.rb rename to lib/virtual/compiler/if_expression.rb index 34b2c8cf..b548a380 100644 --- a/lib/compiler/if_expression.rb +++ b/lib/virtual/compiler/if_expression.rb @@ -1,4 +1,5 @@ -module Compiler +module Virtual + module Compiler # if - attr_reader :cond, :if_true, :if_false def self.compile_if expression , method @@ -37,4 +38,5 @@ module Compiler #TODO should return the union of the true and false types last end + end end diff --git a/lib/compiler/module_expression.rb b/lib/virtual/compiler/module_expression.rb similarity index 90% rename from lib/compiler/module_expression.rb rename to lib/virtual/compiler/module_expression.rb index f8e78bd3..c3086536 100644 --- a/lib/compiler/module_expression.rb +++ b/lib/virtual/compiler/module_expression.rb @@ -1,10 +1,11 @@ -module Compiler +module Virtual + module Compiler # module attr_reader :name ,:expressions def self.compile_module expression , context return clazz end - def self.compile_class expression , method + def self.compile_class expression , method clazz = ::Virtual::BootSpace.space.get_or_create_class expression.name puts "Created class #{clazz.name.inspect}" expression.expressions.each do |expr| @@ -19,4 +20,5 @@ module Compiler return clazz end + end end diff --git a/lib/compiler/operator_expressions.rb b/lib/virtual/compiler/operator_expressions.rb similarity index 86% rename from lib/compiler/operator_expressions.rb rename to lib/virtual/compiler/operator_expressions.rb index 4f4203ef..6f16297f 100644 --- a/lib/compiler/operator_expressions.rb +++ b/lib/virtual/compiler/operator_expressions.rb @@ -1,7 +1,9 @@ -module Compiler +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 diff --git a/lib/compiler/return_expression.rb b/lib/virtual/compiler/return_expression.rb similarity index 95% rename from lib/compiler/return_expression.rb rename to lib/virtual/compiler/return_expression.rb index f2dc8627..599d2a5f 100644 --- a/lib/compiler/return_expression.rb +++ b/lib/virtual/compiler/return_expression.rb @@ -1,4 +1,5 @@ -module Compiler +module Virtual + module Compiler # return attr_reader :expression def self.compile_return expression, scope ,method @@ -19,4 +20,5 @@ module Compiler #function.set_return return_reg return return_reg end + end end diff --git a/lib/compiler/while_expression.rb b/lib/virtual/compiler/while_expression.rb similarity index 90% rename from lib/compiler/while_expression.rb rename to lib/virtual/compiler/while_expression.rb index cbf5f848..24ab8ed9 100644 --- a/lib/compiler/while_expression.rb +++ b/lib/virtual/compiler/while_expression.rb @@ -1,7 +1,8 @@ -module Compiler +module Virtual + module Compiler # while- attr_reader :condition, :body - def self.compile_while expression, method + def self.compile_while expression, method start = Virtual::Label.new("while_start") method.add_code start is = expression.condition.compile(method ) @@ -22,4 +23,5 @@ module Compiler method.current = merge last end + end end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index e4c07213..d3c2881e 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -35,7 +35,7 @@ module Virtual def initialize @parser = Parser::Salama.new the_end = Halt.new - @message = Message.new(the_end , the_end , :Object) +# @message = Message.new(the_end , the_end , :Object) end attr_reader :message @@ -62,24 +62,6 @@ module Virtual main = Virtual::CompiledMethod.main Compiler.compile( parts , main ) end - end + end - -require_relative "instruction" -require_relative "compiled_method" -require_relative "frame" -require_relative "message" -require_relative "slots/slot" -require_relative "type" -require_relative "object" -require_relative "constants" -require_relative "boot_space" -# the passes _are_ order dependant -require_relative "passes/send_implementation" -require_relative "passes/get_implementation" -require_relative "passes/enter_implementation" -require_relative "passes/frame_implementation" - -Sof::Volotile.add(Virtual::Block , [:method]) -Sof::Volotile.add(Virtual::CompiledMethod , [:current])