<commit_before>#' Initialize a treeSkeleton object.
#'
#' treeSkeleton objects allow you to traverse a reference class object
#' as if it had a tree structure, merely by knowing how to call parent
#' or child nodes.
#'
#' @name treeSkeleton__initialize
#' @param object ANY. If a reference class object, then \code{parent_caller}
#'    and \code{children_caller} will refer to reference class methods.
#'    If an attribute on the object with names of \code{children_caller} and
#'    \code{parent_caller} exists, those will be used. Otherwise, the
#'    generic methods will be used.
#' @param parent_caller character. The name of the reference class method
#'    that returns the parent object, if the object was a node in a tree
#'    structure.
#' @param children_caller character. The name of the reference class method
#'    that returns the child objects, if the object was a node in a tree
#'    structure.
#' @return a treeSkeleton object.
treeSkeleton__initialize <- function(object, parent_caller = 'parent',
                                     children_caller = 'children') {
  stopifnot(!is.null(object))
  self$object  <- object
  self$.parent   <- uninitialized_field()
  self$.children <- uninitialized_field()

  # Make sure parent_caller and children_caller are methods of object
  if (inherits(object, "R6")) {
    stopifnot(all(c(parent_caller, children_caller) %in% ls(object)))
  }

  self$parent_caller   <- parent_caller
  self$children_caller <- children_caller
  NULL
}

#' Attempt to find the successor of the current node.
#'
#' @name treeSkeleton__successor
#' @param index integer. If specified, this is the index of the current node
#'   in the children of its parent. (Sometimes, this cannot be computed
#'   automatically, and should usually be provided.)
#' @return successor for the wrapped object.
treeSkeleton__successor <- function(index = NULL) {
  if (is.null(p <- self$parent())) return(NULL) # no successor of root node

  parent_index <- if (is.null(index)) self$.parent_index() else index
  stopifnot(is.finite(parent_index))

  # If we are the last leaf in the list of our parent's children,
  # our successor is our parent's successor
  if (parent_index == length(p$children()))
    p$successor()
  else
    p$children()[[parent_index + 1]]$first_leaf()
}


#' Find the root node of the tree (the only one with no parent).
#'
#' @name treeSkeleton__root
#' @return The root node of the tree or NULL if empty tree.
treeSkeleton__root <- function() {
  if (is.null(self$parent())) self
  else self$parent()
}

#' Find the first leaf in a tree.
#'
#' @name treeSkeleton__first_leaf
#' @return The first leaf, that is, the first terminal child node.
treeSkeleton__first_leaf <- function() {
  if (length(self$children()) == 0) self
  else self$children()[[1]]$first_leaf()
}

#' Find the last leaf in a tree.
#'
#' @name treeSkeleton__last_leaf
#' @return The last leaf, that is, the last terminal child node.
treeSkeleton__last_leaf <- function() {
  if (length(childs <- self$children()) == 0) self
  else childs[[length(childs)]]$last_leaf()
}

#' Find the parent of the current object wrapped in a treeSkeleton.
#' @name treeSkeleton__parent
treeSkeleton__parent <- function() {
  if (!is.unitialized_field(self$.parent)) return(self$.parent)
  self$.parent <-
    if (is.null(obj <- OOP_type_independent_method(self$object, self$parent_caller))) NULL
    else treeSkeleton$new(obj, parent_caller = self$parent_caller,
                          children_caller = self$children_caller)
}

#' Find the children of the current object wrapped in treeSkeletons.
#' @name treeSkeleton__children
treeSkeleton__children <- function() {
  if (!is.unitialized_field(self$.children)) return(self$.children)
  prechildren <- OOP_type_independent_method(self$object, self$children_caller)
  self$.children <- lapply(prechildren, treeSkeleton$new,
                       parent_caller = self$parent_caller)
}

#' Find the index of the current object in the children of its parent.
#' @name treeSkeleton__.parent_index
treeSkeleton__.parent_index <- function() {
  if (!is.null(ci <- attr(self$object, 'child_index'))) ci
  # Hack for accessing attribute modifications on a reference class object
  # See: http://stackoverflow.com/questions/22752021/why-is-r-capricious-in-its-use-of-attributes-on-reference-class-objects
  else if (is.refClass(self$object) &&
           !is.null(ci <- attr(attr(self$object, '.xData')$.self, 'child_index'))) ci
  else # look through the parent's children and compare to .self
    # <NAME>! This will lead to strange bugs if our tree
    # has several nodes with duplicate objects
    which(vapply(
      self$parent()$children(),
      function(node) identical(node$object, self$object), logical(1)))[1]
}

