///|
pub(all) enum RdfState {
  NQuadsState(NQuadsState)
} derive(Eq, Hash)

///|
pub impl Show for RdfState with fn output(self : RdfState, logger : &Logger) -> Unit {
  match self {
    RdfState::NQuadsState(s) => logger.write(s)
  }
}

///|
pub(all) enum RdfFeature {
  RelativeIri
  Numbers
  Prefixes
  Variables
  NonAsciiIri
  StringEscapes
  LangTags
  LongStrings // ★ 新增
  PunctuationList // ★ 逗号和分号
}

///|
fn allows_feature(mode : RdfLexerMode, feature : RdfFeature) -> Bool {
  match feature {
    RdfFeature::RelativeIri => mode != RdfLexerMode::NTriples
    RdfFeature::Numbers => mode != RdfLexerMode::NTriples
    RdfFeature::Prefixes =>
      mode == RdfLexerMode::Turtle || mode == RdfLexerMode::N3
    RdfFeature::Variables => mode == RdfLexerMode::N3
    RdfFeature::NonAsciiIri =>
      mode == RdfLexerMode::Turtle || mode == RdfLexerMode::N3
    RdfFeature::StringEscapes => true
    RdfFeature::LangTags => mode != RdfLexerMode::NTriples
    RdfFeature::LongStrings => mode != RdfLexerMode::NTriples //  NTriples 不允许
    RdfFeature::PunctuationList => mode != RdfLexerMode::NTriples // 
  }
}

///|
pub impl StateWrapper for RdfState with fn as_state_enum(self) -> RdfState {
  self
}

///|
pub(all) enum RdfLexerMode {
  NTriples
  Turtle
  N3
} derive(Eq)

///|
pub(all) struct RdfLexer {
  mode : RdfLexerMode
  lenient : Bool
  debug_logger : &DebugLogger
}

///|
pub fn RdfLexer::default() -> RdfLexer {
  RdfLexer::RdfLexer(RdfLexerMode::NTriples, true, [])
}

///|
pub fn RdfLexer::RdfLexer(
  mode : RdfLexerMode,
  lenient : Bool,
  _data_buffer : ArrayView[Byte],
  debug_logger? : &DebugLogger = make_mute_logger(),
) -> RdfLexer {
  { mode, lenient, debug_logger }
}

///|
/// 字符分类
pub(all) enum CharClass {
  Other
  Space
  Newline
  LAngle // <
  RAngle // >
  Colon // :
  Semicolon // ;
  Period // .
  Comma // ,
  LParen // (
  RParen // )
  LBracket // [
  RBracket // ]
  LBrace // {
  RBrace // }
  Quote // "
  TripleQuote
  At // @
  QuestionMark // ?
  Plus // +
  Minus // -
  Underscore // _
  Percent // %
  Hash // #
  Slash // /
  Backslash // \\
  Star // *
  Eq // =
  Less // <
  Greater // >
  Caret // ^
  Pipe // |
  Tilde // ~
  Exclamation // !
  Dollar // $
  Ampersand // &
  Apostrophe // '
  // TripleApostrophe // '''
  // 多字符标点
  LtLt // <<
  GtGt // >>
  CaretCaret // ^^
  LBracePipe // {|
  PipeRBrace // |}
  LtLtLParen // <<(
  RParenGtGt // )>>
  LtMinus // <-
  EqGt // =>
  LtEq // <=
  LtLtRParen // <<(
  ColonColon // ::
  ColonSlash // :/ (用于 IRI scheme)
  Digit
  LowerU
  UpperU
} derive(Debug, Eq, Hash)

///|
fn CharClass::to_index(self : Self) -> Int {
  match self {
    CharClass::Other => 0
    CharClass::Space => 1
    CharClass::Newline => 2
    CharClass::LAngle => 3
    CharClass::RAngle => 4
    CharClass::Colon => 5
    CharClass::Semicolon => 6
    CharClass::Period => 7
    CharClass::Comma => 8
    CharClass::LParen => 9
    CharClass::RParen => 10
    CharClass::LBracket => 11
    CharClass::RBracket => 12
    CharClass::LBrace => 13
    CharClass::RBrace => 14
    CharClass::Quote => 15
    CharClass::TripleQuote => 16
    CharClass::At => 17
    CharClass::QuestionMark => 18
    CharClass::Plus => 19
    CharClass::Minus => 20
    CharClass::Underscore => 21
    CharClass::Percent => 22
    CharClass::Hash => 23
    CharClass::Slash => 24
    CharClass::Backslash => 25
    CharClass::Star => 26
    CharClass::Eq => 27
    CharClass::Less => 28
    CharClass::Greater => 29
    CharClass::Caret => 30
    CharClass::Pipe => 31
    CharClass::Tilde => 32
    CharClass::Exclamation => 33
    CharClass::Dollar => 34
    CharClass::Ampersand => 35
    CharClass::Apostrophe => 36
    CharClass::LtLt => 37
    CharClass::GtGt => 38
    CharClass::CaretCaret => 39
    CharClass::LBracePipe => 40
    CharClass::PipeRBrace => 41
    CharClass::LtLtLParen => 42
    CharClass::RParenGtGt => 43
    CharClass::LtMinus => 44
    CharClass::EqGt => 45
    CharClass::LtEq => 46
    CharClass::LtLtRParen => 47
    CharClass::ColonColon => 48
    CharClass::ColonSlash => 49
    CharClass::Digit => 50
    CharClass::LowerU => 51
    CharClass::UpperU => 52
  }
}

///|
pub impl Show for CharClass with fn output(self : CharClass, logger : &Logger) -> Unit {
  match self {
    CharClass::Other => logger.write("Other")
    CharClass::Space => logger.write("Space")
    CharClass::Newline => logger.write("Newline")
    CharClass::LAngle => logger.write("LAngle")
    CharClass::RAngle => logger.write("RAngle")
    CharClass::Colon => logger.write("Colon")
    CharClass::Semicolon => logger.write("Semicolon")
    CharClass::Period => logger.write("Period")
    CharClass::Comma => logger.write("Comma")
    CharClass::LParen => logger.write("LParen")
    CharClass::RParen => logger.write("RParen")
    CharClass::LBracket => logger.write("LBracket")
    CharClass::RBracket => logger.write("RBracket")
    CharClass::LBrace => logger.write("LBrace")
    CharClass::RBrace => logger.write("RBrace")
    CharClass::Quote => logger.write("Quote")
    CharClass::TripleQuote => logger.write("TripleQuote")
    CharClass::At => logger.write("At")
    CharClass::QuestionMark => logger.write("QuestionMark")
    CharClass::Plus => logger.write("Plus")
    CharClass::Minus => logger.write("Minus")
    CharClass::Underscore => logger.write("Underscore")
    CharClass::Percent => logger.write("Percent")
    CharClass::Hash => logger.write("Hash")
    CharClass::Slash => logger.write("Slash")
    CharClass::Backslash => logger.write("Backslash")
    CharClass::Star => logger.write("Star")
    CharClass::Eq => logger.write("Eq")
    CharClass::Less => logger.write("Less")
    CharClass::Greater => logger.write("Greater")
    CharClass::Caret => logger.write("Caret")
    CharClass::Pipe => logger.write("Pipe")
    CharClass::Tilde => logger.write("Tilde")
    CharClass::Exclamation => logger.write("Exclamation")
    CharClass::Dollar => logger.write("Dollar")
    CharClass::Ampersand => logger.write("Ampersand")
    CharClass::Apostrophe => logger.write("Apostrophe")
    // CharClass::TripleApostrophe => logger.write("TripleApostrophe")
    CharClass::LtLt => logger.write("LtLt")
    CharClass::GtGt => logger.write("GtGt")
    CharClass::LtMinus => logger.write("LtMinus")
    CharClass::EqGt => logger.write("EqGt")
    CharClass::LtLtLParen => logger.write("LtLtLParen")
    CharClass::LtLtRParen => logger.write("LtLtRParen")
    CharClass::CaretCaret => logger.write("CaretCaret")
    CharClass::LBracePipe => logger.write("LBracePipe")
    CharClass::ColonColon => logger.write("ColonColon")
    CharClass::ColonSlash => logger.write("ColonSlash")
    CharClass::PipeRBrace => logger.write("PipeRBrace")
    CharClass::RParenGtGt => logger.write("RParenGtGt")
    CharClass::LtEq => logger.write("LtEq")
    CharClass::Digit => logger.write("Digit")
    CharClass::LowerU => logger.write("LowerU")
    CharClass::UpperU => logger.write("UpperU")
  }
}

