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 "}"))
68 (let lp((k (car lst)))
72 (when (null? (cdr lst))
73 (throw 'mal-error "read_hashmap: lack of value" k))
76 (lp (cddr lst)))))))))
78 (define (read_atom reader)
81 (string-sub s "\\\\\"" "\"")
83 (let ((token (reader 'next)))
85 ((string-match "^-?[0-9][0-9.]*$" token)
86 => (lambda (m) (string->number (match:substring m 0))))
87 ((string-match "^\"(.*)(.)$" token)
89 (if (string=? "\"" (match:substring m 2))
90 (->str (match:substring m 1))
91 (throw 'mal-error "expected '\"'"))))
92 ((string-match "^:(.*)" token)
93 => (lambda (m) (_keyword (match:substring m 1))))
94 ((string=? "nil" token) nil)
95 ((string=? "true" token) #t)
96 ((string=? "false" token) #f)
97 (else (string->symbol token)))))
99 (define (read_form reader)
100 (define (next) (reader 'next))
101 (define (more) (read_form reader))
102 (match (reader 'peek)
103 (() (throw 'mal-error "blank line")) ; FIXME: what should be returned?
104 ("'" (next) (list 'quote (more)))
105 ("`" (next) (list 'quasiquote (more)))
106 ("~" (next) (list 'unquote (more)))
107 ("~@" (next) (list 'splice-unquote (more)))
108 ("^" (next) (let ((meta (more))) `(with-meta ,(more) ,meta)))
109 ("@" (next) `(deref ,(more)))
110 (")" (next) (throw 'mal-error "unexpected ')'"))
111 ("(" (next) (read_list reader))
112 ("]" (throw 'mal-error "unexpected ']'"))
113 ("[" (next) (read_vector reader))
114 ("}" (throw 'mal-error "unexpected '}'"))
115 ("{" (next) (read_hashmap reader))
116 ("" (next) (read_form reader))
117 (else (read_atom reader))))
119 (define (read_str str)
120 (if (eof-object? str)
122 (let ((tokens (tokenizer str)))
123 (read_form (make-Reader (if (null? tokens) (list str) tokens))))))