Class: Clojure::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/clojure/reader.rb

Overview

read Clojure as Ruby’s data-structures

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ Reader

Returns a new instance of Reader.



4
5
6
7
8
9
10
11
12
13
14
# 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

Instance Attribute Details

#astObject (readonly)

Returns the value of attribute ast.



20
21
22
# File 'lib/clojure/reader.rb', line 20

def ast
  @ast
end

Instance Method Details

#cursorObject



22
23
24
# File 'lib/clojure/reader.rb', line 22

def cursor
  @cursor || next_char
end

#eof?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/clojure/reader.rb', line 26

def eof?
  @cursor == :eof
end

#inspectObject



16
17
18
# File 'lib/clojure/reader.rb', line 16

def inspect
  @ast
end

#next_charObject



30
31
32
# File 'lib/clojure/reader.rb', line 30

def next_char
  @cursor = @io.getc || :eof
end

#read_form(till: ")", into: []) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
# 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_keywordObject



98
99
100
101
102
103
104
105
# 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_nextObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 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_numberObject



90
91
92
93
94
95
96
# 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_quoteObject



107
108
109
110
# File 'lib/clojure/reader.rb', line 107

def read_quote
  skip_char # '
  ["quote", read_next]
end

#read_sexp_commentObject



61
62
63
64
65
# File 'lib/clojure/reader.rb', line 61

def read_sexp_comment
  next_char
  read_next
  nil
end

#read_specialObject



54
55
56
57
58
59
# 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_stringObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# 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_symbolObject



135
136
137
138
139
140
141
# File 'lib/clojure/reader.rb', line 135

def read_symbol
  symbol = cursor
  while next_char.match(/\w|-|\.|\?|\+|\//)
    symbol << cursor
  end
  symbol
end

#skip_charObject



67
68
69
70
# File 'lib/clojure/reader.rb', line 67

def skip_char
  next_char
  nil
end

#skip_commentObject



72
73
74
75
# File 'lib/clojure/reader.rb', line 72

def skip_comment
  next_char until cursor == "\n" || eof?
  nil
end