///|
pub struct TriGParser {
  mut lenient : Bool
  mut base_iri : Iri?
  prefixes : Map[String, Iri]
} derive(Default)

///|
pub fn TriGParser::new() -> TriGParser {
  TriGParser::default()
}

///|
pub fn TriGParser::lenient(self : TriGParser) -> TriGParser {
  self.lenient = true
  self
}

///|
pub fn TriGParser::with_base_iri(
  self : TriGParser,
  base_iri : IriRef,
) -> Result[TriGParser, IriError] {
  let parsed_iri = if self.lenient {
    // 宽松模式:直接解析,不检查有效性
    IriRef::parse_unchecked(base_iri)
  } else {
    // 严格模式:检查解析结果
    match IriRef::parse(base_iri) {
      Ok(iri) => iri
      Err(e) => return Err(e)
    }
  }
  self.base_iri = Some(parsed_iri)
  Ok(self)
}

///|
pub fn TriGParser::with_prefix(
  self : TriGParser,
  prefix_name : String,
  prefix_iri : IriRef,
) -> Result[TriGParser, IriError] {
  let parsed_iri = if self.lenient {
    // 宽松模式:直接解析,不检查有效性
    IriRef::parse_unchecked(prefix_iri)
  } else {
    // 严格模式:检查解析结果
    match IriRef::parse(prefix_iri) {
      Ok(iri) => iri
      Err(e) => return Err(e)
    }
  }
  self.prefixes.set(prefix_name, parsed_iri)
  Ok(self)
}

///|
pub fn TriGParser::for_reader(
  self : TriGParser,
  reader : &Reader,
) -> ReaderTriGParser[RdfLexer] {
  { inner: self.low_level().parser.for_reader(reader) }
}

///|
pub fn TriGParser::for_async_reader(
  self : TriGParser,
  reader : &Reader,
) -> AsyncReaderTriGParser[RdfLexer] {
  { inner: self.low_level().parser.for_async_reader(reader) }
}

///|
pub fn TriGParser::for_slice(
  self : TriGParser,
  slice : Bytes,
) -> SliceTriGParser[TriGRecognizer] {
  let parser = TriGRecognizer::new_parser(
    slice.to_array(),
    true,
    true,
    self.lenient,
    self.base_iri,
    self.prefixes,
  )
  { inner: { parser, } }
}

///|
pub fn TriGParser::low_level(self : TriGParser) -> LowLevelTriGParser[RdfLexer] {
  {
    parser: TriGRecognizer::new_parser(
      [],
      false,
      true,
      self.lenient,
      self.base_iri,
      self.prefixes,
    ),
  }
}

///|
pub struct ReaderTriGParser[RL] {
  inner : ReaderIterator[RL, TriGRecognizer]
}

///|
pub fn[RL] ReaderTriGParser::prefixes(
  self : ReaderTriGParser[RL],
) -> TriGPrefixesIter {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) => { inner: ctx.prefixes.iter() }
    _ => { inner: [].iter() }
  }
}

///|
pub fn[RL] ReaderTriGParser::base_iri(self : ReaderTriGParser[RL]) -> String? {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      ctx.lexer_options.base_iri.map(fn(iri) { iri.to_string() })
    _ => None
  }
}

///|
pub struct AsyncReaderTriGParser[RL] {
  inner : AsyncReaderIterator[RL, TriGRecognizer]
}

///|
pub async fn[RL : TokenRecognizer] AsyncReaderTriGParser::next(
  self : AsyncReaderTriGParser[RL],
) -> Result[Quad, TurtleError]? {
  self.inner
  .next()
  .map(fn(res) {
    res
    .map(fn(lex_output) {
      match lex_output {
        RdfOut::Triple(triple) =>
          Quad::Quad(
            triple.subject,
            triple.predicate,
            triple.object,
            GraphName::default(),
          )
        RdfOut::Quad(quad) => quad
        RdfOut::N3Quad(n3quad) =>
          match n3quad.predicate.to_node() {
            // 修复:使用 NamedNode(_) 忽略内部字段,消除警告
            NamedNode(node) =>
              Quad::Quad(
                n3quad.subject.to_node(),
                node,
                n3quad.object.to_term(),
                n3quad.graph_name,
              )
            // 建议:添加默认分支以处理其他可能的节点类型,避免运行时 panic 或未定义行为
            _ =>
              Quad::Quad(
                n3quad.subject.to_node(),
                NamedNode::default(),
                n3quad.object.to_term(),
                n3quad.graph_name,
              )
          }
      }
    })
    .map_err(fn(e) { TurtleError::InvalidCharacter(e.to_string()) }) // 根据实际错误类型调整
  })
}

