R/parse.R

Defines functions yaml_parse_all yaml_parse

Documented in yaml_parse yaml_parse_all

#' Parse YAML
#'
#' `yaml_parse()` parses a single YAML document. `yaml_parse_all()` parses a
#' YAML *stream* and returns one element per document.
#'
#' Both functions parse the input as a stream. `yaml_parse()` then requires it
#' to contain exactly one document, so trailing documents are never silently
#' discarded:
#'
#' | documents | `yaml_parse()` | `yaml_parse_all()` |
#' | --------- | -------------- | ------------------ |
#' | 0         | error          | `list()`           |
#' | 1         | the object     | list of length 1   |
#' | more      | error          | list of that length |
#'
#' A zero-document stream is an error rather than `NULL`, because `NULL` is
#' the legitimate result of parsing a document whose content is `null`.
#' Comment-only input is a zero-document stream.
#'
#' @param x A length-one character vector containing YAML, or a raw vector of
#'   UTF-8 YAML bytes.
#' @param simplify If `TRUE`, sequences whose elements are all scalars of the
#'   same type collapse to an atomic vector. The default is `FALSE`, so the
#'   shape of the result never depends on the contents of the document.
#' @param aliases How to treat YAML aliases. `"resolve"` (the default) replaces
#'   each alias with the value of its target; node identity is not preserved.
#'   `"error"` rejects any document containing an alias.
#' @param max_nodes Maximum number of R values materialised, or `0` for
#'   unlimited. This is the limit that bounds alias expansion: a
#'   billion-laughs document is small and shallow, so neither `max_size` nor
#'   `max_depth` constrains it. The default leaves roughly fifty times the
#'   headroom a very large document needs.
#' @param big_integers How to represent integers too large for an R numeric
#'   type to hold exactly (beyond 2^53). `"bigint"` (the default) returns a
#'   [zuyaml_bigint] character vector holding the decimal value, `"double"` is
#'   an explicit opt-in to lossy conversion, and `"error"` refuses the
#'   document. The package never loses integer precision silently.
#' @param tags How to treat an application tag such as `!duration`. Core
#'   schema tags (`!!str`, `!!int`, `!!float`, `!!bool`, `!!null`) always
#'   override resolution, so `!!str 12` is the string `"12"`. `"ignore"` (the
#'   default) converts a tagged value as though it were untagged; `"error"`
#'   rejects the document. Ignoring is the default because rejecting would
#'   refuse a great deal of ordinary YAML.
#' @param duplicate_keys If `FALSE` (the default), a mapping with duplicate
#'   keys is an error. If `TRUE`, duplicates become duplicate names in the
#'   resulting list.
#' @param max_depth Maximum nesting depth, or `0` for unlimited.
#' @param max_size Maximum input size in bytes, or `0` for unlimited.
#' @param path Optional file path, used only to make error messages more
#'   informative. [yaml_read()] and its companions set it for you.
#'
#' @return `yaml_parse()` returns an R object. `yaml_parse_all()` returns a
#'   list with one element per document.
#'
#' @examples
#' yaml_parse("host: localhost\nport: 8080\ntls: true\n")
#'
#' # The core schema, not YAML 1.1: `yes` is a string, and a quoted number
#' # stays a string.
#' str(yaml_parse("answer: yes\nversion: \"42\"\n"))
#'
#' # A stream is not a sequence: one element per document.
#' yaml_parse_all("---\nfirst\n---\nsecond\n")
#' @name yaml_parse
NULL

#' @rdname yaml_parse
#' @export
yaml_parse <- function(x,
                       simplify = FALSE,
                       aliases = c("resolve", "error"),
                       big_integers = c("bigint", "double", "error"),
                       tags = c("ignore", "error"),
                       duplicate_keys = FALSE,
                       max_depth = 128L,
                       max_size = 64 * 1024^2,
                       max_nodes = 1e6,
                       path = NULL) {
  docs <- yaml_parse_all(
    x,
    simplify = simplify,
    aliases = aliases,
    big_integers = big_integers,
    tags = tags,
    duplicate_keys = duplicate_keys,
    max_depth = max_depth,
    max_size = max_size,
    max_nodes = max_nodes,
    path = path
  )

  if (length(docs) != 1L) {
    zuyaml_abort(
      if (length(docs) == 0L) {
        "YAML stream contains no documents."
      } else {
        sprintf(
          "YAML stream contains %d documents; use yaml_parse_all().",
          length(docs)
        )
      },
      code = if (length(docs) == 0L) "no_documents" else "too_many_documents",
      path = path
    )
  }

  docs[[1L]]
}

#' @rdname yaml_parse
#' @export
yaml_parse_all <- function(x,
                           simplify = FALSE,
                           aliases = c("resolve", "error"),
                           big_integers = c("bigint", "double", "error"),
                           tags = c("ignore", "error"),
                           duplicate_keys = FALSE,
                           max_depth = 128L,
                           max_size = 64 * 1024^2,
                           max_nodes = 1e6,
                           path = NULL) {
  check_input(x, path)
  check_flag(simplify, "simplify", path)
  aliases <- match.arg(aliases)
  big_integers <- match.arg(big_integers)
  tags <- match.arg(tags)
  check_flag(duplicate_keys, "duplicate_keys", path)
  max_depth <- check_uint32(max_depth, "max_depth", path)
  max_size <- check_uint32(max_size, "max_size", path)
  max_nodes <- check_count(max_nodes, "max_nodes", path)
  check_path(path)

  .Call(
    zuyaml_parse_, x, simplify, aliases, big_integers, tags,
    duplicate_keys, max_depth, max_size, max_nodes, path
  )
}

Try the zuyaml package in your browser

Any scripts or data that you put into this service are public.

zuyaml documentation built on Oct. 7, 2026, 5:08 p.m.