From 252c0ccdca36b93007ff80258cfb4d17ed07920f Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 27 Sep 2015 16:06:48 +0300 Subject: [PATCH] finish typing variables --- lib/bosl/compiler/class_field.rb | 4 +- lib/bosl/compiler/field_def.rb | 6 +-- lib/bosl/compiler/function_expression.rb | 4 +- lib/bosl/compiler/name_expression.rb | 8 +++- lib/bosl/compiler/operator_expressions.rb | 13 ++++++- lib/parfait/method.rb | 46 ++++++++++++----------- lib/virtual/machine.rb | 1 + test/compiler/test_basic.rb | 4 +- test/compiler/test_field_access.rb | 2 +- test/fragments/test_recursive_fibo.rb | 9 +++-- test/parfait/test_all.rb | 1 + test/parfait/test_method.rb | 23 ++++++++++++ 12 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 test/parfait/test_method.rb diff --git a/lib/bosl/compiler/class_field.rb b/lib/bosl/compiler/class_field.rb index 3eacc1d0..f7bbf96a 100644 --- a/lib/bosl/compiler/class_field.rb +++ b/lib/bosl/compiler/class_field.rb @@ -2,12 +2,12 @@ module Bosl Compiler.class_eval do def on_class_field expression - puts expression.inspect + #puts expression.inspect type , name , value = *expression for_class = self.method.for_class index = for_class.object_layout.variable_index(name) - raise "class field already defined:#{name} for class #{for_class.name}" if index + #raise "class field already defined:#{name} for class #{for_class.name}" if index puts "Define field #{name} on class #{for_class.name}" index = for_class.object_layout.add_instance_variable( name ) #TODO need typing diff --git a/lib/bosl/compiler/field_def.rb b/lib/bosl/compiler/field_def.rb index fa07a2ee..34b24e69 100644 --- a/lib/bosl/compiler/field_def.rb +++ b/lib/bosl/compiler/field_def.rb @@ -2,16 +2,16 @@ module Bosl Compiler.class_eval do def on_field_def expression -# puts expression.inspect + #puts expression.inspect type , name , value = *expression - index = method.ensure_local( name ) + index = method.ensure_local( name , type ) if value value = process( value ) end - Virtual::Return.new( value ) + Virtual::Return.new( type , value ) end end end diff --git a/lib/bosl/compiler/function_expression.rb b/lib/bosl/compiler/function_expression.rb index fcaf9fa3..472b82ad 100644 --- a/lib/bosl/compiler/function_expression.rb +++ b/lib/bosl/compiler/function_expression.rb @@ -2,12 +2,12 @@ module Bosl Compiler.class_eval do # function attr_reader :name, :params, :body , :receiver def on_function expression -# puts expression.inspect + #puts expression.inspect return_type , name , parameters, kids , receiver = *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 == :parameter - Parfait::Variable.new( p.first , p[1]) + Parfait::Variable.new( *p) end if receiver diff --git a/lib/bosl/compiler/name_expression.rb b/lib/bosl/compiler/name_expression.rb index bb3ecbf9..fd0ee9a6 100644 --- a/lib/bosl/compiler/name_expression.rb +++ b/lib/bosl/compiler/name_expression.rb @@ -13,8 +13,12 @@ module Bosl if( index = method.has_arg(name)) method.source.add_code Virtual::Set.new( Virtual::ArgSlot.new(index,:int ) , 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,:int ) , ret ) + index = method.has_local( name ) + if(index) + method.source.add_code Virtual::Set.new(Virtual::FrameSlot.new(index,:int ) , ret ) + else + raise "must define variable #{name} before using it" + end end return ret end diff --git a/lib/bosl/compiler/operator_expressions.rb b/lib/bosl/compiler/operator_expressions.rb index 602e744b..2f5ed142 100644 --- a/lib/bosl/compiler/operator_expressions.rb +++ b/lib/bosl/compiler/operator_expressions.rb @@ -10,8 +10,17 @@ module Bosl name , value = *expression name = name.to_a.first v = process(value) - index = method.ensure_local( name ) - method.source.add_code Virtual::Set.new(Virtual::FrameSlot.new(:int,index ) , v ) + index = method.has_local( name ) + if(index) + method.source.add_code Virtual::Set.new(Virtual::FrameSlot.new(:int,index ) , v ) + else + index = method.has_arg( name ) + if(index) + method.source.add_code Virtual::Set.new(Virtual::ArgSlot.new(:int,index ) , v ) + else + raise "must define variable #{name} before using it in #{@method.inspect}" + end + end end end diff --git a/lib/parfait/method.rb b/lib/parfait/method.rb index 46a6c443..f41bff72 100644 --- a/lib/parfait/method.rb +++ b/lib/parfait/method.rb @@ -34,46 +34,48 @@ module Parfait attributes [:name , :arguments , :for_class , :code , :locals ] - # determine whether this method has a variable by the given name - # variables are locals and and arguments - # used to determine if a send must be issued - # return index of the name into the message if so - def has_var name - raise "has_var #{name}.#{name.class}" unless name.is_a? Symbol - index = has_arg(name) - return index if index - has_local(name) - end - # determine whether this method has an argument by the name def has_arg name raise "has_arg #{name}.#{name.class}" unless name.is_a? Symbol - self.arguments.index_of name + max = self.arguments.get_length + counter = 1 + while( counter <= max ) + if( self.arguments.get(counter).name == name) + return counter + end + counter = counter + 1 + end + return nil end # determine if method has a local variable or tmp (anonymous local) by given name def has_local name raise "has_local #{name}.#{name.class}" unless name.is_a? Symbol - index = self.locals.index_of(name) - index + max = self.locals.get_length + counter = 1 + while( counter <= max ) + if( self.locals.get(counter).name == name) + return counter + end + counter = counter + 1 + end + return nil end - def ensure_local name + def ensure_local name , type index = has_local name return index if index - self.locals.push name + var = Variable.new( type , name) + self.locals.push var self.locals.get_length end - def get_var name - var = has_var name - raise "no var #{name} in method #{self.name} , #{self.locals} #{self.arguments}" unless var - var - end - def sof_reference_name self.name end + def inspect + "#{self.for_class.name}:#{name}(#{arguments.inspect})" + end end end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index 994c978c..7b9b6551 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -93,6 +93,7 @@ module Virtual # Objects are data and get assembled after functions def add_object o return false if @objects[o.object_id] + return if o.is_a? Fixnum raise "adding non parfait #{o.class}" unless o.is_a? Parfait::Object or o.is_a? Symbol @objects[o.object_id] = o true diff --git a/test/compiler/test_basic.rb b/test/compiler/test_basic.rb index e21c7a2a..efbb57e4 100644 --- a/test/compiler/test_basic.rb +++ b/test/compiler/test_basic.rb @@ -34,8 +34,8 @@ class TestBasic < MiniTest::Test check end - def test_name - @string_input = 'foo ' + def test_var + @string_input = 'int foo ' @output = "- Virtual::Return(:type => :int)" check end diff --git a/test/compiler/test_field_access.rb b/test/compiler/test_field_access.rb index 419f541f..f8c17b1b 100644 --- a/test/compiler/test_field_access.rb +++ b/test/compiler/test_field_access.rb @@ -5,7 +5,7 @@ module Virtual class TestFoo < MiniTest::Test include CodeChecker - def test_foo2 + def test_foo3 @string_input = <