2 ;; "Mu Lei" known as "NalaGinrut" <NalaGinrut@gmail.com>
3 ;; This file is free software: you can redistribute it and/or modify
4 ;; it under the terms of the GNU General Public License as published by
5 ;; the Free Software Foundation, either version 3 of the License, or
6 ;; (at your option) any later version.
8 ;; This file is distributed in the hope that it will be useful,
9 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ;; GNU General Public License for more details.
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
18 (import (guile) (pcre) (ice-9 match) (srfi srfi-1)
19 (ice-9 regex) (types) (ice-9 format)))
21 (define (make-Reader tokens)
27 (let ((r (car tokens))) (set! tokens (cdr tokens)) r)))
28 ((peek) (if (null? tokens) '() (car tokens)))
29 (else (error "Reader: Invalid cmd!" cmd)))))
32 (new-pcre "[\\s,]*(~@|[\\[\\]{}()'`~^@]|\"(?:\\\\.|[^\\\\\"])*\"|;[^\n]*|[^\\s\\[\\]{}('\"`,;)]*)"))
34 (define (tokenizer str)
35 (filter (lambda (s) (and (not (string-null? s)) (not (string=? (substring s 0 1) ";"))))
36 (pcre-search *token-re* str)))
38 (define (delim-read reader delim)
39 (let lp((next (reader 'peek)) (ret '()))
41 ((null? next) (throw 'mal-error (format #f "expected '~a'" delim)))
42 ((string=? next delim) (reader 'next) (reverse ret))
44 (let* ((cur (read_form reader))
46 (lp n (cons cur ret)))))))
48 (define (read_list reader)
50 ((string=? ")" (reader 'peek))
53 (else (delim-read reader ")"))))
55 (define (read_vector reader)
57 ((string=? "]" (reader 'peek))
60 (else (list->vector (delim-read reader "]")))))
62 (define (read_hashmap reader)
63 (define ht (make-hash-table))
64 (define lst (delim-read reader "}"))
72 (when (null? (cdr next))
74 (format #f "read_hashmap: '~a' lack of value" (car next))))
78 (lp (cddr next)))))))))
80 (define (read_atom reader)
84 (string-sub s "\\\\\"" "\"")
87 (let ((token (reader 'next)))
89 ((string-match "^-?[0-9][0-9.]*$" token)
90 => (lambda (m) (string->number (match:substring m 0))))
91 ((string-match "^\"(.*)(.)$" token)
93 (if (string=? "\"" (match:substring m 2))
94 (->str (match:substring m 1))
95 (throw 'mal-error "expected '\"'"))))
96 ((string-match "^:(.*)" token)
97 => (lambda (m) (string->keyword (match:substring m 1))))
98 ((string=? "nil" token) nil)
99 ((string=? "true" token) #t)
100 ((string=? "false" token) #f)
101 (else (string->symbol token)))))
103 (define (read_form reader)
108 (lambda (c) (char-set-contains? char-set:whitespace c)))
110 (define (next) (reader 'next))
111 (define (more) (read_form reader))
112 (match (clean (reader 'peek))
113 (() (throw 'mal-error "blank line")) ; FIXME: what should be returned?
114 ("'" (next) (list 'quote (more)))
115 ("`" (next) (list 'quasiquote (more)))
116 ("~" (next) (list 'unquote (more)))
117 ("~@" (next) (list 'splice-unquote (more)))
118 ("^" (next) (let ((meta (more))) `(with-meta ,(more) ,meta)))
119 ("@" (next) `(deref ,(more)))
120 (")" (next) (throw 'mal-error "unexpected ')'"))
121 ("(" (next) (read_list reader))
122 ("]" (throw 'mal-error "unexpected ']'"))
123 ("[" (next) (read_vector reader))
124 ("}" (throw 'mal-error "unexpected '}'"))
125 ("{" (next) (read_hashmap reader))
126 ("" (next) (read_form reader))
127 (else (read_atom reader))))
129 (define (read_str str)
130 (if (eof-object? str)
132 (let* ((tokens (tokenizer str))
133 (t (if (null? tokens)
134 (if (char=? (string-ref str 0) #\;)
138 (read_form (make-Reader t)))))