///|
pub fn[RL] AsyncReaderTriGParser::prefixes(
  self : AsyncReaderTriGParser[RL],
) -> TriGPrefixesIter {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      // 假设 ctx.prefixes 是 Map[String, IriRef] 或类似可迭代结构
      { inner: ctx.prefixes.iter() }
    _ => { inner: [].iter() }
  }
}

///|
pub fn[RL] AsyncReaderTriGParser::base_iri(
  self : AsyncReaderTriGParser[RL],
) -> String? {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      ctx.lexer_options.base_iri.map(fn(iri) { iri.to_string() })
    _ => None
  }
}

///|
pub struct SliceTriGParser[RL] {
  inner : SliceIterator[RdfLexer, RL]
}

///|
pub fn SliceTriGParser::prefixes(
  self : SliceTriGParser[RdfLexer],
) -> TriGPrefixesIter {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      // 假设 ctx.prefixes 是 Map[String, IriRef] 或类似结构
      { inner: ctx.prefixes.iter() }
    _ =>
      // 返回空迭代器,需确保类型匹配 Iter2[String, IriRef]
      // 这里假设存在一个空的 Map 或数组可以生成匹配的 Iter2
      { inner: [].iter() }
  }
}

///|
pub fn SliceTriGParser::base_iri(self : SliceTriGParser[RdfLexer]) -> String? {
  match self.inner.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      ctx.lexer_options.base_iri.map(fn(iri) { iri.to_string() })
    _ => None
  }
}

///|
pub struct LowLevelTriGParser[RL] {
  parser : Parser[RL, TriGRecognizer]
}

///|
pub fn[RL] LowLevelTriGParser::extend_from_slice(
  self : LowLevelTriGParser[RL],
  other : Bytes,
) -> Unit {
  self.parser.extend_from_slice(other)
}

///|
pub fn[RL] LowLevelTriGParser::end(self : LowLevelTriGParser[RL]) -> Unit {
  self.parser.end()
}

///|
pub fn[RL] LowLevelTriGParser::is_end(self : LowLevelTriGParser[RL]) -> Bool {
  self.parser.is_end()
}

///|
pub fn[RL : TokenRecognizer] LowLevelTriGParser::parse_next(
  self : LowLevelTriGParser[RL],
) -> Result[Quad, TurtleError]? {
  self.parser
  .parse_next()
  .map(fn(res) {
    res
    .map(fn(lex_output) {
      match lex_output {
        RdfOut::Triple(triple) =>
          Quad::Quad(
            triple.subject,
            triple.predicate,
            triple.object,
            GraphName::default(),
          )
        RdfOut::Quad(quad) => quad
        RdfOut::N3Quad(n3quad) =>
          match n3quad.predicate.to_node() {
            // 修复:使用 NamedNode(_) 忽略内部字段,消除警告
            NamedNode(node) =>
              Quad::Quad(
                n3quad.subject.to_node(),
                node,
                n3quad.object.to_term(),
                n3quad.graph_name,
              )
            // 建议:添加默认分支以处理其他可能的节点类型,避免运行时 panic 或未定义行为
            _ =>
              Quad::Quad(
                n3quad.subject.to_node(),
                NamedNode::default(),
                n3quad.object.to_term(),
                n3quad.graph_name,
              )
          }
      }
    })
    .map_err(fn(e) { TurtleError::InvalidCharacter(e.to_string()) }) // 根据实际错误类型调整
  })
}

///|
pub fn[RL] LowLevelTriGParser::prefixes(
  self : LowLevelTriGParser[RL],
) -> TriGPrefixesIter {
  match self.parser.context {
    RdfContext::TriGRecognizerContext(ctx) => { inner: ctx.prefixes.iter() }
    _ =>
      // 假设存在一个空的 Map 或数组可以生成匹配的 Iter2[String, IriRef]
      { inner: {}.iter() }
  }
}

