1use std::{collections::HashSet, fmt::Display, ops::Range};
2
3use lsp_core::prelude::{MyQuad, MyTerm, Spanned, StringStyle, Triples2};
4use sophia_iri::resolve::{BaseIri, IriParseError};
5use tracing::info;
6
7use super::context::{Context, ContextKind};
8
9pub trait Based {
10 fn get_base(&self) -> &lsp_types::Url;
11 fn prefixes(&self) -> &[Spanned<TurtlePrefix>];
12}
13
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Variable(pub String, pub usize);
16
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub enum Literal {
19 RDF(RDFLiteral),
20 Boolean(bool),
21 Numeric(String),
22}
23
24impl Literal {
25 pub fn plain_string(&self) -> String {
26 match self {
27 Literal::RDF(s) => s.plain_string(),
28 Literal::Boolean(x) => x.to_string(),
29 Literal::Numeric(x) => x.clone(),
30 }
31 }
32}
33impl Display for Literal {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Literal::RDF(x) => x.fmt(f),
37 Literal::Boolean(x) => write!(f, "{}", x),
38 Literal::Numeric(x) => write!(f, "{}", x),
39 }
40 }
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
44pub struct RDFLiteral {
45 pub value: String,
46 pub quote_style: StringStyle,
47 pub lang: Option<String>,
48 pub ty: Option<NamedNode>,
49 pub idx: usize,
51 pub len: usize,
52}
53
54impl RDFLiteral {
55 pub fn plain_string(&self) -> String {
56 self.value.to_string()
57 }
58}
59
60impl Display for RDFLiteral {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 let quote = match self.quote_style {
63 StringStyle::DoubleLong => "\"\"\"",
64 StringStyle::Double => "\"",
65 StringStyle::SingleLong => "'''",
66 StringStyle::Single => "'",
67 };
68 match (&self.lang, &self.ty) {
69 (None, None) => write!(f, "{}{}{}", quote, self.value, quote),
70 (None, Some(t)) => write!(f, "{}{}{}^^{}", quote, self.value, quote, t),
71 (Some(l), None) => write!(f, "{}{}{}@{}", quote, self.value, quote, l),
72 (Some(l), Some(t)) => write!(f, "{}{}{}@{}^^{}", quote, self.value, quote, l, t),
73 }
74 }
75}
76
77#[derive(Clone, Debug, PartialEq, Eq)]
78pub enum NamedNode {
79 Full(String, usize),
80 Prefixed {
81 prefix: String,
82 value: String,
83 idx: usize,
84 },
85 A(usize),
86 Invalid,
87}
88
89impl NamedNode {
90 pub fn expand<T: Based>(&self, turtle: &T) -> Option<String> {
91 let base = turtle.get_base();
92 let out = self.expand_step(turtle, HashSet::new())?;
93
94 let url = base.join(&out).ok()?;
95
96 Some(url.to_string())
97 }
98
99 pub fn expand_step<'a, T: Based>(
100 &'a self,
101 turtle: &T,
102 mut done: HashSet<&'a str>,
103 ) -> Option<String> {
104 match self {
105 Self::Full(s, _) => s.clone().into(),
106 Self::Prefixed {
107 prefix,
108 value,
109 idx: _,
110 } => {
111 if done.contains(prefix.as_str()) {
112 return None;
113 }
114 done.insert(prefix);
115 let prefix = turtle
116 .prefixes()
117 .iter()
118 .find(|x| x.prefix.as_str() == prefix.as_str())?;
119
120 let expaned = prefix.value.expand_step(turtle, done)?;
121 Some(format!("{}{}", expaned, value))
122 }
123 Self::A(_) => Some("http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string()),
124 Self::Invalid => None,
125 }
126 }
127}
128
129impl Display for NamedNode {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 match self {
132 NamedNode::Full(x, _) => write!(f, "<{}>", x),
133 NamedNode::Prefixed {
134 prefix,
135 value,
136 idx: _,
137 } => write!(f, "{}:{}", prefix, value),
138 NamedNode::A(_) => write!(f, "a"),
139 NamedNode::Invalid => write!(f, "invalid"),
140 }
141 }
142}
143
144#[derive(Clone, Debug, PartialEq, Eq)]
145pub enum BlankNode {
146 Named(String, usize),
147 Unnamed(Vec<Spanned<PO>>, usize, usize),
148 Invalid,
149}
150
151fn rev_range(range: &std::ops::Range<usize>, len: usize) -> std::ops::Range<usize> {
152 (len - range.end)..(len - range.start)
153}
154
155impl BlankNode {
156 pub fn fix_spans(&mut self, len: usize) {
157 match self {
158 BlankNode::Unnamed(ref mut pos, _, _) => {
159 pos.iter_mut().for_each(|span| {
160 span.1 = rev_range(&span.1, len);
161 span.0.fix_spans(len);
162 });
163 }
164 _ => {}
165 }
166 }
167}
168
169impl Display for BlankNode {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 match self {
172 BlankNode::Named(x, _) => write!(f, "_:{}", x),
173 BlankNode::Unnamed(pos, _, _) => {
174 if pos.len() == 0 {
175 write!(f, "[ ]")
176 } else {
177 write!(f, "[ ")?;
178
179 for po in pos {
180 write!(f, "{} ;", po.value())?;
181 }
182
183 write!(f, " ]")
184 }
185 }
186 BlankNode::Invalid => write!(f, "invalid"),
187 }
188 }
189}
190
191#[derive(Clone, Debug, PartialEq, Eq)]
192pub enum Term {
193 Literal(Literal),
194 BlankNode(BlankNode),
195 NamedNode(NamedNode),
196 Collection(Vec<Spanned<Term>>),
197 Variable(Variable),
198 Invalid,
199}
200
201impl Term {
202 pub fn set_context(&self, ctx: &mut Context, kind: ContextKind) {
203 match self {
204 Term::Literal(Literal::RDF(RDFLiteral { idx, len, .. })) => {
205 for i in *idx..*idx + *len {
206 ctx.add(i, kind);
207 }
208 }
209
210 Term::BlankNode(BlankNode::Unnamed(pos, start, end)) => {
211 ctx.add(*start, kind);
212 ctx.add(*end, kind);
213 for po in pos {
214 po.set_context(ctx);
215 }
216 }
217 Term::BlankNode(BlankNode::Named(_, idx))
218 | Term::Variable(Variable(_, idx))
219 | Term::NamedNode(NamedNode::Full(_, idx))
220 | Term::NamedNode(NamedNode::A(idx))
221 | Term::NamedNode(NamedNode::Prefixed { idx, .. }) => ctx.add(*idx, kind),
222 _ => {}
223 }
224 }
225 pub fn fix_spans(&mut self, len: usize) {
226 match self {
227 Term::BlankNode(bn) => bn.fix_spans(len),
228 Term::Collection(pos) => {
229 pos.iter_mut().for_each(|span| {
230 span.1 = rev_range(&span.1, len);
231 span.0.fix_spans(len);
232 });
233 }
234 _ => {}
235 }
236 }
237
238 pub fn named_node(&self) -> Option<&NamedNode> {
239 match self {
240 Term::NamedNode(nn) => Some(&nn),
241 _ => None,
242 }
243 }
244
245 pub fn is_subject(&self) -> bool {
246 match self {
247 Term::BlankNode(_) => true,
248 Term::Variable(_) => true,
249 Term::NamedNode(NamedNode::A(_)) => false,
250 Term::NamedNode(_) => true,
251 Term::Invalid => true,
252 Term::Collection(_) => true,
253 _ => false,
254 }
255 }
256 pub fn is_predicate(&self) -> bool {
257 match self {
258 Term::NamedNode(_) => true,
259 Term::Variable(_) => true,
260 Term::Invalid => true,
261 _ => false,
262 }
263 }
264
265 pub fn is_object(&self) -> bool {
266 match self {
267 Term::NamedNode(NamedNode::A(_)) => false,
268 Term::Variable(_) => true,
269 Term::Invalid => true,
270 Term::Collection(_) => true,
271 _ => true,
272 }
273 }
274 pub fn is_variable(&self) -> bool {
275 match self {
276 Term::Variable(_) => true,
277 Term::Invalid => true,
278 _ => false,
279 }
280 }
281 pub fn ty(&self) -> &'static str {
282 match self {
283 Term::Literal(_) => "literal",
284 Term::BlankNode(_) => "blank node",
285 Term::NamedNode(_) => "named node",
286 Term::Collection(_) => "collection",
287 Term::Invalid => "invalid",
288 Term::Variable(_) => "variable",
289 }
290 }
291 pub fn expand<T: Based>(&self, turtle: &T) -> Option<String> {
292 self.named_node()?.expand(turtle)
293 }
294 pub fn expand_step<'a, T: Based>(
295 &'a self,
296 turtle: &T,
297 done: HashSet<&'a str>,
298 ) -> Option<String> {
299 self.named_node()?.expand_step(turtle, done)
300 }
301}
302
303impl Display for Term {
304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305 match self {
306 Term::Literal(l) => l.fmt(f),
307 Term::BlankNode(b) => b.fmt(f),
308 Term::NamedNode(n) => n.fmt(f),
309 Term::Collection(n) => {
310 write!(f, "( ")?;
311 for l in n {
312 l.fmt(f)?;
313 }
314 write!(f, " )")?;
315 Ok(())
316 }
317 Term::Invalid => write!(f, "invalid"),
318 Term::Variable(x) => write!(f, "{}", x.0),
319 }
320 }
321}
322
323#[derive(Clone, Debug, PartialEq, Eq)]
324pub struct Triple {
325 pub subject: Spanned<Term>,
326 pub po: Vec<Spanned<PO>>,
327}
328
329impl Triple {
330 pub fn fix_spans(&mut self, len: usize) {
331 self.subject.1 = rev_range(&self.subject.1, len);
332 self.subject.0.fix_spans(len);
333
334 self.po.iter_mut().for_each(|span| {
335 span.1 = rev_range(&span.1, len);
336 span.0.fix_spans(len);
337 });
338 }
339
340 pub fn set_context(&self, ctx: &mut Context) {
341 self.subject.set_context(ctx, ContextKind::Subject);
342
343 for po in &self.po {
344 po.set_context(ctx);
345 }
346 }
347}
348
349impl Display for Triple {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 write!(f, "{} {}", self.subject.value(), self.po[0].value())?;
352
353 for po in &self.po[1..] {
354 write!(f, "; {}", po.value())?;
355 }
356
357 write!(f, ".")
358 }
359}
360
361#[derive(Clone, Debug, PartialEq, Eq)]
362pub struct PO {
363 pub predicate: Spanned<Term>,
364 pub object: Vec<Spanned<Term>>,
365}
366impl PO {
367 pub fn fix_spans(&mut self, len: usize) {
368 self.predicate.1 = rev_range(&self.predicate.1, len);
369 self.predicate.0.fix_spans(len);
370
371 self.object.iter_mut().for_each(|span| {
372 span.1 = rev_range(&span.1, len);
373 span.0.fix_spans(len);
374 });
375 }
376
377 pub fn set_context(&self, ctx: &mut Context) {
378 self.predicate.set_context(ctx, ContextKind::Predicate);
379
380 for o in &self.object {
381 o.set_context(ctx, ContextKind::Object);
382 }
383 }
384}
385
386impl Display for PO {
387 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
388 write!(f, "{} {}", self.predicate.value(), self.object[0].value())?;
389
390 for po in &self.object[1..] {
391 write!(f, ", {}", po.value())?;
392 }
393
394 Ok(())
395 }
396}
397
398#[derive(Clone, Debug, PartialEq, Eq)]
399pub struct Base(pub Range<usize>, pub Spanned<NamedNode>);
400impl Display for Base {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 write!(f, "@base {} .", self.1.value())
403 }
404}
405impl Base {
406 pub fn fix_spans(&mut self, len: usize) {
407 self.1 .1 = rev_range(&self.1 .1, len);
408 }
409 pub fn resolve_location(&mut self, location: &lsp_types::Url) {
410 match self.1.value_mut() {
411 NamedNode::Full(s, _) => {
412 if let Some(ns) = location.join(&s).ok() {
413 *s = ns.to_string();
414 }
415 }
416 _ => {}
417 }
418 }
419}
420#[derive(Clone, Debug, PartialEq, Eq)]
421pub struct TurtlePrefix {
422 pub span: Range<usize>,
423 pub prefix: Spanned<String>,
424 pub value: Spanned<NamedNode>,
425}
426impl TurtlePrefix {
427 fn shorten<T: Based>(&self, turtle: &T, url: &str) -> Option<String> {
428 let prefix_url = self.value.expand(turtle)?;
429 let short = url.strip_prefix(&prefix_url)?;
430 Some(format!("{}:{}", self.prefix.value(), short))
431 }
432
433 pub fn fix_spans(&mut self, len: usize) {
434 self.span = rev_range(&self.span, len);
435 self.prefix.1 = rev_range(&self.prefix.1, len);
436 self.value.1 = rev_range(&self.value.1, len);
437 }
438}
439impl Display for TurtlePrefix {
440 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
441 write!(
442 f,
443 "@prefix {}: {} .",
444 self.prefix.value(),
445 self.value.value()
446 )
447 }
448}
449
450#[derive(Debug)]
451pub enum TurtleSimpleError {
452 Parse(IriParseError),
453 UnexpectedBase(&'static str),
454 UnexpectedBaseString(String),
455}
456
457#[derive(Clone, Debug, PartialEq, Eq)]
458pub struct Turtle {
459 pub base: Option<Spanned<Base>>,
460 pub set_base: lsp_types::Url,
461 pub prefixes: Vec<Spanned<TurtlePrefix>>,
462 pub triples: Vec<Spanned<Triple>>,
463}
464impl Based for Turtle {
465 fn get_base(&self) -> &lsp_types::Url {
466 &self.set_base
467 }
468
469 fn prefixes(&self) -> &[Spanned<TurtlePrefix>] {
470 &self.prefixes
471 }
472}
473
474impl Turtle {
475 pub fn fix_spans(&mut self, len: usize) {
476 self.base.iter_mut().for_each(|base| {
477 base.1 = rev_range(&base.1, len);
478 base.0.fix_spans(len);
479 });
480 self.prefixes.iter_mut().for_each(|base| {
481 base.1 = rev_range(&base.1, len);
482 base.0.fix_spans(len);
483 });
484 self.triples.iter_mut().for_each(|base| {
485 base.1 = rev_range(&base.1, len);
486 base.0.fix_spans(len);
487 });
488 }
489
490 pub fn into_triples<'a>(&self, triples: Vec<MyQuad<'a>>) -> Triples2<'a> {
491 let base = match &self.base {
492 Some(Spanned(Base(_, Spanned(named_node, span)), _)) => named_node
493 .expand_step(self, HashSet::new())
494 .map(|st| MyTerm::named_node(st, span.clone())),
495 None => Some(MyTerm::named_node(self.set_base.as_str().to_string(), 0..0)),
496 };
497
498 let base_url = self.set_base.to_string();
499 Triples2 {
500 triples,
501 base,
502 base_url,
503 }
504 }
505}
506
507pub struct TriplesBuilder<'a, T> {
508 pub triples: Vec<MyQuad<'a>>,
509 blank_node: Box<dyn FnMut(std::ops::Range<usize>) -> MyTerm<'a>>,
510 base: BaseIri<String>,
511 based: &'a T,
512}
513
514impl<'a, T: Based> TriplesBuilder<'a, T> {
515 pub fn new(based: &'a T, base: BaseIri<String>) -> Self {
516 let mut count = 0;
517 let blank_node = Box::new(move |span: std::ops::Range<usize>| {
518 count += 1;
519 MyTerm::blank_node(format!("internal_bnode_{}", count), span)
520 });
521 Self {
522 triples: vec![],
523 blank_node,
524 base,
525 based,
526 }
527 }
528
529 fn handle_po(
530 &mut self,
531 pos: &'a [Spanned<PO>],
532 span: std::ops::Range<usize>,
533 subject: MyTerm<'a>,
534 ) -> Result<(), TurtleSimpleError> {
535 if pos.is_empty() {
536 let predicate = MyTerm::named_node("TestPredicate", 0..0);
537 let object = MyTerm::named_node("TestObject", 0..0);
538
539 let quad = MyQuad {
540 subject: subject.clone(),
541 predicate: predicate.clone(),
542 object,
543 span: span.clone(),
544 };
545
546 self.triples.push(quad);
547 }
548 let mut first = true;
549
550 for Spanned(PO { predicate, object }, span2) in pos.iter() {
551 let this_span = if first {
552 first = false;
553 span.clone()
554 } else {
555 span2.clone()
556 };
557
558 let predicate = if let Ok(node) = predicate
559 .value()
560 .expand_step(self.based, HashSet::new())
561 .ok_or(TurtleSimpleError::UnexpectedBase(
562 "Expected valid named node for object",
563 ))
564 .and_then(|n| {
565 self.base
566 .resolve(n.as_str())
567 .map_err(|e| TurtleSimpleError::Parse(e))
568 })
569 .map(|x| x.unwrap())
570 {
571 MyTerm::named_node(node, predicate.span().clone())
572 } else {
573 MyTerm::invalid(predicate.span().clone())
574 };
575
576 let mut first_object = true;
577 for o in object.iter() {
578 let this_span = if first_object {
579 first_object = false;
580 this_span.clone()
581 } else {
582 o.span().clone()
583 };
584 let object = self.term_to_my_term(Ok(o.as_ref()))?;
585
586 let quad = MyQuad {
587 subject: subject.clone(),
588 predicate: predicate.clone(),
589 object,
590 span: this_span,
591 };
592
593 self.triples.push(quad);
594 }
595 }
596 Ok(())
597 }
598
599 fn term_to_my_term(
600 &mut self,
601 term: Result<Spanned<&'a Term>, MyTerm<'a>>,
602 ) -> Result<MyTerm<'a>, TurtleSimpleError> {
603 let object = match term {
604 Ok(Spanned(Term::Variable(Variable(var, _)), span)) => MyTerm::variable(var, span),
605 Ok(Spanned(Term::NamedNode(NamedNode::Invalid), span)) => MyTerm::invalid(span),
606 Ok(Spanned(Term::NamedNode(nn), span)) => MyTerm::named_node(
607 nn.expand_step(self.based, HashSet::new())
608 .ok_or(TurtleSimpleError::UnexpectedBase(
609 "Expected valid named node for object",
610 ))
611 .and_then(|n| {
612 self.base
613 .resolve(n.as_str())
614 .map_err(|e| TurtleSimpleError::Parse(e))
615 })
616 .map(|x| x.unwrap())?,
617 span,
618 ),
619 Ok(Spanned(Term::Literal(literal), span)) => {
620 MyTerm::literal(literal.plain_string(), span)
621 }
622 Ok(Spanned(Term::BlankNode(bn), span)) => match bn {
623 BlankNode::Named(v, _) => MyTerm::blank_node(v, span),
624 BlankNode::Unnamed(v, _, _) => {
625 let out = (self.blank_node)(span.clone());
626 self.handle_po(v, span, out.clone())?;
627 out
628 }
629 BlankNode::Invalid => {
630 return Err(TurtleSimpleError::UnexpectedBase(
631 "Unexpected invalid blank for object",
632 ))
633 }
634 },
635 Ok(Spanned(Term::Collection(terms), span)) => self.handle_collection(&terms, span)?,
636 Ok(Spanned(Term::Invalid, span)) => MyTerm::invalid(span),
637 Err(x) => x,
638 };
639
640 Ok(object)
641 }
642
643 fn handle_collection(
644 &mut self,
645 collection: &'a [Spanned<Term>],
646 span: std::ops::Range<usize>,
647 ) -> Result<MyTerm<'a>, TurtleSimpleError> {
648 let mut prev = MyTerm::named_node(
649 "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil",
650 span.end..span.end,
651 );
652
653 for Spanned(term, s) in collection.iter().rev() {
654 let next = (self.blank_node)(s.clone());
655
656 let quad = MyQuad {
657 subject: next.clone(),
658 predicate: MyTerm::named_node(
659 "http://www.w3.org/1999/02/22-rdf-syntax-ns#first",
660 prev.span.start..prev.span.start,
661 ),
662 object: self.term_to_my_term(Ok(Spanned(term, s.clone())))?,
663 span: span.clone(),
664 };
665
666 self.triples.push(quad);
667
668 let quad = MyQuad {
669 subject: next.clone(),
670 predicate: MyTerm::named_node(
671 "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest",
672 s.start..s.start,
673 ),
674 object: prev,
675 span: s.clone(),
676 };
677
678 self.triples.push(quad);
679 prev = next;
680 }
681
682 Ok(prev)
683 }
684
685 pub fn ingest(
686 &mut self,
687 Spanned(ref triple, span): &'a Spanned<Triple>,
688 ) -> Result<(), TurtleSimpleError> {
689 let sub = match triple.subject.value() {
690 Term::BlankNode(BlankNode::Named(vs, _)) => {
691 MyTerm::blank_node(vs, triple.subject.span().clone())
692 }
693 Term::BlankNode(BlankNode::Unnamed(vs, _, _)) => {
694 let out = (self.blank_node)(triple.subject.span().clone());
695 self.handle_po(&vs, triple.subject.span().clone(), out.clone())?;
696 out
697 }
698 Term::NamedNode(NamedNode::Invalid) => MyTerm::invalid(triple.subject.span().clone()),
699 Term::NamedNode(nn) => MyTerm::named_node(
700 nn.expand_step(self.based, HashSet::new())
701 .ok_or(TurtleSimpleError::UnexpectedBase(
702 "Expected valid named node for object",
703 ))
704 .and_then(|n| {
705 self.base
706 .resolve(n.as_str())
707 .map_err(|e| TurtleSimpleError::Parse(e))
708 })
709 .map(|x| x.unwrap())?,
710 triple.subject.span().clone(),
711 ),
712 Term::Invalid => MyTerm::invalid(triple.subject.span().clone()),
713 Term::Variable(var) => MyTerm::variable(&var.0, triple.subject.span().clone()),
714
715 x => {
716 info!("Failed, unexpected {}", x.ty());
717 return Err(TurtleSimpleError::UnexpectedBaseString(format!(
718 "Unexpected {}",
719 x.ty()
720 )));
721 }
722 };
723
724 self.handle_po(&triple.po, span.clone(), sub.clone())?;
725
726 Ok(())
727 }
728}
729
730impl Turtle {
731 pub fn empty(location: &lsp_types::Url) -> Self {
732 Self::new(None, Vec::new(), Vec::new(), location)
733 }
734
735 pub fn get_simple_triples<'a>(&'a self) -> Result<Triples2<'a>, TurtleSimpleError> {
736 let base = match &self.base {
737 Some(Spanned(Base(_, Spanned(named_node, _)), _)) => {
738 let nn = named_node.expand_step(self, HashSet::new()).ok_or(
739 TurtleSimpleError::UnexpectedBase("Expected valid named node base"),
740 )?;
741 BaseIri::new(nn).map_err(TurtleSimpleError::Parse)?
742 }
743 None => BaseIri::new(self.set_base.as_str().to_string())
744 .map_err(TurtleSimpleError::Parse)?,
745 };
746
747 let mut builder = TriplesBuilder::new(self, base);
748
749 for t in &self.triples {
750 builder.ingest(&t)?;
751 }
752
753 Ok(self.into_triples(builder.triples))
754 }
755}
756
757impl Turtle {
758 pub fn new(
759 mut base: Option<Spanned<Base>>,
760 prefixes: Vec<Spanned<TurtlePrefix>>,
761 triples: Vec<Spanned<Triple>>,
762 location: &lsp_types::Url,
763 ) -> Self {
764 if let Some(b) = base.as_mut() {
765 b.resolve_location(location);
766 }
767 Self {
768 base,
769 prefixes,
770 triples,
771 set_base: location.clone(),
772 }
773 }
774
775 pub fn set_context(&self, ctx: &mut Context) {
776 for t in &self.triples {
777 t.set_context(ctx);
778 }
779 }
780
781 pub fn get_base(&self) -> &lsp_types::Url {
782 &self.set_base
783 }
784
785 pub fn shorten(&self, url: &str) -> Option<String> {
786 self.prefixes
787 .iter()
788 .flat_map(|pref| pref.shorten(self, url))
789 .next()
790 }
791}
792
793impl Display for Turtle {
794 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
795 if let Some(b) = &self.base {
796 writeln!(f, "{}", b.value())?;
797 }
798
799 self.prefixes
800 .iter()
801 .map(|x| x.value())
802 .try_for_each(|x| writeln!(f, "{}", x))?;
803
804 self.triples
805 .iter()
806 .map(|x| x.value())
807 .try_for_each(|x| writeln!(f, "{}", x))?;
808
809 Ok(())
810 }
811}
812
813#[cfg(test)]
814mod test {
815 use std::{collections::HashSet, str::FromStr};
816
817 use lsp_core::prelude::{spanned, MyQuad, Spanned};
818
819 use super::Turtle;
820 use crate::lang::{context::Context, parser as parser2, tokenizer::parse_tokens_str_safe};
821
822 #[derive(Debug)]
823 pub enum Err {
824 Tokenizing,
825 }
826
827 fn parse_turtle(
828 inp: &str,
829 url: &lsp_types::Url,
830 ) -> Result<(Turtle, Vec<Spanned<String>>), Err> {
831 let context = Context::new();
832 let ctx = context.ctx();
833 let tokens = parse_tokens_str_safe(inp).map_err(|e| Err::Tokenizing)?;
834
835 let mut comments: Vec<_> = tokens
836 .iter()
837 .filter(|x| x.0.is_comment())
838 .cloned()
839 .map(|x| spanned(x.0.to_comment(), x.1))
840 .collect();
841 comments.sort_by_key(|x| x.1.start);
842
843 let (turtle, errs) = parser2::parse_turtle(&url, tokens, inp.len(), ctx);
844 for e in errs {
845 println!("Error {:?}", e);
846 }
847
848 Ok((turtle.into_value(), comments))
849 }
850
851 #[test]
852 fn easy_triples() {
853 let txt = r#"
854@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
855@prefix foaf: <http://xmlns.com/foaf/0.1/> .
856# @base <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
857
858[] a foaf:Name;
859 foaf:knows <abc>;.
860"#;
861
862 let url = lsp_types::Url::from_str("http://example.com/ns#").unwrap();
863 let (output, _) = parse_turtle(txt, &url).expect("Simple");
864 let triples = output.get_simple_triples().expect("Triples found");
865
866 assert_eq!(triples.triples.len(), 3);
867 println!("{:?}", triples);
868 }
869
870 #[test]
871 fn easy_triples_2() {
872 let txt = r#"
873@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
874@prefix foaf: <http://xmlns.com/foaf/0.1/> .
875# @base <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
876
877[ foaf:knows <abc>; ]
878 a foaf:Name;
879 foaf:knows [
880 a foaf:Name;
881 foaf:knows [
882 a foaf:Name; ] ].
883"#;
884
885 let url = lsp_types::Url::from_str("http://example.com/ns#").unwrap();
886 let (output, _) = parse_turtle(txt, &url).expect("Simple");
887 let triples = output.get_simple_triples().expect("Triples found");
888
889 assert_eq!(triples.triples.len(), 6);
890 }
891
892 #[test]
893 fn triples_collection() {
894 let txt = r#"
895<e> <pred> (<a> <b> <c>).
896"#;
897
898 let url = lsp_types::Url::from_str("http://example.com/ns#").unwrap();
899 let (output, _) = parse_turtle(txt, &url).expect("Simple collection");
900 let triples = output.get_simple_triples().expect("Triples found");
901
902 let a: &Vec<MyQuad<'_>> = &triples;
903
904 let quads: HashSet<String> = a
905 .iter()
906 .map(|triple| format!("{} {} {}.", triple.subject, triple.predicate, triple.object))
907 .collect();
908
909 let expected_quads: HashSet<String> = "<http://example.com/e> <http://example.com/pred> _:internal_bnode_3.
910_:internal_bnode_3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:internal_bnode_2.
911_:internal_bnode_3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/a>.
912_:internal_bnode_2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:internal_bnode_1.
913_:internal_bnode_2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/b>.
914_:internal_bnode_1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>.
915_:internal_bnode_1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/c>.".split("\n").map(|x|x.trim()).map(String::from).collect();
916
917 for t in &quads {
918 println!("{}", t);
919 }
920 assert_eq!(quads, expected_quads);
921
922 println!("triples {:?}", triples);
923
924 assert_eq!(triples.triples.len(), 7);
925 }
926
927 #[test]
928 fn owl_is_valid() {
929 let txt = include_str!("../../../lov/prefixes/owl.ttl");
930
931 let url = lsp_types::Url::from_str("http://example.com/ns#").unwrap();
932 let (output, _) = parse_turtle(txt, &url).expect("Simple collection");
933 let triples = output.get_simple_triples().expect("Triples found");
934 }
935
936 #[test]
937 fn owl_is_valid_2() {
938 let txt = r#"
939@prefix dc: <http://purl.org/dc/elements/1.1/> .
940@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
941@prefix owl: <http://www.w3.org/2002/07/owl#> .
942@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
943@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
944@prefix xml: <http://www.w3.org/XML/1998/namespace> .
945@prefix grddl: <http://www.w3.org/2003/g/data-view#> .
946
947<http://www.w3.org/2002/07/owl>
948 a owl:Ontology ;
949 rdfs:comment "\r\n This ontology partially describes the built-in " ; .
950 "#;
951
952 let url = lsp_types::Url::from_str("http://example.com/ns#").unwrap();
953 let (output, _) = parse_turtle(txt, &url).expect("Simple collection");
954 output.get_simple_triples().expect("Triples found");
955 }
956}