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.rb 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. module Chervil
  2. class Parser def initialize(lexer)
  3. @lexer = lexer
  4. @tree = Array.new
  5. @current_token = @lexer.get_next_token
  6. end
  7. def parse
  8. until @current_token.type == :eof
  9. @tree << expr
  10. end
  11. @tree
  12. end
  13. def expr
  14. if [:string, :number, :boolean].include?(@current_token.type)
  15. constant
  16. elsif @current_token.type == :identifier
  17. identifier
  18. elsif @current_token.type == :lparen
  19. application
  20. else
  21. raise "Unexpected token #{@current_token.type}: #{@current_token.value}"
  22. end
  23. end
  24. def application
  25. eat(:lparen)
  26. if @current_token.type == :identifier && @current_token.value == 'define'
  27. return definition
  28. end
  29. expression = expr
  30. args = Array.new
  31. until @current_token.type == :rparen
  32. args << expr
  33. end
  34. eat(:rparen)
  35. AST::Application.new(expression, args)
  36. end
  37. def definition
  38. eat(:identifier) # the `define`
  39. if @current_token.type == :identifier
  40. name = identifier
  41. value = expr
  42. eat(:rparen)
  43. AST::Definition.new(name, value)
  44. elsif @current_token.type == :lparen
  45. eat(:lparen)
  46. name = identifier
  47. params = Array.new
  48. until [:rparen, :eof].include?(@current_token.type)
  49. params << expr
  50. end
  51. eat(:rparen)
  52. body = Array.new
  53. until [:rparen, :eof].include?(@current_token.type)
  54. body << expr
  55. end
  56. eat(:rparen)
  57. AST::Definition.new(name, AST::Function.new(name, params, body))
  58. end
  59. end
  60. def identifier
  61. identifier = eat(:identifier)
  62. AST::Identifier.new(identifier.value)
  63. end
  64. def constant
  65. case @current_token.type
  66. when :number
  67. token = eat(:number)
  68. AST::Number.new(token.value.to_f)
  69. when :string
  70. token = eat(:string)
  71. AST::String.new(token.value)
  72. when :boolean
  73. token = eat(:boolean)
  74. AST::Boolean.new(token.value)
  75. end
  76. end
  77. def eat(type)
  78. if @current_token.type == type
  79. token = @current_token
  80. @current_token = @lexer.get_next_token
  81. token
  82. else
  83. raise "Expected #{type} but got #{@current_token.type}"
  84. end
  85. end
  86. end
  87. end