///|
pub fn[RL] LowLevelTriGParser::base_iri(
  self : LowLevelTriGParser[RL],
) -> String? {
  match self.parser.context {
    RdfContext::TriGRecognizerContext(ctx) =>
      ctx.lexer_options.base_iri.map(fn(iri) { iri.to_string() })
    _ => None
  }
}

///|
pub struct TriGPrefixesIter {
  inner : Iter2[String, Iri]
}

///|
pub struct TriGSerializer {
  mut base_iri : Iri?
  prefixes : Map[String, Iri]
} derive(Default)

///|
pub fn TriGSerializer::new() -> TriGSerializer {
  { base_iri: None, prefixes: {} }
}

///|
pub fn TriGSerializer::with_prefix(
  self : TriGSerializer,
  prefix_name : String,
  prefix_iri : IriRef,
) -> Result[TriGSerializer, IriError] {
  match IriRef::parse(prefix_iri) {
    Ok(parsed_iri) => {
      self.prefixes.set(prefix_name, parsed_iri)
      Ok(self)
    }
    Err(e) => Err(e)
  }
}

///|
pub fn TriGSerializer::with_base_iri(
  self : TriGSerializer,
  base_iri : IriRef,
) -> Result[TriGSerializer, IriError] {
  match IriRef::parse(base_iri) {
    Ok(parsed_iri) => {
      self.base_iri = Some(parsed_iri)
      Ok(self)
    }
    Err(e) => Err(e)
  }
}

///|
pub fn[W] TriGSerializer::for_writer(
  self : TriGSerializer,
  writer : W,
) -> WriterTriGSerializer[W] {
  { writer, low_level_writer: self.low_level() }
}

///|
pub fn[W] TriGSerializer::for_async_writer(
  self : TriGSerializer,
  writer : BufferedWriter[W],
) -> AsyncWriterTriGSerializer[W] {
  { buffer_writer: writer, low_level_writer: self.low_level() }
}

///|
pub fn TriGSerializer::low_level(
  self : TriGSerializer,
) -> LowLevelTriGSerializer {
  let sorted_prefixes = sort_prefixes(self.prefixes)
  {
    prefixes: sorted_prefixes,
    base_iri: self.base_iri,
    prelude_written: false,
    current_graph_name: GraphName::DefaultGraph,
    current_subject_predicate: None,
  }
}

///|
pub struct WriterTriGSerializer[W] {
  writer : W
  low_level_writer : LowLevelTriGSerializer
}

///|
pub fn[W] WriterTriGSerializer::serialize_quad(
  self : WriterTriGSerializer[W],
  q : Quad,
) -> Result[String, Unit] {
  self.low_level_writer.serialize_quad(q)
}

///|
pub fn[W] WriterTriGSerializer::finish(self : WriterTriGSerializer[W]) -> W {
  // self.low_level_writer.finish(self.writer)
  self.writer
}

///|
pub struct AsyncWriterTriGSerializer[W] {
  buffer_writer : BufferedWriter[W]
  low_level_writer : LowLevelTriGSerializer
}

///|
pub async fn[W : Writer] AsyncWriterTriGSerializer::serialize_quad(
  self : AsyncWriterTriGSerializer[W],
  q : Quad,
) -> Result[AsyncWriterTriGSerializer[W], SerializationError] {
  let serialized_str = match self.low_level_writer.serialize_quad(q) {
    Ok(serialized_str) => serialized_str
    Err(_) =>
      return Err(SerializationError::FormatError("Serialization failed"))
  }
  let data_bytes = @utf8.encode(serialized_str)
  // let buffer_writer =  self.buffer_writer.write(serialized_str);
  let buffer_writer = self.buffer_writer
  let mut written = 0

  while written < data_bytes.length() {
    let n = buffer_writer.write_once(
      data_bytes,
      offset=written,
      len=data_bytes.length() - written,
    )
    if n == 0 {
      buffer_writer.flush()
      continue
    }
    written += n
  }

  Ok({ buffer_writer, low_level_writer: self.low_level_writer })
}

///|
pub async fn[W : Writer] AsyncWriterTriGSerializer::finish(
  self : AsyncWriterTriGSerializer[W],
) -> Result[BufferedWriter[W], Unit] {
  let buffer_writer = self.buffer_writer
  buffer_writer.flush()
  Ok(buffer_writer)
}

