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::List.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::List.new( [ AST::Identifier.new('+'), AST::List.new( [ AST::Identifier.new('+'), AST::Number.new(1.0), AST::Number.new(2.0) ] ), AST::List.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::List.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