///|
/// 词法分析器状态
pub(all) enum LexStateMachine {
  Start
  // ----- IRI -----
  InIri
  InEsc // \u 或 \U 转义
  InStringEscHex4
  InStringEscHex8
  // ----- Blank Node -----
  InBlank
  InBlankLabel
  // ----- String -----
  InString // "..."
  InStringEsc // \" 转义
  InLongStringEsc // 长字符串转义
  InLongStringQuote // 三引字符串 """... """
  InLongStringQuoteContent // """...""" 内部
  InLongStringQuoteEnd // 匹配结束引号 
  InLongStringSingleQuote // 三单引号 '''...'''
  InLongStringSingleQuoteContent
  InLongStringSingleQuoteEnd
  // ----- Number -----
  InNumber
  InInteger // 整数
  InDecimal // 小数
  InDecimalStart // . 开始
  InDouble // 科学计数法
  InExponent
  // ----- Lang Tag -----
  InLangTag
  InLangTagExt // @lang-ext
  // ----- Variable (N3) -----
  InVariable
  // ----- Pname -----
  InPnamePrefix
  InPnameLocalStart
  InPnameLocal
  // ----- Keyword -----
  InKeyword
  // ----- Punctuation -----
  InPunct
  // ----- Skip -----
  // SkipWhitespace
  SkipLineComment
  SkipBlockComment(Int) // 嵌套层级
  // ----- Error -----
  Error
  // ----- Done -----
  Done
} derive(Debug, Eq, Hash)

///|
fn LexStateMachine::to_index(self : Self) -> Int {
  match self {
    LexStateMachine::Start => 0
    LexStateMachine::InIri => 1
    LexStateMachine::InEsc => 2
    LexStateMachine::InStringEscHex4 => 3
    LexStateMachine::InStringEscHex8 => 4
    LexStateMachine::InBlank => 5
    LexStateMachine::InBlankLabel => 6
    LexStateMachine::InString => 7
    LexStateMachine::InStringEsc => 8
    LexStateMachine::InLongStringQuoteContent => 9
    LexStateMachine::InLongStringQuoteEnd => 10
    LexStateMachine::InLongStringEsc => 11
    LexStateMachine::InLongStringQuote => 12
    LexStateMachine::InLongStringSingleQuoteContent => 13
    LexStateMachine::InLongStringSingleQuoteEnd => 14
    LexStateMachine::InLongStringSingleQuote => 15
    LexStateMachine::InNumber => 16
    LexStateMachine::InInteger => 17
    LexStateMachine::InDecimal => 18
    LexStateMachine::InDecimalStart => 19
    LexStateMachine::InDouble => 20
    LexStateMachine::InExponent => 21
    LexStateMachine::InLangTag => 22
    LexStateMachine::InLangTagExt => 23
    LexStateMachine::InVariable => 24
    LexStateMachine::InPnamePrefix => 25
    LexStateMachine::InPnameLocalStart => 26
    LexStateMachine::InPnameLocal => 27
    LexStateMachine::InKeyword => 28
    LexStateMachine::InPunct => 29
    LexStateMachine::SkipLineComment => 30
    LexStateMachine::SkipBlockComment(_level) => 31
    LexStateMachine::Error => 32
    LexStateMachine::Done => 33
  }
}

///|
pub impl Show for LexStateMachine with fn output(
  self : LexStateMachine,
  logger : &Logger,
) -> Unit {
  match self {
    LexStateMachine::Start => logger.write("Start")
    LexStateMachine::InIri => logger.write("InIri")
    LexStateMachine::InEsc => logger.write("InEsc")
    LexStateMachine::InStringEscHex4 => logger.write("InStringEscHex4")
    LexStateMachine::InStringEscHex8 => logger.write("InStringEscHex8")
    LexStateMachine::InBlank => logger.write("InBlank")
    LexStateMachine::InBlankLabel => logger.write("InBlankLabel")
    LexStateMachine::InString => logger.write("InString")
    LexStateMachine::InStringEsc => logger.write("InStringEsc")
    LexStateMachine::InLongStringQuoteContent =>
      logger.write("InLongStringQuoteContent")
    LexStateMachine::InLongStringQuoteEnd =>
      logger.write("InLongStringQuoteEnd")
    LexStateMachine::InLongStringEsc => logger.write("InLongStringEsc")
    LexStateMachine::InLongStringQuote => logger.write("InLongStringQuote")
    LexStateMachine::InLongStringSingleQuote =>
      logger.write("InLongStringSingleQuote")
    LexStateMachine::InLongStringSingleQuoteContent =>
      logger.write("InLongStringSingleQuoteContent")
    LexStateMachine::InLongStringSingleQuoteEnd =>
      logger.write("InLongStringSingleQuoteEnd")
    LexStateMachine::InNumber => logger.write("InNumber")
    LexStateMachine::InInteger => logger.write("InInteger")
    LexStateMachine::InDecimal => logger.write("InDecimal")
    LexStateMachine::InDecimalStart => logger.write("InDecimalStart")
    LexStateMachine::InDouble => logger.write("InDouble")
    LexStateMachine::InExponent => logger.write("InExponent")
    LexStateMachine::InLangTag => logger.write("InLangTag")
    LexStateMachine::InLangTagExt => logger.write("InLangTagExt")
    LexStateMachine::InVariable => logger.write("InVariable")
    LexStateMachine::InPnamePrefix => logger.write("InPnamePrefix")
    LexStateMachine::InPnameLocalStart => logger.write("InPnameLocalStart")
    LexStateMachine::InPnameLocal => logger.write("InPnameLocal")
    LexStateMachine::InKeyword => logger.write("InKeyword")
    LexStateMachine::InPunct => logger.write("InPunct")
    // LexStateMachine::SkipWhitespace => logger.write("SkipWhitespace")
    LexStateMachine::SkipBlockComment(n) =>
      logger.write("SkipBlockComment \{n}")
    LexStateMachine::Error => logger.write("Error")
    LexStateMachine::Done => logger.write("Done")
    LexStateMachine::SkipLineComment => logger.write("SkipLineComment")
  }
}

///|
/// 词法动作
pub(all) enum LexAction {
  Continue // 继续消费
  Skip // 跳过字符
  EmitToken // 输出当前 token
  EmitTokenWithDirection(BaseDirection?) // 新增:带方向的 Emit
  // PushState(LexStateMachine) // 入栈状态
  // PopState // 出栈状态
  SetState(LexStateMachine) // 设置状态
  StartCapture // 开始捕获
  // StartNestedCapture
  // StartLongStringCapture
  // InLongStringSingleQuoteCapture
  // InLongStringSingleQuoteEndCapture
  AppendCapture // 追加到捕获
  // InLongStringQuoteCapture
  // InLongStringQuoteEndCapture
  // CheckDirectionSuffix // 新增:检查 -bidi 后缀
  EndCapture // 结束捕获
  EndLongStringCapture
  EmitError(String) // 输出错误
  Done // 完成
} derive(Debug, Eq, Hash)

