All: don't ignore */mal. Fixes #99
[jackhill/mal.git] / racket / reader.rkt
CommitLineData
f5223195
JM
1#lang racket
2
3(provide read_str)
4
5(require "types.rkt")
6
7(define Reader%
8 (class object%
9 (init tokens)
10 (super-new)
11 (define toks tokens)
12 (define position 0)
13 (define/public (next)
14 (cond [(>= position (length toks)) null]
15 [else (begin
16 (set! position (+ 1 position))
17 (list-ref toks (- position 1)))]))
18 (define/public (peek)
19 (cond [(>= position (length toks)) null]
20 [else (list-ref toks position )]))))
21
22
23(define (tokenize str)
24 (filter-not (lambda (s) (or (equal? s "") (equal? (substring s 0 1) ";")))
25 (regexp-match* #px"[\\s,]*(~@|[\\[\\]{}()'`~^@]|\"(?:\\\\.|[^\\\\\"])*\"|;[^\n]*|[^\\s\\[\\]{}('\"`,;)]*)"
26 str #:match-select cadr)))
27
28(define (read_atom rdr)
29 (let ([token (send rdr next)])
30 (cond [(regexp-match #px"^-?[0-9]+$" token)
31 (string->number token)]
32 [(regexp-match #px"^-?[0-9][0-9.]*$" token)
33 (string->number token)]
34 [(regexp-match #px"^\".*\"$" token)
35 (string-replace
36 (string-replace
37 (substring token 1 (- (string-length token) 1))
38 "\\\"" "\"")
39 "\\n" "\n")]
40 [(regexp-match #px"^:" token) (_keyword (substring token 1))]
41 [(equal? "nil" token) nil]
42 [(equal? "true" token) #t]
43 [(equal? "false" token) #f]
44 [else (string->symbol token)])))
45
46(define (read_list_entries rdr end)
47 (let ([tok (send rdr peek)])
48 (cond
49 [(eq? tok '()) (raise (string-append "expected '" end "'"))]
50 [(equal? end tok) '()]
51 [else
52 (cons (read_form rdr) (read_list_entries rdr end))])))
53
54(define (read_list rdr start end)
55 (let ([token (send rdr next)])
56 (if (equal? start token)
57 (let ([lst (read_list_entries rdr end)])
58 (send rdr next)
59 lst)
60 (raise (string-append "expected '" start "'")))))
61
62(define (read_form rdr)
63 (let ([token (send rdr peek)])
64 (if (null? token)
65 (raise (make-blank-exn "blank line" (current-continuation-marks)))
66 (cond
67 [(equal? "'" token) (send rdr next) (list 'quote (read_form rdr))]
68 [(equal? "`" token) (send rdr next) (list 'quasiquote (read_form rdr))]
69 [(equal? "~" token) (send rdr next) (list 'unquote (read_form rdr))]
70 [(equal? "~@" token) (send rdr next) (list 'splice-unquote (read_form rdr))]
71 [(equal? "^" token) (send rdr next)
72 (let ([meta (read_form rdr)])
73 (list 'with-meta (read_form rdr) meta))]
74 [(equal? "@" token) (send rdr next) (list 'deref (read_form rdr))]
75
76 [(equal? ")" token) (raise "unexpected ')'")]
77 [(equal? "(" token) (read_list rdr "(" ")")]
78 [(equal? "]" token) (raise "unexpected ']'")]
79 [(equal? "[" token) (list->vector (read_list rdr "[" "]"))]
80 [(equal? "}" token) (raise "unexpected '}'")]
81 [(equal? "{" token) (apply hash (read_list rdr "{" "}"))]
82 [else (read_atom rdr)]))))
83
84(define (read_str str)
85 (read_form (new Reader% [tokens (tokenize str)])))