wat_service 0.2.0

WebAssembly Text Format language service.
Documentation
use crate::{
    binder::{SymbolItemKind, SymbolTable},
    helpers,
    idx::IdentsCtx,
    LanguageService,
};
use line_index::LineIndex;
use lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString};

const DIAGNOSTIC_CODE: &str = "undef";

pub fn check(
    service: &LanguageService,
    diags: &mut Vec<Diagnostic>,
    line_index: &LineIndex,
    symbol_table: &SymbolTable,
) {
    let diagnostics = symbol_table
        .symbols
        .iter()
        .filter(|symbol| match &symbol.kind {
            SymbolItemKind::Module
            | SymbolItemKind::Func
            | SymbolItemKind::Param
            | SymbolItemKind::Local
            | SymbolItemKind::Type
            | SymbolItemKind::GlobalDef
            | SymbolItemKind::MemoryDef
            | SymbolItemKind::TableDef
            | SymbolItemKind::BlockDef => false,
            SymbolItemKind::Call
            | SymbolItemKind::TypeUse
            | SymbolItemKind::GlobalRef
            | SymbolItemKind::MemoryRef
            | SymbolItemKind::TableRef => symbol_table
                .find_defs(symbol.key)
                .is_none_or(|defs| defs.count() == 0),
            SymbolItemKind::LocalRef => symbol_table.find_param_or_local_def(symbol.key).is_none(),
            SymbolItemKind::BlockRef => !symbol_table.blocks.iter().any(|block| {
                block.ref_key == symbol.key && symbol.idx.is_defined_by(&block.def_idx)
            }),
        })
        .map(|symbol| Diagnostic {
            range: helpers::rowan_range_to_lsp_range(line_index, symbol.key.text_range()),
            severity: Some(DiagnosticSeverity::ERROR),
            source: Some("wat".into()),
            code: Some(NumberOrString::String(DIAGNOSTIC_CODE.into())),
            message: format!(
                "cannot find `{}` in this scope",
                symbol
                    .idx
                    .name
                    .map(|name| service.lookup_ident(name))
                    .or_else(|| symbol.idx.num.map(|num| num.to_string()))
                    .unwrap_or_default()
            ),
            ..Default::default()
        });
    diags.extend(diagnostics);
}