verneuil 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.txt +4 -0
 - data/README +12 -5
 - data/Rakefile +1 -1
 - data/bin/verneuil +24 -0
 - data/lib/verneuil.rb +2 -0
 - data/lib/verneuil/address.rb +1 -1
 - data/lib/verneuil/block.rb +8 -4
 - data/lib/verneuil/compiler.rb +58 -14
 - data/lib/verneuil/kernel/fork.rb +14 -0
 - data/lib/verneuil/kernel/process_join.rb +15 -0
 - data/lib/verneuil/method.rb +8 -0
 - data/lib/verneuil/process.rb +160 -30
 - data/lib/verneuil/process/kernel_methods.rb +30 -0
 - data/lib/verneuil/process_group.rb +57 -0
 - data/lib/verneuil/program.rb +5 -15
 - data/lib/verneuil/scope.rb +21 -6
 - data/lib/verneuil/symbol_table.rb +35 -0
 - metadata +8 -2
 
    
        data/HISTORY.txt
    CHANGED
    
    
    
        data/README
    CHANGED
    
    | 
         @@ -6,7 +6,8 @@ rubies - they are too pure and don't have the characteristics of real ones. 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            This is a virtual machine that:
         
     | 
| 
       8 
8 
     | 
    
         
             
              * executes something that is almost Ruby (it looks like it)
         
     | 
| 
       9 
     | 
    
         
            -
              * and that can store its state to disk. And resume.
         
     | 
| 
      
 9 
     | 
    
         
            +
              * and that can store its state to disk. And resume. 
         
     | 
| 
      
 10 
     | 
    
         
            +
                Think: Continuations. Serializable.
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
12 
     | 
    
         
             
            Is it useful? That depends. You could for example use this to
         
     | 
| 
       12 
13 
     | 
    
         
             
              * script website interaction with your user
         
     | 
| 
         @@ -28,9 +29,6 @@ SYNOPSIS 
     | 
|
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
            STATUS
         
     | 
| 
       30 
31 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
            At version pre 0.1 and by no means ready for production. May or may not work, 
         
     | 
| 
       32 
     | 
    
         
            -
            depending on time of day. 
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
32 
     | 
    
         
             
            Verneuil currently handles all the programs in spec/programs. The following
         
     | 
| 
       35 
33 
     | 
    
         
             
            Ruby features should work: 
         
     | 
| 
       36 
34 
     | 
    
         | 
| 
         @@ -41,5 +39,14 @@ Ruby features should work: 
     | 
|
| 
       41 
39 
     | 
    
         
             
             * while
         
     | 
| 
       42 
40 
     | 
    
         
             
             * Masking class methods 
         
     | 
| 
       43 
41 
     | 
    
         
             
             * correct self
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
             * fork, join
         
     | 
| 
      
 43 
     | 
    
         
            +
             
         
     | 
| 
      
 44 
     | 
    
         
            +
            Currently this project lays sleeping for a few months - until I will need it
         
     | 
| 
      
 45 
     | 
    
         
            +
            again. That day is sure to come. 
         
     | 
| 
      
 46 
     | 
    
         
            +
             
         
     | 
| 
      
 47 
     | 
    
         
            +
            CONTRIBUTORS
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            Florian Hanke (florianhanke.com)
         
     | 
| 
      
 50 
     | 
    
         
            +
            Kaspar Schiess (absurd.li)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
         
     | 
| 
       45 
52 
     | 
    
         
             
            (c) 2011 Kaspar Schiess
         
     | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/bin/verneuil
    ADDED
    
    | 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            $:.unshift File.dirname(__FILE__) + "/../lib"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'verneuil'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            verbose = false
         
     | 
| 
      
 7 
     | 
    
         
            +
            if ARGV.first == '-v'
         
     | 
| 
      
 8 
     | 
    
         
            +
              verbose = true 
         
     | 
| 
      
 9 
     | 
    
         
            +
              ARGV.shift
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            program = Verneuil::Compiler.compile(ARGF.read).program
         
     | 
| 
      
 13 
     | 
    
         
            +
            if verbose
         
     | 
| 
      
 14 
     | 
    
         
            +
              p program
         
     | 
| 
      
 15 
     | 
    
         
            +
              puts
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            process = Verneuil::Process.new(program, nil)
         
     | 
| 
      
 19 
     | 
    
         
            +
            retval = process.run
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            if verbose
         
     | 
| 
      
 22 
     | 
    
         
            +
              puts
         
     | 
| 
      
 23 
     | 
    
         
            +
              puts "Program returned #{retval.inspect}." 
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/verneuil.rb
    CHANGED
    
    | 
         @@ -5,6 +5,7 @@ end 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            require 'verneuil/address'
         
     | 
| 
       7 
7 
     | 
    
         
             
            require 'verneuil/method'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'verneuil/symbol_table'
         
     | 
| 
       8 
9 
     | 
    
         
             
            require 'verneuil/block'
         
     | 
| 
       9 
10 
     | 
    
         
             
            require 'verneuil/program'
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
         @@ -13,3 +14,4 @@ require 'verneuil/compiler' 
     | 
|
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
            require 'verneuil/scope'
         
     | 
| 
       15 
16 
     | 
    
         
             
            require 'verneuil/process'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'verneuil/process_group'
         
     | 
    
        data/lib/verneuil/address.rb
    CHANGED
    
    
    
        data/lib/verneuil/block.rb
    CHANGED
    
    | 
         @@ -2,18 +2,22 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            # Abstracts the notion of a block.
         
     | 
| 
       3 
3 
     | 
    
         
             
            #
         
     | 
| 
       4 
4 
     | 
    
         
             
            class Verneuil::Block
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
              # At what address does the block code start?
         
     | 
| 
      
 6 
     | 
    
         
            +
              attr_reader :address
         
     | 
| 
      
 7 
     | 
    
         
            +
              attr_reader :scope
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def initialize(address, process, scope)
         
     | 
| 
      
 10 
     | 
    
         
            +
                @address  = address
         
     | 
| 
       7 
11 
     | 
    
         
             
                @process  = process
         
     | 
| 
       8 
12 
     | 
    
         
             
                @scope    = scope
         
     | 
| 
       9 
13 
     | 
    
         
             
              end
         
     | 
| 
       10 
14 
     | 
    
         | 
| 
       11 
15 
     | 
    
         
             
              def call(*args)
         
     | 
