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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. list
  23. else
  24. @error = Error.new("Unexpected token #{@current_token.type}: #{@current_token.value}")
  25. end
  26. end
  27. def list
  28. eat(:lparen)
  29. if @current_token.type == :identifier
  30. if @current_token.value == 'define'
  31. return definition
  32. elsif @current_token.value == 'if'
  33. return conditional
  34. end
  35. end
  36. elements = Array.new
  37. until @current_token.type == :rparen || @current_token.type == :eof
  38. elements << expr
  39. end
  40. eat(:rparen)
  41. AST::List.new(elements)
  42. end
  43. def definition
  44. eat(:identifier) # the `define`
  45. if @current_token.type == :identifier
  46. name = identifier
  47. value = expr
  48. eat(:rparen)
  49. AST::Definition.new(name, value)
  50. elsif @current_token.type == :lparen
  51. eat(:lparen)
  52. name = identifier
  53. params = Array.new
  54. until [:rparen, :eof].include?(@current_token.type)
  55. params << expr
  56. end
  57. eat(:rparen)
  58. body = Array.new
  59. until [:rparen, :eof].include?(@current_token.type)
  60. body << expr
  61. end
  62. eat(:rparen)
  63. AST::Definition.new(name, AST::Function.new(name, params, body))
  64. end
  65. end
  66. def conditional
  67. eat(:identifier) # the `if`
  68. predicate = expr
  69. true_branch = expr
  70. false_branch = expr
  71. eat(:rparen)
  72. AST::Conditional.new(predicate, true_branch, false_branch)
  73. end
  74. def identifier
  75. identifier = eat(:identifier)
  76. AST::Identifier.new(identifier.value)
  77. end
  78. def constant
  79. case @current_token.type
  80. when :number
  81. token = eat(:number)
  82. AST::Number.new(token.value.to_f)
  83. when :string
  84. token = eat(:string)
  85. AST::String.new(token.value)
  86. when :boolean
  87. token = eat(:boolean)
  88. AST::Boolean.new(token.value)
  89. end
  90. end
  91. def eat(type)
  92. if @current_token.type == type
  93. token = @current_token
  94. @current_token = @lexer.get_next_token
  95. token
  96. else
  97. @error = Error.new("Expected #{type} but got #{@current_token.type}")
  98. end
  99. end
  100. end
  101. end