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