Chervil is a toy Lisp interpreter written in Ruby
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

parser.rb 3.3KB

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