~tim/scheme-vm

ff6e359509ec4c725c1b283e2ef497ff7c92599f — Tim Morgan 6 years ago dc300ce
Add eq? and fix = predicate
4 files changed, 72 insertions(+), 16 deletions(-)

M compiler.rb
M spec/compiler_spec.rb
M spec/vm_spec.rb
M vm.rb
M compiler.rb => compiler.rb +8 -7
@@ 276,13 276,14 @@ class Compiler
  end

  {
    '>'  => VM::CMP_GT,
    '>=' => VM::CMP_GTE,
    '<'  => VM::CMP_LT,
    '<=' => VM::CMP_LTE,
    '='  => VM::CMP_EQ,
    '+'  => VM::ADD,
    '-'  => VM::SUB
    '+'   => VM::ADD,
    '-'   => VM::SUB,
    '>'   => VM::CMP_GT,
    '>='  => VM::CMP_GTE,
    '<'   => VM::CMP_LT,
    '<='  => VM::CMP_LTE,
    '='   => VM::CMP_EQ_NUM,
    'eq?' => VM::CMP_EQ
  }.each do |name, instruction|
    define_method(name) do |args, options|
      compare(instruction, args, options)

M spec/compiler_spec.rb => spec/compiler_spec.rb +22 -9
@@ 644,6 644,23 @@ describe Compiler do
      end
    end

    context 'eq?' do
      before do
        @result = subject.compile([
          ['eq?', '1', '1']
        ])
      end

      it 'compiles into vm instructions' do
        expect(d(@result)).to eq([
          'VM::PUSH_NUM', '1',
          'VM::PUSH_NUM', '1',
          'VM::CMP_EQ',
          'VM::HALT'
        ])
      end
    end

    context '=' do
      before do
        @result = subject.compile([


@@ 655,7 672,7 @@ describe Compiler do
        expect(d(@result)).to eq([
          'VM::PUSH_NUM', '1',
          'VM::PUSH_NUM', '1',
          'VM::CMP_EQ',
          'VM::CMP_EQ_NUM',
          'VM::HALT'
        ])
      end


@@ 665,16 682,14 @@ describe Compiler do
      context 'given value is not used' do
        before do
          @result = subject.compile([
            ['if', ['=', '1', '1'], '2', '3'],
            ['if', '#t', '2', '3'],
            '0'
          ])
        end

        it 'compiles into vm instructions' do
          expect(d(@result)).to eq([
            'VM::PUSH_NUM', '1',
            'VM::PUSH_NUM', '1',
            'VM::CMP_EQ',
            'VM::PUSH_TRUE',
            'VM::JUMP_IF_FALSE', 5,
            'VM::PUSH_NUM', '2',
            'VM::JUMP', 3,


@@ 689,15 704,13 @@ describe Compiler do
      context 'given value is used' do
        before do
          @result = subject.compile([
            ['print', ['if', ['=', '1', '1'], '2', '3']]
            ['print', ['if', '#t', '2', '3']]
          ])
        end

        it 'compiles into vm instructions' do
          expect(d(@result)).to eq([
            'VM::PUSH_NUM', '1',
            'VM::PUSH_NUM', '1',
            'VM::CMP_EQ',
            'VM::PUSH_TRUE',
            'VM::JUMP_IF_FALSE', 5,
            'VM::PUSH_NUM', '2',
            'VM::JUMP', 3,

M spec/vm_spec.rb => spec/vm_spec.rb +37 -0
@@ 641,6 641,41 @@ describe VM do
        VM::PUSH_NUM, '1',
        VM::PUSH_NUM, '2',
        VM::CMP_EQ,
        VM::PUSH_TRUE,
        VM::PUSH_TRUE,
        VM::CMP_EQ,
        VM::PUSH_TRUE,
        VM::PUSH_FALSE,
        VM::CMP_EQ,
        VM::HALT
      ])
    end

    it 'removes both values and puts a #t or #f on the stack' do
      expect(subject.stack_values).to eq([
        VM::BoolTrue.instance,
        VM::BoolFalse.instance,
        VM::BoolTrue.instance,
        VM::BoolFalse.instance
      ])
    end
  end

  describe 'CMP_EQ_NUM' do
    before do
      subject.execute([
        VM::PUSH_NUM, '1',
        VM::PUSH_NUM, '1',
        VM::CMP_EQ_NUM,
        VM::PUSH_NUM, '1',
        VM::PUSH_NUM, '2',
        VM::CMP_EQ_NUM,
        VM::PUSH_TRUE,
        VM::PUSH_TRUE,
        VM::CMP_EQ_NUM,
        VM::PUSH_TRUE,
        VM::PUSH_FALSE,
        VM::CMP_EQ_NUM,
        VM::HALT
      ])
    end


@@ 648,6 683,8 @@ describe VM do
    it 'removes both values and puts a #t or #f on the stack' do
      expect(subject.stack_values).to eq([
        VM::BoolTrue.instance,
        VM::BoolFalse.instance,
        VM::BoolFalse.instance,
        VM::BoolFalse.instance
      ])
    end

M vm.rb => vm.rb +5 -0
@@ 38,6 38,7 @@ class VM
    ['CMP_LT',        0],
    ['CMP_LTE',       0],
    ['CMP_EQ',        0],
    ['CMP_EQ_NUM',    0],
    ['CMP_NULL',      0],
    ['DUP',           0],
    ['ENDF',          0],


@@ 174,6 175,10 @@ class VM
        num2 = pop_val
        num1 = pop_val
        num1 == num2 ? push_true : push_false
      when CMP_EQ_NUM
        num2 = pop_val
        num1 = pop_val
        num1.is_a?(Int) && num2.is_a?(Int) && num1 == num2 ? push_true : push_false
      when CMP_NULL
        val = pop_val
        val == EmptyList.instance ? push_true : push_false