// ===== State: ExpectSubject =====
///|
fn NQuadsRecognizer::handle_expect_subject(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
ctx : NQuadsRecognizerContext,
results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectSubject with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(s), _)) => {
self.subjects.push(NamedNodeRef::new_unchecked(s).as_enum())
self.stack.push(NQuadsState::ExpectPredicate)
self
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::BlankNodeLabel(s), _)
) => {
self.subjects.push(BlankNodeRef::new_unchecked(s).as_enum())
self.stack.push(NQuadsState::ExpectPredicate)
self
}
_ =>
self.error(
ctx,
results,
token,
RuleRecognizerError::BlankNodeOrIriError.err_kind(),
)
}
}
// ===== State: ExpectPredicate =====
///|
fn NQuadsRecognizer::handle_expect_predicate(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
ctx : NQuadsRecognizerContext,
results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectPredicate with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(p), _)) => {
self.predicates.push(NamedNodeRef::new_unchecked(p))
self.stack.push(NQuadsState::ExpectedObject)
self
}
_ =>
self.error(
ctx,
results,
token,
RuleRecognizerError::PredicateNotAnIRI.err_kind(),
)
}
}
// ===== State: ExpectedObject =====
///|
fn NQuadsRecognizer::handle_expected_object(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
ctx : NQuadsRecognizerContext,
results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectedObject with token: \{token} Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(o), _)) => {
self.objects.push(TermRef::NamedNodeRef(NamedNodeRef::new_unchecked(o)))
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::BlankNodeLabel(o), _)
) => {
self.objects.push(NamedNodeRef::new_unchecked(o).as_term())
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::String(value), _)
) => {
self.stack.push(
NQuadsState::ExpectLiteralAnnotationOrGraphNameOrDot(value~),
)
self
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("<<("), _)
) => {
self.stack.push(NQuadsState::AfterQuotedTriple)
self.stack.push(NQuadsState::ExpectSubject)
self
}
_ =>
self.error(
ctx,
results,
token,
RuleRecognizerError::BlankNodeOrIriError.err_kind(),
)
}
}
// ===== State: ExpectLiteralAnnotationOrGraphNameOrDot =====
///|
fn NQuadsRecognizer::handle_expect_literal_annotation_or_graph_name_or_dot(
self : NQuadsRecognizer,
value : String,
token : LocatedTokenOrLineJump,
_ctx : NQuadsRecognizerContext,
_results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectLiteralAnnotation... value: \{value}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::LangTag(language~, direction~), _)
) if direction is Some(_) => {
let dir = match direction {
Some(d) => d
None => BaseDirection::Ltr
}
let lang_tag = try
LanguageTag::from_str(language.to_lower()) |> Ok
catch {
e => Err(e)
}
match lang_tag {
Ok(lang_tag) => {
self.objects.push(
LiteralRef::new_directional_language_tagged_literal_unchecked(
value, lang_tag, dir,
).as_term(),
)
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
Err(_e) => {
self.errors.push(RuleRecognizerError::InvalidLanguageTag)
self.error_recovery_state()
}
}
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::LangTag(language~, direction~), _)
) if direction is None => {
let lang_tag = try
LanguageTag::from_str(language.to_lower()) |> Ok
catch {
e => Err(e)
}
match lang_tag {
Ok(lang_tag) => {
self.objects.push(
TermRef::LiteralRef(
Literal::new_language_tagged_literal_unchecked(
value,
lang_tag.to_string(),
).as_ref(),
),
)
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
Err(_e) => {
self.errors.push(RuleRecognizerError::InvalidLanguageTag)
self.error_recovery_state()
}
}
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("^^"), _)
) => {
self.stack.push(NQuadsState::ExpectLiteralDatatype(value~))
self
}
_ => {
self.objects.push(
TermRef::LiteralRef(LiteralRef::new_simple_literal(value)),
)
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
}
}
// ===== State: ExpectLiteralDatatype =====
///|
fn NQuadsRecognizer::handle_expect_literal_datatype(
self : NQuadsRecognizer,
value : String,
token : LocatedTokenOrLineJump,
ctx : NQuadsRecognizerContext,
results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectLiteralDatatype with value: \{value}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(d), _)) => {
if !self.lenient && d == lwLANG_STRING.to_string() {
self.errors.push(
RuleRecognizerError::SyntaxError(
"The datatype of a literal without a language tag must not be rdf:langString",
Range::default(),
),
)
}
if !self.lenient && d == lwDIR_LANG_STRING.to_string() {
self.errors.push(
RuleRecognizerError::SyntaxError(
"The datatype of a literal without a base direction must not be rdf:dirLangString",
Range::default(),
),
)
}
let d = NamedNodeRef::new_unchecked(d)
let data_value = d.into_datatype(value)
self.objects.push(
TermRef::LiteralRef(LiteralRef::new_typed_literal(data_value, d)),
)
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
_ =>
self.error(
ctx,
results,
token,
RuleRecognizerError::LiteralDatatypeError.err_kind(),
)
}
}
// ===== State: ExpectPossibleGraphOrEndOfQuotedTriple =====
///|
fn NQuadsRecognizer::handle_expect_possible_graph_or_end_of_quoted_triple(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
ctx : NQuadsRecognizerContext,
results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectPossibleGraphOrEndOfQuotedTriple Token stack: \{@debug.to_string(self.stack)}")
match (self.stack.is_empty(), token) {
(
true,
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(g), _)),
) if ctx.with_graph_name => {
self.emit_quad(results, GraphNameRef::new_unchecked(g))
self.stack.push(NQuadsState::ExpectDot)
self
}
(
true,
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::BlankNodeLabel(_g), _)
),
) if ctx.with_graph_name => {
self.emit_quad(results, GraphNameRef::DefaultGraph)
self.stack.push(NQuadsState::ExpectDot)
self
}
(true, _) => {
self.emit_quad(results, GraphName::DefaultGraph.as_ref())
self.stack.push(NQuadsState::ExpectDot)
// 递归处理当前 token,因为它可能是下一个 Triple 的开始
self.recognize_next(
token,
RdfContext::NQuadsRecognizerContext(ctx),
results,
)
}
(
false,
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(")>>"), _)
),
) => return self
(false, _) =>
self.error(
ctx, results, token, "Expecting the end of a quoted triple ')>>'",
)
}
}
// ===== State: ExpectDot =====
///|
fn NQuadsRecognizer::handle_expect_dot(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
_ctx : NQuadsRecognizerContext,
_results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectDot with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("."), _)
) => {
self.stack.push(NQuadsState::ExpectLineJump)
self
}
_ => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Quads must be followed by a dot",
Range::default(),
),
)
self
}
}
}
// ===== State: ExpectLineJump =====
///|
fn NQuadsRecognizer::handle_expect_line_jump(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
_ctx : NQuadsRecognizerContext,
_results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering ExpectLineJump with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.errors.push(
RuleRecognizerError::SyntaxError(
"Only a single triple or quad can be written in a line, found \{token.to_string()}",
Range::default(),
),
)
self
}
// ===== State: AfterQuotedTriple =====
///|
fn NQuadsRecognizer::handle_after_quoted_triple(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
_ctx : NQuadsRecognizerContext,
_results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("Entering AfterQuotedTriple with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let subject_opt = self.subjects.pop()
let predicate_opt = self.predicates.pop()
let object_opt = self.objects.pop()
match (subject_opt, predicate_opt, object_opt) {
(Some(subject), Some(predicate), Some(object)) => {
let triple : TripleRef = { subject, predicate, object }
self.objects.push(TermRef::TripleRef(triple))
self.stack.push(NQuadsState::ExpectPossibleGraphOrEndOfQuotedTriple)
self
}
_ => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: incomplete quoted triple on stack",
Range::default(),
),
)
self.error_recovery_state()
}
}
}
// ===== State: RecoverToLineJump =====
///|
fn NQuadsRecognizer::handle_recover_to_line_jump(
self : NQuadsRecognizer,
token : LocatedTokenOrLineJump,
_ctx : NQuadsRecognizerContext,
_results : Array[RdfOut],
) -> NQuadsRecognizer {
self.debug_logger.info("RecoverToLineJump with token: \{token}Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LineJump(_) =>
// 是 LineJump,恢复完成
return self
_ => {
// 继续等待 LineJump
self.stack.push(NQuadsState::RecoverToLineJump)
self
}
}
}