/lexer.rkt

http://github.com/elibarzilay/rudybot · Shell · 90 lines · 78 code · 9 blank · 3 comment · 0 complexity · 5a74123edc734da3882025ec1901681a MD5 · raw file

  1. #! /bin/sh
  2. #| Hey Emacs, this is -*-scheme-*- code!
  3. exec racket --require "$0" --main -- ${1+"$@"}
  4. |#
  5. #lang racket
  6. (require
  7. rackunit
  8. rackunit/text-ui
  9. )
  10. (define (eat-ws inp)
  11. (regexp-try-match #px"^[[:space:]]+" inp))
  12. (define (parse-prefix inp)
  13. (regexp-match #px"[[:graph:]]+" inp))
  14. (define (parse-command inp)
  15. (regexp-match #px"[0-9]{3}|[[:alpha:]]+" inp))
  16. (define (parse-params inp)
  17. (let loop ([result '()])
  18. (eat-ws inp)
  19. (cond
  20. [(eof-object? (peek-char inp))
  21. (reverse result)]
  22. [(char=? #\: (peek-char inp))
  23. (begin
  24. (read-char inp)
  25. (if (eof-object? (peek-char inp))
  26. result
  27. (loop (cons `(param . ,(regexp-match #px"[^\u0000\r\n]+" inp)) result))))]
  28. [else
  29. (loop (cons `(param . ,(regexp-match #px"[^\u0000\r\n ]+" inp)) result))])))
  30. (check-equal? (parse-params (open-input-string ":"))
  31. '())
  32. (define (parse-crlf inp )
  33. (regexp-match #px"\r\n" inp))
  34. (provide parse-message)
  35. (define/contract parse-message
  36. ((or/c string? input-port?) . -> . list?)
  37. (match-lambda
  38. [(? string? message)
  39. (parse-message (open-input-string message))]
  40. [(? input-port? message)
  41. (begin0
  42. (cons
  43. (if (char=? #\: (peek-char message))
  44. (begin
  45. (read-char message)
  46. (cons 'prefix (parse-prefix message)))
  47. '(prefix))
  48. (begin
  49. (eat-ws message)
  50. (begin0
  51. `([command . ,(parse-command message)]
  52. [params . ,(parse-params message)])
  53. (parse-crlf message)))))]))
  54. (check-equal?
  55. (parse-message
  56. ":offby1!n=user@pdpc/supporter/monthlybyte/offby1 PRIVMSG ##cinema :rudybot: uptime")
  57. '((prefix #"offby1!n=user@pdpc/supporter/monthlybyte/offby1")
  58. (command #"PRIVMSG")
  59. ;; Ahh! It honors multiple consecutive spaces! The old way didn't.
  60. (params (param #"##cinema") (param #"rudybot: uptime"))))
  61. (check-equal?
  62. (parse-message
  63. ":nick!knack@frotz 123 #channel :some stuff")
  64. '((prefix #"nick!knack@frotz")
  65. (command #"123")
  66. (params (param #"#channel")
  67. (param #"some stuff"))))
  68. (provide main)
  69. (define (main)
  70. (if #t
  71. (call-with-input-file
  72. "incoming"
  73. (lambda (ip)
  74. (for ([message (in-port read ip)])
  75. (write (parse-message message))
  76. (newline))))
  77. (parse-message ":anthony.freenode.net 004 rudybot anthony.freenode.net ircd-seven-1.0.1 DOQRSZaghilopswz CFILMPQbcefgijklmnopqrstvz bkloveqjfI")))