///|
/// Original source text, as a tree.
///
/// A tree rather than a string because the parser splices pieces together on
/// nearly every step -- a comment moves from one node's prefix to another's
/// suffix, a commented-out group is rendered into the text around it -- and a
/// `String` would make each of those a copy. It is flattened once, by a
/// preorder walk, when something finally asks for the text.
pub(all) enum Raw {
  Empty
  Str(String)
  Cons(Raw, Raw)
} derive(Eq)

///|
/// The reference's `combine-shrubbery-raw`: joins two, and answers with the
/// other one when either is empty.
pub fn Raw::combine(self : Raw, other : Raw) -> Raw {
  match (self, other) {
    (Empty, _) => other
    (_, Empty) => self
    _ => Cons(self, other)
  }
}

///|
pub fn Raw::is_empty(self : Raw) -> Bool {
  match self {
    Empty => true
    Str(s) => s == ""
    Cons(a, b) => a.is_empty() && b.is_empty()
  }
}

///|
pub fn Raw::write_to(self : Raw, buf : StringBuilder) -> Unit {
  match self {
    Empty => ()
    Str(s) => buf.write_string(s)
    Cons(a, b) => {
      a.write_to(buf)
      b.write_to(buf)
    }
  }
}

///|
pub fn Raw::to_text(self : Raw) -> String {
  let buf = StringBuilder()
  self.write_to(buf)
  buf.to_string()
}

///|
/// The nine raw-text properties a node can carry.
///
/// **The field order is the emission order**, and it is load-bearing: prefix,
/// inner prefix, raw, then either the children or `opaque_content`, then tail,
/// inner suffix, suffix. Anything that emits these in a different order
/// round-trips wrongly on exactly the inputs that have comments in the awkward
/// places, and on nothing else.
pub(all) struct Meta {
  /// Whitespace and comments before the term, belonging to whatever encloses
  /// it. The parser uses this only when the text cannot instead be a preceding
  /// term's suffix.
  mut prefix : Raw
  /// Like `prefix`, but sticking to the term rather than shifting left. The
  /// parser uses it for exactly one thing: the `@` before an at-form.
  mut inner_prefix : Raw
  /// The term's own text; for a compound, its opener.
  mut raw : Raw
  /// Stands in for the children's text, hiding them.
  mut opaque_content : Raw
  /// Supersedes `raw` and `opaque_content` both. Set by macro expansion
  /// downstream, never by the parser.
  mut opaque_raw : Raw
  /// Text after the children but belonging to the compound: its closer.
  mut tail : Raw
  /// Like `suffix`, but sticking to the term. The parser never sets it.
  mut inner_suffix : Raw
  /// Whitespace and comments after the term.
  mut suffix : Raw
  /// A span for a compound tag, which would otherwise only have the derived
  /// one its children imply.
  mut srcloc : @basic.Span?
}

///|
pub fn Meta::new() -> Meta {
  {
    prefix: Empty,
    inner_prefix: Empty,
    raw: Empty,
    opaque_content: Empty,
    opaque_raw: Empty,
    tail: Empty,
    inner_suffix: Empty,
    suffix: Empty,
    srcloc: None,
  }
}

///|
/// Whether anything at all is recorded here.
pub fn Meta::is_empty(self : Meta) -> Bool {
  self.prefix.is_empty() &&
  self.inner_prefix.is_empty() &&
  self.raw.is_empty() &&
  self.opaque_content.is_empty() &&
  self.opaque_raw.is_empty() &&
  self.tail.is_empty() &&
  self.inner_suffix.is_empty() &&
  self.suffix.is_empty()
}