~tim/scheme-vm

af394fe08b0a565b8b0bb0489a8d3bbc9ac2b338 — Tim Morgan 2 years ago 11e6d2b
Fix bug defining bindings in a libary
3 files changed, 74 insertions(+), 31 deletions(-)

A spec/lib/define-spec.scm
M spec/vm_spec.rb
M vm.rb
A spec/lib/define-spec.scm => spec/lib/define-spec.scm +18 -0
@@ 0,0 1,18 @@
(import (scheme base)
        (assert))

(define (fn1 x) x)
(define fn2 fn1)

(define-library (define-in-lib-test)
  (import (only (scheme base) define))
  (export fn4)
  (begin
    (define (fn3 x) x)
    (define fn4 fn3)))

(import (define-in-lib-test))

(assert (= 'a (fn1 'a)))
(assert (= 'a (fn2 'a)))
(assert (= 'a (fn4 'a)))

M spec/vm_spec.rb => spec/vm_spec.rb +55 -30
@@ 1080,44 1080,69 @@ describe VM do
  end

  describe 'DEFINE_VAR' do
    before do
      subject.execute([
        VM::PUSH_FUNC,
        VM::PUSH_STR, 'func.',
        VM::DEFINE_VAR, 'x',
        VM::PUSH_VAR, 'x',
        VM::INT, VM::INT_WRITE,
        VM::POP,
        VM::RETURN,
        VM::ENDF,
        VM::DEFINE_VAR, 'fn',
    context do
      before do
        subject.execute([
          VM::PUSH_FUNC,
          VM::PUSH_STR, 'func.',
          VM::DEFINE_VAR, 'x',
          VM::PUSH_VAR, 'x',
          VM::INT, VM::INT_WRITE,
          VM::POP,
          VM::RETURN,
          VM::ENDF,
          VM::DEFINE_VAR, 'fn',

        VM::PUSH_VAR, 'fn',
        VM::CALL,
          VM::PUSH_VAR, 'fn',
          VM::CALL,

        VM::PUSH_STR, 'main.',
        VM::DEFINE_VAR, 'x',
          VM::PUSH_STR, 'main.',
          VM::DEFINE_VAR, 'x',

        VM::PUSH_VAR, 'x',
        VM::INT, VM::INT_WRITE,
        VM::POP,
          VM::PUSH_VAR, 'x',
          VM::INT, VM::INT_WRITE,
          VM::POP,

        VM::PUSH_VAR, 'fn',
        VM::CALL,
          VM::PUSH_VAR, 'fn',
          VM::CALL,

        VM::HALT
      ])
    end
          VM::HALT
        ])
      end

    it 'stores the stack value in given variable index' do
      expect(subject.local_values['x']).to eq(
        VM::ByteArray.new('main.')
      )
      it 'stores the stack value in given variable index' do
        expect(subject.local_values['x']).to eq(
          VM::ByteArray.new('main.')
        )
      end

      it 'keeps locals from different call frames separate' do
        subject.stdout.rewind
        expect(subject.stdout.read).to eq('func.main.func.')
      end
    end

    it 'keeps locals from different call frames separate' do
      subject.stdout.rewind
      expect(subject.stdout.read).to eq('func.main.func.')
    context 'inside a library' do
      before do
        subject.execute([
          VM::SET_LIB, 'my-lib',
          VM::PUSH_FUNC,
          VM::PUSH_ARG,
          VM::NAME_ARG, 'x',
          VM::PUSH_VAR, 'x',
          VM::RETURN,
          VM::ENDF,
          VM::DEFINE_VAR, 'fn3',
          VM::PUSH_VAR, 'fn3',
          VM::DEFINE_VAR, 'fn4',
          VM::ENDL,
          VM::HALT
        ])
      end

      it 'stores the library and does not cause an exception' do
        expect(subject.libs['my-lib']).to be
      end
    end
  end


M vm.rb => vm.rb +1 -1
@@ 302,7 302,7 @@ class VM
  end

  def find_call_stack_frame_with_symbol(name)
    @call_stack.reverse.detect { |f| f[:named_args].key?(name) }
    @call_stack.reverse.detect { |f| f[:named_args] && f[:named_args].key?(name) }
  end

  def build_pair(car, cdr)