Sexps are the basic storage mechanism of SexpProcessor. Sexps have a
type
(to be renamed node_type
) which is the first
element of the Sexp. The type is used by SexpProcessor to determine whom to dispatch
the Sexp to for processing.
Creates a new Sexp from Array a
.
# File lib/sexp.rb, line 27 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
Create a new Sexp containing args
.
# File lib/sexp.rb, line 20 def initialize(*args) super(args) end
Returns true if this Sexp's pattern matches sexp
.
# 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
Returns true if this Sexp matches
pattern
. (Opposite of #===.)
# File lib/sexp.rb, line 69 def =~(pattern) return pattern === self end
Returns true if the node_type is array
or args
.
REFACTOR: to TypedSexp - we only care when we have units.
# File lib/sexp.rb, line 78 def array_type? type = self.first @@array_types.include? type end
Recursively enumerates the sexp yielding to block
for every
element. TODO: test
# File lib/sexp.rb, line 91 def deep_each(&block) self.each_sexp do |sexp| block[sexp] sexp.deep_each(&block) end end
Enumeratates the sexp yielding to b
when the node_type ==
t
.
# File lib/sexp.rb, line 101 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
Recursively enumerates all sub-sexps skipping non-Sexp elements. TODO: test
# File lib/sexp.rb, line 114 def each_sexp self.each do |sexp| next unless Sexp === sexp yield sexp end end
Replaces all elements whose node_type is from
with
to
. Used only for the most trivial of rewrites.
# File lib/sexp.rb, line 126 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
# File lib/sexp.rb, line 163 def find_node name, delete = false matches = find_nodes name case matches.size when 0 then nil when 1 then match = matches.first delete match if delete match else raise NoMethodError, "multiple nodes for #{name} were found in #{inspect}" end end
Find every node with type name
.
# File lib/sexp.rb, line 181 def find_nodes name find_all { | sexp | Sexp === sexp and sexp.first == name } end
Replaces all Sexps matching pattern
with Sexp repl
.
# File lib/sexp.rb, line 139 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
If passed a line number, sets the line and returns self. Otherwise returns the line number. This allows you to do message cascades and still get the sexp back.
# File lib/sexp.rb, line 190 def line(n=nil) if n then @line = n self else @line ||= nil end end
Returns the size of the sexp, flattened.
# File lib/sexp.rb, line 202 def mass @mass ||= self.structure.flatten.size end
Returns the node named node
, deleting it if
delete
is true.
# File lib/sexp.rb, line 209 def method_missing meth, delete = false find_node meth, delete end
Returns the Sexp body, ie the values without the node type.
# File lib/sexp.rb, line 232 def sexp_body self[1..-1] end
Returns the node type of the Sexp.
# File lib/sexp.rb, line 225 def sexp_type first end
Returns the bare bones structure of the sexp. s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))
# File lib/sexp.rb, line 249 def structure result = self.class.new if Array === self.first then raise "When does this happen? #{self.inspect}" # TODO: remove >= 4.2.0 result = self.first.structure else result << self.first self.grep(Sexp).each do |subexp| result << subexp.structure end end result end
Replaces the Sexp matching pattern
with repl
.
# File lib/sexp.rb, line 266 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