Commit | Line | Data |
---|---|---|
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)]))) |