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.4KB

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