| 
       12 
     | 
    
         
            -
                @process.enter_block(args, @ 
     | 
| 
      
 16 
     | 
    
         
            +
                @process.enter_block(args, @address, @scope)
         
     | 
| 
       13 
17 
     | 
    
         
             
                throw :verneuil_code
         
     | 
| 
       14 
18 
     | 
    
         
             
              end
         
     | 
| 
       15 
19 
     | 
    
         | 
| 
       16 
20 
     | 
    
         
             
              def inspect
         
     | 
| 
       17 
     | 
    
         
            -
                "block@#{@ 
     | 
| 
      
 21 
     | 
    
         
            +
                "block@#{@address.ip}(#{@scope.inspect})"
         
     | 
| 
       18 
22 
     | 
    
         
             
              end
         
     | 
| 
       19 
23 
     | 
    
         
             
            end
         
     | 
    
        data/lib/verneuil/compiler.rb
    CHANGED
    
    | 
         @@ -13,7 +13,8 @@ class Verneuil::Compiler 
     | 
|
| 
       13 
13 
     | 
    
         
             
              end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
              def self.compile(*args)
         
     | 
| 
       16 
     | 
    
         
            -
                new. 
     | 
| 
      
 16 
     | 
    
         
            +
                new.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  tap { |compiler| compiler.compile(*args) }
         
     | 
| 
       17 
18 
     | 
    
         
             
              end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
              # Compiles a piece of code within the current program. This means that any
         
     | 
| 
         @@ -55,11 +56,34 @@ class Verneuil::Compiler 
     | 
|
| 
       55 
56 
     | 
    
         
             
                  raise NotImplementedError, "No acceptor for #{sexp}." \
         
     | 
| 
       56 
57 
     | 
    
         
             
                    unless respond_to? sym
         
     | 
| 
       57 
58 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                   
     | 
| 
      
 59 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 60 
     | 
    
         
            +
                    self.send(sym, *args)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  rescue ArgumentError => ex
         
     | 
| 
      
 62 
     | 
    
         
            +
                    if md=ex.message.match(/wrong number of arguments \(([^)]+)\)/)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      sexp_skeleton = s(sexp[0], *sexp[1..-1].map { |e| e && s(e.first, '...') })
         
     | 
| 
      
 64 
     | 
    
         
            +
                      raise ArgumentError, "wrong number of elements in #{sexp_skeleton} (#{md[1]})."
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
       59 
68 
     | 
    
         
             
                end
         
     | 
| 
       60 
69 
     | 
    
         | 
| 
       61 
70 
     | 
    
         
             
                #--------------------------------------------------------- visitor methods
         
     | 
| 
       62 
71 
     | 
    
         | 
| 
      
 72 
     | 
    
         
            +
                # s(:colon2, s(:const, :Verneuil), :Process) - access something inside
         
     | 
| 
      
 73 
     | 
    
         
            +
                # a namespace. Constants are resolved at compile time!
         
     | 
| 
      
 74 
     | 
    
         
            +
                #
         
     | 
| 
      
 75 
     | 
    
         
            +
                def accept_colon2(left, right)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  left_const = visit(left)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  const = left_const.const_get(right)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  @generator.load const
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
                
         
     | 
| 
      
 81 
     | 
    
         
            +
                # s(:const, :Verneuil) - Resolve a constant globally and return it. 
         
     | 
| 
      
 82 
     | 
    
         
            +
                #
         
     | 
| 
      
 83 
     | 
    
         
            +
                def accept_const(const)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  eval(const.to_s)
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
                
         
     | 
| 
       63 
87 
     | 
    
         
             
                # s(:call, RECEIVER, NAME, ARGUMENTS) - Method calls with or without
         
     | 
| 
       64 
88 
     | 
    
         
             
                # receiver.
         
     | 
| 
       65 
89 
     | 
    
         
             
                # 
         
     | 
| 
         @@ -105,6 +129,14 @@ class Verneuil::Compiler 
     | 
|
| 
       105 
129 
     | 
    
         
             
                  @generator.load value
         
     | 
| 
       106 
130 
     | 
    
         
             
                end
         
     | 
| 
       107 
131 
     | 
    
         | 
| 
      
 132 
     | 
    
         
            +
                # s(:array, ELEMENTS) - array literal. 
         
     | 
| 
      
 133 
     | 
    
         
            +
                # 
         
     | 
| 
      
 134 
     | 
    
         
            +
                def accept_array(*elements)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  elements.each { |el| visit(el) }
         
     | 
| 
      
 136 
     | 
    
         
            +
                  @generator.load Array
         
     | 
| 
      
 137 
     | 
    
         
            +
                  @generator.ruby_call :"[]", elements.size
         
     | 
| 
      
 138 
     | 
    
         
            +
                end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
       108 
140 
     | 
    
         
             
                # s(:if, COND, THEN, ELSE) - an if statement
         
     | 
| 
       109 
141 
     | 
    
         
             
                #
         
     | 
| 
       110 
142 
     | 
    
         
             
                def accept_if(cond, _then, _else)
         
     | 
| 
         @@ -157,14 +189,20 @@ class Verneuil::Compiler 
     | 
|
| 
       157 
189 
     | 
    
         | 
| 
       158 
190 
     | 
    
         
             
                # s(:defined, s(:lvar, :a)) - test if a local variable is defined. 
         
     | 
| 
       159 
191 
     | 
    
         
             
                #
         
     | 