///|
pub impl Show for LexAction with fn output(self : LexAction, logger : &Logger) -> Unit {
  match self {
    LexAction::Continue => logger.write("Continue")
    LexAction::Skip => logger.write("Skip")
    LexAction::EmitToken => logger.write("EmitToken")
    LexAction::EmitTokenWithDirection(dir) =>
      logger.write("EmitTokenWithDirection \{@debug.to_string(dir)}")
    // LexAction::PushState(state) => logger.write("PushState \{state}")
    // LexAction::PopState => logger.write("PopState")
    LexAction::SetState(state) => logger.write("SetState \{state}")
    LexAction::StartCapture => logger.write("StartCapture")
    // LexAction::StartNestedCapture => logger.write("StartNestedCapture")
    // LexAction::StartLongStringCapture => logger.write("StartLongStringCapture")
    // LexAction::InLongStringSingleQuoteContent =>
    //   logger.write("InLongStringSingleQuoteContent")
    // LexAction::InLongStringSingleQuoteCapture =>
    //   logger.write("InLongStringSingleQuoteCapture")
    // LexAction::InLongStringQuoteEndCapture =>
    //   logger.write("InLongStringQuoteEndCapture")
    // LexAction::InLongStringSingleQuoteEndCapture =>
    //   logger.write("InLongStringSingleQuoteEndCapture")
    //  LexAction::InLongStringQuoteCapture =>
    //   logger.write("InLongStringQuoteCapture") 
    LexAction::AppendCapture => logger.write("AppendCapture")
    LexAction::EndCapture => logger.write("EndCapture")
    LexAction::EndLongStringCapture => logger.write("EndLongStringCapture")
    LexAction::EmitError(msg) => logger.write("EmitError \{msg}")
    LexAction::Done => logger.write("Done")
  }
}

///|
/// 转换规则
pub(all) struct Transition {
  from : LexStateMachine
  char_class : CharClass
  to : LexStateMachine
  action : LexAction
  priority : Int // ★ 新增:优先级
} derive(Debug, Eq, Hash)

///|
pub impl Show for Transition with fn output(self : Transition, logger : &Logger) -> Unit {
  logger.write("Transition: ")
  self.from.output(logger)
  logger.write(" -> ")
  self.to.output(logger)
  logger.write(" char_class: ")
  self.char_class.output(logger)
  logger.write("action: ")
  self.action.output(logger)
}

///|
pub fn Transition::Transition(
  from : LexStateMachine,
  char_class : CharClass,
  to : LexStateMachine,
  action : LexAction,
  priority? : Int,
) -> Transition {
  { from, char_class, to, action, priority: priority.unwrap_or(0) }
}

