wat_service 0.7.0

WebAssembly Text Format language service.
Documentation
use crate::helpers;
use line_index::LineIndex;
use lspt::{Diagnostic, DiagnosticSeverity, Range, Union2};
use rowan::ast::AstNode;
use wat_syntax::{SyntaxNode, ast::Instr};

const DIAGNOSTIC_CODE: &str = "const-expr";

pub fn check(line_index: &LineIndex, node: &SyntaxNode) -> Option<Diagnostic> {
    let first = node.first_child_by_kind(&Instr::can_cast)?;
    let last = node
        .children()
        .filter(|child| Instr::can_cast(child.kind()))
        .last()?;
    if node.descendants().filter_map(Instr::cast).all(|instr| {
        if let Instr::Plain(plain) = instr {
            plain.instr_name().is_some_and(|instr_name| {
                matches!(
                    instr_name.text().split_once('.'),
                    Some((_, "const"))
                        | Some(("i32" | "i64", "add" | "sub" | "mul"))
                        | Some(("global", "get"))
                        | Some(("ref", "null" | "i31" | "func"))
                        | Some(("struct" | "array", "new" | "new_default"))
                        | Some(("array", "new_fixed"))
                        | Some(("any", "convert_extern"))
                        | Some(("extern", "convert_any"))
                )
            })
        } else {
            false
        }
    }) {
        None
    } else {
        Some(Diagnostic {
            range: Range {
                start: helpers::rowan_pos_to_lsp_pos(line_index, first.text_range().start()),
                end: helpers::rowan_pos_to_lsp_pos(line_index, last.text_range().end()),
            },
            severity: Some(DiagnosticSeverity::Error),
            source: Some("wat".into()),
            code: Some(Union2::B(DIAGNOSTIC_CODE.into())),
            message: "expression must be constant".into(),
            ..Default::default()
        })
    }
}