#' Find the key with the given index using the names of the lists
#' that parametrize each node's children.
#'
#' For example, if our tree structure is given by
#'   \code{list(a = list(b = 1, c = 2))}
#' then calling \code{find('a/b')} on the root node will return \code{1}.
#'
#' @name treeSkeleton__find
#' @param key character. The key to find in the given tree structure,
#'    whether nodes are named by their name in the \code{children()}
#'    list. Numeric indices can be used to refer to unnamed nodes.
#'    For example, if key is \code{a/2/b}, this method would try to find
#'    the current node's child \code{a}'s second child's \code{b} child.
#'    (Just look at the examples).
#' @return the subtree or terminal node with the given key.
#' @examples 
#' \dontrun{
#' sr <- stageRunner$new(new.env(), list(a = list(force, list(b = function(x) x + 1))))
#' stagerunner:::treeSkeleton$new(sr)$find('a/2/b') # function(x) x + 1
#' }
treeSkeleton__find <- function(key) {
  stopifnot(is.character(key))
  if (length(key) == 0 || identical(key, '')) return(self$object)
  # Extract "foo" from "foo/bar/baz"
  subkey <- regmatches(key, regexec('^[^/]+', key))[[1]]
  key_remainder <- substr(key, nchar(subkey) + 2, nchar(key))
  if (grepl('^[0-9]+', subkey)) {
    subkey <- as.integer(subkey)
    key_falls_within_children <- length(self$children()) >= subkey
    stopifnot(key_falls_within_children)
  } else {
    matches <- grepl(subkey, names(self$children()))
    stopifnot(length(matches) == 1)
    key <- which(matches)
  }
  self$children()[[key]]$find(key_remainder)
}

#' This class implements iterators for a tree-based structure
#' without an actual underlying tree.<commit_msg>comment out this method for now<commit_after>#' Initialize a treeSkeleton object.
#'
#' treeSkeleton objects allow you to traverse a reference class object
#' as if it had a tree structure, merely by knowing how to call parent
#' or child nodes.
#'
#' @name treeSkeleton__initialize
#' @param object ANY. If a reference class object, then \code{parent_caller}
#'    and \code{children_caller} will refer to reference class methods.
#'    If an attribute on the object with names of \code{children_caller} and
#'    \code{parent_caller} exists, those will be used. Otherwise, the
#'    generic methods will be used.
#' @param parent_caller character. The name of the reference class method
#'    that returns the parent object, if the object was a node in a tree
#'    structure.
#' @param children_caller character. The name of the reference class method
#'    that returns the child objects, if the object was a node in a tree
#'    structure.
#' @return a treeSkeleton object.
treeSkeleton__initialize <- function(object, parent_caller = 'parent',
                                     children_caller = 'children') {
  stopifnot(!is.null(object))
  self$object  <- object
  self$.parent   <- uninitialized_field()
  self$.children <- uninitialized_field()

  # Make sure parent_caller and children_caller are methods of object
  if (inherits(object, "R6")) {
    stopifnot(all(c(parent_caller, children_caller) %in% ls(object)))
  }

  self$parent_caller   <- parent_caller
  self$children_caller <- children_caller
  NULL
}

#' Attempt to find the successor of the current node.
#'
#' @name treeSkeleton__successor
#' @param index integer. If specified, this is the index of the current node
#'   in the children of its parent. (Sometimes, this cannot be computed
#'   automatically, and should usually be provided.)
#' @return successor for the wrapped object.
treeSkeleton__successor <- function(index = NULL) {
  if (is.null(p <- self$parent())) return(NULL) # no successor of root node

  parent_index <- if (is.null(index)) self$.parent_index() else index
  stopifnot(is.finite(parent_index))

  # If we are the last leaf in the list of our parent's children,
  # our successor is our parent's successor
  if (parent_index == length(p$children()))
    p$successor()
  else
    p$children()[[parent_index + 1]]$first_leaf()
}


#' Find the root node of the tree (the only one with no parent).
#'
#' @name treeSkeleton__root
#' @return The root node of the tree or NULL if empty tree.
treeSkeleton__root <- function() {
  if (is.null(self$parent())) self
  else self$parent()
}

