vb: add seq and string?
[jackhill/mal.git] / ruby / reader.rb
CommitLineData
107d9694 1require_relative "types"
f705f0fc
JM
2
3class Reader
4 def initialize(tokens)
5 @position = 0
6 @tokens = tokens
7 end
8 def peek
9 return @tokens[@position]
10 end
11 def next
12 @position += 1
13 return @tokens[@position-1]
14 end
15end
16
17
18def tokenize(str)
19 re = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/
46dbc0d8
JM
20 return str.scan(re).map{|m| m[0]}.select{ |t|
21 t != "" && t[0..0] != ";"
22 }
f705f0fc
JM
23end
24
8d78bc26
JM
25def parse_str(t) # trim and unescape
26 return t[1..-2].gsub(/\\"/, '"').gsub(/\\n/, "\n").gsub(/\\\\/, "\\")
f705f0fc
JM
27end
28
29def read_atom(rdr)
30 token = rdr.next
31 return case token
32 when /^-?[0-9]+$/ then token.to_i # integer
33 when /^-?[0-9][0-9.]*$/ then token.to_f # float
96f1845a 34 when /^".*"$/ then parse_str(token) # string
b8ee29b2 35 when /^:/ then "\u029e" + token[1..-1] # keyword
f705f0fc
JM
36 when "nil" then nil
37 when "true" then true
38 when "false" then false
39 else token.to_sym # symbol
40 end
41end
42
43def read_list(rdr, klass, start="(", last =")")
44 ast = klass.new
45 token = rdr.next()
46 if token != start
47 raise "expected '" + start + "'"
48 end
49 while (token = rdr.peek) != last
50 if not token
51 raise "expected '" + last + "', got EOF"
52 end
53 ast.push(read_form(rdr))
54 end
55 rdr.next
56 return ast
57end
58
59def read_form(rdr)
f705f0fc
JM
60 return case rdr.peek
61 when ";" then nil
01e25489
JM
62 when "'" then rdr.next; List.new [:quote, read_form(rdr)]
63 when "`" then rdr.next; List.new [:quasiquote, read_form(rdr)]
64 when "~" then rdr.next; List.new [:unquote, read_form(rdr)]
65 when "~@" then rdr.next; List.new [:"splice-unquote", read_form(rdr)]
3a56f91a
JM
66 when "^" then rdr.next; meta = read_form(rdr);
67 List.new [:"with-meta", read_form(rdr), meta]
68 when "@" then rdr.next; List.new [:deref, read_form(rdr)]
69
f705f0fc
JM
70 when "(" then read_list(rdr, List, "(", ")")
71 when ")" then raise "unexpected ')'"
72 when "[" then read_list(rdr, Vector, "[", "]")
73 when "]" then raise "unexpected ']'"
3a56f91a 74 when "{" then Hash[read_list(rdr, List, "{", "}").each_slice(2).to_a]
f705f0fc
JM
75 when "}" then raise "unexpected '}'"
76 else read_atom(rdr)
77 end
78end
79
80def read_str(str)
81 tokens = tokenize(str)
46dbc0d8 82 return nil if tokens.size == 0
f705f0fc
JM
83 return read_form(Reader.new(tokens))
84end
85