///|
fn Parser::error_at(self : Parser, code : String, pos : Int) -> Unit {
  self.errors.push(self.make_error_at(code, pos))
}

///|
fn Parser::make_error_at(
  self : Parser,
  code : String,
  pos : Int,
) -> @core.ParseError {
  let (line, column) = line_col_at(self.input, pos)
  @core.ParseError::new(
    code,
    line~,
    column~,
    category=@core.parser_error_category(code),
  )
}

///|
fn Parser::report_current_noncharacter(self : Parser) -> Unit {
  match self.current() {
    Some(ch) if is_xml_noncharacter(ch) =>
      self.error_at("noncharacter-in-input-stream", self.pos)
    _ => ()
  }
}

///|
fn view_starts_with_at(
  input : StringView,
  pos : Int,
  prefix : StringView,
) -> Bool {
  @syn.view_starts_with_at(input, pos, prefix)
}

///|
fn find_markup_close(input : StringView, start : Int) -> Int? {
  let mut pos = start
  while pos < input.length() {
    match input.get_char(pos) {
      Some('>') => return Some(pos)
      Some(ch) => pos += ch.utf16_len()
      None => break
    }
  }
  None
}

///|
fn find_comment_close(input : StringView, start : Int) -> Int? {
  let scan = @tok.scan_comment_data(input, start + "