4 def initialize(@tokens)
9 @tokens[@pos] rescue nil
31 regex = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/
32 str.scan(regex).map{|m| m[1]}.reject(&.empty?)
36 r = Reader.new(tokenize(str))
41 raise "expected EOF, got #{r.peek.to_s}"
47 raise Mal::ParseException.new msg
50 def read_sequence(reader, init, open, close)
52 parse_error "expected '#{open}', got EOF" unless token
53 parse_error "expected '#{open}', got #{token}" unless token[0] == open
57 parse_error "expected '#{close}', got EOF" unless token
58 break if token[0] == close
60 init << read_form reader
69 read_sequence(reader, Mal::List.new, '(', ')')
72 def read_vector(reader)
73 read_sequence(reader, Mal::Vector.new, '[', ']')
78 parse_error "expected Atom but got EOF" unless token
81 when token =~ /^-?\d+$/ then token.to_i
82 when token == "true" then true
83 when token == "false" then false
84 when token == "nil" then nil
85 when token[0] == '"' then token[1..-2].gsub(/\\"/, "\"")
86 else Mal::Symbol.new token
90 def list_of(symname, reader)
92 Mal::List.new << Mal::Symbol.new(symname) << read_form(reader)
95 def read_form(reader) : Mal::Type
98 parse_error "unexpected EOF" unless token
99 parse_error "unexpected comment" if token[0] == ';'
102 when "(" then read_list reader
103 when ")" then parse_error "unexpected ')'"
104 when "[" then read_vector reader
105 when "]" then parse_error "unexpected ']'"
106 when "'" then list_of("quote", reader)
107 when "`" then list_of("quasiquote", reader)
108 when "~" then list_of("unquote", reader)
109 when "~@" then list_of("splice-unquote", reader)
110 when "^" then list_of("with-meta", reader)
111 when "@" then list_of("deref", reader)
112 else read_atom reader
117 puts pr_str(read_str("[+ 1 2] ; bar"))