///|
pub struct LowLevelTriGSerializer {
  prefixes : Array[(String, String)]
  base_iri : Iri?
  mut prelude_written : Bool
  mut current_graph_name : GraphName
  mut current_subject_predicate : (NamedOrBlankNode, NamedNode)?
}

///|
pub fn LowLevelTriGSerializer::serialize_quad(
  self : LowLevelTriGSerializer,
  q : Quad,
) -> Result[String, Unit] {
  let writer = StringBuilder::new()

  if !self.prelude_written {
    self.prelude_written = true
    if self.base_iri is Some(base_iri) {
      writer.write("@base <\{base_iri}> .")
    }
    for _item in self.prefixes {
      let (prefix_name, prefix_iri) = _item
      // writer.write("@prefix \{prefix_name}: <{}> .")
      writer.write("@prefix ")
      writer.write(prefix_name)
      writer.write(": <")
      match self.base_iri {
        Some(base) => writer.write(relative_iri(prefix_iri, base))
        None => writer.write(prefix_iri)
      }
      writer.write("> .")
    }
  }
  // let q = q.into_owned()
  if q.graph_name == self.current_graph_name {
    if self.current_subject_predicate
      is Some((current_subject, current_predicate)) {
      if q.subject == current_subject {
        if q.predicate == current_predicate {
          self.current_subject_predicate = Some(
            (current_subject, current_predicate),
          )
          // writer.write(",{}",self.term (q.object))
          writer.write(",")
          writer.write(self.term(q.object).to_string())
          Ok(writer.to_string())
        } else {
          self.current_subject_predicate = Some((current_subject, q.predicate))
          writer.write(" ;")
          if !self.current_graph_name.is_default_graph() {
            writer.write("\t")
          }
          // writer.write("\t{} {}",self.predicate (q.predicate),self.term (q.object))
          writer.write("\t")
          writer.write(self.predicate(q.predicate).to_string())
          writer.write(" ")
          writer.write(self.term(q.object).to_string())
          Ok(writer.to_string())
        }
      } else {
        self.current_subject_predicate = Some((q.subject, q.predicate))
        writer.write(" .")
        if !self.current_graph_name.is_default_graph() {
          writer.write("\t")
        }
        // writer.write("{} {} {}",self.term (q.subject),self.predicate (q.predicate),self.term (q.object))
        writer.write(self.term(q.subject.as_term()).to_string())
        writer.write(" ")
        writer.write(self.predicate(q.predicate).to_string())
        writer.write(" ")
        writer.write(self.term(q.object).to_string())
        Ok(writer.to_string())
      }
    } else {
      self.current_subject_predicate = Some((q.subject, q.predicate))
      if !self.current_graph_name.is_default_graph() {
        writer.write("\t")
      }
      // writer.write("{} {} {}",self.term (q.subject),self.predicate (q.predicate),self.term (q.object))
      writer.write(self.term(q.subject.as_term()).to_string())
      writer.write(" ")
      writer.write(self.predicate(q.predicate).to_string())
      writer.write(" ")
      writer.write(self.term(q.object).to_string())
      Ok(writer.to_string())
    }
  } else {
    if self.current_subject_predicate is Some(_) {
      writer.write(" .")
    }
    if !self.current_graph_name.is_default_graph() {
      writer.write("}}")
    }
    self.current_graph_name = q.graph_name.into_owned()
    self.current_subject_predicate = Some((q.subject, q.predicate))
    match self.current_graph_name {
      GraphName::NamedNode(g) => {
        // writer.write("{} {{",self.term (g))
        writer.write(self.term(Term::NamedNode(g)).to_string())
        writer.write(" {{")
        writer.write("\t")
      }
      GraphName::BlankNode(g) => {
        // writer.write("{} {{",self.term (g))
        writer.write(self.term(Term::BlankNode(g)).to_string())
        writer.write(" {")
        writer.write("\t")
      }
      GraphName::DefaultGraph => ()
    }
    // writer.write("{} {} {}",self.term (q.subject),self.predicate (q.predicate),self.term (q.object))
    writer.write(self.term(q.subject.as_term()).to_string())
    writer.write(" ")
    writer.write(self.predicate(q.predicate).to_string())
    writer.write(" ")
    writer.write(self.term(q.object).to_string())
    Ok(writer.to_string())
  }
}

