Chervil is a toy Lisp interpreter written in Ruby
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parser_spec.rb 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. module Chervil
  2. RSpec.describe Parser do
  3. def parse(source)
  4. lexer = Lexer.new(source)
  5. parser = Parser.new(lexer)
  6. parser.parse
  7. end
  8. it 'parses a number' do
  9. expect(parse('1').first).to eq(AST::Number.new(1.0))
  10. end
  11. it 'parses a string' do
  12. expect(parse('"hello world"').first).to eq(AST::String.new('hello world'))
  13. end
  14. it 'parses an identifier' do
  15. expect(parse('+').first).to eq(AST::Identifier.new('+'))
  16. end
  17. it 'parses booleans' do
  18. expect(parse('#t #f')).to eq(
  19. [AST::Boolean.new(true), AST::Boolean.new(false)]
  20. )
  21. end
  22. it 'parses an application' do
  23. expect(parse('(+ 1 2)').first).to eq(
  24. AST::List.new(
  25. [AST::Identifier.new('+'), AST::Number.new(1.0), AST::Number.new(2.0)]
  26. )
  27. )
  28. end
  29. it 'parses a definition' do
  30. expect(parse('(define x 5)').first).to eq(
  31. AST::Definition.new(AST::Identifier.new('x'), AST::Number.new(5.0))
  32. )
  33. end
  34. it 'parses a nested expression' do
  35. expect(parse('(+ (+ 1 2) (- 3 4))').first).to eq(
  36. AST::List.new(
  37. [
  38. AST::Identifier.new('+'),
  39. AST::List.new(
  40. [
  41. AST::Identifier.new('+'),
  42. AST::Number.new(1.0),
  43. AST::Number.new(2.0)
  44. ]
  45. ),
  46. AST::List.new(
  47. [
  48. AST::Identifier.new('-'),
  49. AST::Number.new(3.0),
  50. AST::Number.new(4.0)
  51. ]
  52. )
  53. ]
  54. )
  55. )
  56. end
  57. it 'parses a function definition' do
  58. expect(parse('(define (square x) (* x x))').first).to eq(
  59. AST::Definition.new(
  60. AST::Identifier.new('square'),
  61. AST::Function.new(
  62. AST::Identifier.new('square'),
  63. [AST::Identifier.new('x')],
  64. [
  65. AST::List.new(
  66. [
  67. AST::Identifier.new('*'),
  68. AST::Identifier.new('x'),
  69. AST::Identifier.new('x')
  70. ]
  71. )
  72. ]
  73. )
  74. )
  75. )
  76. end
  77. it 'returns a syntax error object instead of raising' do
  78. expect(parse('(+ 1')).to eq(Error.new('Expected rparen but got eof'))
  79. expect(parse('1)')).to eq(Error.new('Unexpected token rparen: )'))
  80. end
  81. it 'parses a conditional' do
  82. expect(parse('(if #t 1 0)').first).to eq(
  83. AST::Conditional.new(
  84. AST::Boolean.new(true),
  85. AST::Number.new(1.0),
  86. AST::Number.new(0.0)
  87. )
  88. )
  89. end
  90. it 'parses a quoted value' do
  91. expect(parse('\'(1 2 3)').first).to eq(
  92. AST::Quotation.new(
  93. AST::List.new(
  94. [
  95. AST::Number.new(1.0),
  96. AST::Number.new(2.0),
  97. AST::Number.new(3.0),
  98. ]
  99. )
  100. )
  101. )
  102. end
  103. it 'parses a lambda expression' do
  104. expect(parse('(lambda (x) (* x x))').first).to eq(
  105. AST::Function.new(
  106. AST::Identifier.new("lambda"),
  107. [AST::Identifier.new("x")],
  108. [
  109. AST::List.new(
  110. [
  111. AST::Identifier.new("*"),
  112. AST::Identifier.new("x"),
  113. AST::Identifier.new("x"),
  114. ]
  115. ),
  116. ]
  117. )
  118. )
  119. end
  120. end
  121. end