DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / hy / reader.hy
CommitLineData
58ff8110 1(import [hy.models [HyInteger :as Int HyKeyword :as Keyword
081c3223 2 HyString :as Str HySymbol :as Sym]]
58ff8110
JM
3 [re])
4
5(defclass Blank [Exception])
6
7(defclass Reader []
8 (defn --init-- [self tokens &optional [position 0]]
9 (setv self.tokens tokens self.position position))
10 (defn next [self]
11 (setv self.position (+ 1 self.position))
12 (get self.tokens (- self.position 1)))
13 (defn peek [self]
14 (if (> (len self.tokens) self.position)
15 (get self.tokens self.position)
16 None)))
17
18(def tok-re (.compile re "[\\s,]*(~@|[\\[\\]{}()'`~^@]|\"(?:[\\\\].|[^\\\\\"])*\"?|;.*|[^\\s\\[\\]{}()'\"`@,;]+)"))
19(def int-re (.compile re "-?[0-9]+$"))
9a4896ef 20(def str-re (.compile re "^\"(?:[\\\\].|[^\\\\\"])*\"$"))
4aa0ebdf 21(def str-bad-re (.compile re "^\".*$"))
58ff8110
JM
22
23(defn tokenize [str]
24 (list-comp
25 t
26 (t (.findall re tok-re str))
27 (!= (get t 0) ";")))
28
29(defn unescape [s]
42aecee6
JM
30 (-> s (.replace "\\\\" "\u029e")
31 (.replace "\\\"" "\"")
32 (.replace "\\n" "\n")
33 (.replace "\u029e" "\\")))
58ff8110
JM
34
35(defn read-atom [rdr]
36 (setv token (.next rdr))
37 (if
38 (.match re int-re token) (int token)
4aa0ebdf 39 (.match re str-re token) (Str (unescape (cut token 1 -1)))
6c4cc8ad 40 (.match re str-bad-re token) (raise (Exception "expected '\"', got EOF"))
58ff8110
JM
41 (= ":" (get token 0)) (Keyword token)
42 (= "nil" token) None
43 (= "true" token) True
44 (= "false" token) False
45 True (Sym token)))
46
47(defn read-seq [rdr &optional [start "("] [end ")"]]
48 (setv ast (list)
49 token (.next rdr))
50 (if (!= token start)
51 (raise (Exception (+ "expected '" start "'")))
52 (do
53 (setv token (.peek rdr))
54 (while (!= token end)
55 (if (not token) (raise (Exception (+ "expected '" end
56 ", got EOF"))))
57 (.append ast (read-form rdr))
58 (setv token (.peek rdr)))
59 (.next rdr)
60 ast)))
61
62(defn read-form [rdr]
63 (setv token (.peek rdr))
64 (if
65 (= ";" (get token 0)) (.next rdr)
66
67 (= "'" token) (do (.next rdr)
68 (tuple [(Sym "quote") (read-form rdr)]))
69 (= "`" token) (do (.next rdr)
70 (tuple [(Sym "quasiquote") (read-form rdr)]))
71 (= "~" token) (do (.next rdr)
72 (tuple [(Sym "unquote") (read-form rdr)]))
73 (= "~@" token) (do (.next rdr)
74 (tuple [(Sym "splice-unquote")
75 (read-form rdr)]))
76 (= "^" token) (do (.next rdr)
77 (setv meta (read-form rdr))
78 (tuple [(Sym "with-meta") (read-form rdr) meta]))
79 (= "@" token) (do (.next rdr)
80 (tuple [(Sym "deref") (read-form rdr)]))
81
82 (= ")" token) (raise (Exception "unexpected ')'"))
83 (= "(" token) (tuple (read-seq rdr "(" ")"))
84
85 (= "]" token) (raise (Exception "unexpected ')'"))
86 (= "[" token) (read-seq rdr "[" "]")
87
88 (= "}" token) (raise (Exception "unexpected '}'"))
081c3223 89 (= "{" token) (dict (partition (read-seq rdr "{" "}") 2))
58ff8110
JM
90
91 True (read-atom rdr)))
92
93(defn read-str [str]
94 (setv tokens (tokenize str))
95 (if (= 0 (len tokens)) (raise (Blank "blank line")))
96 (read-form (Reader tokens)))