module Chervil RSpec.describe Parser do def parse(source) lexer = Lexer.new(source) parser = Parser.new(lexer) parser.parse end it 'parses a number' do expect(parse('1').first).to eq(AST::Number.new(1.0)) end it 'parses a string' do expect(parse('"hello world"').first).to eq(AST::String.new('hello world')) end it 'parses an identifier' do expect(parse('+').first).to eq(AST::Identifier.new('+')) end it 'parses booleans' do expect(parse('#t #f')).to eq( [ AST::Boolean.new(true), AST::Boolean.new(false), ] ) end it 'parses an application' do expect(parse('(+ 1 2)').first).to eq( AST::Application.new( AST::Identifier.new('+'), [AST::Number.new(1.0), AST::Number.new(2.0)] ) ) end it 'parses a definition' do expect(parse('(define x 5)').first).to eq( AST::Definition.new(AST::Identifier.new('x'), AST::Number.new(5.0)) ) end it 'parses a nested expression' do expect(parse('(+ (+ 1 2) (- 3 4))').first).to eq( AST::Application.new( AST::Identifier.new("+"), [ AST::Application.new( AST::Identifier.new("+"), [ AST::Number.new(1.0), AST::Number.new(2.0), ] ), AST::Application.new( AST::Identifier.new("-"), [ AST::Number.new(3.0), AST::Number.new(4.0), ] ), ] ) ) end it 'parses a function definition' do expect(parse('(define (square x) (* x x))').first).to eq( AST::Definition.new( AST::Identifier.new("square"), AST::Function.new( AST::Identifier.new("square"), [ AST::Identifier.new("x") ], [ AST::Application.new( AST::Identifier.new("*"), [ AST::Identifier.new("x"), AST::Identifier.new("x"), ] ) ] ) ) ) end it 'returns a syntax error object instead of raising' do expect(parse('(+ 1')).to eq(Error.new("Expected rparen but got eof")) expect(parse('1)')).to eq(Error.new("Unexpected token rparen: )")) end it 'parses a conditional' do expect(parse('(if #t 1 0)').first).to eq( AST::Conditional.new( AST::Boolean.new(true), AST::Number.new(1.0), AST::Number.new(0.0), ) ) end end end