///|
fn decode_cell(token : String, sentinel : Double) -> Double? raise WellError {
  let value = parse_number(token)
  if value == sentinel {
    None
  } else {
    Some(value)
  }
}

///|
/// Decode LAS2 ASCII. Wrapped records must begin with a depth-only line.
pub fn parse(text : String) -> Log raise WellError {
  let h = read_header(text)
  let rows : Array[Array[Double?]] = []
  let mut pending : Array[Double?] = []
  for line in h.data {
    let tokens = words(line.text)
    if h.wrapped {
      if pending.length() == 0 && h.curves.length() > 1 && tokens.length() != 1 {
        fail(
          "wrapped record must start with depth alone at line " +
          line.number.to_string(),
        )
      }
      if pending.length() + tokens.length() > h.curves.length() {
        fail("wrapped record overflow at line " + line.number.to_string())
      }
      for token in tokens {
        pending.push(decode_cell(token, h.null_value))
      }
      if pending.length() == h.curves.length() {
        rows.push(pending)
        pending = []
      }
    } else {
      if tokens.length() != h.curves.length() {
        fail(
          "ASCII width differs from Curve section at line " +
          line.number.to_string(),
        )
      }
      let row : Array[Double?] = []
      for token in tokens {
        row.push(decode_cell(token, h.null_value))
      }
      rows.push(row)
    }
    if rows.length() > 1000000 {
      fail("row limit is 1000000")
    }
  }
  if pending.length() != 0 {
    fail("incomplete wrapped record at end of input")
  }
  let log = make_log(
    h.curves,
    rows,
    headers=h.well,
    parameters=h.parameters,
    other=h.other,
    null_value=h.null_value,
    version_headers=h.version_headers,
    extra_sections=h.extra_sections,
  )
  if rows.length() > 0 {
    let start = parse_number(header_value(h.well, "STRT").value)
    let declared_step = parse_number(header_value(h.well, "STEP").value)
    if declared_step != 0.0 {
      for i in 1.. 1.0e-8 * (1.0 + declared_step.abs()) {
          fail("STEP disagrees with ASCII depth intervals")
        }
      }
    }
    let stop = parse_number(header_value(h.well, "STOP").value)
    let first = rows[0][0].unwrap()
    let last = rows[rows.length() - 1][0].unwrap()
    // Scale before summing so finite endpoint magnitudes cannot disable checks.
    let tolerance = 1.0e-8 + 1.0e-8 * first.abs() + 1.0e-8 * last.abs()
    if (start - first).abs() > tolerance || (stop - last).abs() > tolerance {
      fail("STRT/STOP disagree with ASCII depth endpoints")
    }
  }
  log
}