use rowan::{Language, SyntaxKind as RawSyntaxKind};
use crate::SyntaxKind;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct PraxisLanguage;
impl Language for PraxisLanguage {
type Kind = SyntaxKind;
#[inline]
fn kind_from_raw(raw: RawSyntaxKind) -> Self::Kind {
SyntaxKind::from_raw_u16(raw.0)
}
#[inline]
fn kind_to_raw(kind: Self::Kind) -> RawSyntaxKind {
RawSyntaxKind(kind as u16)
}
}
pub type SyntaxNode = rowan::SyntaxNode<PraxisLanguage>;
pub type SyntaxToken = rowan::SyntaxToken<PraxisLanguage>;
pub type SyntaxElement = rowan::SyntaxElement<PraxisLanguage>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kinds_round_trip_through_raw() {
for kind in [
SyntaxKind::Whitespace,
SyntaxKind::Ident,
SyntaxKind::KW_IF,
SyntaxKind::PLUS,
SyntaxKind::EOF,
SyntaxKind::ERROR,
SyntaxKind::SOURCE_FILE,
SyntaxKind::PARSE_ERROR,
] {
let raw = PraxisLanguage::kind_to_raw(kind);
assert_eq!(PraxisLanguage::kind_from_raw(raw), kind);
}
}
#[test]
fn every_raw_value_in_range_round_trips() {
for raw in 0..=SyntaxKind::PARSER_NAMED_ARG as u16 {
let kind = PraxisLanguage::kind_from_raw(RawSyntaxKind(raw));
assert_eq!(
PraxisLanguage::kind_to_raw(kind).0,
raw,
"raw {raw} did not round-trip"
);
}
}
#[test]
fn repr_is_u16() {
assert_eq!(
std::mem::size_of::<SyntaxKind>(),
std::mem::size_of::<u16>()
);
}
#[test]
fn out_of_range_raw_kind_maps_to_a_safe_error_kind() {
assert_eq!(
PraxisLanguage::kind_from_raw(RawSyntaxKind(u16::MAX)),
SyntaxKind::ERROR,
"the safe rowan Language boundary must not construct an invalid enum discriminant"
);
}
}