5 def initialize(@tokens : Array(String))
10 @tokens[@pos] rescue nil
30 def read_sequence(init, open, close)
32 parse_error "expected '#{open}', got EOF" unless token
33 parse_error "expected '#{open}', got #{token}" unless token[0] == open
37 parse_error "expected '#{close}', got EOF" unless token
38 break if token[0] == close
49 Mal::Type.new read_sequence(Mal::List.new, '(', ')')
53 Mal::Type.new read_sequence(Mal::Vector.new, '[', ']')
57 types = read_sequence([] of Mal::Type, '{', '}')
59 parse_error "odd number of elements for hash-map: #{types.size}" if types.size.odd?
60 map = Mal::HashMap.new
62 types.each_slice(2) do |kv|
63 k, v = kv[0].unwrap, kv[1]
68 parse_error("key of hash-map must be string or keyword")
77 parse_error "expected Atom but got EOF" unless token
80 when token =~ /^-?\d+$/ then token.to_i64
81 when token == "true" then true
82 when token == "false" then false
83 when token == "nil" then nil
84 when token[0] == '"' then token[1..-2].gsub(/\\"/, "\"")
87 when token[0] == ':' then "\u029e#{token[1..-1]}"
88 else Mal::Symbol.new token
93 Mal::List.new << gen_type(Mal::Symbol, symname) << read_form
99 parse_error "unexpected EOF" unless token
100 parse_error "unexpected comment" if token[0] == ';'
102 Mal::Type.new case token
103 when "(" then read_list
104 when ")" then parse_error "unexpected ')'"
105 when "[" then read_vector
106 when "]" then parse_error "unexpected ']'"
107 when "{" then read_hashmap
108 when "}" then parse_error "unexpected '}'"
109 when "'" then self.next; list_of("quote")
110 when "`" then self.next; list_of("quasiquote")
111 when "~" then self.next; list_of("unquote")
112 when "~@" then self.next; list_of("splice-unquote")
113 when "@" then self.next; list_of("deref")
117 list_of("with-meta") << meta
125 regex = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/
126 str.scan(regex).map{|m| m[1]}.reject(&.empty?)
130 r = Reader.new(tokenize(str))
135 raise Mal::ParseException.new "expected EOF, got #{r.peek.to_s}"