module Macros::Sexp

Public Instance Methods

node?(node) click to toggle source
# File lib/macros/sexp.rb, line 50
def node?(node)
  node.is_a?(AST::Node)
end
s(type, *children) click to toggle source
# File lib/macros/sexp.rb, line 6
def s(type, *children)
  Parser::AST::Node.new(type, children)
end
seval(ast) click to toggle source
# File lib/macros/sexp.rb, line 54
def seval(ast)
  eval(Unparser.unparse(ast))
end
sfind(sexp, specs) click to toggle source

Traverse into sexp by type and child position

# File lib/macros/sexp.rb, line 11
def sfind(sexp, specs)
  specs.inject(sexp) do |node, spec|
    return NotFound if node.nil?

    if spec.is_a?(Symbol) && node.type == spec
      node
    elsif spec.is_a?(Integer) && node.children.length > spec
      node.children[spec]
    elsif spec.is_a?(Array)
      node.children.grep(AST::Node)
        .flat_map { |child| sfind(child, spec) }
        .reject { |child| child == NotFound }
    else
      return NotFound
    end
  end
end
smatch?(node, pattern) click to toggle source
# File lib/macros/sexp.rb, line 43
def smatch?(node, pattern)
  return false unless node.type == pattern.type
  pattern.children.zip(node.children).all? do |a, b|
    a == b || node?(a) && smatch?(b, a)
  end
end
treefilter(node, &block) click to toggle source
# File lib/macros/sexp.rb, line 36
def treefilter(node, &block)
  acc = []
  acc << node if block.call(node)
  treemap(node) { |n| acc << n if block.call(n) ; n}
  acc.freeze
end
treemap(node, &block) click to toggle source
# File lib/macros/sexp.rb, line 29
def treemap(node, &block)
  block.call(s(node.type, *node.children.map do |child|
      next child unless child.is_a? AST::Node
      block.call(treemap(child, &block))
    end))
end