blues-lsp 0.1.0

LSP language server for the Bluespec SystemVerilog language
Documentation
use arcstr::Substr;

use crate::{
    symbols::name::SymName,
    syntax::cst::{
        kind::TreeKind, tree::NodeRef, view::{self, TypeVar, View}
    },
    util::data::either::Either,
};

pub trait ScopeWalk {
    type R;

    fn scope(
        &mut self,
        node: NodeRef,
        inner: impl FnOnce(&mut Self) -> Option<Self::R>,
    ) -> Option<Self::R>;
    fn def(&mut self, node: NodeRef, name: SymName) -> Option<Self::R>;
    fn link(&mut self, node: NodeRef, pkg: Option<Substr>, name: SymName) -> Option<Self::R>;
    fn ty_var(&mut self, node: TypeVar) -> Option<Self::R>;

    fn link_qual(&mut self, qid: view::QualId, is_ty: bool) -> Option<Self::R> {
        let name = qid.name()?;
        let pkg = qid.pkg().map(|id| id.str());
        use SymName::*;
        self.link(
            name.syntax(),
            pkg,
            if is_ty {
                Type(name.str())
            } else {
                Value(name.str())
            },
        )
    }

    fn walk(&mut self, node: NodeRef) -> Option<Self::R> {
        self.walk_impl(node)
    }

