All: fix read/print of \\, and \n
[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
8d78bc26
JM
37 (string-replace
38 (substring token 1 (- (string-length token) 1))
39 "\\\"" "\"")
40 "\\n" "\n")
41 "\\\\" "\\")]
f5223195
JM
42 [(regexp-match #px"^:" token) (_keyword (substring token 1))]
43 [(equal? "nil" token) nil]
44 [(equal? "true" token) #t]
45 [(equal? "false" token) #f]
46 [else (string->symbol token)])))
47
48(define (read_list_entries rdr end)
49 (let ([tok (send rdr peek)])
50 (cond
51 [(eq? tok '()) (raise (string-append "expected '" end "'"))]
52 [(equal? end tok) '()]
53 [else
54 (cons (read_form rdr) (read_list_entries rdr end))])))
55
56(define (read_list rdr start end)
57 (let ([token (send rdr next)])
58 (if (equal? start token)
59 (let ([lst (read_list_entries rdr end)])
60 (send rdr next)
61 lst)
62 (raise (string-append "expected '" start "'")))))
63
64(define (read_form rdr)
65 (let ([token (send rdr peek)])
66 (if (null? token)
67 (raise (make-blank-exn "blank line" (current-continuation-marks)))
68 (cond
69 [(equal? "'" token) (send rdr next) (list 'quote (read_form rdr))]
70 [(equal? "`" token) (send rdr next) (list 'quasiquote (read_form rdr))]
71 [(equal? "~" token) (send rdr next) (list 'unquote (read_form rdr))]
72 [(equal? "~@" token) (send rdr next) (list 'splice-unquote (read_form rdr))]
73 [(equal? "^" token) (send rdr next)
74 (let ([meta (read_form rdr)])
75 (list 'with-meta (read_form rdr) meta))]
76 [(equal? "@" token) (send rdr next) (list 'deref (read_form rdr))]
77
78 [(equal? ")" token) (raise "unexpected ')'")]
79 [(equal? "(" token) (read_list rdr "(" ")")]
80 [(equal? "]" token) (raise "unexpected ']'")]
81 [(equal? "[" token) (list->vector (read_list rdr "[" "]"))]
82 [(equal? "}" token) (raise "unexpected '}'")]
83 [(equal? "{" token) (apply hash (read_list rdr "{" "}"))]
84 [else (read_atom rdr)]))))
85
86(define (read_str str)
87 (read_form (new Reader% [tokens (tokenize str)])))