///|
fn LowLevelTriGSerializer::predicate(
  self : LowLevelTriGSerializer,
  named_node : NamedNode,
) -> TurtlePredicate {
  {
    named_node: named_node.as_ref(),
    prefixes: self.prefixes,
    base_iri: self.base_iri,
  }
}

///|
fn LowLevelTriGSerializer::term(
  self : LowLevelTriGSerializer,
  term : Term,
) -> TurtleTerm {
  TurtleTerm::{ term, prefixes: self.prefixes, base_iri: self.base_iri }
}

///|
pub async fn[W : Writer] LowLevelTriGSerializer::finish(
  self : LowLevelTriGSerializer,
  writer : BufferedWriter[W],
) -> Result[Unit, Unit] {
  if self.current_subject_predicate is Some(_) {
    writer.write(" .")
  }
  if !self.current_graph_name.is_default_graph() {
    writer.write("}}")
  }
  Ok(())
}

///|
priv struct TurtlePredicate {
  named_node : NamedNodeRef
  prefixes : Array[(String, String)]
  base_iri : Iri?
}

///|
impl Show for TurtlePredicate with fn output(
  self : TurtlePredicate,
  f : &Logger,
) -> Unit {
  if self.named_node == lwTYPE {
    f.write_string("a")
  } else {
    f.write_string(
      {
        term: Term::NamedNode(self.named_node.into_owned()),
        prefixes: self.prefixes,
        base_iri: self.base_iri,
      }.to_string(),
    )
  }
}

///|
priv struct TurtleTerm {
  term : Term
  prefixes : Array[(String, String)]
  base_iri : Iri?
}

///|
impl Show for TurtleTerm with fn output(self : TurtleTerm, logger : &Logger) -> Unit {
  match self.term {
    Term::NamedNode(v) => {
      for _item in self.prefixes {
        let (prefix_name, prefix_iri) = _item
        if v.to_string().strip_prefix(prefix_iri) is Some(local_name) {
          if local_name.is_empty() {
            logger.write_string("\{prefix_name}:")
          } else if escape_local_name(local_name) is Some(escaped_local_name) {
            logger.write_string("\{prefix_name}:\{escaped_local_name}")
          }
        }
      }
      let iri_str = v.to_string()
      match self.base_iri {
        Some(base) =>
          // 调用 relative_iri,它现在接受非空的 Iri
          logger.write_string("<\{relative_iri(iri_str, base)}>")
        None =>
          // 没有 base_iri,直接输出绝对 IRI
          logger.write_string("<\{iri_str}>")
      }
    }
    Term::BlankNode(v) => logger.write_string("\{v}")
    Term::Literal(v) => {
      let value = v.value()
      let dt = v.datatype()
      let is_plain = dt == lwSTRING ||
        dt == lwLANG_STRING ||
        dt == lwDIR_LANG_STRING
      // v.datatype() is (lwSTRING | lwLANG_STRING)
      if is_plain {
        logger.write_string("\{v}")
      } else {
        let inline = if dt == lwBOOLEAN {
          is_turtle_boolean(value)
        } else if dt == lwINTEGER {
          is_turtle_integer(value)
        } else if dt == lwDECIMAL {
          is_turtle_decimal(value)
        } else if dt == lwDOUBLE {
          is_turtle_double(value)
        } else {
          false
        }
        if inline {
          logger.write_string(value)
        } else {
          let literal = LiteralRef::new_simple_literal(v.value()).to_string()
          let turtle = TurtleTerm::{
            term: Term::NamedNode(dt.into_owned()),
            prefixes: self.prefixes,
            base_iri: self.base_iri,
          }.to_string()
          logger.write_string("\{literal}")
          logger.write_string("^^")
          logger.write_string("\{turtle}")
        }
      }
    }
    Term::Triple(t) => {
      //  logger.write_string("<<( {} {} {} )>>")
      logger.write_string("<<( ")
      logger.write_string(
        {
          term: t.subject.as_term(),
          prefixes: self.prefixes,
          base_iri: self.base_iri,
        }.to_string(),
      )
      logger.write_string(" ")
      logger.write_string(
        {
          term: Term::NamedNode(t.predicate),
          prefixes: self.prefixes,
          base_iri: self.base_iri,
        }.to_string(),
      )
      logger.write_string(" ")
      logger.write_string(
        { term: t.object, prefixes: self.prefixes, base_iri: self.base_iri }.to_string(),
      )
      logger.write_string(" )>>")
    }
  }
}

