given a BaseX in x, explore its ATTRS (doing the right thing for VARLEN).
  return a list of tree-paths (i.e. tuples) for tree children that match match_fn. The root elt won't match.

def sub_slots(x,match_fn,path=(),arr=None,match=False,recurse_into_matches=True):
  """given a BaseX in x, explore its ATTRS (doing the right thing for VARLEN).
  return a list of tree-paths (i.e. tuples) for tree children that match match_fn. The root elt won't match.
  """
  # todo: rename match to topmatch for clarity
  # todo: profiling suggests this getattr-heavy recursive process is the next bottleneck
  if arr is None: arr=[]
  if match and match_fn(x):
    arr.append(path)
    if not recurse_into_matches:
      return arr
  if isinstance(x, PathTree):
    for attr in x.ATTRS:
      val = getattr(x,attr)
      if attr in x.VARLEN:
        for i,elt in enumerate(val or ()):
          nextpath = path + ((attr,i),)
          sub_slots(elt,match_fn,nextpath,arr,True,recurse_into_matches)
      else:
        nextpath = path + (attr,)
        sub_slots(val,match_fn,nextpath,arr,True,recurse_into_matches)
  return arr