forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreader.jl
132 lines (117 loc) · 2.94 KB
/
reader.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
module reader
export read_str
import types
type Reader
tokens
position::Int64
end
function next(rdr::Reader)
if rdr.position > length(rdr.tokens)
return nothing
end
rdr.position += 1
rdr.tokens[rdr.position-1]
end
function peek(rdr::Reader)
if rdr.position > length(rdr.tokens)
return nothing
end
rdr.tokens[rdr.position]
end
function tokenize(str)
re = r"[\s,]*(~@|[\[\]{}()'`~^@]|\"(?:\\.|[^\\\"])*\"?|;.*|[^\s\[\]{}('\"`,;)]*)"
tokens = map((m) -> m.captures[1], eachmatch(re, str))
filter((t) -> t != "" && t[1] != ';', tokens)
end
function read_atom(rdr)
token = next(rdr)
if ismatch(r"^-?[0-9]+$", token)
parse(Int,token)
elseif ismatch(r"^-?[0-9][0-9.]*$", token)
float(token)
elseif ismatch(r"^\".*\"$", token)
replace(token[2:end-1], r"\\.", (r) -> get(Dict("\\n"=>"\n",
"\\\""=>"\"",
"\\\\"=>"\\"), r, r))
elseif ismatch(r"^\".*$", token)
error("expected '\"', got EOF")
elseif token[1] == ':'
"\u029e$(token[2:end])"
elseif token == "nil"
nothing
elseif token == "true"
true
elseif token == "false"
false
else
symbol(token)
end
end
function read_list(rdr, start="(", last=")")
ast = Any[]
token = next(rdr)
if (token != start)
error("expected '$(start)'")
end
while ((token = peek(rdr)) != last)
if token == nothing
error("expected '$(last)', got EOF")
end
push!(ast, read_form(rdr))
end
next(rdr)
ast
end
function read_vector(rdr)
lst = read_list(rdr, "[", "]")
tuple(lst...)
end
function read_hash_map(rdr)
lst = read_list(rdr, "{", "}")
types.hash_map(lst...)
end
function read_form(rdr)
token = peek(rdr)
if token == "'"
next(rdr)
[[:quote]; Any[read_form(rdr)]]
elseif token == "`"
next(rdr)
[[:quasiquote]; Any[read_form(rdr)]]
elseif token == "~"
next(rdr)
[[:unquote]; Any[read_form(rdr)]]
elseif token == "~@"
next(rdr)
[[symbol("splice-unquote")]; Any[read_form(rdr)]]
elseif token == "^"
next(rdr)
meta = read_form(rdr)
[[symbol("with-meta")]; Any[read_form(rdr)]; Any[meta]]
elseif token == "@"
next(rdr)
[[symbol("deref")]; Any[read_form(rdr)]]
elseif token == ")"
error("unexpected ')'")
elseif token == "("
read_list(rdr)
elseif token == "]"
error("unexpected ']'")
elseif token == "["
read_vector(rdr)
elseif token == "}"
error("unexpected '}'")
elseif token == "{"
read_hash_map(rdr)
else
read_atom(rdr)
end
end
function read_str(str)
tokens = tokenize(str)
if length(tokens) == 0
return nothing
end
read_form(Reader(tokens, 1))
end
end