rexx, ruby: remove extraneous mal files.
[jackhill/mal.git] / ruby / reader.rb
1 require_relative "types"
2
3 class 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
15 end
16
17
18 def tokenize(str)
19 re = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]*)/
20 return str.scan(re).map{|m| m[0]}.select{ |t|
21 t != "" && t[0..0] != ";"
22 }
23 end
24
25 def parse_str(t) # trim and unescape
26 return t[1..-2].gsub(/\\./, {"\\\\" => "\\", "\\n" => "\n", "\\\"" => '"'})
27 end
28
29 def 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
34 when /^".*"$/ then parse_str(token) # string
35 when /^".*$/ then raise "expected '\"', got EOF"
36 when /^:/ then "\u029e" + token[1..-1] # keyword
37 when "nil" then nil
38 when "true" then true
39 when "false" then false
40 else token.to_sym # symbol
41 end
42 end
43
44 def read_list(rdr, klass, start="(", last =")")
45 ast = klass.new
46 token = rdr.next()
47 if token != start
48 raise "expected '" + start + "'"
49 end
50 while (token = rdr.peek) != last
51 if not token
52 raise "expected '" + last + "', got EOF"
53 end
54 ast.push(read_form(rdr))
55 end
56 rdr.next
57 return ast
58 end
59
60 def read_form(rdr)
61 return case rdr.peek
62 when ";" then nil
63 when "'" then rdr.next; List.new [:quote, read_form(rdr)]
64 when "`" then rdr.next; List.new [:quasiquote, read_form(rdr)]
65 when "~" then rdr.next; List.new [:unquote, read_form(rdr)]
66 when "~@" then rdr.next; List.new [:"splice-unquote", read_form(rdr)]
67 when "^" then rdr.next; meta = read_form(rdr);
68 List.new [:"with-meta", read_form(rdr), meta]
69 when "@" then rdr.next; List.new [:deref, read_form(rdr)]
70
71 when "(" then read_list(rdr, List, "(", ")")
72 when ")" then raise "unexpected ')'"
73 when "[" then read_list(rdr, Vector, "[", "]")
74 when "]" then raise "unexpected ']'"
75 when "{" then Hash[read_list(rdr, List, "{", "}").each_slice(2).to_a]
76 when "}" then raise "unexpected '}'"
77 else read_atom(rdr)
78 end
79 end
80
81 def read_str(str)
82 tokens = tokenize(str)
83 return nil if tokens.size == 0
84 return read_form(Reader.new(tokens))
85 end
86