///|
/// 状态转移表
pub let initialize_transitions : FixedArray[Transition] = [
  // ============================================================
  // Start 状态 - 词法分析入口
  // ============================================================

  // ----- 空白和注释 -----

  // 空格 -> 跳过空白状态
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::Skip, // ★ 不发射 token,只跳过
  ),

  // 换行 -> 发射 LineJump
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Newline,
    LexStateMachine::Start,
    LexAction::Skip,
  ),

  // # 注释开始
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Hash,
    LexStateMachine::SkipLineComment,
    LexAction::Continue,
  ),

  // ----- Token 开始 -----

  // IRI 开始: <
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::LAngle,
    LexStateMachine::InIri,
    LexAction::StartCapture,
  ),

  // Start → _ → InBlank
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Underscore,
    LexStateMachine::InBlank,
    LexAction::StartCapture,
  ),
  // Blank Node 开始: _: 或 :
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Underscore,
    LexStateMachine::InBlankLabel,
    LexAction::StartCapture,
  ),

  // 双引号字符串开始: "
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Quote,
    LexStateMachine::InString,
    LexAction::StartCapture,
  ),

  // 单引号字符串开始: '
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Apostrophe,
    LexStateMachine::InString,
    LexAction::StartCapture,
  ),

  // 三双引号长字符串: """ 
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Quote,
    LexStateMachine::InLongStringQuoteContent,
    LexAction::StartCapture,
  ),

  // 三单引号长字符串: ''' 
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Apostrophe,
    LexStateMachine::InLongStringSingleQuoteContent,
    LexAction::StartCapture,
  ),

  // Lang Tag 开始: @
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::At,
    LexStateMachine::InLangTag,
    LexAction::StartCapture,
  ),

  // 数字开始: +/-
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Plus,
    LexStateMachine::InInteger,
    LexAction::StartCapture,
  ),
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Minus,
    LexStateMachine::InInteger,
    LexAction::StartCapture,
  ),

  // 句号(单独)
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Period,
    LexStateMachine::Start,
    LexAction::EmitToken,
    priority=50,
  ),

  // 多字符标点: ^^
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Caret,
    LexStateMachine::InPunct,
    LexAction::StartCapture,
  ),

  // 其他字符作为关键字开始
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Other,
    LexStateMachine::InKeyword,
    LexAction::StartCapture,
  ),

  // ============================================================
  // IRI 状态
  // ============================================================

  // IRI 内普通字符
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Other,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),

  // IRI 内特殊字符
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Colon,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Slash,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),
  // IRI 内转义开始
  // Transition::Transition(
  //   LexStateMachine::InIri,
  //   CharClass::Backslash,
  //   LexStateMachine::InEsc,
  //   LexAction::AppendCapture,
  // ),
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Period,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Hash,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::QuestionMark,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Percent,
    LexStateMachine::InIri,
    LexAction::AppendCapture,
  ),

  // IRI 结束: >
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::RAngle,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // IRI 错误:未编码空格
  Transition::Transition(
    LexStateMachine::InIri,
    CharClass::Space,
    LexStateMachine::Error,
    LexAction::EmitError("Invalid IRI: space should be encoded as %20"),
    priority=80,
  ),

  // 非法:\ 后面不是 u/U
  Transition::Transition(
    LexStateMachine::InEsc,
    CharClass::Other,
    LexStateMachine::Error,
    LexAction::EmitError("Invalid IRI escape: expected \\u or \\U"),
  ),
  // ============================================================
  // 字符串状态
  // ============================================================

  // 字符串内普通字符
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Other,
    LexStateMachine::InString,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Colon,
    LexStateMachine::InString,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Space,
    LexStateMachine::InString,
    LexAction::AppendCapture, // 空格保留在字符串中
  ),

  // 字符串结束: "
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Quote,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // 字符串转义开始: \
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Backslash,
    LexStateMachine::InStringEsc,
    LexAction::AppendCapture,
  ),

  // 字符串错误:单引号不能结束
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Apostrophe,
    LexStateMachine::Error,
    LexAction::EmitError("Invalid string terminator: ' instead of \""),
  ),

  // 字符串错误:未闭合(空白结束)
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Space,
    LexStateMachine::Error,
    LexAction::EmitError("Unclosed string"),
  ),
  // 字符串错误:未编码空格
  Transition::Transition(
    LexStateMachine::InString,
    CharClass::Space,
    LexStateMachine::Error,
    LexAction::EmitError("Unclosed string"),
  ),

  // ============================================================
  // 字符串转义状态
  // ============================================================

  // 转义字符处理

  Transition::Transition(
    LexStateMachine::InStringEsc,
    CharClass::Quote,
    LexStateMachine::Start,
    LexAction::EmitToken,
    priority=100,
  ),

  // InStringEsc - 处理转义字符
  Transition::Transition(
    LexStateMachine::InStringEsc,
    CharClass::LowerU,
    LexStateMachine::InStringEscHex4,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InStringEsc,
    CharClass::UpperU,
    LexStateMachine::InStringEscHex8,
    LexAction::AppendCapture,
  ),

  // 转义其他字符(如 \" \\ \n)
  Transition::Transition(
    LexStateMachine::InStringEsc,
    CharClass::Other,
    LexStateMachine::InString,
    LexAction::AppendCapture,
  ),

  // \u + 4位十六进制
  Transition::Transition(
    LexStateMachine::InStringEscHex4,
    CharClass::Digit,
    LexStateMachine::InStringEscHex4,
    LexAction::AppendCapture,
  ),

  // 4位十六进制完成
  Transition::Transition(
    LexStateMachine::InStringEscHex4,
    CharClass::Other,
    LexStateMachine::InString,
    LexAction::AppendCapture,
    priority=-1, // 通配符回退
  ),

  // \U + 8位十六进制
  Transition::Transition(
    LexStateMachine::InStringEscHex8,
    CharClass::Digit,
    LexStateMachine::InStringEscHex8,
    LexAction::AppendCapture,
  ),

  // 8位十六进制完成
  Transition::Transition(
    LexStateMachine::InStringEscHex8,
    CharClass::Other,
    LexStateMachine::InString,
    LexAction::AppendCapture,
  ),

  // ============================================================
  // 三双引号长字符串状态
  // ============================================================

  // 内容状态
  Transition::Transition(
    LexStateMachine::InLongStringQuoteContent,
    CharClass::Other,
    LexStateMachine::InLongStringQuoteContent,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InLongStringQuoteContent,
    CharClass::Space,
    LexStateMachine::InLongStringQuoteContent,
    LexAction::AppendCapture,
  ),
  // 遇到 """ 结束
  Transition::Transition(
    LexStateMachine::InLongStringQuoteContent,
    CharClass::Quote,
    LexStateMachine::Start,
    LexAction::EndLongStringCapture,
  ),

  // Start → 直接进入内容状态
  Transition::Transition(
    LexStateMachine::Start,
    CharClass::Apostrophe,
    LexStateMachine::InLongStringSingleQuoteContent,
    LexAction::StartCapture,
  ),

  // 内容状态
  Transition::Transition(
    LexStateMachine::InLongStringSingleQuoteContent,
    CharClass::Other,
    LexStateMachine::InLongStringSingleQuoteContent,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InLongStringSingleQuoteContent,
    CharClass::Space,
    LexStateMachine::InLongStringSingleQuoteContent,
    LexAction::AppendCapture,
  ),

  // 遇到 ''' 结束
  Transition::Transition(
    LexStateMachine::InLongStringSingleQuoteContent,
    CharClass::Apostrophe,
    LexStateMachine::Start,
    LexAction::EndLongStringCapture,
  ),

  // ============================================================
  // Blank Node 状态
  // ============================================================

  Transition::Transition(
    LexStateMachine::InBlank,
    CharClass::Colon,
    LexStateMachine::InBlankLabel,
    LexAction::Continue,
  ),
  Transition::Transition(
    LexStateMachine::InBlank,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::EndCapture,
  ),
  Transition::Transition(
    LexStateMachine::InBlankLabel,
    CharClass::Other,
    LexStateMachine::InBlankLabel,
    LexAction::EndCapture,
  ),
  // InBlankLabel 贪婪消费
  Transition::Transition(
    LexStateMachine::InBlankLabel,
    CharClass::Colon,
    LexStateMachine::InBlankLabel,
    LexAction::AppendCapture, // ★ 贪婪消费冒号
  ),
  Transition::Transition(
    LexStateMachine::InBlankLabel,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::EndCapture,
  ),
  Transition::Transition(
    LexStateMachine::InBlankLabel,
    CharClass::Period,
    LexStateMachine::Start,
    LexAction::EndCapture,
  ),

  // ============================================================
  // Lang Tag 状态
  // ============================================================

  Transition::Transition(
    LexStateMachine::InLangTag,
    CharClass::Other,
    LexStateMachine::InLangTag,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InLangTag,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),
  Transition::Transition(
    LexStateMachine::InLangTag,
    CharClass::Newline,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),
  Transition::Transition(
    LexStateMachine::InLangTag,
    CharClass::Period,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // ============================================================
  // Keyword 状态
  // ============================================================

  Transition::Transition(
    LexStateMachine::InKeyword,
    CharClass::Other,
    LexStateMachine::InKeyword,
    LexAction::AppendCapture,
  ),
  Transition::Transition(
    LexStateMachine::InKeyword,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // ============================================================
  // 标点和 Pname 状态
  // ============================================================

  // ^^ 标点
  Transition::Transition(
    LexStateMachine::InPunct,
    CharClass::Caret,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // Pname 前缀
  Transition::Transition(
    LexStateMachine::InPnamePrefix,
    CharClass::Other,
    LexStateMachine::InPnamePrefix,
    LexAction::AppendCapture,
  ),
  // 前缀结束,遇到 :
  Transition::Transition(
    LexStateMachine::InPnamePrefix,
    CharClass::Colon,
    LexStateMachine::InPnameLocalStart,
    LexAction::AppendCapture,
  ),

  // Pname 本地部分
  Transition::Transition(
    LexStateMachine::InPnameLocalStart,
    CharClass::Other,
    LexStateMachine::InPnameLocal,
    LexAction::AppendCapture,
  ),
  // 局部名继续
  Transition::Transition(
    LexStateMachine::InPnameLocal,
    CharClass::Other,
    LexStateMachine::InPnameLocal,
    LexAction::AppendCapture,
  ),
  // 结束
  Transition::Transition(
    LexStateMachine::InPnameLocal,
    CharClass::Space,
    LexStateMachine::Start,
    LexAction::EmitToken,
  ),

  // ============================================================
  // 跳过状态
  // ============================================================

  // 跳过行注释
  Transition::Transition(
    LexStateMachine::SkipLineComment,
    CharClass::Newline,
    LexStateMachine::Start,
    LexAction::Skip,
  ),
  Transition::Transition(
    LexStateMachine::SkipLineComment,
    CharClass::Other,
    LexStateMachine::SkipLineComment,
    LexAction::Skip,
  ),
]

///|
/// 256 字节的字符分类表
pub let initialize_char_class_table : FixedArray[CharClass] = {
  let table = FixedArray::make(256, CharClass::Other)

  // 空格类
  table[b' '.to_int()] = CharClass::Space
  table[b'\t'.to_int()] = CharClass::Space
  table[b'\r'.to_int()] = CharClass::Space

  // 换行
  table[b'\n'.to_int()] = CharClass::Newline

  // 标点符号
  table[b'<'.to_int()] = CharClass::LAngle
  table[b'>'.to_int()] = CharClass::RAngle
  table[b':'.to_int()] = CharClass::Colon
  table[b';'.to_int()] = CharClass::Semicolon
  table[b'.'.to_int()] = CharClass::Period
  table[b','.to_int()] = CharClass::Comma
  table[b'('.to_int()] = CharClass::LParen
  table[b')'.to_int()] = CharClass::RParen
  table[b'['.to_int()] = CharClass::LBracket
  table[b']'.to_int()] = CharClass::RBracket
  table[b'{'.to_int()] = CharClass::LBrace
  table[b'}'.to_int()] = CharClass::RBrace
  table[b'@'.to_int()] = CharClass::At
  table[b'?'.to_int()] = CharClass::QuestionMark
  table[b'+'.to_int()] = CharClass::Plus
  table[b'-'.to_int()] = CharClass::Other
  table[b'_'.to_int()] = CharClass::Underscore
  table[b'%'.to_int()] = CharClass::Percent
  table[b'#'.to_int()] = CharClass::Hash
  table[b'/'.to_int()] = CharClass::Slash
  table[b'\\'.to_int()] = CharClass::Backslash
  table[b'*'.to_int()] = CharClass::Star
  table[b'='.to_int()] = CharClass::Eq
  table[b'^'.to_int()] = CharClass::Caret
  table[b'|'.to_int()] = CharClass::Pipe
  table[b'~'.to_int()] = CharClass::Tilde
  table[b'!'.to_int()] = CharClass::Exclamation
  table[b'$'.to_int()] = CharClass::Dollar
  table[b'&'.to_int()] = CharClass::Ampersand
  table[b'\''.to_int()] = CharClass::Apostrophe // 单引号 '
  table[b'"'.to_int()] = CharClass::Quote // 双引号 "

  table
}

///|
/// 二维转换索引表
let transition_index : Array[Array[Transition?]] = {
  let state_count = LexStateMachine::Done.to_index() + 1
  let class_count = CharClass::UpperU.to_index() + 1

  // ★ 使用 make 明确类型
  let table : Array[Array[Transition?]] = Array::make(state_count, [])
  for i in 0.. Transition? {
  let si = ctx.state.to_index()
  let ci = char_class.to_index()

  // 精确匹配
  match transition_index[si][ci] {
    Some(t) => Some(t)
    None => transition_index[si][CharClass::Other.to_index()]
  }
}

///|
/// 快速字符分类 - O(1)
pub fn classify_byte(b : Byte) -> CharClass {
  if b.to_int() < 256 {
    initialize_char_class_table[b.to_int()]
  } else {
    CharClass::Other
  }
}

///|
/// 追踪长字符串引号匹配状态
pub(all) enum EscapeQuote {
  None // 正常内容状态
  // 开始阶段
  StartDouble(Int) // """
  StartSingle(Int) // '''

  // 内容阶段
  Content

  // 嵌套阶段
  NestDouble(Int) // 嵌套 """
  NestSingle(Int) // 嵌套 '''

  // 结束阶段
  EndDouble(Int) // 结束 """
  EndSingle(Int) // 结束 '''
} derive(Debug, Eq, Hash)

///|
pub impl Show for EscapeQuote with fn output(
  self : EscapeQuote,
  logger : &Logger,
) -> Unit {
  match self {
    EscapeQuote::None => logger.write("EscapeQuote::None")
    EscapeQuote::StartDouble(n) => {
      logger.write("EscapeQuote::StartDouble(")
      logger.write(n)
      logger.write(")")
    }
    EscapeQuote::StartSingle(n) => {
      logger.write("EscapeQuote::StartSingle(")
      logger.write(n)
      logger.write(")")
    }
    EscapeQuote::Content => logger.write("EscapeQuote::Content")
    EscapeQuote::NestDouble(n) => {
      logger.write("EscapeQuote::NestDouble(")
      logger.write(n)
      logger.write(")")
    }
    EscapeQuote::NestSingle(n) => {
      logger.write("EscapeQuote::NestSingle(")
      logger.write(n)
      logger.write(")")
    }
    EscapeQuote::EndDouble(n) => {
      logger.write("EscapeQuote::EndDouble(")
      logger.write(n)
      logger.write(")")
    }
    EscapeQuote::EndSingle(n) => {
      logger.write("EscapeQuote::EndSingle(")
      logger.write(n)
      logger.write(")")
    }
  }
}

///|
pub fn EscapeQuote::default() -> EscapeQuote {
  EscapeQuote::None
}

///|
/// ===== 状态机上下文 =====
pub(all) struct LexContext {
  data_buffer : ArrayView[Byte]
  mut position : Int
  mut state : LexStateMachine
  mut capture_start : Int
  mut capture_current : Int
  state_stack : Array[LexStateMachine]
  is_ending : Bool
  mut captured : String?
  mut escape_quote : EscapeQuote
  mut has_error : Bool
  mut error_message : String?
  mut prev_char : Byte?
}

///|
pub impl Show for LexContext with fn output(self : LexContext, logger : &Logger) -> Unit {
  logger.write("LexContext::")
  logger.write("{ ")
  logger.write("position: ")
  logger.write(self.position)
  logger.write(", ")
  logger.write("state: ")
  logger.write(self.state)
  logger.write(", ")
  logger.write("capture_start: ")
  logger.write(self.capture_start)
  logger.write(", ")
  logger.write("capture_current: ")
  logger.write(self.capture_current)
  logger.write(", ")
  logger.write("captured: ")
  logger.write(@debug.to_string(self.captured))
  logger.write(", ")
  logger.write(", ")
  logger.write("escape_quote: ")
  logger.write(self.escape_quote)
  logger.write("}")
}

///|
pub fn LexContext::default() -> LexContext {
  {
    data_buffer: [],
    position: 0,
    state: LexStateMachine::Start,
    capture_start: 0,
    capture_current: 0,
    state_stack: [],
    is_ending: false, // 是否结束,
    captured: None,
    escape_quote: EscapeQuote::default(),
    has_error: false,
    error_message: None,
    prev_char: None,
  }
}

///|
pub fn LexContext::new(
  data_buffer : ArrayView[Byte],
  is_ending? : Bool = false,
) -> LexContext {
  {
    data_buffer,
    position: 0,
    state: LexStateMachine::Start,
    capture_start: 0,
    capture_current: 0,
    state_stack: [],
    is_ending,
    captured: None,
    escape_quote: EscapeQuote::default(),
    has_error: false,
    error_message: None,
    prev_char: None,
  }
}

///|
pub fn LexContext::current_char(self : LexContext) -> Byte? {
  if self.position < self.data_buffer.length() {
    Some(self.data_buffer[self.position])
  } else {
    None
  }
}

///|
pub fn LexContext::peek_char(self : LexContext) -> Byte? {
  if self.position + 1 < self.data_buffer.length() {
    Some(self.data_buffer[self.position + 1])
  } else {
    None
  }
}

///|
pub fn LexContext::advance(self : LexContext) -> Unit {
  self.prev_char = self.data_buffer.get(self.position)
  self.position += 1
}

///|
pub fn LexContext::get_capture(self : LexContext) -> String {
  let result = StringBuilder::new()
  let mut i = self.capture_start

  while i < self.capture_current {
    let remaining = self.data_buffer[i:]

    // ★ 组合子检测
    if match_seq(remaining, [b'\\', b'u', b'0', b'0', b'2', b'0']) {
      result.write_char(' ') // 空格
      i += 6
    } else if match_seq(remaining, [b'\\', b'n']) {
      result.write_char('\n')
      i += 2
    } else if match_seq(remaining, [b'\\', b't']) {
      result.write_char('\t')
      i += 2
    } else if match_seq(remaining, [b'\\', b'r']) {
      result.write_char('\r')
      i += 2
    } else if match_seq(remaining, [b'\\', b'"']) {
      result.write_char('"')
      i += 2
    } else {
      // 普通字符
      result.write_char(self.data_buffer[i].to_int().unsafe_to_char())
      i += 1
    }
  }

  result.to_string()
}

// 组合子:检测模式

///|
fn match_seq(bs : ArrayView[Byte], pattern : Array[Byte]) -> Bool {
  if bs.length() < pattern.length() {
    return false
  }
  for i in 0.. Bool {
  (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z')
}

///|
/// 是否为 ASCII 数字 (0-9)
fn Byte::is_ascii_digit(b : Byte) -> Bool {
  b >= b'0' && b <= b'9'
}

///|
/// 是否为 ASCII 字母或数字
fn Byte::is_ascii_alnum(b : Byte) -> Bool {
  b.is_ascii_alpha() || b.is_ascii_digit()
}

///|
/// IRI 有效字符
fn Byte::is_iri_char(b : Byte) -> Bool {
  if b.is_ascii_alnum() {
    return true
  }
  match b {
    b':'
    | b'/'
    | b'.'
    | b'-'
    | b'_'
    | b'~'
    | b'@'
    | b'$'
    | b'&'
    | b'='
    | b'+'
    | b'!'
    | b'*'
    | b'\''
    | b'('
    | b')'
    | b','
    | b'#'
    | b'%'
    | b'?' => true
    _ => false
  }
}

///|
/// Blank Node 标签有效字符
fn Byte::is_blank_label_char(b : Byte) -> Bool {
  b.is_ascii_alnum() || b == b'-' || b == b'_'
}

///|
/// ===== 状态机执行器 =====
pub fn RdfLexer::execute_action(
  self : RdfLexer,
  action : LexAction,
  ctx : LexContext,
  current : Byte,
  _data_buffer : ArrayView[Byte],
) -> (LexAction, LexContext) {
  self.debug_logger.info(
    "@@ execute_action: action=\{action}, state=\{ctx.state}, position=\{ctx.position}",
  )
  match action {
    // ============================================================
    // EmitToken - 发射 token
    // ============================================================
    LexAction::EmitToken => {
      ctx.capture_current = ctx.position + 1
      let s = ctx.get_capture()
      self.debug_logger.info("@@@EmitToken: s=\{s}")
      // ★ 状态检查
      match ctx.state {
        // 普通字符串检查
        LexStateMachine::InString | LexStateMachine::InStringEsc => {
          // let has_start_quote = s.length() > 0 && s[0] == '"'
          // let has_end_quote = s.length() > 0 && s[s.length() - 1] == '"'

          // if !(has_start_quote && has_end_quote) || ctx.has_error {
          if ctx.has_error {
            self.debug_logger.info("ERROR: Unclosed string: '\{s}'")
            ctx.advance()
            ctx.has_error = true
            return (LexAction::EmitError("Unclosed string"), ctx)
          }

          ctx.captured = Some(s)
          // ctx.emit_state = Some(ctx.state)
          ctx.advance()
          (LexAction::EmitToken, ctx)
        }

        // 长字符串检查
        LexStateMachine::InLongStringQuoteContent
        | LexStateMachine::InLongStringSingleQuoteContent => {
          ctx.captured = Some(s)
          ctx.advance()
          (LexAction::EmitToken, ctx)
        }
        LexStateMachine::InIri => {
          let s = if s.length() >= 2 && s[0] == '<' && s[s.length() - 1] == '>' {
            s[1:s.length() - 1]
          } else {
            s
          }
          ctx.captured = Some(s.to_owned())
          ctx.advance()
          (LexAction::EmitToken, ctx)
        }
        _ => {
          ctx.captured = Some(s)
          ctx.advance()
          (LexAction::EmitToken, ctx)
        } // 其他状态正常发射
      }
    }

    // ============================================================
    // StartCapture - 开始捕获
    // ============================================================

    LexAction::StartCapture => {
      let pos = ctx.position
      ctx.capture_start = pos
      ctx.capture_current = pos + 1

      // 前瞻检测
      let next1 = ctx.data_buffer.get(ctx.position)
      let next2 = ctx.data_buffer.get(ctx.position + 1)

      // 检测三引号
      let is_triple_quote = next1 == Some(b'"') && next2 == Some(b'"')
      let is_triple_apostrophe = next1 == Some(b'\'') && next2 == Some(b'\'')
      // 双引号(非三引号)
      let is_normal_double_quote = current == b'"' && !is_triple_quote
      let is_normal_single_quote = current == b'\'' && !is_triple_apostrophe // ★ 新增
      match current {
        // ========== 字符串 ==========
        _ if is_normal_double_quote => {
          // 普通双引号字符串 "..."
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InString
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: Normal string, state=InString")
        }
        _ if is_normal_single_quote => {
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InString
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info(
            "StartCapture: Normal Single string, state=InString",
          )
        }
        _ if is_triple_quote => {
          // 三引号长字符串:NTriples 不允许
          if !allows_feature(self.mode, RdfFeature::LongStrings) {
            ctx.has_error = true
            ctx.error_message = Some(
              "Long strings (triple quotes) not allowed in N-Triples",
            )
            return (LexAction::EmitError("Long strings not allowed"), ctx)
          }

          // """ 长字符串:预消费所有三个引号
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InLongStringQuoteContent
          ctx.has_error = false
          ctx.advance() // 消费第1个 "
          ctx.advance() // 消费第2个 "
          ctx.advance() // 消费第3个 "
          ctx.escape_quote = EscapeQuote::Content // 标记为内容状态
          ctx.capture_start = ctx.position
          ctx.capture_current = ctx.position

          self.debug_logger.info(
            "StartCapture: Triple quote, state=InLongStringQuoteContent",
          )
        }
        _ if is_triple_apostrophe => {
          // 三单引号长字符串:NTriples 不允许
          if !allows_feature(self.mode, RdfFeature::LongStrings) {
            ctx.has_error = true
            ctx.error_message = Some(
              "Long strings (triple quotes) not allowed in N-Triples",
            )
            return (LexAction::EmitError("Long strings not allowed"), ctx)
          }
          // ''' 长字符串
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InLongStringSingleQuoteContent
          ctx.has_error = false
          ctx.advance()
          ctx.advance()
          ctx.advance()
          ctx.escape_quote = EscapeQuote::Content
          ctx.capture_start = ctx.position
          ctx.capture_current = ctx.position

          self.debug_logger.info(
            "StartCapture: Triple apostrophe, state=InLongStringSingleQuoteContent",
          )
        }

        // ========== IRI ==========
        b'<' => {
          // 前瞻检测绝对 IRI
          let p = ctx.position + 1
          let is_http = ctx.data_buffer.get(p) == Some(b'h') &&
            ctx.data_buffer.get(p + 1) == Some(b't') &&
            ctx.data_buffer.get(p + 2) == Some(b't') &&
            ctx.data_buffer.get(p + 3) == Some(b'p')

          let is_urn = ctx.data_buffer.get(p) == Some(b'u') &&
            ctx.data_buffer.get(p + 1) == Some(b'r') &&
            ctx.data_buffer.get(p + 2) == Some(b'n')

          if !is_http && !is_urn {
            ctx.has_error = true
            return (LexAction::EmitError("Relative IRI not allowed"), ctx)
          }
          // ★ 快速扫描到 >
          let mut has_escape = false
          let mut has_space = false

          let mut end = p
          while end < ctx.data_buffer.length() &&
                ctx.data_buffer.get(end) != Some(b'>') {
            let b = ctx.data_buffer.get(end)
            if b == Some(b'\\') {
              has_escape = true
            } else if b == Some(b' ') || b == Some(b'\t') {
              has_space = true
            }
            end += 1
          }
          // 检查非法字符
          if has_escape {
            ctx.has_error = true
            ctx.error_message = Some(
              "Invalid IRI: escape sequences not allowed in N-Triples",
            )
            return (LexAction::EmitError("Invalid IRI: escape sequences"), ctx)
          }

          if has_space {
            ctx.has_error = true
            ctx.error_message = Some("Invalid IRI: unencoded space")
            return (LexAction::EmitError("Invalid IRI: unencoded space"), ctx)
          }

          end = if end < ctx.data_buffer.length() { end + 1 } else { end }

          // ★ 直接设置 captured
          let s = ctx.data_buffer[ctx.position:end]

          let iri_bytes = if s.length() >= 2 &&
            s[0] == b'<' &&
            s[s.length() - 1] == b'>' {
            s[1:s.length() - 1]
          } else {
            s
          }
          let iri_str = @utf8.decode_lossy(array_to_view(iri_bytes))

          ctx.captured = Some(iri_str)

          // 移动位置
          ctx.position = end
          ctx.state = LexStateMachine::InIri // 恢复状态

          return (LexAction::EmitToken, ctx)
          // ctx.state = LexStateMachine::InIri
          // ctx.advance()
        }
        // ========== Blank Node ==========

        b'_' => {
          // ★ 前置检查
          let next1 = ctx.data_buffer.get(ctx.position + 1)
          if next1 != Some(b':') {
            ctx.has_error = true
            ctx.error_message = Some(
              "Invalid blank node: _ must be followed by :",
            )
            return (
              LexAction::EmitError(
                "Invalid blank node: _ must be followed by :",
              ),
              ctx,
            )
          }

          ctx.state = LexStateMachine::InBlankLabel
          ctx.escape_quote = EscapeQuote::None
          ctx.has_error = false
          ctx.capture_start = ctx.position
          ctx.capture_current = ctx.position + 1
          ctx.advance() // 消费 :
        }
        b':' =>
          match ctx.prev_char {
            // 字母数字 : → PrefixedName
            Some(c) if c.is_ascii_alnum() =>
              ctx.state = LexStateMachine::InPnamePrefix
            // 其他情况(_、空白、开头)→ Blank Node
            _ => ctx.state = LexStateMachine::InBlankLabel
          }
        // ========== Lang Tag ==========
        b'@' => {
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InLangTag
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info(
            "StartCapture: Lang tag start, state=InLangTag",
          )
        }

        // ========== 数字 ==========
        b'+' | b'-' | _ if current.to_char().is_ascii_digit() => {

          // N-Triples 不允许数字
          if !allows_feature(self.mode, RdfFeature::Numbers) {
            ctx.has_error = true
            ctx.error_message = Some("Numbers not allowed in N-Triples")
            self.debug_logger.info("Error: Numbers not allowed in N-Triples")
            return (LexAction::EmitError("Numbers not allowed"), ctx)
          }

          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InInteger
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: Number start, state=InInteger")
        }

        // ========== 标点符号 ==========
        // b':'
        // |
        b';' | b',' | b'.' | b'(' | b')' | b'[' | b']' | b'{' | b'}' | b'*' => {
          // ★ N-Triples 不允许逗号和分号
          if !allows_feature(self.mode, RdfFeature::PunctuationList) &&
            (current == b',' || current == b';') {
            ctx.has_error = true
            ctx.error_message = Some("Punctuation not allowed")
            return (LexAction::EmitError("Punctuation not allowed"), ctx)
          }

          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::Start
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: Punctuation")
          return (LexAction::EmitToken, ctx)
        }

        // ========== 类型修饰符 ==========
        b'^' => {
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InPunct
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: Punct start, state=InPunct")
        }

        // ========== 注释 ==========
        b'#' => {
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::SkipLineComment
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info(
            "StartCapture: Comment start, state=SkipLineComment",
          )
        }
        b'\\' => {
          // 需要在下一字符判断是否是 u/U
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InEsc
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: IRI escape start, state=InEsc")
        }
        // ========== 默认:关键字/标识符 ==========
        _ => {
          ctx.escape_quote = EscapeQuote::None
          ctx.state = LexStateMachine::InKeyword
          ctx.has_error = false
          ctx.advance()
          self.debug_logger.info("StartCapture: Keyword start, state=InKeyword")
        }
      }

      (LexAction::Continue, ctx)
    }

    // ============================================================
    // AppendCapture - 追加到捕获
    // ============================================================

    LexAction::AppendCapture => {
      ctx.advance()
      ctx.capture_current = ctx.position

      match ctx.state {

        // ========== 普通字符串 ==========
        LexStateMachine::InString =>
          while ctx.position < ctx.data_buffer.length() {
            let b = ctx.data_buffer.get(ctx.position)
            match b {
              // 转义字符,跳过下一个
              Some(b'\\') => ctx.advance()
              // if ctx.position < ctx.data_buffer.length() {
              //   ctx.advance() // 跳过转义目标
              // }
              // 结束引号,停止
              Some(b'"') => break
              // 其他字符,消费
              Some(_c) => ctx.advance()
              _ => break
            }
          }

        // ========== IRI ==========
        LexStateMachine::InIri =>
          while ctx.position < ctx.data_buffer.length() {
            let b = ctx.data_buffer.get(ctx.position)
            match b {
              // 有效 IRI 字符
              Some(c) if c.is_iri_char() => {
                ctx.advance()
                ctx.capture_current = ctx.position
              }

              // ★ 转义字符:报错
              Some(b'\\') => {
                ctx.has_error = true
                ctx.error_message = Some(
                  "Invalid IRI: escape sequences not allowed",
                )
                break
              }

              // IRI 结束
              Some(b'>') => break

              // 其他字符,停止
              _ => break
            }
          }
        _ => ()
      }

      (LexAction::Continue, ctx)
    }
    // ============================================================
    // Continue - 继续(不发射)
    // ============================================================
    LexAction::Continue => {
      ctx.advance()
      if ctx.capture_start == 0 {
        ctx.capture_start = ctx.position
        ctx.capture_current = ctx.position
      }
      ctx.capture_current = ctx.position
      (LexAction::Continue, ctx)
    }

    // ============================================================
    // Skip - 跳过(不追加)
    // ============================================================
    LexAction::Skip => {
      ctx.advance()
      ctx.capture_start = ctx.position
      ctx.capture_current = ctx.position
      (LexAction::Skip, ctx)
    }
    LexAction::EndLongStringCapture => {
      let quote_char = match ctx.state {
        LexStateMachine::InLongStringQuoteContent => b'"'
        LexStateMachine::InLongStringSingleQuoteContent => b'\'' // ★ 三单引号
        _ => b'\''
      }

      let start_pos = ctx.position

      // 检查是否是三引号
      if ctx.data_buffer.get(start_pos) == Some(quote_char) &&
        ctx.data_buffer.get(start_pos + 1) == Some(quote_char) &&
        ctx.data_buffer.get(start_pos + 2) == Some(quote_char) {
        // 找到三引号
        ctx.position = start_pos + 3
        let s = ctx.get_capture()
        ctx.captured = Some(s)
        return (LexAction::EmitToken, ctx)
      }

      // 没找到
      if ctx.is_ending || ctx.position >= ctx.data_buffer.length() {
        ctx.has_error = true
        return (LexAction::EmitError("Unclosed long string"), ctx)
      }

      ctx.advance()
      (LexAction::Continue, ctx)
    }

    // ============================================================
    // EmitError - 发射错误
    // ============================================================
    LexAction::EmitError(msg) => {
      self.debug_logger.info("EmitError: \{msg}")
      ctx.has_error = true
      ctx.error_message = Some(msg)
      ctx.advance()
      (LexAction::EmitError(msg), ctx)
    }
    LexAction::EndCapture => {
      // ★ 贪婪消费剩余有效字符
      match ctx.state {
        LexStateMachine::InBlankLabel =>
          while ctx.position < ctx.data_buffer.length() {
            let b = ctx.data_buffer.get(ctx.position)
            match b {
              // ★ 不消费冒号!
              Some(b':') => break // 遇到冒号停止
              Some(c) if c.is_blank_label_char() => {
                ctx.advance()
                ctx.capture_current = ctx.position
              }
              _ => break
            }
          }
        LexStateMachine::InIri =>
          while ctx.position < ctx.data_buffer.length() {
            let b = ctx.data_buffer.get(ctx.position)
            match b {
              Some(c) if c.is_iri_char() => {
                ctx.advance()
                ctx.capture_current = ctx.position
              }
              Some(b'\\') => {
                ctx.has_error = true
                ctx.error_message = Some(
                  "Invalid IRI: escape sequences not allowed",
                )
                break
              }
              _ => break
            }
          }
        _ => ()
      }

      let s = ctx.get_capture()

      // ★ Blank Node 格式检查
      if ctx.state == LexStateMachine::InBlankLabel ||
        ctx.state == LexStateMachine::InBlank {
        // 必须以 _ 或 : 开头
        if s.is_empty() ||
          (s[0] != b'_'.to_uint16() && s[0] != b':'.to_uint16()) {
          ctx.has_error = true
          return (
            LexAction::EmitError(
              "Invalid blank node label: must start with _ or :",
            ),
            ctx,
          )
        }

        // 检查冒号:只能有一个,且不能在开头后连续
        if s.contains("::") {
          ctx.has_error = true
          return (LexAction::EmitError("Invalid blank node: double colon"), ctx)
        }

        let colon_count = s.iter().filter(c => c == b':'.to_char()).count()
        if colon_count > 1 {
          ctx.has_error = true
          return (
            LexAction::EmitError("Invalid blank node: too many colons"),
            ctx,
          )
        }
      }

      ctx.captured = Some(s)
      self.debug_logger.info("EndCapture: content='\{s}'")
      (LexAction::EmitToken, ctx)
    }
    // ============================================================
    // 其他 action
    // ============================================================
    _ => {
      ctx.advance()
      (action, ctx)
    }
  }
}

///|
/// 创建 Token(包含完整的 LangTag)
pub fn make_token(
  ctx : LexContext,
  content : String,
) -> Result[N3Token, String] {
  let (state, has_error) = (ctx.state, ctx.has_error)
  // debug("make_token: state=\{state}, content=\{content}")
  match state {
    LexStateMachine::InIri =>
      if has_error {
        return Err("Invalid IRI")
      } else {
        Ok(N3Token::Iri(content))
      }
    LexStateMachine::InBlankLabel => Ok(N3Token::BlankNodeLabel(content))
    LexStateMachine::InString | LexStateMachine::InStringEsc =>
      Ok(N3Token::String(content))
    LexStateMachine::InLongStringQuoteContent
    | LexStateMachine::InLongStringSingleQuoteContent =>
      Ok(N3Token::LongString(content))
    LexStateMachine::InLangTag => {
      let direction = if content.has_suffix("-bidi") {
        Some(BaseDirection::Rtl)
      } else {
        None
      }
      Ok(N3Token::LangTag(language=content, direction~))
    }
    LexStateMachine::InVariable => Ok(N3Token::Variable(content))
    LexStateMachine::InKeyword => Ok(N3Token::PlainKeyword(content))
    LexStateMachine::InInteger => Ok(N3Token::Integer(content))
    LexStateMachine::InDecimal => Ok(N3Token::Decimal(content))
    LexStateMachine::InDouble => Ok(N3Token::Double(content))
    LexStateMachine::InPunct =>
      if content == "^^" {
        Ok(N3Token::Punctuation("^^"))
      } else {
        Ok(N3Token::Punctuation(content))
      }
    LexStateMachine::InPnamePrefix | LexStateMachine::InPnameLocal =>
      match content.find(":") {
        Some(idx) => {
          let prefix = content.sub(start=0, end=idx).to_owned()
          let localx = content
            .sub(start=idx + 1, end=content.length())
            .to_owned()
          Ok(
            N3Token::PrefixedName(prefix~, localx~, might_be_invalid_iri=false),
          )
        }
        None => Ok(N3Token::PlainKeyword(content))
      }
    LexStateMachine::InLongStringQuoteEnd
    | LexStateMachine::InLongStringSingleQuoteEnd =>
      Ok(N3Token::LongString(content))
    LexStateMachine::Start => {
      let s = match ctx.prev_char {
        Some(b',') => ","
        Some(b';') => ";"
        Some(b'.') => "."
        Some(b'(') => "("
        Some(b')') => ")"
        Some(b'[') => "["
        Some(b']') => "]"
        Some(b'{') => "{"
        Some(b'}') => "}"
        _ => ctx.get_capture()
      }

      match s {
        "," | ";" | "." | "(" | ")" | "[" | "]" | "{" | "}" | ":" =>
          Ok(N3Token::Punctuation(s))

        // 关键字
        "a" => Ok(N3Token::PlainKeyword("a"))
        _ => Ok(N3Token::PlainKeyword(content))
      }
    }
    _ => Ok(N3Token::PlainKeyword(content))
  }
}

///|
/// 单步执行状态机
/// 返回 (action, pos),如果无法继续则返回 None
fn RdfLexer::step(
  self : RdfLexer,
  ctx : LexContext,
  data_buffer : ArrayView[Byte],
) -> (LexAction, LexContext)? {
  let current = match ctx.data_buffer.get(ctx.position) {
    Some(b) => b
    None => return None
  }

  let char_class = classify_byte(current)

  let t = self.find_transition(ctx, char_class)
  self.debug_logger.info(
    "step: pos=\{ctx.position}, char='\{current.to_int().unsafe_to_char().to_string()}', char_class=\{char_class}, state=\{ctx.state} ctx=\{ctx}",
  )

  match t {
    Some(transition) => {
      let (action, new_ctx) = self.execute_action(
        transition.action,
        ctx,
        current,
        data_buffer,
      )

      // 根据 action 类型决定返回值
      let final_ctx = match action {
        LexAction::EmitToken | LexAction::EmitError(_) => new_ctx
        _ =>
          // 状态变化时更新
          if new_ctx.state != ctx.state {
            { ..new_ctx, state: transition.to }
          } else {
            new_ctx
          }
      }
      Some((action, final_ctx))
    }
    None => None
  }
}

///|
/// 跳过空白字符,返回跳过的数量
pub fn[RL] Lexer::skip_whitespace(self : Lexer[RL]) -> Int {
  let mut count = 0
  while self.position.buffer_offset + count < self.data.length() {
    let b = self.data[self.position.buffer_offset + count]
    match b {
      b' ' | b'\t' | b'\r' => count += 1
      _ => break
    }
  }
  count
}

///|
/// 跳过空白和注释
pub fn[RL] Lexer::skip_whitespaces_and_comments(self : Lexer[RL]) -> Bool {
  let mut skipped = 0

  for ;; {
    if self.position.buffer_offset + skipped >= self.data.length() {
      // 没有更多数据
      break
    }

    let b = self.data[self.position.buffer_offset + skipped]

    // 空白字符
    if b == b' ' || b == b'\t' || b == b'\r' || b == b'\n' {
      skipped += 1
      // 注释(# 开头)
    } else if b == b'#' {
      skipped += 1
      // 跳过注释直到行尾
      for ;; {
        if self.position.buffer_offset + skipped >= self.data.length() {
          break
        }
        if self.data[self.position.buffer_offset + skipped] == b'\n' {
          break
        }
        skipped += 1
      }
      // 非空白字符,结束
    } else {
      break
    }
  }

  // 更新位置
  if skipped > 0 {
    self.position.buffer_offset += skipped
    self.position.global_offset += skipped

    // 统计换行
    let view = self.data[self.position.buffer_offset - skipped:self.position.buffer_offset]
    for b in view {
      if b == b'\n' {
        self.position.global_line += 1
      }
    }
  }

  skipped > 0
}

///|
/// ===== TokenRecognizer 实现 =====
pub impl TokenRecognizer for RdfLexer with fn recognize_next_token(
  self : RdfLexer,
  data_buffer : ArrayView[Byte],
  is_ending : Bool,
  _options : LexerOptions?,
  location_pos : SourcePos,
) -> (Int, Result[LocatedToken, TokenRecognizerError])? {
  let mut ctx = LexContext::new(data_buffer, is_ending~)

  for ;; {
    self.debug_logger.info("step: pos=\{ctx.position}, state=\{ctx.state}")

    match self.step(ctx, data_buffer) {
      Some((action, new_ctx)) => {
        ctx = new_ctx // ★ 更新 ctx

        match action {
          LexAction::EmitToken => {
            // let state = ctx.emit_state.unwrap_or(ctx.state) // ★ 使用 emit_state
            let token = make_token(ctx, ctx.captured.unwrap_or(""))
            match token {
              Ok(token) => {
                self.debug_logger.info("  -> Emit: \{token}")
                let range = Range::Range(
                  location_pos.offset,
                  location_pos.offset + ctx.position,
                )
                return Some((ctx.position, Ok(LocatedToken(token, range))))
              }
              Err(err) => {
                let range = Range::Range(
                  location_pos.offset,
                  location_pos.offset + ctx.position + 1,
                )
                return Some(
                  (
                    ctx.position,
                    Err(
                      TokenRecognizerError::InvalidToken(
                        err, data_buffer, range,
                      ),
                    ),
                  ),
                )
              }
            }
          }
          LexAction::EmitError(err) => {
            let range = Range::Range(
              location_pos.offset,
              location_pos.offset + ctx.position + 1,
            )
            return Some(
              (
                ctx.position,
                Err(TokenRecognizerError::InvalidToken(err, data_buffer, range)),
              ),
            )
          }
          _ => continue
        }
      }
      None => {
        // ★ 无转换,检查是否到达 buffer 末尾

        // 未闭合的 token 检测
        let unclosed_states = [
          LexStateMachine::InString,
          LexStateMachine::InLongStringQuote,
          LexStateMachine::InLongStringSingleQuote,
          LexStateMachine::InIri,
          LexStateMachine::InBlankLabel,
        ]

        let is_unclosed = unclosed_states.iter().any(s => ctx.state == s)

        if ctx.position >= data_buffer.length() || is_ending {
          // 到达 buffer 末尾或文件结束
          if is_unclosed {
            // 未闭合的 token,报错
            let pos = ctx.position
            let range = Range::Range(
              location_pos.offset,
              location_pos.offset + pos,
            )
            // debug(
            //   "Unclosed token: state=\{ctx.state}, content=\{ctx.get_capture()}",
            // )
            return Some(
              (
                pos,
                Err(
                  TokenRecognizerError::InvalidToken(
                    "Unclosed token:", data_buffer, range,
                  ),
                ),
              ),
            )
          }
          // 正常结束
          return None
        }

        // 还有剩余数据但无转换,尝试恢复
        if ctx.capture_current > ctx.capture_start {
          let token = make_token(ctx, ctx.get_capture())
          match token {
            Ok(token) => {
              let pos = ctx.position
              let range = Range::Range(
                location_pos.offset,
                location_pos.offset + pos,
              )
              return Some((ctx.capture_current, Ok(LocatedToken(token, range))))
            }
            Err(err) => {
              let range = Range::Range(
                location_pos.offset,
                location_pos.offset + ctx.position + 1,
              )
              return Some(
                (
                  ctx.position + 1,
                  Err(
                    TokenRecognizerError::InvalidToken(err, data_buffer, range),
                  ),
                ),
              )
            }
          }
        }

        let range = Range::Range(
          location_pos.offset,
          location_pos.offset + ctx.position + 1,
        )
        return Some(
          (
            ctx.position + 1,
            Err(
              TokenRecognizerError::InvalidToken(
                "Something Err", data_buffer, range,
              ),
            ),
          ),
        )
      }
    }
  }
}