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 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
Create a new Sexp containing args.
# File lib/sexp.rb, line 19 def initialize(*args) super(args) end
Returns true if this Sexp’s pattern matches sexp.
# File lib/sexp.rb, line 52 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 68 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 77 def array_type? type = self.first @@array_types.include? type end
Recursively enumerates the sexp yielding to block for every
element.
# File lib/sexp.rb, line 89 def deep_each(&block) return enum_for(:deep_each) unless block_given? self.each_sexp do |sexp| block[sexp] sexp.deep_each(&block) end end
# File lib/sexp.rb, line 98 def depth 1 + (each_sexp.map(&:depth).max || 0) end
Enumeratates the sexp yielding to b when the node_type ==
t.
# File lib/sexp.rb, line 105 def each_of_type(t, &b) return enum_for(:each_of_type) unless block_given? 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.
# File lib/sexp.rb, line 119 def each_sexp return enum_for(:each_sexp) unless block_given? 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 133 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 170 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 188 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 146 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 197 def line(n=nil) if n then @line = n self else @line ||= nil end end
Returns the maximum line number of the children of self.
# File lib/sexp.rb, line 209 def line_max @line_max ||= self.deep_each.map(&:line).max end
Returns the size of the sexp, flattened.
# File lib/sexp.rb, line 216 def mass @mass ||= inject(1) { |t, s| if Sexp === s then t + s.mass else t end } end
Returns the node named node, deleting it if
delete is true.
# File lib/sexp.rb, line 230 def method_missing meth, delete = false r = find_node meth, delete if ENV["DEBUG"] then if r.nil? then warn "%p.method_missing(%p) => nil from %s" % [self, meth, caller.first] elsif ENV["VERBOSE"] warn "%p.method_missing(%p) from %s" % [self, meth, caller.first] end end r end
Returns the Sexp body, ie the values without the node type.
# File lib/sexp.rb, line 273 def sexp_body self[1..-1] end
Returns the node type of the Sexp.
# File lib/sexp.rb, line 259 def sexp_type first end
Sets the node type of the Sexp.
# File lib/sexp.rb, line 266 def sexp_type= v self[0] = v 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 293 def structure if Array === self.first then s(:bogus, *self).structure # TODO: remove >= 4.2.0 else result = s(self.first) self.each do |subexp| result << subexp.structure if Sexp === subexp end result end end
Replaces the Sexp matching pattern
with repl.
# File lib/sexp.rb, line 308 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