use std::{fmt::Debug, hash::Hash};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LanguageCategory {
Programming,
Markup,
Config,
StyleSheet,
Dsl,
Modeling,
Other,
}
pub trait Language: Send + Sync {
const NAME: &'static str;
const CATEGORY: LanguageCategory = LanguageCategory::Programming;
type TokenType: TokenType;
type ElementType: ElementType;
type TypedRoot;
}
macro_rules! define_token_type {
($($bound:tt)*) => {
pub trait TokenType: Copy + Eq + Hash + Send + Sync + std::fmt::Debug $($bound)* {
type Role: TokenRole;
const END_OF_STREAM: Self;
fn role(&self) -> Self::Role;
fn is_role(&self, role: Self::Role) -> bool {
self.role() == role
}
fn is_universal(&self, role: UniversalTokenRole) -> bool {
self.role().universal() == role
}
fn is_comment(&self) -> bool {
self.is_universal(UniversalTokenRole::Comment)
}
fn is_whitespace(&self) -> bool {
self.is_universal(UniversalTokenRole::Whitespace)
}
fn is_error(&self) -> bool {
self.is_universal(UniversalTokenRole::Error)
}
fn is_ignored(&self) -> bool {
self.is_whitespace() || self.is_comment()
}
fn is_end_of_stream(&self) -> bool {
*self == Self::END_OF_STREAM
}
}
};
}
define_token_type!();
pub trait TokenRole: Copy + Eq + Send {
fn universal(&self) -> UniversalTokenRole;
fn name(&self) -> &str;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum UniversalTokenRole {
Keyword,
Name,
Literal,
Escape,
Operator,
Punctuation,
Comment,
Whitespace,
Error,
None,
Eof,
}
impl TokenRole for UniversalTokenRole {
fn universal(&self) -> UniversalTokenRole {
*self
}
fn name(&self) -> &str {
match *self {
UniversalTokenRole::Keyword => "keyword",
UniversalTokenRole::Name => "variable.other",
UniversalTokenRole::Literal => "constant",
UniversalTokenRole::Escape => "constant.character.escape",
UniversalTokenRole::Operator => "keyword.operator",
UniversalTokenRole::Punctuation => "punctuation",
UniversalTokenRole::Comment => "comment",
UniversalTokenRole::Whitespace => "punctuation.whitespace",
UniversalTokenRole::Error => "invalid",
UniversalTokenRole::None => "none",
UniversalTokenRole::Eof => "punctuation.eof",
}
}
}
macro_rules! define_element_type {
($($bound:tt)*) => {
pub trait ElementType: Copy + Eq + Hash + Send + Sync + std::fmt::Debug $($bound)* {
type Role: ElementRole;
fn role(&self) -> Self::Role;
fn is_role(&self, role: Self::Role) -> bool {
self.role() == role
}
fn is_universal(&self, role: UniversalElementRole) -> bool {
self.role().universal() == role
}
fn is_root(&self) -> bool {
self.is_universal(UniversalElementRole::Root)
}
fn is_error(&self) -> bool {
self.is_universal(UniversalElementRole::Error)
}
}
};
}
define_element_type!();
pub trait ElementRole: Copy + Eq + Send {
fn universal(&self) -> UniversalElementRole;
fn name(&self) -> &str;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[non_exhaustive]
pub enum UniversalElementRole {
Root,
Container,
Definition,
Binding,
Reference,
Typing,
Documentation,
Metadata,
Attribute,
AttributeKey,
Detail,
Name,
Statement,
Expression,
Call,
Value,
Embedded,
Error,
None,
}
impl ElementRole for UniversalElementRole {
fn universal(&self) -> UniversalElementRole {
*self
}
fn name(&self) -> &str {
match *self {
UniversalElementRole::Container => "meta.block",
UniversalElementRole::Statement => "meta.statement",
UniversalElementRole::Binding => "variable.other.declaration",
UniversalElementRole::Reference => "variable.other.usage",
UniversalElementRole::Call => "entity.name.function.call",
UniversalElementRole::Expression => "meta.expression",
UniversalElementRole::Value => "constant",
UniversalElementRole::Definition => "entity.name.function",
UniversalElementRole::Typing => "entity.name.type",
UniversalElementRole::Metadata => "meta.preprocessor",
UniversalElementRole::Attribute => "entity.other.attribute-name",
UniversalElementRole::AttributeKey => "entity.other.attribute-name.key",
UniversalElementRole::Detail => "meta.detail",
UniversalElementRole::Name => "entity.name",
UniversalElementRole::Embedded => "meta.embedded",
UniversalElementRole::Documentation => "comment.block.documentation",
UniversalElementRole::Root => "source",
UniversalElementRole::Error => "invalid",
UniversalElementRole::None => "none",
}
}
}