~tim/scheme-vm

87a290df112f196a468cee000bdda98b6ea78825 — Tim Morgan 5 years ago a7e5be6
Move PrettyPrint into its own class
5 files changed, 41 insertions(+), 36 deletions(-)

M compiler.rb
M program.rb
M spec/spec_helper.rb
M vm.rb
A vm/pretty_print.rb
M compiler.rb => compiler.rb +4 -34
@@ 46,30 46,6 @@ class Compiler
    end
  end

  def pretty_format(instructions, grouped: false, ip: false)
    instructions = instructions.dup.flatten.compact
    count = 0
    [].tap do |pretty|
      while instructions.any?
        group = []
        group << count if ip
        if (instruction = instructions.shift)
          (name, arity) = VM::INSTRUCTIONS[instruction]
          group << "VM::#{name}"
          arity.times { group << instructions.shift }
          pretty << group
          count += group.size - 1
        else
          pretty << nil
        end
      end
    end.send(grouped ? :to_a : :flatten)
  end

  def pretty_print(instructions)
    pp pretty_format(instructions, grouped: true, ip: true)
  end

  def mangle_identifier(name)
    @mangled_identifiers[name] ||= 0
    version = @mangled_identifiers[name] += 1


@@ 102,12 78,15 @@ class Compiler
    Optimizer.new(instructions).optimize
  end

  # rubocop:disable Metrics/PerceivedComplexity
  def compile_sexp(sexp, options = { use: false, locals: {} })
    sexp = sexp.to_ruby if sexp.is_a?(VM::Pair)
    return compile_literal(sexp, options) unless sexp.is_a?(Array)
    sexp.compact! # datum comments #;(...) come in as nil due to our parser :-(
    return [] if sexp.empty?
    dispatch(sexp, options)
  end

  def dispatch(sexp, options)
    (name, *args) = sexp
    if options[:quote] || options[:quasiquote]
      compile_quoted_sexp(sexp, options)


@@ 127,7 106,6 @@ class Compiler
      fail VM::VariableUndefined, name
    end
  end
  # rubocop:enable Metrics/PerceivedComplexity

  def compile_quoted_sexp(sexp, options)
    (name, *_args) = sexp


@@ 290,12 268,4 @@ class Compiler
    end
    nil
  end

  def lispify(sexp)
    if sexp.is_a?(Array)
      '(' + sexp.map { |s| lispify(s) }.join(' ') + ')'
    else
      sexp
    end
  end
end

M program.rb => program.rb +1 -1
@@ 11,7 11,7 @@ class Program

  def run(debug: 0)
    @instr = @compiler.compile
    @compiler.pretty_print(@instr) if debug >= 1
    VM::PrettyPrinter.new(@instr).print if debug >= 1
    vm.execute(@instr, debug: debug)
    vm.return_value
  rescue VM::VariableUndefined => e

M spec/spec_helper.rb => spec/spec_helper.rb +1 -1
@@ 8,7 8,7 @@ RSpec.configure do |c|
  c.run_all_when_everything_filtered = true

  def d(instructions, skip_libs: true)
    pretty = subject.pretty_format(instructions)
    pretty = VM::PrettyPrinter.new(instructions).format
    if skip_libs
      pretty.slice_after('VM::ENDL').to_a.last
    else

M vm.rb => vm.rb +1 -0
@@ 7,6 7,7 @@ require_relative 'vm/empty_list'
require_relative 'vm/bool_true'
require_relative 'vm/bool_false'
require_relative 'vm/exceptions'
require_relative 'vm/pretty_print'
require_relative 'vm/gc'
require_relative 'vm/debug_output'
require_relative 'vm/operations'

A vm/pretty_print.rb => vm/pretty_print.rb +34 -0
@@ 0,0 1,34 @@
require 'pp'

class VM
  class PrettyPrinter
    def initialize(instructions, grouped: false, ip: false)
      @instructions = instructions.dup.flatten.compact
      @grouped = grouped
      @ip = ip
    end

    def format
      count = 0
      [].tap do |pretty|
        while @instructions.any?
          group = []
          group << count if @ip
          if (instruction = @instructions.shift)
            (name, arity) = VM::INSTRUCTIONS[instruction]
            group << "VM::#{name}"
            arity.times { group << @instructions.shift }
            pretty << group
            count += group.size - 1
          else
            pretty << nil
          end
        end
      end.send(@grouped ? :to_a : :flatten)
    end

    def print
      pp(format)
    end
  end
end