Class: EDN::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/edn/parser.rb

Instance Method Summary collapse

Constructor Details

#initialize(source, *extra) ⇒ Parser

Returns a new instance of Parser.



85
86
87
88
# File 'lib/edn/parser.rb', line 85

def initialize(source, *extra)
  io = source.instance_of?(String) ? StringIO.new(source) : source
  @s = CharStream.new(io)
end

Instance Method Details

#call_reader(reader) ⇒ Object



224
225
226
227
228
229
230
# File 'lib/edn/parser.rb', line 224

def call_reader(reader)
  if reader.instance_of? Symbol
    self.send(reader)
  else
    self.instance_exec(&reader)
  end
end

#eof?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/edn/parser.rb', line 100

def eof?
  @s.eof?
end

#escape_char(ch) ⇒ Object



198
199
200
201
202
203
204
# File 'lib/edn/parser.rb', line 198

def escape_char(ch)
  return '\\' if ch == '\\'
  return "\n" if ch == 'n'
  return "\t" if ch == 't'
  return "\r" if ch == 'r'
  ch
end

#finish_float(whole_part) ⇒ Object



262
263
264
265
266
267
268
269
270
271
# File 'lib/edn/parser.rb', line 262

def finish_float(whole_part)
  result = whole_part
  result += @s.skip_past('.', 'Expected .')
  result += read_digits(1)
  if @s.current == 'e' || @s.current == 'E'
    @s.advance
    result = result + 'e' + read_digits
  end
  result.to_f 
end

#readObject



90
91
92
93
94
95
96
97
98
# File 'lib/edn/parser.rb', line 90

def read
  meta = read_meta
  value = read_basic
  if meta
    value.extend EDN::Metadata
    value. = meta
  end
  value
end

#read_basicObject



232
233
234
235
236
237
238
239
240
241
# File 'lib/edn/parser.rb', line 232

def read_basic
  @s.skip_ws
  ch = @s.current
  result = call_reader(READERS[ch])
  while result == NOTHING
    @s.skip_ws
    result = call_reader(READERS[@s.current])
  end
  result
end

#read_charObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/edn/parser.rb', line 112

def read_char
  result = @s.advance
  @s.advance
  until @s.eof?
    break unless @s.digit? || @s.alpha?
    result += @s.current
    @s.advance
  end

  return result if result.size == 1

  case result
  when 'newline'
    "\n"
  when 'return'
    "\r"
  when 'tab'
    "\t"
  when 'space'
    " "
  else
    raise "Unknown char #{result}"
  end
end

#read_collection(clazz, closing) ⇒ Object



321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/edn/parser.rb', line 321

def read_collection(clazz, closing)
  result = clazz.new

  @s.skip_ws

  ch = @s.current
  while ch != closing
    raise "Unexpected eof" if ch == :eof
    result << read
    @s.skip_ws
    ch = @s.current
  end
  @s.advance
  result
end

#read_digits(min_digits = 0) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/edn/parser.rb', line 243

def read_digits(min_digits=0)
  result = ''

  if @s.current == '+' || @s.current == '-'
    result << @s.current
    @s.advance
  end
 
  n_digits = 0
  while @s.current =~ /[0-9]/
    n_digits += 1
    result << @s.current
    @s.advance
  end

  raise "Expected at least #{min_digits} digits, found #{result}" unless n_digits >= min_digits
  result
end

#read_eofObject



108
109
110
# File 'lib/edn/parser.rb', line 108

def read_eof
  EOF
end

#read_extensionObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/edn/parser.rb', line 169

def read_extension
  @s.advance
  if @s.current == '{'
    @s.advance
    read_collection(Set, '}')
  elsif @s.current == "_"
    @s.advance
    x = read
    NOTHING
  else
    tag = read_symbol_chars
    value = read
    EDN.tagged_element(tag, value)
  end
end

#read_keywordObject



193
194
195
196
# File 'lib/edn/parser.rb', line 193

def read_keyword
  @s.advance
  read_symbol_chars.to_sym
end

#read_listObject



304
305
306
307
# File 'lib/edn/parser.rb', line 304

def read_list
  @s.advance
  read_collection(EDN::Type::List, ')')
end

#read_mapObject



314
315
316
317
318
319
# File 'lib/edn/parser.rb', line 314

def read_map
  @s.advance
  array = read_collection(Array, '}')
  raise "Need an even number of items for a map" unless array.count.even?
  Hash[*array]
end

#read_metaObject



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/edn/parser.rb', line 285

def read_meta
   = []
  @s.skip_ws
  while @s.current == '^'
    @s.advance
     << read_basic
    @s.skip_ws
  end

   = .reverse.reduce({}) do |acc, m|
    case m
    when Symbol then acc.merge(m => true)
    when EDN::Type::Symbol then acc.merge(:tag => m)
    else acc.merge(m)
    end
  end
  .empty? ? nil : 
end

#read_number(leading = '') ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
# File 'lib/edn/parser.rb', line 273

def read_number(leading='')
  result = leading + read_digits

  if @s.current == '.'
    return finish_float(result)
  elsif @s.skip_past('M') || @s.skip_past('N')
    result.to_i
  else
    result.to_i
  end
end

#read_number_or_symbolObject



142
143
144
145
146
147
# File 'lib/edn/parser.rb', line 142

def read_number_or_symbol
  leading = @s.current
  @s.advance
  return read_number(leading) if @s.digit?
  read_symbol(leading)
end

#read_slashObject



137
138
139
140
# File 'lib/edn/parser.rb', line 137

def read_slash
  @s.advance
  Type::Symbol.new('/')
end

#read_stringObject



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/edn/parser.rb', line 206

def read_string
  @s.advance

  result = ''
  until @s.current == '"'
    raise "Unexpected eof" if @s.eof?
    if @s.current == '\\'
      @s.advance
      result << escape_char(@s.current)
    else
      result << @s.current
    end
    @s.advance
  end
  @s.advance
  result
end

#read_symbol(leading = '') ⇒ Object



185
186
187
188
189
190
191
# File 'lib/edn/parser.rb', line 185

def read_symbol(leading='')
  token = leading + read_symbol_chars
  return true if token == "true"
  return false if token == "false"
  return nil if token == "nil"
  Type::Symbol.new(token)
end

#read_symbol_charsObject



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/edn/parser.rb', line 149

def read_symbol_chars
  result = ''

  ch = @s.current
  while SYMBOL_INTERIOR_CHARS.include?(ch)
    result << ch
    ch = @s.advance
  end
  return result unless @s.skip_past('/')

  result << '/'
  ch = @s.current
  while SYMBOL_INTERIOR_CHARS.include?(ch)
    result << ch
    ch = @s.advance
  end

  result
end

#read_vectorObject



309
310
311
312
# File 'lib/edn/parser.rb', line 309

def read_vector
  @s.advance
  read_collection(Array, ']')
end

#unknownObject



104
105
106
# File 'lib/edn/parser.rb', line 104

def unknown
  raise "Don't know what to do with #{@s.current} #{@s.current.class}"
end