    fn walk_impl(&mut self, node: NodeRef) -> Option<Self::R> {
        use SymName::*;
        use view::*;
        match node.open_kind()? {
            TreeKind::Body => self.scoped_children(node),

            // 'Value' Definitions
            TreeKind::StmtModule => StmtModule::cast(node)
                .name()
                .and_then(|n| self.def(node, Value(n.str())))
                .or_else(|| self.scoped_children(node)),
            TreeKind::ModuleParam => ModuleParam::cast(node)
                .typed_name()
                .and_then(|n| n.name())
                .and_then(|n| self.def(node, SymName::Value(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::ModulePortParam => ModulePortParam::cast(node)
                .name()
                .and_then(|n| self.def(node, SymName::Value(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::StmtFunction => {
                let fun = StmtFunction::cast(node);
                fun.typed_name()
                    .and_then(|n| n.name())
                    .and_then(|n| self.def(node, Value(n.str())))
                    .or_else(|| {
                        self.scope(node, |slf| {
                            fun.param_list()
                                .and_then(|l| {
                                    l.params().find_map(|p| {
                                        p.typed_name()
                                            .and_then(|n| n.name())
                                            .and_then(|n| slf.def(p.syntax(), Value(n.str())))
                                            .or_else(|| slf.walk_children(node))
                                    })
                                })
                                .or_else(|| slf.walk_children(node))
                        })
                    })
            }
            TreeKind::StmtMethod => {
                let fun = StmtMethod::cast(node);
                fun.typed_name()
                    .and_then(|n| n.name())
                    .and_then(|n| self.def(node, Value(n.str())))
                    .or_else(|| {
                        self.scope(node, |slf| {
                            fun.param_list()
                                .and_then(|l| {
                                    l.params().find_map(|p| {
                                        p.typed_name()
                                            .and_then(|n| n.name())
                                            .and_then(|n| slf.def(p.syntax(), Value(n.str())))
                                            .or_else(|| slf.walk_children(node))
                                    })
                                })
                                .or_else(|| slf.walk_children(node))
                        })
                    })
            }
            TreeKind::VarInit => VarInit::cast(node)
                .target()
                .and_then(Either::left)
                .and_then(|n| self.def(node, Value(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::DeclPattern => DeclPattern::cast(node)
                .name()
                .and_then(Either::right)
                .and_then(|n| self.def(node, Value(n.str())))
                .or_else(|| self.walk_children(node)),

            // 'Type' Definitions
            TreeKind::StmtInterface => StmtInterface::cast(node)
                .name()
                .and_then(|n| self.def(node, Type(n.str())))
                .or_else(|| self.scoped_children(node)),
            TreeKind::StmtTypedef => StmtTypedef::cast(node)
                .kind()
                .and_then(|kind| match kind {
                    TypedefKind::Enum(tydef) => tydef
                        .name()
                        .and_then(|n| self.def(tydef.syntax(), SymName::Type(n.str()))),
                    TypedefKind::Struct(tydef) => tydef
                        .name()
                        .and_then(|n| self.def(tydef.syntax(), SymName::Type(n.str()))),
                    TypedefKind::Union(tydef) => tydef
                        .name()
                        .and_then(|n| self.def(tydef.syntax(), SymName::Type(n.str()))),
                    TypedefKind::Alias(tydef) => tydef
                        .name()
                        .and_then(|n| self.def(tydef.syntax(), SymName::Type(n.str()))),
                })
                .or_else(|| self.scoped_children(node)),
            // These nodes have params after body, need to override walk order.
            TreeKind::TypedefEnum => {
                let tydef = TypedefEnum::cast(node);
                tydef
                    .param_list()
                    .and_then(|n| self.walk(n.syntax()))
                    .or_else(|| tydef.derives().and_then(|n| self.walk(n.syntax())))
                    .or_else(|| tydef.variant_list().and_then(|n| self.walk(n.syntax())))
            }
            TreeKind::TypedefStruct => {
                let tydef = TypedefStruct::cast(node);
                tydef
                    .param_list()
                    .and_then(|n| self.walk(n.syntax()))
                    .or_else(|| tydef.derives().and_then(|n| self.walk(n.syntax())))
                    .or_else(|| tydef.field_list().and_then(|n| self.walk(n.syntax())))
            }
            TreeKind::TypedefUnion => {
                let tydef = TypedefUnion::cast(node);
                tydef
                    .param_list()
                    .and_then(|n| self.walk(n.syntax()))
                    .or_else(|| tydef.derives().and_then(|n| self.walk(n.syntax())))
                    .or_else(|| tydef.field_list().and_then(|n| self.walk(n.syntax())))
            }
            TreeKind::TypedefAlias => {
                let tydef = TypedefAlias::cast(node);
                tydef
                    .param_list()
                    .and_then(|n| self.walk(n.syntax()))
                    .or_else(|| tydef.derives().and_then(|n| self.walk(n.syntax())))
                    .or_else(|| tydef.definition().and_then(|n| self.walk(n.syntax())))
            }
            TreeKind::TypedefParam => TypedefParam::cast(node)
                .name()
                .and_then(|n| self.def(node, SymName::Type(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::StmtInstance => self.scoped_children(node),
            TreeKind::StmtTypeclass => StmtTypeclass::cast(node)
                .name()
                .and_then(|n| self.def(node, SymName::Type(n.str())))
                .or_else(|| self.scoped_children(node)),

            // References
            TreeKind::ExprVar => ExprVar::cast(node)
                .id()
                .and_then(|n| self.link_qual(n, false))
                .or_else(|| self.walk_children(node)),
            TreeKind::TypeCons => TypeCons::cast(node)
                .id()
                .and_then(|n| self.link_qual(n, true))
                .or_else(|| self.walk_children(node)),
            TreeKind::TypeVar => self
                .ty_var(TypeVar::cast(node))
                .or_else(|| self.walk_children(node)),
            TreeKind::QualId => QualId::cast(node)
                .pkg()
                .and_then(|n| self.link(n.syntax(), None, SymName::Pkg(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::ImportItem => ImportItem::cast(node)
                .name()
                .and_then(|n| self.link(n.syntax(), None, SymName::Pkg(n.str())))
                .or_else(|| self.walk_children(node)),
            TreeKind::ExportItem => ExportItem::cast(node).kind().and_then(|k| match k {
                ExportItemKind::Def(ident) => self
                    .link(ident.syntax(), None, SymName::Value(ident.str()))
                    .or_else(|| self.link(ident.syntax(), None, SymName::Type(ident.str()))),
                ExportItemKind::Package(ident) => {
                    self.link(ident.syntax(), None, SymName::Pkg(ident.str()))
                }
                ExportItemKind::Struct(ident) => {
                    self.link(ident.syntax(), None, SymName::Type(ident.str()))
                }
            }),
            TreeKind::Error => None,
            _ => self.walk_children(node),
        }
    }

    fn walk_children(&mut self, node: NodeRef) -> Option<Self::R> {
        node.children().find_map(|child| self.walk(child))
    }

    fn scoped_children(&mut self, node: NodeRef) -> Option<Self::R> {
        self.scope(node, |slf| slf.walk_children(node))
    }
}