class Clojure::Reader

read Clojure as Ruby’s data-structures

Attributes

ast[R]

Public Class Methods

new(source) click to toggle source
# File lib/clojure/reader.rb, line 4
def initialize(source)
  @source = source
  @io = StringIO.new source
  @ast = []
  loop do
    break if eof?
    r = read_next
    @ast << r if r
  end
  true
end

Public Instance Methods

cursor() click to toggle source
# File lib/clojure/reader.rb, line 22
def cursor
  @cursor || next_char
end
eof?() click to toggle source
# File lib/clojure/reader.rb, line 26
def eof?
  @cursor == :eof
end
inspect() click to toggle source
# File lib/clojure/reader.rb, line 16
def inspect
  @ast
end
next_char() click to toggle source
# File lib/clojure/reader.rb, line 30
def next_char
  @cursor = @io.getc || :eof
end
read_form(till: ")", into: []) click to toggle source
# File lib/clojure/reader.rb, line 77
def read_form(till: ")", into: [])
  opening = cursor
  skip_char # opening parenthesis
  ast = into
  until cursor == till
    raise Exception, "Unbalanced #{opening}#{till}" if eof?
    r = read_next
    ast << r if r
  end
  skip_char # closing parenthesis
  ast
end
read_keyword() click to toggle source
# File lib/clojure/reader.rb, line 98
def read_keyword
  next_char
  k = cursor
  while next_char.match /\w|\.|#|-|_/
    k << cursor
  end
  k.to_sym
end
read_next() click to toggle source
# File lib/clojure/reader.rb, line 34
def read_next
  # puts "reading next"
  # puts "-> #{cursor}"
  case cursor
  when :eof then return
  when /\s/ then skip_char
  when /\,/ then skip_char
  when /\;/ then skip_comment
  when /\d/ then read_number
  when /\(/ then read_form
  when /\[/ then read_form till: "]", into: ["vector"]
  when /\{/ then read_form till: "}", into: ["hash-map"]
  when /\:/ then read_keyword
  when /\"/ then read_string
  when /\'/ then read_quote
  when /\#/ then read_special
  when /\S/ then read_symbol
  end
end
read_number() click to toggle source
# File lib/clojure/reader.rb, line 90
def read_number
  n = cursor
  while next_char.match /[\d|.]/
    n << cursor
  end
  Integer(n) rescue Float(n)
end
read_quote() click to toggle source
# File lib/clojure/reader.rb, line 107
def read_quote
  skip_char # '
  ["quote", read_next]
end
read_sexp_comment() click to toggle source
# File lib/clojure/reader.rb, line 61
def read_sexp_comment
  next_char
  read_next
  nil
end
read_special() click to toggle source
# File lib/clojure/reader.rb, line 54
def read_special
  case next_char
  when /\_/ then read_sexp_comment
  else raise Exception, "Unknown token: ##{cur}"
  end
end
read_string() click to toggle source
# File lib/clojure/reader.rb, line 112
def read_string
  next_char
  if cursor == '"'
    next_char
    return ['str', ['quote', '']]
  end
  s = cursor.dup
  prev = cursor
  until (next_char == '"' && prev != "\\")
    if cursor == "\\"
    elsif cursor == "\""
      s << cursor
    elsif prev == "\\"
      s << "\\#{cursor}"
    else
      s << cursor
    end
    prev = cursor
  end
  next_char
  ['str', ['quote', s]]
end
read_symbol() click to toggle source
# File lib/clojure/reader.rb, line 135
def read_symbol
  symbol = cursor
  while next_char.match(/\w|-|\.|\?|\+|\//)
    symbol << cursor
  end
  symbol
end
skip_char() click to toggle source
# File lib/clojure/reader.rb, line 67
def skip_char
  next_char
  nil
end
skip_comment() click to toggle source
# File lib/clojure/reader.rb, line 72
def skip_comment
  next_char until cursor == "\n" || eof?
  nil
end