Permalink
Browse files

import script

  • Loading branch information...
0 parents commit e81b4c9112ab7425c5796e0afa8505c38dd2fae0 @txus txus committed Jun 17, 2011
Showing with 226 additions and 0 deletions.
  1. +5 −0 .gitignore
  2. +1 −0 .rvmrc
  3. +4 −0 Gemfile
  4. +2 −0 Rakefile
  5. +3 −0 bin/rexpl
  6. +18 −0 lib/rexpl.rb
  7. +25 −0 lib/rexpl/environment.rb
  8. +45 −0 lib/rexpl/generator_methods.rb
  9. +99 −0 lib/rexpl/generator_proxy.rb
  10. +3 −0 lib/rexpl/version.rb
  11. +21 −0 rexpl.gemspec
@@ -0,0 +1,5 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
+*.rbc
1 .rvmrc
@@ -0,0 +1 @@
+rvm --create use rbx-2.0.0pre@rexpl
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in replx.gemspec
+gemspec
@@ -0,0 +1,2 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
@@ -0,0 +1,3 @@
+#!/usr/bin/env rbx
+require 'rexpl'
+Rexpl::Environment.run
@@ -0,0 +1,18 @@
+# Rexpl is an interactive bytecode console for the Rubinius VM.
+#
+# It intends to be a fun tool to use when learning how to use Rubinius
+# bytecodes, for example when bootstraping a new language targeting the
+# Rubinius VM.
+#
+# Implemented as a REPL-like executable (think of it as an IRB for Rubinius
+# bytecode), Rexpl accepts any command that can be issued to an instance of
+# Rubinius::Generator, plus some custom commands to list the current program
+# instructions or print out the state of the stack after each instruction, for
+# example.
+#
+module Rexpl
+end
+
+require 'rexpl/generator_proxy'
+require 'rexpl/generator_methods'
+require 'rexpl/environment'
@@ -0,0 +1,25 @@
+module Rexpl
+ class Environment
+ @@generator = Rexpl::GeneratorProxy.new
+
+ def self.run
+ puts "\nRbx bytecode REPL. Kind of."
+ puts "---------------------------\n"
+ puts "\nJust enter generator instructions.\n'reset' to reset, 'list' to list the current program instructions, 'draw' to print.\n"
+ while (print '> '; input = gets)
+ @@generator.instance_eval input.chomp
+
+ dynamic_method(:run) do |g|
+ @@generator.visit(g)
+ if @@generator.instructions.any?
+ g.show_stack
+ else
+ g.push_nil
+ end
+ g.ret
+ end
+ new.run
+ end
+ end
+ end
+end
@@ -0,0 +1,45 @@
+module Rexpl
+ # Extends the Rubinius::Generator class with some utility methods used by
+ # Replx.
+ #
+ module GeneratorMethods
+ # Prints the topmost element on the stack and the stack's current size.
+ #
+ # Calling #show_stack neither consumes nor produces stack, it's just used
+ # for debugging the current state.
+ #
+ # @param [String] name an optional label to print out, to make debugging
+ # easier.
+ def show_stack(name = nil)
+ dup
+ push :self
+ swap_stack
+ send :inspect, 0, true
+ push_literal "[#{name || 'DEBUG'}] [STACK SIZE: #{size}]: "
+ swap_stack
+ push_literal "\n"
+ send :print, 3, true
+ pop
+ end
+
+ # Returns an array with all the elements currently in the stack.
+ #
+ # Calling #return_stack increases by 1 the stack size (being the topmost
+ # element an array containing a duplicate of every other element in the
+ # stack).
+ def return_stack
+ initial_size = size
+ dup_many initial_size
+ make_array initial_size
+ end
+
+ # Returns the current size of the stack.
+ #
+ # @return [Fixnum] the current size of the stack.
+ def size
+ @current_block.instance_eval { @stack }
+ end
+ end
+end
+
+Rubinius::Generator.__send__ :include, Rexpl::GeneratorMethods
@@ -0,0 +1,99 @@
+module Rexpl
+ class GeneratorProxy
+ protected_methods = %w(class to_s inspect instance_eval tainted?)
+ instance_methods.each { |method| undef_method method unless method.to_s =~ /^_/ || protected_methods.include?(method.to_s)}
+ attr_accessor :instructions
+
+ def initialize
+ @instructions = []
+ end
+
+ def reset
+ puts 'Reseted!'
+ initialize
+ end
+
+ def list
+ puts
+ @instructions.each_with_index do |instruction, idx|
+ puts "[#{idx}]: #{instruction.first} #{instruction[1..-1].map(&:inspect)}"
+ end
+ puts
+ end
+
+ def draw
+
+ instructions = @instructions.dup
+ klass = Class.new do
+ def print_stack(arr)
+ puts "\n\t#{'Current stack'.center(25, ' ')}"
+ puts "\t-------------------------"
+ arr.reverse.each do |element|
+ puts "\t|#{element.inspect.center(23, ' ')}|"
+ puts "\t-------------------------"
+ end
+ puts "\n"
+ nil
+ end
+ dynamic_method(:draw) do |g|
+
+ g.push :self
+ g.push_literal "\n"
+ g.send :puts, 1, true
+ g.pop
+
+ instructions.each_with_index do |instruction, idx|
+ # Execute the instruction
+ before = g.size
+ g.__send__ *instruction
+ after = g.size
+
+ # Print the instruction header
+ produced = after - before
+ verb = 'produced'
+ if produced < 0
+ verb = 'consumed'
+ produced = produced.abs
+ end
+
+ g.push_self
+ g.push_literal "[#{idx}] [#{instruction.first} #{instruction[1..-1].map(&:inspect).join(', ')}] #{verb} #{produced} stack, size is now #{after}"
+ g.send :puts, 1, true
+ g.pop
+
+ # Print the entire stack
+ g.return_stack
+ g.push_self
+ g.swap_stack
+ g.send :print_stack, 1, true
+ g.pop
+ end
+
+ g.push_nil
+ g.ret
+ end
+ end
+
+ klass.new.draw
+ end
+
+ def method_missing(m, *args)
+ @instructions << [m, *args]
+ nil
+ end
+
+ def visit(generator)
+ last_instruction = nil
+ begin
+ @instructions.each do |instruction|
+ last_instruction = instruction
+ generator.__send__ *instruction
+ end
+ rescue NameError, ArgumentError=>e
+ puts "[ERROR]: #{e}"
+ @instructions.delete(last_instruction)
+ end
+ !!@instructions.any?
+ end
+ end
+end
@@ -0,0 +1,3 @@
+module Rexpl
+ VERSION = "0.0.1"
+end
@@ -0,0 +1,21 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "rexpl/version"
+
+Gem::Specification.new do |s|
+ s.name = "rexpl"
+ s.version = Rexpl::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Josep M. Bach"]
+ s.email = ["josep.m.bach@gmail.com"]
+ s.homepage = "http://github.com/txus/rexpl"
+ s.summary = %q{Rexpl is an interactive bytecode REPL for Rubinius}
+ s.description = %q{Rexpl is an interactive bytecode REPL for Rubinius}
+
+ s.rubyforge_project = "rexpl"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+end

0 comments on commit e81b4c9

Please sign in to comment.