///|
fn N3Recognizer::handle_term_token(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> N3Recognizer {
match token {
LocatedTokenOrLineJump::LocatedN3Token(located) =>
match located {
LocatedN3Token(N3Token::Iri(iri), _) => {
self.terms.push(NamedNodeRef::new_unchecked(iri).as_n3term())
self
}
LocatedN3Token(
N3Token::PrefixedName(prefix~, localx~, might_be_invalid_iri~),
_
) =>
match context {
RdfContext::N3RecognizerContext(ctx) =>
match
resolve_local_name(
prefix,
localx,
might_be_invalid_iri,
ctx.prefixes,
) {
Ok(t) => {
self.terms.push(t.as_n3term())
self
}
Err(e) => self.error(e)
}
_ => self.error("Invalid context for N3Term")
}
LocatedN3Token(N3Token::BlankNodeLabel(bnode), _) => {
self.terms.push(BlankNodeRef::new_unchecked(bnode).as_n3term())
self
}
LocatedN3Token(N3Token::Variable(name), _) => {
self.terms.push(N3Term::Variable(name))
self
}
LocatedN3Token(N3Token::String(value), _)
| LocatedN3Token(N3Token::LongString(value), _) => {
self.stack.push(N3State::LiteralPossibleSuffix(value~))
self
}
LocatedN3Token(N3Token::Integer(v), _) => {
self.terms.push(
LiteralRef::new_typed_literal(VarDataType::IntegerVar(v), lwINTEGER).as_n3term(),
)
self
}
LocatedN3Token(N3Token::Decimal(v), _) => {
self.terms.push(
LiteralRef::new_typed_literal(VarDataType::IntegerVar(v), lwDECIMAL).as_n3term(),
)
self
}
LocatedN3Token(N3Token::Double(v), _) => {
self.terms.push(
LiteralRef::new_typed_literal(VarDataType::IntegerVar(v), lwDOUBLE).as_n3term(),
)
self
}
LocatedN3Token(N3Token::PlainKeyword("true"), _) => {
self.terms.push(
LiteralRef::new_typed_literal(
VarDataType::IntegerVar("true"),
lwBOOLEAN,
).as_n3term(),
)
self
}
LocatedN3Token(N3Token::PlainKeyword("false"), _) => {
self.terms.push(
LiteralRef::new_typed_literal(
VarDataType::IntegerVar("false"),
lwBOOLEAN,
).as_n3term(),
)
self
}
_ => self.error("TOKEN is not a valid RDF value")
}
_ => self.error("TOKEN is not a valid RDF value")
}
}
///|
fn N3Recognizer::finish_formula(self : N3Recognizer) -> N3Recognizer {
let ctx = match self.contexts.pop() {
Some(c) => c
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: contexts stack empty in finish_formula",
Range::default(),
),
)
return self
}
}
// 将公式对应的 BlankNode 作为 Term 压入
self.terms.push(ctx.as_n3term())
// 关键修复:清理状态栈
// 1. 弹出 PathFollowUp (如果存在)
if self.stack.last() == Some(N3State::PathFollowUp) {
let _ = self.stack.pop()
}
// 2. 弹出 FormulaContentExpectDot (如果存在,防止残留)
if self.stack.last() == Some(N3State::FormulaContentExpectDot) {
let _ = self.stack.pop()
}
// 3. 重要:公式结束后,我们实际上完成了一个 PathItem。
// 如果栈顶现在是 TriplesMiddle 或 ObjectsListEnd 等,它们应该能处理后续 token。
// 但如果栈顶是 PathFollowUp 的上一层(例如 Path),我们需要确保不会再次进入 PathFollowUp 的错误逻辑。
// self.debug_logger.info("Stack after finish_formula: \{@debug.to_string(self.stack)}")
self
}
///|
fn N3Recognizer::handle_n3_doc(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering N3Doc with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.stack.push(N3State::N3Doc)
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword(k), _)
) if eq_ignore_ascii_case(k, "base") => {
self.stack.push(N3State::BaseExpectIri)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword(k), _)
) if eq_ignore_ascii_case(k, "prefix") => {
self.stack.push(N3State::PrefixExpectPrefix)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::LangTag(language="prefix", direction=None), _)
) => {
self.stack.push(N3State::N3DocExpectDot)
self.stack.push(N3State::PrefixExpectPrefix)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::LangTag(language="base", direction=None), _)
) => {
self.stack.push(N3State::N3DocExpectDot)
self.stack.push(N3State::BaseExpectIri)
HandleResult::Stop(self)
}
_ => {
self.stack.push(N3State::N3DocExpectDot)
self.stack.push(N3State::Triples)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_n3_doc_expect_dot(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering N3DocExpectDot with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("."), _)
) => HandleResult::Stop(self)
_ => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"A dot is expected at the end of N3 statements",
Range::default(),
),
)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_base_expect_iri(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering BaseExpectIri with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
if token
is LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Iri(iri), _)
) {
match context {
RdfContext::N3RecognizerContext(ctx) =>
ctx.lexer_options.base_iri = Some(Iri::Iri(iri))
_ => ()
}
HandleResult::Stop(self)
} else {
HandleResult::Stop(
self.error("The BASE keyword should be followed by an IRI"),
)
}
}
///|
fn N3Recognizer::handle_prefix_expect_prefix(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PrefixExpectPrefix with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PrefixedName(prefix~, localx~, ..), _)
) if localx.is_empty() => {
self.stack.push(N3State::PrefixExpectIri(name=prefix))
HandleResult::Stop(self)
}
_ =>
HandleResult::Stop(
self.error(
"The PREFIX keyword should be followed by a prefix like 'ex:'",
),
)
}
}
///|
fn N3Recognizer::handle_prefix_expect_iri(
self : N3Recognizer,
name : String,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> HandleResult {
self.debug_logger.info(
"Entering PrefixExpectIri(\{name}) with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
if token
is LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Iri(iri), _)
) {
match context {
RdfContext::N3RecognizerContext(ctx) =>
ctx.prefixes.set(name, Iri::Iri(iri))
_ => ()
}
HandleResult::Stop(self)
} else {
HandleResult::Stop(
self.error(
"The PREFIX declaration should be followed by a prefix and its value as an IRI",
),
)
}
}
///|
fn N3Recognizer::handle_triples(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering Triples with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.stack.push(N3State::TriplesMiddle)
self.stack.push(N3State::Path)
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_triples_middle(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering TriplesMiddle with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
if token
is LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("." | "]" | "}" | ")"), _)
) {
HandleResult::Continue(self)
} else {
self.stack.push(N3State::TriplesEnd)
self.stack.push(N3State::PredicateObjectList)
HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_triples_end(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering TriplesEnd with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let _ = self.terms.pop()
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_predicate_object_list(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PredicateObjectList with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.stack.push(N3State::PredicateObjectListEnd)
self.stack.push(N3State::ObjectsList)
self.stack.push(N3State::Verb)
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_predicate_object_list_end(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PredicateObjectListEnd with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let _ = self.predicates.pop()
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(";"), _)
) => {
self.stack.push(N3State::PredicateObjectListPossibleContinuation)
HandleResult::Stop(self)
}
_ => HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_predicate_object_list_possible_continuation(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info(
"Entering PredicateObjectListPossibleContinuation with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(";"), _)
) => {
self.stack.push(N3State::PredicateObjectListPossibleContinuation)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("."), _)
) => HandleResult::Stop(self)
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("}"), _)
) => HandleResult::Stop(self)
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("]"), _)
) => HandleResult::Stop(self)
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(")"), _)
) => HandleResult::Stop(self)
_ => {
self.stack.push(N3State::PredicateObjectListEnd)
self.stack.push(N3State::ObjectsList)
self.stack.push(N3State::Verb)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_objects_list(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering ObjectsList with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.stack.push(N3State::ObjectsListEnd)
self.stack.push(N3State::Path)
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_objects_list_end(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
results : Array[RdfOut],
) -> HandleResult {
self.debug_logger.info("Entering ObjectsListEnd with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let object = match self.terms.pop() {
Some(o) => o
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (object)",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
let subject = match self.terms.last() {
Some(s) => s
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (subject)",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
let predicate_opt = match self.predicates.last() {
Some(p) => p
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: predicates stack empty",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
results.push(
match predicate_opt {
Predicate::Regular(predicate) =>
RdfOut::N3Quad(self.quad(subject, predicate, object))
Predicate::Inverted(predicate) =>
RdfOut::N3Quad(self.quad(object, predicate, subject))
},
)
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(","), _)
) => {
self.stack.push(N3State::ObjectsListEnd)
self.stack.push(N3State::Path)
HandleResult::Stop(self)
}
_ => HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_verb(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering Verb with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword("a"), _)
) => {
self.predicates.push(Predicate::Regular(lwTYPE.as_n3term()))
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword("has"), _)
) => {
self.stack.push(N3State::AfterRegularVerb)
self.stack.push(N3State::Path)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword("is"), _)
) => {
self.stack.push(N3State::AfterVerbIs)
self.stack.push(N3State::Path)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("="), _)
) => {
self.predicates.push(
Predicate::Regular(
NamedNodeRef::new_unchecked("http://www.w3.org/2002/07/owl#sameAs").as_n3term(),
),
)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("=>"), _)
) => {
self.predicates.push(
Predicate::Regular(
NamedNodeRef::new_unchecked(
"http://www.w3.org/2000/10/swap/log#implies",
).as_n3term(),
),
)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("<="), _)
) => {
self.predicates.push(
Predicate::Inverted(
NamedNodeRef::new_unchecked(
"http://www.w3.org/2000/10/swap/log#implies",
).as_n3term(),
),
)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("<-"), _)
) => {
self.stack.push(N3State::AfterInvertedVerb)
self.stack.push(N3State::Path)
HandleResult::Stop(self)
}
_ => {
self.stack.push(N3State::AfterRegularVerb)
self.stack.push(N3State::Path)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_after_regular_verb(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering AfterRegularVerb with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let term = match self.terms.pop() {
Some(t) => t
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty in AfterRegularVerb",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
self.predicates.push(Predicate::Regular(term))
HandleResult::Stop(self)
}
///|
fn N3Recognizer::handle_after_inverted_verb(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering AfterInvertedVerb with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let term = match self.terms.pop() {
Some(t) => t
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty in AfterInvertedVerb",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
self.predicates.push(Predicate::Inverted(term))
HandleResult::Stop(self)
}
///|
fn N3Recognizer::handle_after_verb_is(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering AfterVerbIs with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword("of"), _)
) => {
let term = match self.terms.pop() {
Some(t) => t
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty in AfterVerbIs",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
self.predicates.push(Predicate::Inverted(term))
HandleResult::Stop(self)
}
_ =>
HandleResult::Stop(
self.error(
"The keyword 'is' should be followed by a predicate then by the keyword 'of'",
),
)
}
}
///|
fn N3Recognizer::handle_path(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering Path with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
self.stack.push(N3State::PathFollowUp)
self.stack.push(N3State::PathItem)
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_path_follow_up(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PathFollowUp with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("!"), _)
) => {
self.stack.push(N3State::PathAfterIndicator(is_inverse=false))
self.stack.push(N3State::PathItem)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("^"), _)
) => {
self.stack.push(N3State::PathAfterIndicator(is_inverse=false))
self.stack.push(N3State::PathItem)
HandleResult::Stop(self)
}
_ => HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_path_after_indicator(
self : N3Recognizer,
is_inverse : Bool,
token : LocatedTokenOrLineJump,
_context : RdfContext,
results : Array[RdfOut],
) -> HandleResult {
self.debug_logger.info(
"Entering PathAfterIndicator(is_inverse=\{is_inverse}) with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let predicate = match self.terms.pop() {
Some(p) => p
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (predicate) in PathAfterIndicator",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
let previous = match self.terms.pop() {
Some(prev) => prev
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (previous) in PathAfterIndicator",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
let current = BlankNode::default().as_n3term()
results.push(
if is_inverse {
RdfOut::N3Quad(self.quad(current, predicate, previous))
} else {
RdfOut::N3Quad(self.quad(previous, predicate, current))
},
)
self.terms.push(current)
self.stack.push(N3State::PathFollowUp)
HandleResult::Continue(self)
}
///|
fn N3Recognizer::handle_path_item(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PathItem with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("["), _)
) => {
self.stack.push(N3State::PropertyListMiddle)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("("), _)
) => {
self.stack.push(N3State::CollectionBeginning)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("{"), _)
) => {
self.contexts.push(BlankNode::default())
self.stack.push(N3State::FormulaContent)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("}"), _)
) => {
if self.contexts.is_empty() {
return HandleResult::Stop(
self.error("Unexpected '}' outside of formula"),
)
}
let ctx = self.contexts.pop().unwrap()
self.terms.push(ctx.as_n3term())
if self.stack.last() == Some(N3State::PathFollowUp) {
let _ = self.stack.pop()
}
HandleResult::Stop(self)
}
_ =>
// 使用之前重构的 handle_term_token
HandleResult::Stop(self.handle_term_token(token, context))
}
}
///|
fn N3Recognizer::handle_property_list_middle(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PropertyListMiddle with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("]"), _)
) => {
self.terms.push(BlankNode::default().as_n3term())
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword("id"), _)
) => {
self.stack.push(N3State::IriPropertyList)
HandleResult::Stop(self)
}
_ => {
self.terms.push(BlankNode::default().as_n3term())
self.stack.push(N3State::PropertyListEnd)
self.stack.push(N3State::PredicateObjectList)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_property_list_end(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering PropertyListEnd with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("]"), _)
) => HandleResult::Stop(self)
_ => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"blank node property lists should end with a ']'",
Range::default(),
),
)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_iri_property_list(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering IriPropertyList with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(LocatedN3Token(N3Token::Iri(id), _)) => {
self.terms.push(NamedNodeRef::new_unchecked(id).as_n3term())
self.stack.push(N3State::PropertyListEnd)
self.stack.push(N3State::PredicateObjectList)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(
N3Token::PrefixedName(prefix~, localx~, might_be_invalid_iri~),
_
)
) =>
match context {
RdfContext::N3RecognizerContext(ctx) =>
match
resolve_local_name(
prefix,
localx,
might_be_invalid_iri,
ctx.prefixes,
) {
Ok(t) => {
self.terms.push(t.as_n3term())
HandleResult::Stop(self)
}
Err(e) => HandleResult::Stop(self.error(e.to_string()))
}
_ =>
HandleResult::Stop(
self.error("Invalid context for prefix resolution"),
)
}
_ =>
HandleResult::Stop(
self.error("The '[ id' construction should be followed by an IRI"),
)
}
}
///|
fn N3Recognizer::handle_collection_beginning(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering CollectionBeginning with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
if token
is LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(")"), _)
) {
self.terms.push(lwNIL.as_n3term())
HandleResult::Stop(self)
} else {
let root = BlankNode::default()
self.terms.push(root.as_n3term())
self.terms.push(root.as_n3term())
self.stack.push(N3State::CollectionPossibleEnd)
self.stack.push(N3State::Path)
HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_collection_possible_end(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
results : Array[RdfOut],
) -> HandleResult {
self.debug_logger.info("Entering CollectionPossibleEnd with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
let value = match self.terms.pop() {
Some(v) => v
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (value) in CollectionPossibleEnd",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
let old = match self.terms.pop() {
Some(o) => o
None => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"Internal error: terms stack empty (old) in CollectionPossibleEnd",
Range::default(),
),
)
return HandleResult::Stop(self)
}
}
results.push(RdfOut::N3Quad(self.quad(old, lwFIRST.as_n3term(), value)))
if token
is LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation(")"), _)
) {
results.push(
RdfOut::N3Quad(self.quad(old, lwREST.as_n3term(), lwNIL.as_n3term())),
)
HandleResult::Stop(self)
} else {
let new = BlankNode::default()
results.push(
RdfOut::N3Quad(self.quad(old, lwREST.as_n3term(), new.as_n3term())),
)
self.terms.push(new.as_n3term())
self.stack.push(N3State::CollectionPossibleEnd)
self.stack.push(N3State::Path)
HandleResult::Continue(self)
}
}
///|
fn N3Recognizer::handle_literal_possible_suffix(
self : N3Recognizer,
value : String,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info(
"Entering LiteralPossibleSuffix(\{value}) with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::LangTag(language~, direction~), _)
) => {
if direction is Some(_) {
return HandleResult::Stop(
self.error("rdf:dirLangString is not supported in N3"),
)
}
self.terms.push(
Literal::new_language_tagged_literal_unchecked(
value,
language.to_lower(),
).as_n3term(),
)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("^^"), _)
) => {
self.stack.push(N3State::LiteralExpectDatatype(value~))
HandleResult::Stop(self)
}
_ => {
self.terms.push(Literal::new_simple_literal(value).as_n3term())
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_literal_expect_datatype(
self : N3Recognizer,
value : String,
token : LocatedTokenOrLineJump,
context : RdfContext,
) -> HandleResult {
self.debug_logger.info(
"Entering LiteralExpectDatatype(\{value}) with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Iri(datatype), _)
) => {
let datatype = NamedNodeRef::new_unchecked(datatype)
self.terms.push(
LiteralRef::new_typed_literal(datatype.into_datatype(value), datatype).as_n3term(),
)
HandleResult::Stop(self)
}
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(
N3Token::PrefixedName(prefix~, localx~, might_be_invalid_iri~),
_
)
) =>
match context {
RdfContext::N3RecognizerContext(ctx) =>
match
resolve_local_name(
prefix,
localx,
might_be_invalid_iri,
ctx.prefixes,
) {
Ok(datatype) => {
self.terms.push(
LiteralRef::new_typed_literal(
datatype.into_datatype(value),
datatype,
).as_n3term(),
)
HandleResult::Stop(self)
}
Err(e) => HandleResult::Stop(self.error(e))
}
_ =>
HandleResult::Stop(
self.error("Invalid context for prefix resolution"),
)
}
_ => HandleResult::Stop(self.error("Unexpected token in formula content"))
}
}
///|
fn N3Recognizer::handle_formula_content(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info("Entering FormulaContent with token: \{token}")
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("}"), _)
) => HandleResult::Stop(self.finish_formula())
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::PlainKeyword(k), _)
) if eq_ignore_ascii_case(k, "base") => {
self.stack.push(N3State::FormulaContent)
self.stack.push(N3State::BaseExpectIri)
HandleResult::Stop(self)
}
_ => {
self.stack.push(N3State::FormulaContentExpectDot)
self.stack.push(N3State::Triples)
HandleResult::Continue(self)
}
}
}
///|
fn N3Recognizer::handle_formula_content_expect_dot(
self : N3Recognizer,
token : LocatedTokenOrLineJump,
_context : RdfContext,
) -> HandleResult {
self.debug_logger.info(
"Entering FormulaContentExpectDot with token: \{token}",
)
self.debug_logger.info("Token stack: \{@debug.to_string(self.stack)}")
match token {
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("}"), _)
) => HandleResult::Stop(self.finish_formula())
LocatedTokenOrLineJump::LocatedN3Token(
LocatedN3Token(N3Token::Punctuation("."), _)
) => {
self.stack.push(N3State::FormulaContent)
HandleResult::Stop(self)
}
_ => {
self.errors.push(
RuleRecognizerError::SyntaxError(
"A dot or '}' is expected at the end of N3 statements inside formula",
Range::default(),
),
)
self.stack.push(N3State::FormulaContent)
HandleResult::Continue(self)
}
}
}