Class: Sexp

Inherits:
Array show all
Defined in:
lib/sexp.rb

Overview

unless defined $TESTING

Direct Known Subclasses

SexpMatchSpecial

Constant Summary collapse

@@array_types =

ZenTest FULL

[ :array, :args, ]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Sexp

Create a new Sexp containing args.



21
22
23
24
# File 'lib/sexp.rb', line 21

def initialize(*args)
  @accessors = []
  super(args)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *a, &b) ⇒ Object

Fancy-Schmancy method used to implement named positional accessors via accessors.

Example:

class MyProcessor < SexpProcessor
  def initialize
    super
    self.require_empty = false
    self.sexp_accessors = {
      :call => [:lhs, :name, :rhs]
    }
    ...
  end

  def process_call(exp)
    lhs = exp.lhs
    name = exp.name
    rhs = exp.rhs
    ...
  end
end


150
151
152
153
154
155
# File 'lib/sexp.rb', line 150

def method_missing(meth, *a, &b)
  super unless @accessors.include? meth

  index = @accessors.index(meth) + 1 # skip type
  return self.at(index)
end

Instance Attribute Details

#accessorsObject

Named positional parameters. Use with SexpProcessor.require_empty=false.



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

def accessors
  @accessors
end

Class Method Details

.from_array(a) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/sexp.rb', line 26

def self.from_array(a)
  ary = Array === a ? a : [a]

  result = self.new

  ary.each do |x|
    case x
    when Sexp
      result << x
    when Array
      result << self.from_array(x)
    else
      result << x
    end
  end

  result
end

Instance Method Details

#==(obj) ⇒ Object

:nodoc:



45
46
47
48
49
50
51
# File 'lib/sexp.rb', line 45

def ==(obj) # :nodoc:
  if obj.class == self.class then
    super
  else
    false
  end
end

#===(sexp) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/sexp.rb', line 53

def ===(sexp)
  return nil unless Sexp === sexp
  pattern = self # this is just for my brain

  return true if pattern == sexp

  sexp.each do |subset|
    return true if pattern === subset
  end

  return nil
end

#=~(pattern) ⇒ Object



66
67
68
# File 'lib/sexp.rb', line 66

def =~(pattern)
  return pattern === self
end

#array_type?Boolean

Returns true if the node_type is array or args.

REFACTOR: to TypedSexp - we only care when we have units.

Returns:

  • (Boolean)


75
76
77
78
# File 'lib/sexp.rb', line 75

def array_type?
  type = self.first
  @@array_types.include? type
end

#each_of_type(t, &b) ⇒ Object

Enumeratates the sexp yielding to b when the node_type == t.



83
84
85
86
87
88
89
90
# File 'lib/sexp.rb', line 83

def each_of_type(t, &b)
  each do | elem |
    if Sexp === elem then
      elem.each_of_type(t, &b)
      b.call(elem) if elem.first == t
    end
  end
end

#find_and_replace_all(from, to) ⇒ Object

Replaces all elements whose node_type is from with to. Used only for the most trivial of rewrites.



96
97
98
99
100
101
102
103
104
# File 'lib/sexp.rb', line 96

def find_and_replace_all(from, to)
  each_with_index do | elem, index |
    if Sexp === elem then
      elem.find_and_replace_all(from, to)
    else
      self[index] = to if elem == from
    end
  end
end

#gsub(pattern, repl) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/sexp.rb', line 106

def gsub(pattern, repl)
  return repl if pattern == self

  new = self.map do |subset|
    case subset
    when Sexp then
      subset.gsub(pattern, repl)
    else
      subset
    end
  end

  return Sexp.from_array(new)
end

#inspectObject

:nodoc:



121
122
123
124
# File 'lib/sexp.rb', line 121

def inspect # :nodoc:
  sexp_str = self.map {|x|x.inspect}.join(', ')
  return "s(#{sexp_str})"
end

#pretty_print(q) ⇒ Object

:nodoc:



157
158
159
160
161
# File 'lib/sexp.rb', line 157

def pretty_print(q) # :nodoc:
  q.group(1, 's(', ')') do
    q.seplist(self) {|v| q.pp v }
  end
end

#sexp_bodyObject

Returns the Sexp without the node_type.



166
167
168
# File 'lib/sexp.rb', line 166

def sexp_body
  self[1..-1]
end

#shiftObject

If run with debug, Sexp will raise if you shift on an empty Sexp. Helps with debugging.



174
175
176
177
# File 'lib/sexp.rb', line 174

def shift
  raise "I'm empty" if self.empty?
  super
end

#structureObject

Returnes the bare bones structure of the sexp. s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/sexp.rb', line 183

def structure
  result = self.class.new
  if Array === self.first then
    result = self.first.structure
  else
    result << self.shift
    self.grep(Array).each do |subexp|
      result << subexp.structure
    end
  end
  result
end

#sub(pattern, repl) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/sexp.rb', line 196

def sub(pattern, repl)
  return repl.dup if pattern == self

  done = false

  new = self.map do |subset|
    if done then
      subset
    else
      case subset
      when Sexp then
        if pattern == subset then
          done = true
          repl.dup
        elsif pattern === subset then
          done = true
          subset.sub pattern, repl
        else
          subset
        end
      else
        subset
      end
    end
  end

  return Sexp.from_array(new)
end

#to_aObject

:nodoc:



225
226
227
# File 'lib/sexp.rb', line 225

def to_a # :nodoc:
  self.map { |o| Sexp === o ? o.to_a : o }
end

#to_sObject

:nodoc:



229
230
231
# File 'lib/sexp.rb', line 229

def to_s # :nodoc:
  inspect
end