wat_service 0.8.0

WebAssembly Text Format language service.
Documentation
use crate::{
    LanguageService,
    binder::{SymbolKey, SymbolTable},
    helpers,
};
use lspt::{
    Declaration, DeclarationParams, Definition, DefinitionParams, TypeDefinitionParams, Union2,
};
use wat_syntax::SyntaxKind;

impl LanguageService {
    /// Handler for `textDocument/definition` request.
    pub fn goto_definition(&self, params: DefinitionParams) -> Option<Definition> {
        let document = self.get_document(&params.text_document.uri)?;
        let root = document.root_tree(self);
        let token = super::find_meaningful_token(self, document, &root, params.position)?;

        let parent = token
            .parent()
            .filter(|parent| matches!(parent.kind(), SyntaxKind::IMMEDIATE | SyntaxKind::INDEX))?;
        let line_index = document.line_index(self);
        let symbol_table = SymbolTable::of(self, document);
        let key = SymbolKey::new(&parent);
        symbol_table.resolved.get(&key).map(|key| {
            Union2::A(helpers::create_location_by_symbol(
                params.text_document.uri.clone(),
                line_index,
                *key,
                &root,
            ))
        })
    }

    /// Handler for `textDocument/typeDefinition` request.
    pub fn goto_type_definition(&self, params: TypeDefinitionParams) -> Option<Definition> {
        let document = self.get_document(&params.text_document.uri)?;
        let line_index = document.line_index(self);
        let root = document.root_tree(self);
        let symbol_table = SymbolTable::of(self, document);
        let token = super::find_meaningful_token(self, document, &root, params.position)?;

        let parent = token
            .parent()
            .filter(|parent| parent.kind() == SyntaxKind::IMMEDIATE)?;
        symbol_table
            .resolved
            .get(&SymbolKey::new(&parent))
            .and_then(|key| {
                key.try_to_node(&root)?
                    .children()
                    .find_map(|child| match child.kind() {
                        SyntaxKind::TYPE_USE | SyntaxKind::HEAP_TYPE => {
                            child.first_child_by_kind(&|kind| kind == SyntaxKind::INDEX)
                        }
                        SyntaxKind::REF_TYPE => child
                            .first_child_by_kind(&|kind| kind == SyntaxKind::HEAP_TYPE)
                            .and_then(|node| {
                                node.first_child_by_kind(&|kind| kind == SyntaxKind::INDEX)
                            }),
                        SyntaxKind::GLOBAL_TYPE => child
                            .first_child_by_kind(&|kind| kind == SyntaxKind::REF_TYPE)
                            .and_then(|node| {
                                node.first_child_by_kind(&|kind| kind == SyntaxKind::HEAP_TYPE)
                            })
                            .and_then(|node| {
                                node.first_child_by_kind(&|kind| kind == SyntaxKind::INDEX)
                            }),
                        _ => None,
                    })
                    .and_then(|type_idx| symbol_table.resolved.get(&SymbolKey::new(&type_idx)))
            })
            .map(|key| {
                Union2::A(helpers::create_location_by_symbol(
                    params.text_document.uri.clone(),
                    line_index,
                    *key,
                    &root,
                ))
            })
    }

    /// Handler for `textDocument/declaration` request.
    pub fn goto_declaration(&self, params: DeclarationParams) -> Option<Declaration> {
        self.goto_definition(DefinitionParams {
            text_document: params.text_document,
            position: params.position,
            work_done_token: params.work_done_token,
            partial_result_token: params.partial_result_token,
        })
    }
}