diff --git a/lib/ast/basic_expressions.rb b/lib/ast/basic_expressions.rb index dcd698b8..a31b75f8 100644 --- a/lib/ast/basic_expressions.rb +++ b/lib/ast/basic_expressions.rb @@ -4,7 +4,7 @@ module Ast class IntegerExpression < Expression # attr_reader :value - def compile binding + def compile frame Virtual::IntegerConstant.new value end end @@ -13,9 +13,10 @@ module Ast # attr_reader :name # compiling a variable resolves it. if it wasn't defined, raise an exception - def compile context - raise "Undefined variable #{name}, defined locals #{context.locals.keys.join('-')}" unless context.locals.has_key?(name) - context.locals[name] + def compile frame + # either a variable or needs to be called. + frame.get(name) +# frame.send name end end diff --git a/lib/virtual/frame.rb b/lib/virtual/frame.rb new file mode 100644 index 00000000..6b77e3f4 --- /dev/null +++ b/lib/virtual/frame.rb @@ -0,0 +1,20 @@ +module Virtual + # A frame, or activation frame, represents a function call during calling. So not the static definition of the function + # but the dynamic invokation of it. + # + # In a minimal c world this would be just the return address, but with exceptions and continuations things get more + # complicated. How much more we shall see + # + # The current list comprises + # - next normal instruction + # - next exception instruction + # - self (me) + # - argument mappings + # - local variable mapping + class Frame + def initialize + + end + attr_reader :next_normal, :next_exception, :me, :argument_names + end +end diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 21562e0f..34708c5c 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -7,8 +7,16 @@ module Virtual # It is actully the point of the virtual machine layer to express oo functionality in the set of instructions, thus # defining a minimal set of instructions needed to implement oo. - # This is partly because jumping over this layer and doing in straight in assember was too bi a step + # This is partly because jumping over this layer and doing in straight in assember was too big a step class Instruction + end + # the first instruction we need is to stop. Off course in a real machine this would be a syscall, but that is just + # an implementation (in a programm it would be a function). But in a virtual machine, not only do we need this instruction, + # it is indeed the first instruction as just this instruction is the smallest possible programm for the machine. + # As such it is the next instruction for any first instruction that we generate. + class Halt < Instruction + + end end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index 1e5ad9ae..a51ce1b0 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -58,6 +58,7 @@ end require_relative "list" require_relative "instruction" +require_relative "frame" require_relative "value" require_relative "mystery" require_relative "object" diff --git a/test/virtual/test_basic.rb b/test/virtual/test_basic.rb index 9389ae82..7f544fa7 100644 --- a/test/virtual/test_basic.rb +++ b/test/virtual/test_basic.rb @@ -12,35 +12,35 @@ class TestBasic < MiniTest::Test def test_name @string_input = 'foo ' - @output = Ast::NameExpression.new('foo') - @parser = @parser.name + @output = [nil] + check end def test_name_underscode_start @string_input = '_bar ' @output = Ast::NameExpression.new('_bar') - @parser = @parser.name + check end def test_name_underscode_middle @string_input = 'foo_bar ' @parse_output = {:name => 'foo_bar'} @output = Ast::NameExpression.new('foo_bar') - @parser = @parser.name + check end def test_instance_variable @string_input = '@foo_bar ' @parse_output = {:instance_variable=>{:name=>"foo_bar"}} @output = Ast::VariableExpression.new(:foo_bar) - @parser = @parser.instance_variable + check end def test_module_name @string_input = 'FooBar ' @parse_output = {:module_name=>"FooBar"} @output = Ast::ModuleName.new("FooBar") - @parser = @parser.module_name + check end def test_comment @@ -48,14 +48,14 @@ class TestBasic < MiniTest::Test @string_input = out.dup #NEEDS the return, which is what delimits the comment @parse_output = out @output = @parse_output #dont transform - @parser = @parser.comment + check end def test_string @string_input = "\"hello\"" @parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]} @output = Ast::StringExpression.new('hello') - @parser = @parser.string + check end def test_string_escapes @@ -64,7 +64,7 @@ class TestBasic < MiniTest::Test @parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}, {:char=>" "}, {:char=>" "}, {:esc=>"n"}, {:char=>"y"}, {:char=>"o"}, {:char=>"u"}]} @output = Ast::StringExpression.new(out) - @parser = @parser.string + check end end \ No newline at end of file