///|
/// Everything that starts with `#`.
///
/// The order here is the order of decreasing length, because the reference's
/// lexer takes the longest match: `#//` before `#/`, `#true` before `#`.
fn Scanner::scan_hash(self : Scanner, start : @basic.Pos, from : Int) -> Token {
  if self.has(from, "#//") {
    return self.finish(start, from + 3, GroupComment)
  }
  if self.has(from, "#\"") {
    return self.scan_byte_string(start, from)
  }
  if self.has(from, "#{") {
    return self.scan_sexp_escape(start, from, keyword=false)
  }
  // `#!` opens a script line, but only when followed by a space or `/`.
  // Anything else after `#!` is an error, and the reference makes the error
  // token stop at the first whitespace.
  if self.has(from, "#!") {
    match self.at(from + 2) {
      Some(' ') | Some('/') =>
        return self.finish(start, self.scan_script(from), Comment)
      _ => {
        let mut i = from + 2
        while i < self.src.length() {
          match self.at(i) {
            Some(c) if !@unicode.is_whitespace(c) => i = self.step(i)
            _ => break
          }
        }
        return self.finish(start, i, Fail(ReadError))
      }
    }
  }
  // The constant words. Each is subject to the delimiter rule, which the
  // `bad-hash` tail below enforces by reaching further than the word does.
  let word = self.hash_word(from)
  match word {
    Some((e, datum)) =>
      if self.hash_tail(from) <= e {
        return self.finish(start, e, Literal(datum), mode=Continuing)
      }
    None => ()
  }
  match self.scan_identifier(from) {
    Some(e) => return self.finish(start, e, Identifier, mode=Continuing)
    None => ()
  }
  match self.at(from + 1) {
    Some(c) if is_escopchar(c) => {
      let e = self.absorb_slash(from + 2)
      let text = self.src.clamped_view(start=from, end=e).to_owned()
      return if (self.variant.allow_operator)(text) {
        self.finish(start, e, Operator)
      } else {
        self.finish(start, e, Fail(ReadError))
      }
    }
    _ => ()
  }
  // `bad-hash`: `#` and any alphanumeric run after it.
  self.finish(start, self.hash_tail(from), Fail(ReadError))
}

///|
/// One of the `#` constants, if the source has it here.
fn Scanner::hash_word(self : Scanner, from : Int) -> (Int, @sexp.Datum)? {
  if self.has(from, "#true") {
    Some((from + 5, Bool_(true)))
  } else if self.has(from, "#false") {
    Some((from + 6, Bool_(false)))
  } else if self.has(from, "#void") {
    Some((from + 5, Void))
  } else if self.has(from, "#neginf") {
    Some((from + 7, Flo(@double.neg_infinity)))
  } else if self.has(from, "#inf") {
    Some((from + 4, Flo(@double.infinity)))
  } else if self.has(from, "#nan") {
    Some((from + 4, Flo(@double.not_a_number)))
  } else {
    None
  }
}

///|
/// How far `#` plus alphanumerics reaches — the extent of a `bad-hash`, and the
/// delimiter check for the constants.
fn Scanner::hash_tail(self : Scanner, from : Int) -> Int {
  let mut i = from + 1
  while i < self.src.length() {
    match self.at(i) {
      Some(c) if is_non_delim(c) => i = self.step(i)
      _ => break
    }
  }
  i
}

///|
/// `#!` to the end of the line, with a trailing `\` continuing onto the next.
fn Scanner::scan_script(self : Scanner, from : Int) -> Int {
  let mut i = from + 2
  while i < self.src.length() {
    match self.at(i) {
      Some('\\') =>
        match self.at(i + 1) {
          Some('\n') => i = i + 2
          Some('\r') => i = if self.has(i + 1, "\r\n") { i + 3 } else { i + 2 }
          _ => i = self.step(i)
        }
      Some('\n') | Some('\r') => break
      _ => i = self.step(i)
    }
  }
  i
}