module Chervil RSpec.describe Interpreter do def interpret(source, env) lexer = Lexer.new(source) tree = Parser.new(lexer).parse Interpreter.new(tree, env).interpret end it 'interprets a definition and variable usage' do env = Env.new interpret('(define x 5)', env) expect(env.get('x')).to eq(AST::Number.new(5.0)) expect(interpret('x', env).first).to eq(5.0) end it 'interprets a recursive function' do env = Env.new interpret('(define (fact x) (if (= x 0) 1 (* x (fact (- x 1)))))', env) expect(interpret('(fact 5)', env).first).to eq(120.0) end it 'supports closures' do env = Env.new interpret('(define one 1)', env) interpret('(define (plus-one x) (+ x one))', env) expect(interpret('(plus-one 2)', env).first).to eq(3.0) end it "doesn't leave variables bound after function execution" do env = Env.new interpret('(define (plus-one x) (+ 1 x))', env) interpret('(plus-one 5)', env) expect(env.get('x')).to eq(nil) end it 'returns a type error for invalid operation' do expect(interpret('(+ 1 "hello")', Env.new).first).to eq( Error.new('Expected an argument of type number but got string') ) end end end