///|
fn relative_iri(iri : String, base_iri : Iri) -> String {
  // 尝试解析 base_iri,如果失败则直接使用原始 iri
  match IriRef::parse(base_iri.as_ref()) {
    Ok(parsed_base) =>
      match parsed_base.as_ref().resolve(iri) {
        Ok(resolved) => resolved.into_string()
        Err(_) => iri // 解析相对路径失败,返回原值
      }
    Err(_) => iri // Base IRI 本身无效,返回原值
  }
}

///|
fn is_turtle_boolean(value : StringView) -> Bool {
  value is ("true" | "false")
}

///|
fn is_turtle_integer(value : StringView) -> Bool {
  let mut value = @utf8.encode(value).to_array()[:]
  if value.strip_prefix(Bytes::to_array(b"+")) is Some(v) {
    value = v
  } else if value.strip_prefix(Bytes::to_array(b"-")) is Some(v) {
    value = v
  }
  !value.is_empty() && value.all(a => Byte::to_char(a).is_ascii_digit())
}

///|
fn is_turtle_decimal(value : StringView) -> Bool {
  let mut value = @utf8.encode(value).to_array()[:]
  if value.strip_prefix(Bytes::to_array(b"+")) is Some(v) {
    value = v
  } else if value.strip_prefix(Bytes::to_array(b"-")) is Some(v) {
    value = v
  }
  while value.get(0) is Some(_) &&
        value.all(a => Byte::to_char(a).is_ascii_digit()) {
    value = value[1:]
  }
  match value.strip_prefix(Bytes::to_array(b".")) {
    Some(v) => {
      value = v
      !value.is_empty() && value.all(a => Byte::to_char(a).is_ascii_digit())
    }
    None => false
  }
}

///|
fn is_turtle_double(value : StringView) -> Bool {
  let mut value = @utf8.encode(value).to_array()[:]

  if value.strip_prefix(Bytes::to_array(b"+")) is Some(v) {
    value = v
  } else if value.strip_prefix(Bytes::to_array(b"-")) is Some(v) {
    value = v
  }
  let mut with_before = false
  while value.get(0) is Some(a) && Byte::to_char(a).is_ascii_digit() {
    value = value[1:]
    with_before = true
  }
  let mut with_after = false
  if value.strip_prefix(Bytes::to_array(b".")) is Some(v) {
    value = v
    while value.get(0) is Some(a) && Byte::to_char(a).is_ascii_digit() {
      value = value[1:]
      with_after = true
    }
  }
  if value.strip_prefix(Bytes::to_array(b"e")) is Some(v) {
    value = v
  } else if value.strip_prefix(Bytes::to_array(b"E")) is Some(v) {
    value = v
  } else {
    return false
  }
  if value.strip_prefix(Bytes::to_array(b"+")) is Some(v) {
    value = v
  } else if value.strip_prefix(Bytes::to_array(b"-")) is Some(v) {
    value = v
  }
  (with_before || with_after) && !value.is_empty()
}

///|
fn escape_local_name(value : StringView) -> String? {
  let output = StringBuilder::new(size_hint=value.length())
  // let mut chars = value.iter()
  let first = match value.get_char(0) {
    Some(c) => c
    None => return None // 如果字符串为空,直接返回 None
  }
  if RdfLexer::is_possible_pn_chars_u(first) || first == ':' || first == '.' {
    output.write_char(first)
  } else if can_be_escaped_in_local_name(first) {
    output.write_char('\'')
    output.write_char(first)
  } else {
    return None
  }
  for c in value {
    if RdfLexer::is_possible_pn_chars(c) ||
      c == ':' ||
      (c == '.' && !value.is_empty()) {
      output.write_char(c)
    } else if can_be_escaped_in_local_name(c) {
      output.write_char('\'')
      output.write_char(c)
    } else {
      return None
    }
  }
  Some(output.to_string())
}

///|
fn can_be_escaped_in_local_name(c : Char) -> Bool {
  c
  is ('_'
  | '~'
  | '.'
  | '-'
  | '!'
  | '$'
  | '&'
  | '\''
  | '('
  | ')'
  | '*'
  | '+'
  | ','
  | ';'
  | '='
  | '/'
  | '?'
  | '#'
  | '@'
  | '%')
}