#' Find the first leaf in a tree.
#'
#' @name treeSkeleton__first_leaf
#' @return The first leaf, that is, the first terminal child node.
treeSkeleton__first_leaf <- function() {
  if (length(self$children()) == 0) self
  else self$children()[[1]]$first_leaf()
}

#' Find the last leaf in a tree.
#'
#' @name treeSkeleton__last_leaf
#' @return The last leaf, that is, the last terminal child node.
treeSkeleton__last_leaf <- function() {
  if (length(childs <- self$children()) == 0) self
  else childs[[length(childs)]]$last_leaf()
}

#' Find the parent of the current object wrapped in a treeSkeleton.
#' @name treeSkeleton__parent
treeSkeleton__parent <- function() {
  if (!is.unitialized_field(self$.parent)) return(self$.parent)
  self$.parent <-
    if (is.null(obj <- OOP_type_independent_method(self$object, self$parent_caller))) NULL
    else treeSkeleton$new(obj, parent_caller = self$parent_caller,
                          children_caller = self$children_caller)
}

#' Find the children of the current object wrapped in treeSkeletons.
#' @name treeSkeleton__children
treeSkeleton__children <- function() {
  if (!is.unitialized_field(self$.children)) return(self$.children)
  prechildren <- OOP_type_independent_method(self$object, self$children_caller)
  self$.children <- lapply(prechildren, treeSkeleton$new,
                       parent_caller = self$parent_caller)
}

#' Find the index of the current object in the children of its parent.
#' @name treeSkeleton__.parent_index
treeSkeleton__.parent_index <- function() {
  if (!is.null(ci <- attr(self$object, 'child_index'))) ci
  # Hack for accessing attribute modifications on a reference class object
  # See: http://stackoverflow.com/questions/22752021/why-is-r-capricious-in-its-use-of-attributes-on-reference-class-objects
  else if (is.refClass(self$object) &&
           !is.null(ci <- attr(attr(self$object, '.xData')$.self, 'child_index'))) ci
  else # look through the parent's children and compare to .self
    # <NAME>! This will lead to strange bugs if our tree
    # has several nodes with duplicate objects
    which(vapply(
      self$parent()$children(),
      function(node) identical(node$object, self$object), logical(1)))[1]
}

#' Find the key with the given index using the names of the lists
#' that parametrize each node's children.
#'
#' For example, if our tree structure is given by
#'   \code{list(a = list(b = 1, c = 2))}
#' then calling \code{find('a/b')} on the root node will return \code{1}.
#'
#' @name treeSkeleton__find
#' @param key character. The key to find in the given tree structure,
#'    whether nodes are named by their name in the \code{children()}
#'    list. Numeric indices can be used to refer to unnamed nodes.
#'    For example, if key is \code{a/2/b}, this method would try to find
#'    the current node's child \code{a}'s second child's \code{b} child.
#'    (Just look at the examples).
#' @return the subtree or terminal node with the given key.
#' @examples 
#' \dontrun{
#' sr <- stageRunner$new(new.env(), list(a = list(force, list(b = function(x) x + 1))))
#' stagerunner:::treeSkeleton$new(sr)$find('a/2/b') # function(x) x + 1
#' }
treeSkeleton__find <- function(key) {
#  stopifnot(is.character(key))
#  if (length(key) == 0 || identical(key, '')) return(self$object)
#  # Extract "foo" from "foo/bar/baz"
#  subkey <- regmatches(key, regexec('^[^/]+', key))[[1]]
#  key_remainder <- substr(key, nchar(subkey) + 2, nchar(key))
#  if (grepl('^[0-9]+', subkey)) {
#    subkey <- as.integer(subkey)
#    key_falls_within_children <- length(self$children()) >= subkey
#    stopifnot(key_falls_within_children)
#  } else {
#    matches <- grepl(subkey, names(self$children()))
#    stopifnot(length(matches) == 1)
#    key <- which(matches)
#  }
#  self$children()[[key]]$find(key_remainder)
}

#' This class implements iterators for a tree-based structure
#' without an actual underlying tree.
{'fraction_non_alphanumeric': 0.1262225644974971, 'fraction_numerical': 0.00431266846361186, 'mean_word_length': 4.161367249602543, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1020702', 'n_tokens_mistral': 4274, 'n_tokens_neox': 3941, 'n_words': 1316}