Skip to main content

ll_sparql_parser/
lib.rs

1pub mod ast;
2mod parser;
3mod rules;
4pub mod syntax_kind;
5mod syntax_node;
6mod utils;
7
8#[cfg(target_arch = "wasm32")]
9use js_sys::{Array, Object, Reflect};
10pub use parser::{guess_operation_type, ParseError, TopEntryPoint};
11#[cfg(target_arch = "wasm32")]
12use rowan::TextSize;
13use syntax_kind::SyntaxKind;
14pub use syntax_node::*;
15pub use utils::*;
16#[cfg(target_arch = "wasm32")]
17use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
18
19use crate::parser::lex;
20
21pub fn parse_query(input: &str) -> (SyntaxNode, Vec<ParseError>) {
22    let (root, errors) = parser::parse_text(input, parser::TopEntryPoint::QueryUnit);
23    (SyntaxNode::new_root(root), errors)
24}
25
26pub fn parse_update(input: &str) -> (SyntaxNode, Vec<ParseError>) {
27    let (root, errors) = parser::parse_text(input, parser::TopEntryPoint::UpdateUnit);
28    (SyntaxNode::new_root(root), errors)
29}
30
31pub fn parse(input: &str) -> (SyntaxNode, Vec<ParseError>) {
32    match guess_operation_type(input) {
33        Some(TopEntryPoint::QueryUnit) | None => parse_query(input),
34        Some(TopEntryPoint::UpdateUnit) => parse_update(input),
35    }
36}
37
38pub enum QueryType {
39    SelectQuery,
40    ConstructQuery,
41    DescribeQuery,
42    AskQuery,
43}
44
45pub fn guess_query_type(input: &str) -> Option<QueryType> {
46    let tokens = lex(input);
47    tokens.iter().find_map(|(token, _)| match token.kind() {
48        SyntaxKind::SELECT => Some(QueryType::SelectQuery),
49        SyntaxKind::CONSTRUCT => Some(QueryType::ConstructQuery),
50        SyntaxKind::ASK => Some(QueryType::AskQuery),
51        SyntaxKind::DESCRIBE => Some(QueryType::DescribeQuery),
52        _ => None,
53    })
54}
55
56#[cfg(test)]
57mod tests;
58
59#[cfg(target_arch = "wasm32")]
60#[wasm_bindgen]
61pub fn get_parse_tree(input: &str, offset: u32) -> JsValue {
62    let root = parse(input).0;
63    build_js_tree(&root, TextSize::new(offset))
64}
65
66#[cfg(target_arch = "wasm32")]
67fn build_js_tree(node: &SyntaxNode, offset: TextSize) -> JsValue {
68    let obj = Object::new();
69    Reflect::set(
70        &obj,
71        &JsValue::from_str("kind"),
72        &JsValue::from_str(&format!("{:?}", node.kind())),
73    )
74    .unwrap();
75    Reflect::set(&obj, &JsValue::from_str("type"), &JsValue::from_str("node")).unwrap();
76    Reflect::set(
77        &obj,
78        &JsValue::from_str("active"),
79        &JsValue::from_bool(node.text_range().contains(offset)),
80    )
81    .unwrap();
82
83    let children = Array::from_iter(node.children_with_tokens().filter_map(|child| match child {
84        rowan::NodeOrToken::Node(node) => Some(build_js_tree(&node, offset)),
85        rowan::NodeOrToken::Token(token) => {
86            let token_obj = Object::new();
87            Reflect::set(
88                &token_obj,
89                &JsValue::from_str("kind"),
90                &JsValue::from_str(&format!("{:?}", token.kind())),
91            )
92            .unwrap();
93            Reflect::set(
94                &token_obj,
95                &JsValue::from_str("type"),
96                &JsValue::from_str("token"),
97            )
98            .unwrap();
99            Reflect::set(
100                &token_obj,
101                &JsValue::from_str("text"),
102                &JsValue::from_str(token.text()),
103            )
104            .unwrap();
105            Reflect::set(
106                &token_obj,
107                &JsValue::from_str("active"),
108                &JsValue::from_bool(token.text_range().contains(offset)),
109            )
110            .unwrap();
111            Some(token_obj.into())
112        }
113    }));
114    Reflect::set(&obj, &JsValue::from_str("children"), &children.into()).unwrap();
115    obj.into()
116}