use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum VarKind {
Scalar,
Array,
Hash,
}
impl VarKind {
#[inline]
pub const fn sigil(self) -> &'static str {
match self {
VarKind::Scalar => "$",
VarKind::Array => "@",
VarKind::Hash => "%",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SymbolKind {
Package,
Class,
Role,
Subroutine,
Method,
Variable(VarKind),
Constant,
Import,
Export,
Label,
Format,
}
impl SymbolKind {
#[inline]
pub const fn to_lsp_kind(self) -> u32 {
match self {
SymbolKind::Package => 2, SymbolKind::Class => 5, SymbolKind::Role => 8, SymbolKind::Subroutine => 12, SymbolKind::Method => 6, SymbolKind::Variable(_) => 13, SymbolKind::Constant => 14, SymbolKind::Import => 2, SymbolKind::Export => 12, SymbolKind::Label => 20, SymbolKind::Format => 23, }
}
#[inline]
pub const fn to_lsp_kind_document_symbol(self) -> u32 {
match self {
SymbolKind::Package => 2, SymbolKind::Class => 5, SymbolKind::Role => 8, SymbolKind::Subroutine => 12, SymbolKind::Method => 6, SymbolKind::Variable(VarKind::Scalar) => 13, SymbolKind::Variable(VarKind::Array) => 18, SymbolKind::Variable(VarKind::Hash) => 19, SymbolKind::Constant => 14, SymbolKind::Import => 2, SymbolKind::Export => 12, SymbolKind::Label => 20, SymbolKind::Format => 23, }
}
#[inline]
pub const fn sigil(self) -> Option<&'static str> {
match self {
SymbolKind::Variable(vk) => Some(vk.sigil()),
_ => None,
}
}
#[inline]
pub const fn is_variable(self) -> bool {
matches!(self, SymbolKind::Variable(_))
}
#[inline]
pub const fn is_callable(self) -> bool {
matches!(self, SymbolKind::Subroutine | SymbolKind::Method)
}
#[inline]
pub const fn is_namespace(self) -> bool {
matches!(self, SymbolKind::Package | SymbolKind::Class | SymbolKind::Role)
}
#[inline]
pub const fn scalar() -> Self {
SymbolKind::Variable(VarKind::Scalar)
}
#[inline]
pub const fn array() -> Self {
SymbolKind::Variable(VarKind::Array)
}
#[inline]
pub const fn hash() -> Self {
SymbolKind::Variable(VarKind::Hash)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_var_kind_sigils() {
assert_eq!(VarKind::Scalar.sigil(), "$");
assert_eq!(VarKind::Array.sigil(), "@");
assert_eq!(VarKind::Hash.sigil(), "%");
}
#[test]
fn test_symbol_kind_sigils() {
assert_eq!(SymbolKind::Variable(VarKind::Scalar).sigil(), Some("$"));
assert_eq!(SymbolKind::Variable(VarKind::Array).sigil(), Some("@"));
assert_eq!(SymbolKind::Variable(VarKind::Hash).sigil(), Some("%"));
assert_eq!(SymbolKind::Subroutine.sigil(), None);
assert_eq!(SymbolKind::Package.sigil(), None);
}
#[test]
fn test_lsp_kind_mapping() {
assert_eq!(SymbolKind::Package.to_lsp_kind(), 2);
assert_eq!(SymbolKind::Class.to_lsp_kind(), 5);
assert_eq!(SymbolKind::Method.to_lsp_kind(), 6);
assert_eq!(SymbolKind::Role.to_lsp_kind(), 8);
assert_eq!(SymbolKind::Subroutine.to_lsp_kind(), 12);
assert_eq!(SymbolKind::Variable(VarKind::Scalar).to_lsp_kind(), 13);
assert_eq!(SymbolKind::Constant.to_lsp_kind(), 14);
assert_eq!(SymbolKind::Label.to_lsp_kind(), 20);
assert_eq!(SymbolKind::Format.to_lsp_kind(), 23);
}
#[test]
fn test_lsp_kind_document_symbol_mapping() {
assert_eq!(SymbolKind::Package.to_lsp_kind_document_symbol(), 2);
assert_eq!(SymbolKind::Class.to_lsp_kind_document_symbol(), 5);
assert_eq!(SymbolKind::Subroutine.to_lsp_kind_document_symbol(), 12);
assert_eq!(SymbolKind::Variable(VarKind::Scalar).to_lsp_kind_document_symbol(), 13); assert_eq!(SymbolKind::Variable(VarKind::Array).to_lsp_kind_document_symbol(), 18); assert_eq!(SymbolKind::Variable(VarKind::Hash).to_lsp_kind_document_symbol(), 19); }
#[test]
fn test_convenience_constructors() {
assert_eq!(SymbolKind::scalar(), SymbolKind::Variable(VarKind::Scalar));
assert_eq!(SymbolKind::array(), SymbolKind::Variable(VarKind::Array));
assert_eq!(SymbolKind::hash(), SymbolKind::Variable(VarKind::Hash));
}
#[test]
fn test_category_predicates() {
assert!(SymbolKind::Variable(VarKind::Scalar).is_variable());
assert!(!SymbolKind::Subroutine.is_variable());
assert!(SymbolKind::Subroutine.is_callable());
assert!(SymbolKind::Method.is_callable());
assert!(!SymbolKind::Variable(VarKind::Scalar).is_callable());
assert!(SymbolKind::Package.is_namespace());
assert!(SymbolKind::Class.is_namespace());
assert!(SymbolKind::Role.is_namespace());
assert!(!SymbolKind::Subroutine.is_namespace());
}
}