| 
       160 
     | 
    
         
            -
                def accept_defined( 
     | 
| 
       161 
     | 
    
         
            -
                  type,  
     | 
| 
       162 
     | 
    
         
            -
                  
         
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 192 
     | 
    
         
            +
                def accept_defined(exp)
         
     | 
| 
      
 193 
     | 
    
         
            +
                  type, * = exp
         
     | 
| 
      
 194 
     | 
    
         
            +
                  case type
         
     | 
| 
      
 195 
     | 
    
         
            +
                    when :call
         
     | 
| 
      
 196 
     | 
    
         
            +
                      # s(:call, nil, :a, s(:arglist))
         
     | 
| 
      
 197 
     | 
    
         
            +
                      @generator.test_defined exp[2]
         
     | 
| 
      
 198 
     | 
    
         
            +
                    when :lvar
         
     | 
| 
      
 199 
     | 
    
         
            +
                      # s(:lvar, :a)
         
     | 
| 
      
 200 
     | 
    
         
            +
                      @generator.test_defined exp.last
         
     | 
| 
      
 201 
     | 
    
         
            +
                    when :lit
         
     | 
| 
      
 202 
     | 
    
         
            +
                      @generator.load 'expression'
         
     | 
| 
      
 203 
     | 
    
         
            +
                  else
         
     | 
| 
      
 204 
     | 
    
         
            +
                    fail "Don't know how to implement defined? with #{variable.inspect}."
         
     | 
| 
      
 205 
     | 
    
         
            +
                  end
         
     | 
| 
       168 
206 
     | 
    
         
             
                end
         
     | 
| 
       169 
207 
     | 
    
         | 
| 
       170 
208 
     | 
    
         
             
                # s(:lasgn, VARIABLE, VALUE) - assignment of local variables. 
         
     | 
| 
         @@ -195,10 +233,11 @@ class Verneuil::Compiler 
     | 
|
| 
       195 
233 
     | 
    
         
             
                  adr_end = @generator.fwd_adr
         
     | 
| 
       196 
234 
     | 
    
         
             
                  @generator.jump adr_end
         
     | 
| 
       197 
235 
     | 
    
         | 
| 
       198 
     | 
    
         
            -
                   
     | 
| 
      
 236 
     | 
    
         
            +
                  method = Verneuil::Method.new(
         
     | 
| 
       199 
237 
     | 
    
         
             
                    @class_context.last, 
         
     | 
| 
       200 
238 
     | 
    
         
             
                    name, 
         
     | 
| 
       201 
239 
     | 
    
         
             
                    @generator.current_adr)
         
     | 
| 
      
 240 
     | 
    
         
            +
                  @generator.program.symbols.add(method)
         
     | 
| 
       202 
241 
     | 
    
         | 
| 
       203 
242 
     | 
    
         
             
                  # Enters a new local scope and defines arguments
         
     | 
| 
       204 
243 
     | 
    
         
             
                  visit(args)
         
     | 
| 
         @@ -256,7 +295,7 @@ class Verneuil::Compiler 
     | 
|
| 
       256 
295 
     | 
    
         
             
                # s(:iter, s(:call, RECEIVER, METHOD, ARGUMENTS), ASSIGNS, BLOCK) - call
         
     | 
| 
       257 
296 
     | 
    
         
             
                # a method with a block. 
         
     | 
| 
       258 
297 
     | 
    
         
             
                #
         
     | 
| 
       259 
     | 
    
         
            -
                def accept_iter(call, assigns, block)
         
     | 
| 
      
 298 
     | 
    
         
            +
                def accept_iter(call, assigns, block=nil)
         
     | 
| 
       260 
299 
     | 
    
         
             
                  # Jump over the block code
         
     | 
| 
       261 
300 
     | 
    
         
             
                  adr_end_of_block = @generator.fwd_adr
         
     | 
| 
       262 
301 
     | 
    
         
             
                  @generator.jump adr_end_of_block
         
     | 
| 
         @@ -269,7 +308,7 @@ class Verneuil::Compiler 
     | 
|
| 
       269 
308 
     | 
    
         
             
                      unless type == :lasgn
         
     | 
| 
       270 
309 
     | 
    
         
             
                    accept_args(*names)
         
     | 
| 
       271 
310 
     | 
    
         
             
                  end
         
     | 
| 
       272 
     | 
    
         
            -
                  visit(block)
         
     | 
| 
      
 311 
     | 
    
         
            +
                  visit(block) if block
         
     | 
| 
       273 
312 
     | 
    
         
             
                  @generator.return 
         
     | 
| 
       274 
313 
     | 
    
         | 
| 
       275 
314 
     | 
    
         
             
                  adr_end_of_block.resolve
         
     | 
| 
         @@ -298,6 +337,11 @@ class Verneuil::Compiler 
     | 
|
| 
       298 
337 
     | 
    
         
             
                def accept_self
         
     | 
| 
       299 
338 
     | 
    
         
             
                  @generator.load_self
         
     | 
| 
       300 
339 
     | 
    
         
             
                end
         
     | 
| 
       301 
     | 
    
         
            -
             
     | 
| 
      
 340 
     | 
    
         
            +
               
         
     | 
| 
      
 341 
     | 
    
         
            +
                # nil
         
     | 
| 
      
 342 
     | 
    
         
            +
                #
         
     | 
| 
      
 343 
     | 
    
         
            +
                def accept_nil
         
     | 
| 
      
 344 
     | 
    
         
            +
                  @generator.load nil
         
     | 
| 
      
 345 
     | 
    
         
            +
                end
         
     | 
| 
       302 
346 
     | 
    
         
             
              end
         
     | 
| 
       303 
347 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            # Fork the current Verneuil process. Returns the new process instance to the
         
     | 
| 
      
 3 
     | 
    
         
            +
            # caller; never exits the block in the child. 
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Example: (V-code)
         
     | 
| 
      
 6 
     | 
    
         
            +
            #   child = fork do 
         
     | 
| 
      
 7 
     | 
    
         
            +
            #     # do forked stuff here
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            Verneuil::Process.kernel_method nil, :fork do |process, _|
         
     | 
| 
      
 11 
     | 
    
         
            +
              block = process.current_block
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              process.fork_child(block)
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            # Joins the V-process. This means that the joining process will be stopped
         
     | 
| 
      
 3 
     | 
    
         
            +
            # until the joinee halts. Returns the process return value. 
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Running this method only makes sense on childs of the current process. 
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            # Example: 
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   child = fork { ...; 42 }
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   child.join # waits and eventually returns 42
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            Verneuil::Process.kernel_method :'Verneuil::Process', :join do |parent, child|
         
     | 
| 
      
 12 
     | 
    
         
            +
              parent.joining << child
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              nil
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/verneuil/method.rb
    CHANGED
    
    | 
         @@ -2,4 +2,12 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            # Represents a method that can be called. 
         
     | 
| 
       3 
3 
     | 
    
         
             
            #
         
     | 
| 
       4 
4 
     | 
    
         
             
            class Verneuil::Method < Struct.new(:receiver, :name, :address)
         
     | 
| 
      
 5 
     | 
    
         
            +
              def invoke(process, recv_obj)
         
     | 
| 
      
 6 
     | 
    
         
            +
                if receiver
         
     | 
| 
      
 7 
     | 
    
         
            +
                  process.call address, recv_obj
         
     | 
| 
      
 8 
     | 
    
         
            +
                else
         
     | 
| 
      
 9 
     | 
    
         
            +
                  process.call address
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                throw :verneuil_code
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
       5 
13 
     | 
    
         
             
            end
         
     | 
    
        data/lib/verneuil/process.rb
    CHANGED
    
    | 
         @@ -21,7 +21,20 @@ class Verneuil::Process 
     | 
|
| 
       21 
21 
     | 
    
         
             
                @ip = 0
         
     | 
| 
       22 
22 
     | 
    
         
             
                # Should we stop immediately? Cannot restart after setting this. 
         
     | 
| 
       23 
23 
     | 
    
         
             
                @halted = false
         
     | 
| 
      
 24 
     | 
    
         
            +
                # This process' children
         
     | 
| 
      
 25 
     | 
    
         
            +
                @children = []
         
     | 
| 
      
 26 
     | 
    
         
            +
                # The list of processes that this process waits for currently. 
         
     | 
| 
      
 27 
     | 
    
         
            +
                @joining = []
         
     | 
| 
       24 
28 
     | 
    
         
             
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              # Instruction pointer
         
     | 
| 
      
 31 
     | 
    
         
            +
              attr_accessor :ip
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
              # A process is also a process group, containing its children. 
         
     | 
| 
      
 34 
     | 
    
         
            +
              attr_reader :children
         
     | 
| 
      
 35 
     | 
    
         
            +
              
         
     | 
| 
      
 36 
     | 
    
         
            +
              # The list of processes that this process waits for currently. 
         
     | 
| 
      
 37 
     | 
    
         
            +
              attr_reader :joining
         
     | 
| 
       25 
38 
     | 
    
         | 
| 
       26 
39 
     | 
    
         
             
              # Runs the program until it completes and returns the last expression
         
     | 
| 
       27 
40 
     | 
    
         
             
              # in the program.
         
     | 
| 
         @@ -31,29 +44,64 @@ class Verneuil::Process 
     | 
|
| 
       31 
44 
     | 
    
         
             
                  step
         
     | 
| 
       32 
45 
     | 
    
         
             
                end
         
     | 
| 
       33 
46 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                 
     | 
| 
      
 47 
     | 
    
         
            +
                value
         
     | 
| 
       35 
48 
     | 
    
         
             
              end
         
     | 
| 
       36 
49 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
              # Runs one instruction 
     | 
| 
       38 
     | 
    
         
            -
              # it  
     | 
| 
      
 50 
     | 
    
         
            +
              # Runs one instruction. If the current process waits on another process
         
     | 
| 
      
 51 
     | 
    
         
            +
              # (joining not empty), it will run an instruction in the other process
         
     | 
| 
      
 52 
     | 
    
         
            +
              # instead.
         
     | 
| 
       39 
53 
     | 
    
         
             
              #
         
     | 
| 
       40 
54 
     | 
    
         
             
              def step
         
     | 
| 
       41 
     | 
    
         
            -
                 
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
                verify_wait_conditions if waiting?
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                # If we're still waiting for someone, let's give them a little shove. 
         
     | 
| 
      
 58 
     | 
    
         
            +
                if waiting?
         
     | 
| 
      
 59 
     | 
    
         
            +
                  joining.first.step
         
     | 
| 
      
 60 
     | 
    
         
            +
                  return 
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
                
         
     | 
| 
       43 
63 
     | 
    
         
             
                instruction = fetch_and_advance
         
     | 
| 
       44 
64 
     | 
    
         
             
                dispatch(instruction)
         
     | 
| 
       45 
65 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                # p [ 
     | 
| 
      
 66 
     | 
    
         
            +
                # p [self, instruction, @stack, @call_stack, current_scope]
         
     | 
| 
       47 
67 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
                 
     | 
| 
       49 
     | 
    
         
            -
                
         
     | 
| 
       50 
     | 
    
         
            -
                 
     | 
| 
      
 68 
     | 
    
         
            +
                # If we just ran into uncharted memory - and we're not still waiting
         
     | 
| 
      
 69 
     | 
    
         
            +
                # for someone - we'll just stop the machine.
         
     | 
| 
      
 70 
     | 
    
         
            +
                instr_halt if !waiting? && !instruction_pointer_valid?
         
     | 
| 
       51 
71 
     | 
    
         
             
              end
         
     | 
| 
       52 
72 
     | 
    
         | 
| 
       53 
73 
     | 
    
         
             
              # Returns true if the process has halted because it has reached its end.
         
     | 
| 
       54 
74 
     | 
    
         
             
              #
         
     | 
| 
       55 
75 
     | 
    
         
             
              def halted?
         
     | 
| 
       56 
     | 
    
         
            -
                 
     | 
| 
      
 76 
     | 
    
         
            +
                @halted
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              # Returns true if the process waits for something to happen.
         
     | 
| 
      
 80 
     | 
    
         
            +
              #
         
     | 
| 
      
 81 
     | 
    
         
            +
              def waiting?
         
     | 
| 
      
 82 
     | 
    
         
            +
                not @joining.empty?
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
              
         
     | 
| 
      
 85 
     | 
    
         
            +
              # Once the process has halted?, this returns the top of the stack. This is 
         
     | 
| 
      
 86 
     | 
    
         
            +
              # like the return value of the process. 
         
     | 
| 
      
 87 
     | 
    
         
            +
              #
         
     | 
| 
      
 88 
     | 
    
         
            +
              def value
         
     | 
| 
      
 89 
     | 
    
         
            +
                @stack.last
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
              
         
     | 
| 
      
 92 
     | 
    
         
            +
              # Internal helper methods --------------------------------------------------
         
     | 
| 
      
 93 
     | 
    
         
            +
              
         
     | 
| 
      
 94 
     | 
    
         
            +
              # Checks if the conditions that make this process wait still apply. This may
         
     | 
| 
      
 95 
     | 
    
         
            +
              # clear up the wait state so that waiting? changes value after this method.
         
     | 
| 
      
 96 
     | 
    
         
            +
              #
         
     | 
| 
      
 97 
     | 
    
         
            +
              def verify_wait_conditions
         
     | 
| 
      
 98 
     | 
    
         
            +
                @joining.delete_if { |process| process.halted? }
         
     | 
| 
      
 99 
     | 
    
         
            +
              end
         
     | 
| 
      
 100 
     | 
    
         
            +
              
         
     | 
| 
      
 101 
     | 
    
         
            +
              # Returns the process group having this process as root node. 
         
     | 
| 
      
 102 
     | 
    
         
            +
              #
         
     | 
| 
      
 103 
     | 
    
         
            +
              def group
         
     | 
| 
      
 104 
     | 
    
         
            +
                @group ||= Verneuil::ProcessGroup.new(self)
         
     | 
| 
       57 
105 
     | 
    
         
             
              end
         
     | 
| 
       58 
106 
     | 
    
         | 
| 
       59 
107 
     | 
    
         
             
              # Fetches the next instruction and advances @ip.
         
     | 
| 
         @@ -61,7 +109,7 @@ class Verneuil::Process 
     | 
|
| 
       61 
109 
     | 
    
         
             
              def fetch_and_advance
         
     | 
| 
       62 
110 
     | 
    
         
             
                # Pretends that the memory beyond the current space is filled with :halt
         
     | 
| 
       63 
111 
     | 
    
         
             
                # instructions.
         
     | 
| 
       64 
     | 
    
         
            -
                return :halt  
     | 
| 
      
 112 
     | 
    
         
            +
                return :halt unless instruction_pointer_valid?
         
     | 
| 
       65 
113 
     | 
    
         | 
| 
       66 
114 
     | 
    
         
             
                instruction = @program[@ip]
         
     | 
| 
       67 
115 
     | 
    
         
             
                @ip += 1
         
     | 
| 
         @@ -70,7 +118,7 @@ class Verneuil::Process 
     | 
|
| 
       70 
118 
     | 
    
         
             
              end
         
     | 
| 
       71 
119 
     | 
    
         | 
| 
       72 
120 
     | 
    
         
             
              # Decodes the instruction into opcode and arguments and calls a method
         
     | 
| 
       73 
     | 
    
         
            -
              # on this instance called  
     | 
| 
      
 121 
     | 
    
         
            +
              # on this instance called instr_OPCODE giving the arguments as method 
         
     | 
| 
       74 
122 
     | 
    
         
             
              # arguments. 
         
     | 
| 
       75 
123 
     | 
    
         
             
              #
         
     | 
| 
       76 
124 
     | 
    
         
             
              def dispatch(instruction)
         
     | 
| 
         @@ -103,7 +151,7 @@ class Verneuil::Process 
     | 
|
| 
       103 
151 
     | 
    
         
             
              def scope(context)
         
     | 
| 
       104 
152 
     | 
    
         
             
                Verneuil::Scope.new(context)
         
     | 
| 
       105 
153 
     | 
    
         
             
              end
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
      
 154 
     | 
    
         
            +
                
         
     | 
| 
       107 
155 
     | 
    
         
             
              # Returns the currently active scope. 
         
     | 
| 
       108 
156 
     | 
    
         
             
              #
         
     | 
| 
       109 
157 
     | 
    
         
             
              def current_scope
         
     | 
| 
         @@ -129,13 +177,92 @@ class Verneuil::Process 
     | 
|
| 
       129 
177 
     | 
    
         
             
              end
         
     | 
| 
       130 
178 
     | 
    
         | 
| 
       131 
179 
     | 
    
         
             
              # Calls the given address. (like a jump, but puts something on the return
         
     | 
| 
       132 
     | 
    
         
            -
              # stack)
         
     | 
| 
      
 180 
     | 
    
         
            +
              # stack) If context is left empty, it will call inside the current context.
         
     | 
| 
       133 
181 
     | 
    
         
             
              #
         
     | 
| 
       134 
182 
     | 
    
         
             
              def call(adr, context=nil)
         
     | 
| 
       135 
183 
     | 
    
         
             
                @scopes.push scope(context || current_scope.context)
         
     | 
| 
       136 
184 
     | 
    
         
             
                @call_stack.push @ip
         
     | 
| 
       137 
185 
     | 
    
         
             
                jump adr
         
     | 
| 
       138 
186 
     | 
    
         
             
              end
         
     | 
| 
      
 187 
     | 
    
         
            +
                
         
     | 
| 
      
 188 
     | 
    
         
            +
              # Looks up a method in internal tables. 
         
     | 
| 
      
 189 
     | 
    
         
            +
              #
         
     | 
| 
      
 190 
     | 
    
         
            +
              def lookup_method(receiver, name)
         
     | 
| 
      
 191 
     | 
    
         
            +
                [
         
     | 
| 
      
 192 
     | 
    
         
            +
                  @program.symbols, 
         
     | 
| 
      
 193 
     | 
    
         
            +
                  self.class.symbols
         
     | 
| 
      
 194 
     | 
    
         
            +
                ].each do |table|
         
     | 
| 
      
 195 
     | 
    
         
            +
                  method = table.lookup_method(receiver, name)
         
     | 
| 
      
 196 
     | 
    
         
            +
                  return method if method
         
     | 
| 
      
 197 
     | 
    
         
            +
                end
         
     | 
| 
      
 198 
     | 
    
         
            +
                return nil
         
     | 
| 
      
 199 
     | 
    
         
            +
              end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
              # Returns the currently active block or nil if no such block is available. 
         
     | 
| 
      
 202 
     | 
    
         
            +
              #
         
     | 
| 
      
 203 
     | 
    
         
            +
              def current_block
         
     | 
| 
      
 204 
     | 
    
         
            +
                @blocks.last
         
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
      
 206 
     | 
    
         
            +
              
         
     | 
| 
      
 207 
     | 
    
         
            +
              # Forks a new process that starts its execution at address and that halts 
         
     | 
| 
      
 208 
     | 
    
         
            +
              # when encountering a 'return' instruction. Returns that new process 
         
     | 
| 
      
 209 
     | 
    
         
            +
              # instance. 
         
     | 
| 
      
 210 
     | 
    
         
            +
              #
         
     | 
| 
      
 211 
     | 
    
         
            +
              # The newly created child process is also stored in this process' children
         
     | 
| 
      
 212 
     | 
    
         
            +
              # array. You can run the process and all of its children by calling 
         
     | 
| 
      
 213 
     | 
    
         
            +
              #
         
     | 
| 
      
 214 
     | 
    
         
            +
              #   process.group.run
         
     | 
| 
      
 215 
     | 
    
         
            +
              #
         
     | 
| 
      
 216 
     | 
    
         
            +
              def fork_child(block)
         
     | 
| 
      
 217 
     | 
    
         
            +
                child = Verneuil::Process.new(@program, nil)
         
     | 
| 
      
 218 
     | 
    
         
            +
                child.run_block(block)
         
     | 
| 
      
 219 
     | 
    
         
            +
                
         
     | 
| 
      
 220 
     | 
    
         
            +
                @children << child
         
     | 
| 
      
 221 
     | 
    
         
            +
                
         
     | 
| 
      
 222 
     | 
    
         
            +
                return child
         
     | 
| 
      
 223 
     | 
    
         
            +
              end
         
     | 
| 
      
 224 
     | 
    
         
            +
              
         
     | 
| 
      
 225 
     | 
    
         
            +
              # Confines execution to a single method. This means setting up the return
         
     | 
| 
      
 226 
     | 
    
         
            +
              # stack to return into nirvana once the VM reaches a 'return' instruction. 
         
     | 
| 
      
 227 
     | 
    
         
            +
              #
         
     | 
| 
      
 228 
     | 
    
         
            +
              def run_block(block)
         
     | 
| 
      
 229 
     | 
    
         
            +
                @call_stack.push(-1)
         
     | 
| 
      
 230 
     | 
    
         
            +
                jump block.address
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                @scopes = [block.scope]
         
     | 
| 
      
 233 
     | 
    
         
            +
              end
         
     | 
| 
      
 234 
     | 
    
         
            +
              
         
     | 
| 
      
 235 
     | 
    
         
            +
              # True if the current instruction pointer is valid. 
         
     | 
| 
      
 236 
     | 
    
         
            +
              #
         
     | 
| 
      
 237 
     | 
    
         
            +
              def instruction_pointer_valid?
         
     | 
| 
      
 238 
     | 
    
         
            +
                @ip >= 0 && 
         
     | 
| 
      
 239 
     | 
    
         
            +
                  @ip < @program.size
         
     | 
| 
      
 240 
     | 
    
         
            +
              end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
              # Inspection of processes
         
     | 
| 
      
 243 
     | 
    
         
            +
              #
         
     | 
| 
      
 244 
     | 
    
         
            +
              def inspect
         
     | 
| 
      
 245 
     | 
    
         
            +
                "process(#{object_id}, #{@ip}, #{@call_stack}, w:#{@joining.size}, c:#{children.size}, h:#{halted?})"
         
     | 
| 
      
 246 
     | 
    
         
            +
              end
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
              # Try to dispatch a method call to a method defined inside the Verneuil 
         
     | 
| 
      
 249 
     | 
    
         
            +
              # VM. There are currently two kinds of methods in this category: 
         
     | 
| 
      
 250 
     | 
    
         
            +
              #
         
     | 
| 
      
 251 
     | 
    
         
            +
              #   * Kernel methods
         
     | 
| 
      
 252 
     | 
    
         
            +
              #   * Methods implemented in V
         
     | 
| 
      
 253 
     | 
    
         
            +
              #
         
     | 
| 
      
 254 
     | 
    
         
            +
              def dispatch_to_verneuil(receiver, name)
         
     | 
| 
      
 255 
     | 
    
         
            +
                if v_method = lookup_method(receiver, name)
         
     | 
| 
      
 256 
     | 
    
         
            +
                  catch(:verneuil_code) {
         
     | 
| 
      
 257 
     | 
    
         
            +
                    retval = v_method.invoke(self, receiver)
         
     | 
| 
      
 258 
     | 
    
         
            +
                    @stack.push retval
         
     | 
| 
      
 259 
     | 
    
         
            +
                  } 
         
     | 
| 
      
 260 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 261 
     | 
    
         
            +
                end
         
     | 
| 
      
 262 
     | 
    
         
            +
                
         
     | 
| 
      
 263 
     | 
    
         
            +
                return false
         
     | 
| 
      
 264 
     | 
    
         
            +
              end
         
     | 
| 
      
 265 
     | 
    
         
            +
              
         
     | 
| 
       139 
266 
     | 
    
         | 
| 
       140 
267 
     | 
    
         
             
              # VM Implementation --------------------------------------------------------
         
     | 
| 
       141 
268 
     | 
    
         | 
| 
         @@ -149,11 +276,7 @@ class Verneuil::Process 
     | 
|
| 
       149 
276 
     | 
    
         
             
                end
         
     | 
| 
       150 
277 
     | 
    
         | 
| 
       151 
278 
     | 
    
         
             
                # Verneuil method?
         
     | 
| 
       152 
     | 
    
         
            -
                 
     | 
| 
       153 
     | 
    
         
            -
                if v_method
         
     | 
| 
       154 
     | 
    
         
            -
                  call v_method.address
         
     | 
| 
       155 
     | 
    
         
            -
                  return
         
     | 
| 
       156 
     | 
    
         
            -
                end
         
     | 
| 
      
 279 
     | 
    
         
            +
                return if dispatch_to_verneuil(nil, name)
         
     | 
| 
       157 
280 
     | 
    
         | 
| 
       158 
281 
     | 
    
         
             
                # Ruby method! (or else)
         
     | 
| 
       159 
282 
     | 
    
         
             
                args = @stack.pop(argc)
         
     | 
| 
         @@ -164,15 +287,14 @@ class Verneuil::Process 
     | 
|
| 
       164 
287 
     | 
    
         
             
              #
         
     | 
| 
       165 
288 
     | 
    
         
             
              def instr_ruby_call(name, argc)
         
     | 
| 
       166 
289 
     | 
    
         
             
                receiver = @stack.pop
         
     | 
| 
      
 290 
     | 
    
         
            +
                
         
     | 
| 
      
 291 
     | 
    
         
            +
                # TODO Fix argument count handling
         
     | 
| 
      
 292 
     | 
    
         
            +
                # Currently the caller decides with how many arguments he calls the
         
     | 
| 
      
 293 
     | 
    
         
            +
                # block and the callee pops off the stack what he wants. This is not a
         
     | 
| 
      
 294 
     | 
    
         
            +
                # good situation.
         
     | 
| 
       167 
295 
     | 
    
         | 
| 
       168 
296 
     | 
    
         
             
                # Verneuil method? (class method mask)
         
     | 
| 
       169 
     | 
    
         
            -
                 
     | 
| 
       170 
     | 
    
         
            -
                  receiver.class.name.to_sym, 
         
     | 
| 
       171 
     | 
    
         
            -
                  name)
         
     | 
