diff --git a/lib/ast/basic_expressions.rb b/lib/ast/basic_expressions.rb index 56c1f6fa..85a8985a 100644 --- a/lib/ast/basic_expressions.rb +++ b/lib/ast/basic_expressions.rb @@ -14,11 +14,13 @@ module Ast Virtual::TrueValue.new end end + class FalseExpression def compile frame Virtual::FalseValue.new end end + class NilExpression def compile frame Virtual::NilValue.new @@ -28,9 +30,15 @@ module Ast class NameExpression < Expression # attr_reader :name - # compiling a variable resolves it. If it's not defined look call it as a menthod (which may raise NoMethodFound) - def compile frame - frame.get(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 ussued. + # this makes the namespace static, ie when eval and co are implemented method needs recompilation + def compile frame , method + if method.has_var(name) + frame.compile_get(name , method ) + else + frame.compile_send( name , method ) + end end end diff --git a/lib/ast/expression_list.rb b/lib/ast/expression_list.rb index 2f3081cb..99537710 100644 --- a/lib/ast/expression_list.rb +++ b/lib/ast/expression_list.rb @@ -1,8 +1,8 @@ module Ast class ExpressionList < Expression # attr_reader :expressions - def compile binding - expressions.collect { |part| part.compile( binding ) } + def compile binding , method + expressions.collect { |part| part.compile( binding , method ) } end end end \ No newline at end of file diff --git a/lib/virtual/frame.rb b/lib/virtual/frame.rb index 83bfcc15..c30a6897 100644 --- a/lib/virtual/frame.rb +++ b/lib/virtual/frame.rb @@ -22,5 +22,14 @@ module Virtual @binding = List.new end attr_reader :next_normal, :next_exception, :me, :binding + + # + def compile_get name , method + method.add FrameGet.new(name) + end + + def compile_send name , method + method.add FrameSend.new(name) + end end end diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 34708c5c..e12cc7f1 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -9,7 +9,11 @@ module Virtual # This is partly because jumping over this layer and doing in straight in assember was too big a step class Instruction + attr_accessor :next + def inspect + self.class.name + ".new()" + end end # the first instruction we need is to stop. Off course in a real machine this would be a syscall, but that is just @@ -19,4 +23,30 @@ module Virtual class Halt < Instruction end + + # following classes are stubs. currently in brainstorming mode, so anything may change anytime + class MethodEnter < Instruction + end + + class FrameGet < Instruction + def initialize name + @name = name + end + end + + class FrameSend < Instruction + + def initialize name + @name = name.to_sym + end + attr_reader :name + + def == other + self.class == other.class && self.name == other.name + end + def inspect + self.class.name + ".new(:#{@name})" + end + end + end diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index f82d6802..7316ff0a 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -37,7 +37,7 @@ module Virtual end def initialize - the_end = HaltInstruction.new + the_end = Halt.new @frame = Frame.new(the_end , the_end , :Object) end attr_reader :frame @@ -51,15 +51,12 @@ module Virtual instruction = next_instruction end end - #return an anonymous new function (the top level) into which code is compiled - def anonymous - - end end end require_relative "list" require_relative "instruction" +require_relative "method" require_relative "frame" require_relative "value" require_relative "mystery" diff --git a/lib/virtual/method.rb b/lib/virtual/method.rb new file mode 100644 index 00000000..8d8d3427 --- /dev/null +++ b/lib/virtual/method.rb @@ -0,0 +1,38 @@ +module Virtual + # static description of a method + # name + # args (with defaults) + # code + # return arg (usually mystery, but for coded ones can be more specific) + # known local variable names + # temp variables (numbered) + # + class Method + #return the main function (the top level) into which code is compiled + def Method.main + Method.new(:main) + end + def initialize name , args = [] + @name = name + @args = args + @locals = [] + @start = MethodEnter.new + @current = @start + end + attr_reader :name + + def add instruction + @current.next = instruction + @current = instruction + end + + # 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 + def has_var name + var = @args.find {|a| a == name } + var = @locals.find {|a| a == name } unless var + var + end + end +end diff --git a/test/virtual/test_basic.rb b/test/virtual/test_basic.rb index 0b65020c..5f88acb7 100644 --- a/test/virtual/test_basic.rb +++ b/test/virtual/test_basic.rb @@ -28,7 +28,7 @@ class TestBasic < MiniTest::Test def test_name @string_input = 'foo ' - @output = [nil] + @output = [Virtual::FrameSend.new(:foo)] check end diff --git a/test/virtual/virtual_helper.rb b/test/virtual/virtual_helper.rb index b1947c81..2c2e52d2 100644 --- a/test/virtual/virtual_helper.rb +++ b/test/virtual/virtual_helper.rb @@ -12,7 +12,7 @@ module VirtualHelper syntax = parser.parse_with_debug(@string_input) parts = Parser::Transform.new.apply(syntax) machine = Virtual::Machine.new - expressions = parts.compile(machine.frame , machine.anonymous) + expressions = parts.compile(machine.frame , Virtual::Method.main ) assert_equal @output , expressions end