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.

lexer.rb 1.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. module Chervil
  2. class Lexer
  3. def initialize(source)
  4. @source = source
  5. @position = 0
  6. end
  7. def current_char
  8. @source[@position]
  9. end
  10. def advance(step = 1)
  11. @position += step
  12. end
  13. def get_next_token
  14. while @source.slice(@position..-1).match(/^\s/)
  15. advance
  16. end
  17. case current_char
  18. when nil
  19. Token.new(:eof, "eof")
  20. when '('
  21. advance
  22. Token.new(:lparen, "(")
  23. when ')'
  24. advance
  25. Token.new(:rparen, ")")
  26. when '#'
  27. advance
  28. if current_char == 't'
  29. advance
  30. Token.new(:boolean, true)
  31. elsif current_char == 'f'
  32. advance
  33. Token.new(:boolean, false)
  34. else
  35. raise "Unexpected character #{current_char}"
  36. end
  37. when '\''
  38. advance
  39. Token.new(:quote, '\'')
  40. when '"'
  41. delimiter = current_char
  42. advance
  43. string = String.new
  44. until current_char == delimiter || current_char.nil?
  45. string << current_char
  46. advance
  47. end
  48. if current_char.nil?
  49. return Error.new("Unterminated string")
  50. end
  51. advance
  52. Token.new(:string, string)
  53. else
  54. source = @source.slice(@position..-1)
  55. if match = source.match(/^[0-9]+(\.[0-9]+)?/)
  56. advance(match[0].size)
  57. Token.new(:number, match[0])
  58. elsif match = source.match(/^[a-z!$%&*\/:<=>?~_^+\-][a-z0-9@!$%&*\/:<=>?~_^+\-]*/)
  59. advance(match[0].size)
  60. Token.new(:identifier, match[0])
  61. else
  62. raise "Unrecognized character #{current_char}"
  63. end
  64. end
  65. end
  66. def tokenize
  67. tokens = Array.new
  68. loop do
  69. token = get_next_token
  70. tokens << token unless token.nil?
  71. break if token.type == :eof
  72. end
  73. tokens
  74. end
  75. end
  76. end