| 
       172 
     | 
    
         
            -
                if v_method
         
     | 
| 
       173 
     | 
    
         
            -
                  call v_method.address, receiver
         
     | 
| 
       174 
     | 
    
         
            -
                  return
         
     | 
| 
       175 
     | 
    
         
            -
                end
         
     | 
| 
      
 297 
     | 
    
         
            +
                return if dispatch_to_verneuil(receiver, name)
         
     | 
| 
       176 
298 
     | 
    
         | 
| 
       177 
299 
     | 
    
         
             
                # Must be a Ruby method then. The catch allows internal classes like 
         
     | 
| 
       178 
300 
     | 
    
         
             
                # Verneuil::Block to skip the stack.push.
         
     | 
| 
         @@ -231,7 +353,7 @@ class Verneuil::Process 
     | 
|
| 
       231 
353 
     | 
    
         | 
| 
       232 
354 
     | 
    
         
             
              # Tests if the local variable exists. Puts true/false to the stack. 
         
     | 
| 
       233 
355 
     | 
    
         
             
              #
         
     | 
| 
       234 
     | 
    
         
            -
              def  
     | 
| 
      
 356 
     | 
    
         
            +
              def instr_test_defined(name)
         
     | 
| 
       235 
357 
     | 
    
         
             
                @stack.push current_scope.defined?(name)
         
     | 
