swls_lang_turtle/lang/
parser.rs1use rdf_parsers::{
2 model::Turtle,
3 turtle::{convert::convert, Lang, Rule, SyntaxKind},
4 IncrementalBias, PrevParseInfo,
5};
6use swls_core::prelude::SimpleDiagnostic;
7
8#[derive(Debug, Clone)]
9pub struct TurtleParseError {
10 pub range: std::ops::Range<usize>,
11 pub msg: String,
12}
13
14impl From<TurtleParseError> for SimpleDiagnostic {
15 fn from(e: TurtleParseError) -> Self {
16 SimpleDiagnostic::new(e.range, e.msg)
17 }
18}
19
20impl From<&TurtleParseError> for SimpleDiagnostic {
21 fn from(e: &TurtleParseError) -> Self {
22 SimpleDiagnostic::new(e.range.clone(), e.msg.clone())
23 }
24}
25
26pub type TurtleNode = rowan::SyntaxNode<Lang>;
27
28pub fn parse_new(
32 source: &str,
33 base_url: &str,
34 prev: Option<&PrevParseInfo>,
35) -> (
36 Turtle,
37 Vec<TurtleParseError>,
38 PrevParseInfo,
39 TurtleNode,
40 rowan::GreenNode,
41) {
42 let (parse, prev_info) = rdf_parsers::parse_incremental(
43 Rule::new(SyntaxKind::TurtleDoc),
44 source,
45 prev,
46 IncrementalBias::default(),
47 );
48
49 let node: TurtleNode = parse.syntax::<Lang>();
50 let mut model = convert(&node);
51 model.set_base = Some(base_url.to_string());
52
53 let errors = collect_errors(&node);
54 (model, errors, prev_info, node, parse.green_node)
55}
56
57pub fn collect_errors(node: &TurtleNode) -> Vec<TurtleParseError> {
58 use rowan::NodeOrToken;
59 let mut errors = Vec::new();
60 let mut stack = vec![node.clone()];
61 while let Some(current) = stack.pop() {
62 for child in current.children_with_tokens() {
63 match child {
64 NodeOrToken::Node(n) => {
65 if n.kind() == SyntaxKind::Error {
66 let range = rdf_parsers::effective_error_span::<Lang>(&n);
67 let msg = n
68 .parent()
69 .map(|p| format!("Expected: {:?}", p.kind()))
70 .unwrap_or_else(|| format!("Unexpected: {}", n.text()));
71 errors.push(TurtleParseError { range, msg });
72 } else {
73 stack.push(n);
74 }
75 }
76 NodeOrToken::Token(t) => {
77 if t.kind() == SyntaxKind::Error {
78 let range = t.text_range();
79 errors.push(TurtleParseError {
80 range: range.start().into()..range.end().into(),
81 msg: format!("Unexpected: {}", t.text()),
82 });
83 }
84 }
85 }
86 }
87 }
88 errors
89}