| 
       236 
358 
     | 
    
         
             
              end
         
     | 
| 
       237 
359 
     | 
    
         | 
| 
         @@ -246,7 +368,10 @@ class Verneuil::Process 
     | 
|
| 
       246 
368 
     | 
    
         
             
              # Pushes a block context to the block stack. 
         
     | 
| 
       247 
369 
     | 
    
         
             
              #
         
     | 
| 
       248 
370 
     | 
    
         
             
              def instr_push_block(block_adr)
         
     | 
| 
       249 
     | 
    
         
            -
                @blocks.push Verneuil::Block.new( 
     | 
| 
      
 371 
     | 
    
         
            +
                @blocks.push Verneuil::Block.new(
         
     | 
| 
      
 372 
     | 
    
         
            +
                  block_adr, 
         
     | 
| 
      
 373 
     | 
    
         
            +
                  self, 
         
     | 
| 
      
 374 
     | 
    
         
            +
                  current_scope.child)
         
     | 
| 
       250 
375 
     | 
    
         
             
              end
         
     | 
| 
       251 
376 
     | 
    
         | 
| 
       252 
377 
     | 
    
         
             
              # Loads the currently set implicit block to the stack. This is used when
         
     | 
| 
         @@ -255,7 +380,7 @@ class Verneuil::Process 
     | 
|
| 
       255 
380 
     | 
    
         
             
              #
         
     | 
| 
       256 
381 
     | 
    
         
             
              def instr_load_block
         
     | 
| 
       257 
382 
     | 
    
         
             
                fail "BUG: No implicit block!" if @blocks.empty?
         
     | 
| 
       258 
     | 
    
         
            -
                @stack.push  
     | 
| 
      
 383 
     | 
    
         
            +
                @stack.push current_block
         
     | 
| 
       259 
384 
     | 
    
         
             
              end
         
     | 
| 
       260 
385 
     | 
    
         | 
| 
       261 
386 
     | 
    
         
             
              # Unloads a block
         
     | 
| 
         @@ -279,4 +404,9 @@ class Verneuil::Process 
     | 
|
| 
       279 
404 
     | 
    
         
             
                @stack.push current_scope.context
         
     | 
| 
       280 
405 
     | 
    
         
             
              end
         
     | 
| 
       281 
406 
     | 
    
         | 
| 
       282 
     | 
    
         
            -
            end
         
     | 
| 
      
 407 
     | 
    
         
            +
            end
         
     | 
| 
      
 408 
     | 
    
         
            +
             
     | 
| 
      
 409 
     | 
    
         
            +
            require 'verneuil/process/kernel_methods'
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
      
 411 
     | 
    
         
            +
            require 'verneuil/kernel/fork'
         
     | 
| 
      
 412 
     | 
    
         
            +
            require 'verneuil/kernel/process_join'
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Verneuil::Process
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A kernel method points to a Ruby method somewhere.
         
     | 
| 
      
 3 
     | 
    
         
            +
              #
         
     | 
| 
      
 4 
     | 
    
         
            +
              class KernelMethod < Struct.new(:receiver, :name, :method)
         
     | 
| 
      
 5 
     | 
    
         
            +
                def invoke(process, receiver)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  method.call(process, receiver)
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Extends the Process' class with methods that allow managing kernel methods. 
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              class <<self
         
     | 
| 
      
 13 
     | 
    
         
            +
                # The VMs own kernel method table. 
         
     | 
| 
      
 14 
     | 
    
         
            +
                # 
         
     | 
| 
      
 15 
     | 
    
         
            +
                def symbols
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @symbols ||= Verneuil::SymbolTable.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                # Registers a kernel method. These methods have precedence over the 
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Ruby bridge, but can still be overridden by user methods. 
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                def kernel_method(klass_name, method_name, &method_definition)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  symbols.add(
         
     | 
| 
      
 24 
     | 
    
         
            +
                    KernelMethod.new(
         
     | 
| 
      
 25 
     | 
    
         
            +
                      klass_name, 
         
     | 
| 
      
 26 
     | 
    
         
            +
                      method_name, 
         
     | 
| 
      
 27 
     | 
    
         
            +
                      method_definition))
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # A group of processes identified by their root process. 
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            class Verneuil::ProcessGroup
         
     | 
| 
      
 4 
     | 
    
         
            +
              def initialize(root)
         
     | 
| 
      
 5 
     | 
    
         
            +
                @root = root
         
     | 
| 
      
 6 
     | 
    
         
            +
                @counter = 0
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              # Make our root conform to the interface group#step implements.
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Root < Struct.new(:process)
         
     | 
| 
      
 11 
     | 
    
         
            +
                def step
         
     | 
| 
      
 12 
     | 
    
         
            +
                  process.step
         
     | 
| 
      
 13 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                def halted?
         
     | 
| 
      
 17 
     | 
    
         
            +
                  process.halted?
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              # Steps one of the processes in this group once. Returns true if all child 
         
     | 
| 
      
 22 
     | 
    
         
            +
              # process groups have made one step. 
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              def step
         
     | 
| 
      
 25 
     | 
    
         
            +
                list = processes
         
     | 
| 
      
 26 
     | 
    
         
            +
                idx =  @counter % list.size
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                if list[idx].step
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # Child tree has finished 'one round' of stepping, carry over 
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @counter += 1
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Should we return a carry to our parent?
         
     | 
| 
      
 34 
     | 
    
         
            +
                if @counter >= list.size
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @counter = 0
         
     | 
| 
      
 36 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                return false
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              # Runs this process group until all processes have halted.
         
     | 
| 
      
 43 
     | 
    
         
            +
              #
         
     | 
| 
      
 44 
     | 
    
         
            +
              def run
         
     | 
| 
      
 45 
     | 
    
         
            +
                until halted?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  step
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def halted?
         
     | 
| 
      
 51 
     | 
    
         
            +
                processes.all? { |p| p.halted? }
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              def processes
         
     | 
| 
      
 55 
     | 
    
         
            +
                [Root.new(@root)] + @root.children.map { |p| p.group }
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/verneuil/program.rb
    CHANGED
    
    | 
         @@ -7,10 +7,12 @@ require 'verneuil/instruction' 
     | 
|
| 
       7 
7 
     | 
    
         
             
            class Verneuil::Program
         
     | 
| 
       8 
8 
     | 
    
         
             
              # Gives access to the internal array of instructions (the program memory)
         
     | 
| 
       9 
9 
     | 
    
         
             
              attr_reader :instructions
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Access to the programs symbol table.
         
     | 
| 
      
 11 
     | 
    
         
            +
              attr_reader :symbols
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
              def initialize
         
     | 
| 
       12 
14 
     | 
    
         
             
                @instructions = []
         
     | 
| 
       13 
     | 
    
         
            -
                @ 
     | 
| 
      
 15 
     | 
    
         
            +
                @symbols = Verneuil::SymbolTable.new
         
     | 
| 
       14 
16 
     | 
    
         
             
              end
         
     | 
| 
       15 
17 
     | 
    
         | 
| 
       16 
18 
     | 
    
         
             
              # Make programs behave nicely with respect to comparison. 
         
     | 
| 
         @@ -41,26 +43,14 @@ class Verneuil::Program 
     | 
|
| 
       41 
43 
     | 
    
         
             
              def add(instruction)
         
     | 
| 
       42 
44 
     | 
    
         
             
                @instructions << instruction
         
     | 
| 
       43 
45 
     | 
    
         
             
              end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
              # Defines a function. 
         
     | 
| 
       46 
     | 
    
         
            -
              #
         
     | 
| 
       47 
     | 
    
         
            -
              def add_method(klass, name, adr)
         
     | 
| 
       48 
     | 
    
         
            -
                @functions[[klass, name]] = Verneuil::Method.new(klass, name, adr)
         
     | 
| 
       49 
     | 
    
         
            -
              end
         
     | 
| 
       50 
     | 
    
         
            -
              
         
     | 
| 
       51 
     | 
    
         
            -
              # Returns the function that matches the given receiver and method name. 
         
     | 
| 
       52 
     | 
    
         
            -
              #
         
     | 
| 
       53 
     | 
    
         
            -
              def lookup_method(recv, name)
         
     | 
| 
       54 
     | 
    
         
            -
                @functions[[recv, name]]
         
     | 
| 
       55 
     | 
    
         
            -
              end
         
     | 
| 
       56 
     | 
    
         
            -
              
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
       57 
47 
     | 
    
         
             
              # Printing
         
     | 
| 
       58 
48 
     | 
    
         
             
              # 
         
     | 
| 
       59 
49 
     | 
    
         
             
              def inspect
         
     | 
| 
       60 
50 
     | 
    
         
             
                s = ''
         
     | 
| 
       61 
51 
     | 
    
         
             
                @instructions.each_with_index do |instruction, idx|
         
     | 
| 
       62 
52 
     | 
    
         
             
                  method_label = ''
         
     | 
| 
       63 
     | 
    
         
            -
                  if entry 
     | 
| 
      
 53 
     | 
    
         
            +
                  if entry=symbols.methods.find { |(r,n), m| m.address.ip == idx }
         
     | 
| 
       64 
54 
     | 
    
         
             
                    m = entry.last
         
     | 
| 
       65 
55 
     | 
    
         
             
                    method_label = [m.receiver, m.name].inspect
         
     | 
| 
       66 
56 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/verneuil/scope.rb
    CHANGED
    
    | 
         @@ -4,6 +4,7 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            # to user code. 
         
     | 
| 
       5 
5 
     | 
    
         
             
            #
         
     | 
| 
       6 
6 
     | 
    
         
             
            class Verneuil::Scope
         
     | 
| 
      
 7 
     | 
    
         
            +
              # In Ruby, we also call this the 'self'.
         
     | 
| 
       7 
8 
     | 
    
         
             
              attr_reader :context
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
              def initialize(context, local_vars={}, parent=nil)
         
     | 
| 
         @@ -12,19 +13,26 @@ class Verneuil::Scope 
     | 
|
| 
       12 
13 
     | 
    
         
             
                @parent = parent
         
     | 
| 
       13 
14 
     | 
    
         
             
              end
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
              def enter
         
     | 
| 
       16 
     | 
    
         
            -
                Verneuil::Scope.new(context, {}, nil)
         
     | 
| 
       17 
     | 
    
         
            -
              end
         
     | 
| 
       18 
     | 
    
         
            -
              
         
     | 
| 
       19 
16 
     | 
    
         
             
              def lvar_exist?(name)
         
     | 
| 
      
 17 
     | 
    
         
            +
                lvar_exist_locally?(name) || @parent && @parent.lvar_exist?(name)
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
              def lvar_exist_locally?(name)
         
     | 
| 
       20 
20 
     | 
    
         
             
                @local_vars.has_key?(name)
         
     | 
| 
       21 
21 
     | 
    
         
             
              end
         
     | 
| 
       22 
22 
     | 
    
         
             
              def lvar_get(name)
         
     | 
| 
       23 
     | 
    
         
            -
                 
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 23 
     | 
    
         
            +
                unless lvar_exist_locally? name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  return @parent.lvar_get(name) if @parent
         
     | 
| 
      
 25 
     | 
    
         
            +
                  
         
     | 
| 
      
 26 
     | 
    
         
            +
                  raise Verneuil::NameError, "No such local variable #{name.inspect}."
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       25 
29 
     | 
    
         
             
                @local_vars[name]
         
     | 
| 
       26 
30 
     | 
    
         
             
              end
         
     | 
| 
       27 
31 
     | 
    
         
             
              def lvar_set(name, value)
         
     | 
| 
      
 32 
     | 
    
         
            +
                unless lvar_exist_locally? name
         
     | 
| 
      
 33 
     | 
    
         
            +
                  return @parent.lvar_set(name, value) if @parent && @parent.lvar_exist?(name)
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
       28 
36 
     | 
    
         
             
                @local_vars[name] = value
         
     | 
| 
       29 
37 
     | 
    
         
             
              end
         
     | 
| 
       30 
38 
     | 
    
         
             
              def defined?(name)
         
     | 
| 
         @@ -33,6 +41,13 @@ class Verneuil::Scope 
     | 
|
| 
       33 
41 
     | 
    
         
             
                nil
         
     | 
| 
       34 
42 
     | 
    
         
             
              end
         
     | 
| 
       35 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
              # Returns a nested scope that has access to the current scope in a Ruby 1.9
         
     | 
| 
      
 45 
     | 
    
         
            +
              # fashion. 
         
     | 
| 
      
 46 
     | 
    
         
            +
              #
         
     | 
| 
      
 47 
     | 
    
         
            +
              def child(local_vars={})
         
     | 
| 
      
 48 
     | 
    
         
            +
                self.class.new(context, local_vars, self)
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
       36 
51 
     | 
    
         
             
              def method_call(name, *args)
         
     | 
| 
       37 
52 
     | 
    
         
             
                context.send(name, *args)
         
     | 
| 
       38 
53 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            # A registry for methods. 
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            class Verneuil::SymbolTable
         
     | 
| 
      
 5 
     | 
    
         
            +
              attr_reader :methods
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 8 
     | 
    
         
            +
                @methods = {}
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              # Defines a function. This function will override the default of calling
         
     | 
| 
      
 12 
     | 
    
         
            +
              # back to Ruby. Methods added here must support at least #receiver, 
         
     | 
| 
      
 13 
     | 
    
         
            +
              # #name and #invoke. 
         
     | 
| 
      
 14 
     | 
    
         
            +
              #
         
     | 
| 
      
 15 
     | 
    
         
            +
              # Example: 
         
     | 
| 
      
 16 
     | 
    
         
            +
              #   # Replaces Foo#bar with the V method at address 15.
         
     | 
| 
      
 17 
     | 
    
         
            +
              #   add(method_obj)
         
     | 
| 
      
 18 
     | 
    
         
            +
              #
         
     | 
| 
      
 19 
     | 
    
         
            +
              def add(method)
         
     | 
| 
      
 20 
     | 
    
         
            +
                key = [method.receiver, method.name]
         
     | 
| 
      
 21 
     | 
    
         
            +
                @methods[key] = method
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
              
         
     | 
| 
      
 24 
     | 
    
         
            +
              # Returns the function that matches the given receiver and method name. 
         
     | 
| 
      
 25 
     | 
    
         
            +
              #
         
     | 
| 
      
 26 
     | 
    
         
            +
              def lookup_method(recv, name)
         
     | 
| 
      
 27 
     | 
    
         
            +
                key = if recv
         
     | 
| 
      
 28 
     | 
    
         
            +
                  [recv.class.name.to_sym, name]
         
     | 
| 
      
 29 
     | 
    
         
            +
                else
         
     | 
| 
      
 30 
     | 
    
         
            +
                  [nil, name]
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                @methods[key]
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version 
     | 
|
| 
       4 
4 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       5 
5 
     | 
    
         
             
              segments: 
         
     | 
| 
       6 
6 
     | 
    
         
             
              - 0
         
     | 
| 
       7 
     | 
    
         
            -
              -  
     | 
| 
      
 7 
     | 
    
         
            +
              - 2
         
     | 
| 
       8 
8 
     | 
    
         
             
              - 0
         
     | 
| 
       9 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 9 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
       10 
10 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       11 
11 
     | 
    
         
             
            authors: 
         
     | 
| 
       12 
12 
     | 
    
         
             
            - Kaspar Schiess
         
     | 
| 
         @@ -71,15 +71,21 @@ files: 
     | 
|
| 
       71 
71 
     | 
    
         
             
            - LICENSE
         
     | 
| 
       72 
72 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       73 
73 
     | 
    
         
             
            - README
         
     | 
| 
      
 74 
     | 
    
         
            +
            - bin/verneuil
         
     | 
| 
       74 
75 
     | 
    
         
             
            - lib/verneuil/address.rb
         
     | 
| 
       75 
76 
     | 
    
         
             
            - lib/verneuil/block.rb
         
     | 
| 
       76 
77 
     | 
    
         
             
            - lib/verneuil/compiler.rb
         
     | 
| 
       77 
78 
     | 
    
         
             
            - lib/verneuil/generator.rb
         
     | 
| 
       78 
79 
     | 
    
         
             
            - lib/verneuil/instruction.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - lib/verneuil/kernel/fork.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - lib/verneuil/kernel/process_join.rb
         
     | 
| 
       79 
82 
     | 
    
         
             
            - lib/verneuil/method.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/verneuil/process/kernel_methods.rb
         
     | 
| 
       80 
84 
     | 
    
         
             
            - lib/verneuil/process.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - lib/verneuil/process_group.rb
         
     | 
| 
       81 
86 
     | 
    
         
             
            - lib/verneuil/program.rb
         
     | 
| 
       82 
87 
     | 
    
         
             
            - lib/verneuil/scope.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/verneuil/symbol_table.rb
         
     | 
| 
       83 
89 
     | 
    
         
             
            - lib/verneuil.rb
         
     | 
| 
       84 
90 
     | 
    
         
             
            has_rdoc: true
         
     | 
| 
       85 
91 
     | 
    
         
             
            homepage: http://kschiess.github.com/verneuil
         
     |