cst: eliminate manual synchronization between enum variants and numeric values

This commit is contained in:
raf 2025-06-02 14:32:36 +03:00
commit b9d8cb6d5d
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
3 changed files with 260 additions and 221 deletions

57
Cargo.lock generated
View file

@ -281,6 +281,7 @@ dependencies = [
"cstree", "cstree",
"glob", "glob",
"logos", "logos",
"num_enum",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",
@ -288,6 +289,27 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "num_enum"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.3" version = "0.12.3"
@ -311,6 +333,15 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
"toml_edit",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.95" version = "1.0.95"
@ -487,6 +518,23 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "toml_datetime"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
[[package]]
name = "toml_edit"
version = "0.22.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]] [[package]]
name = "triomphe" name = "triomphe"
version = "0.1.14" version = "0.1.14"
@ -573,3 +621,12 @@ name = "windows_x86_64_msvc"
version = "0.52.4" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]]
name = "winnow"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]

View file

@ -14,5 +14,6 @@ cstree = "0.12"
text-size = "1.1" text-size = "1.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
regex = "1.11.1" regex = "1.11"
glob = "0.3" glob = "0.3"
num_enum = "0.7"

View file

@ -4,11 +4,15 @@
use crate::lexer::{Token, TokenKind}; use crate::lexer::{Token, TokenKind};
use cstree::{RawSyntaxKind, green::GreenNode, util::NodeOrToken}; use cstree::{RawSyntaxKind, green::GreenNode, util::NodeOrToken};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::fmt; use std::fmt;
use thiserror::Error; use thiserror::Error;
/// nftables syntax node types /// nftables syntax node types
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] /// Uses `TryFromPrimitive` for safe conversion from raw values with fallback to `Error`.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TryFromPrimitive, IntoPrimitive,
)]
#[repr(u16)] #[repr(u16)]
pub enum SyntaxKind { pub enum SyntaxKind {
// Root and containers // Root and containers
@ -161,116 +165,128 @@ pub enum SyntaxKind {
impl From<TokenKind> for SyntaxKind { impl From<TokenKind> for SyntaxKind {
fn from(kind: TokenKind) -> Self { fn from(kind: TokenKind) -> Self {
use TokenKind::*;
match kind { match kind {
TokenKind::Table => SyntaxKind::TableKw, // Keywords -> Kw variants
TokenKind::Chain => SyntaxKind::ChainKw, Table => SyntaxKind::TableKw,
TokenKind::Rule => SyntaxKind::RuleKw, Chain => SyntaxKind::ChainKw,
TokenKind::Set => SyntaxKind::SetKw, Rule => SyntaxKind::RuleKw,
TokenKind::Map => SyntaxKind::MapKw, Set => SyntaxKind::SetKw,
TokenKind::Element => SyntaxKind::ElementKw, Map => SyntaxKind::MapKw,
TokenKind::Include => SyntaxKind::IncludeKw, Element => SyntaxKind::ElementKw,
TokenKind::Define => SyntaxKind::DefineKw, Include => SyntaxKind::IncludeKw,
TokenKind::Flush => SyntaxKind::FlushKw, Define => SyntaxKind::DefineKw,
TokenKind::Add => SyntaxKind::AddKw, Flush => SyntaxKind::FlushKw,
TokenKind::Delete => SyntaxKind::DeleteKw, Add => SyntaxKind::AddKw,
TokenKind::Insert => SyntaxKind::InsertKw, Delete => SyntaxKind::DeleteKw,
TokenKind::Replace => SyntaxKind::ReplaceKw, Insert => SyntaxKind::InsertKw,
Replace => SyntaxKind::ReplaceKw,
TokenKind::Filter => SyntaxKind::FilterKw, // Chain types and hooks
TokenKind::Nat => SyntaxKind::NatKw, Filter => SyntaxKind::FilterKw,
TokenKind::Route => SyntaxKind::RouteKw, Nat => SyntaxKind::NatKw,
Route => SyntaxKind::RouteKw,
Input => SyntaxKind::InputKw,
Output => SyntaxKind::OutputKw,
Forward => SyntaxKind::ForwardKw,
Prerouting => SyntaxKind::PreroutingKw,
Postrouting => SyntaxKind::PostroutingKw,
TokenKind::Input => SyntaxKind::InputKw, // Protocols and families
TokenKind::Output => SyntaxKind::OutputKw, Ip => SyntaxKind::IpKw,
TokenKind::Forward => SyntaxKind::ForwardKw, Ip6 => SyntaxKind::Ip6Kw,
TokenKind::Prerouting => SyntaxKind::PreroutingKw, Inet => SyntaxKind::InetKw,
TokenKind::Postrouting => SyntaxKind::PostroutingKw, Arp => SyntaxKind::ArpKw,
Bridge => SyntaxKind::BridgeKw,
Netdev => SyntaxKind::NetdevKw,
Tcp => SyntaxKind::TcpKw,
Udp => SyntaxKind::UdpKw,
Icmp => SyntaxKind::IcmpKw,
Icmpv6 => SyntaxKind::Icmpv6Kw,
TokenKind::Ip => SyntaxKind::IpKw, // Match keywords
TokenKind::Ip6 => SyntaxKind::Ip6Kw, Sport => SyntaxKind::SportKw,
TokenKind::Inet => SyntaxKind::InetKw, Dport => SyntaxKind::DportKw,
TokenKind::Arp => SyntaxKind::ArpKw, Saddr => SyntaxKind::SaddrKw,
TokenKind::Bridge => SyntaxKind::BridgeKw, Daddr => SyntaxKind::DaddrKw,
TokenKind::Netdev => SyntaxKind::NetdevKw, Protocol => SyntaxKind::ProtocolKw,
TokenKind::Tcp => SyntaxKind::TcpKw, Nexthdr => SyntaxKind::NexthdrKw,
TokenKind::Udp => SyntaxKind::UdpKw, Type => SyntaxKind::TypeKw,
TokenKind::Icmp => SyntaxKind::IcmpKw, Hook => SyntaxKind::HookKw,
TokenKind::Icmpv6 => SyntaxKind::Icmpv6Kw, Priority => SyntaxKind::PriorityKw,
Policy => SyntaxKind::PolicyKw,
Iifname => SyntaxKind::IifnameKw,
Oifname => SyntaxKind::OifnameKw,
Ct => SyntaxKind::CtKw,
State => SyntaxKind::StateKw,
TokenKind::Sport => SyntaxKind::SportKw, // Actions
TokenKind::Dport => SyntaxKind::DportKw, Accept => SyntaxKind::AcceptKw,
TokenKind::Saddr => SyntaxKind::SaddrKw, Drop => SyntaxKind::DropKw,
TokenKind::Daddr => SyntaxKind::DaddrKw, Reject => SyntaxKind::RejectKw,
TokenKind::Protocol => SyntaxKind::ProtocolKw, Return => SyntaxKind::ReturnKw,
TokenKind::Nexthdr => SyntaxKind::NexthdrKw, Jump => SyntaxKind::JumpKw,
TokenKind::Type => SyntaxKind::TypeKw, Goto => SyntaxKind::GotoKw,
TokenKind::Hook => SyntaxKind::HookKw, Continue => SyntaxKind::ContinueKw,
TokenKind::Priority => SyntaxKind::PriorityKw, Log => SyntaxKind::LogKw,
TokenKind::Policy => SyntaxKind::PolicyKw, Comment => SyntaxKind::CommentKw,
TokenKind::Iifname => SyntaxKind::IifnameKw,
TokenKind::Oifname => SyntaxKind::OifnameKw,
TokenKind::Ct => SyntaxKind::CtKw,
TokenKind::State => SyntaxKind::StateKw,
TokenKind::Accept => SyntaxKind::AcceptKw, // States
TokenKind::Drop => SyntaxKind::DropKw, Established => SyntaxKind::EstablishedKw,
TokenKind::Reject => SyntaxKind::RejectKw, Related => SyntaxKind::RelatedKw,
TokenKind::Return => SyntaxKind::ReturnKw, New => SyntaxKind::NewKw,
TokenKind::Jump => SyntaxKind::JumpKw, Invalid => SyntaxKind::InvalidKw,
TokenKind::Goto => SyntaxKind::GotoKw,
TokenKind::Continue => SyntaxKind::ContinueKw,
TokenKind::Log => SyntaxKind::LogKw,
TokenKind::Comment => SyntaxKind::CommentKw,
TokenKind::Established => SyntaxKind::EstablishedKw, // Additional protocol keywords
TokenKind::Related => SyntaxKind::RelatedKw, Vmap => SyntaxKind::VmapKw,
TokenKind::New => SyntaxKind::NewKw, NdRouterAdvert => SyntaxKind::NdRouterAdvertKw,
TokenKind::Invalid => SyntaxKind::InvalidKw, NdNeighborSolicit => SyntaxKind::NdNeighborSolicitKw,
NdNeighborAdvert => SyntaxKind::NdNeighborAdvertKw,
EchoRequest => SyntaxKind::EchoRequestKw,
DestUnreachable => SyntaxKind::DestUnreachableKw,
RouterAdvertisement => SyntaxKind::RouterAdvertisementKw,
TimeExceeded => SyntaxKind::TimeExceededKw,
ParameterProblem => SyntaxKind::ParameterProblemKw,
PacketTooBig => SyntaxKind::PacketTooBigKw,
TokenKind::Vmap => SyntaxKind::VmapKw, // Operators - direct mapping
TokenKind::NdRouterAdvert => SyntaxKind::NdRouterAdvertKw, Eq => SyntaxKind::EqOp,
TokenKind::NdNeighborSolicit => SyntaxKind::NdNeighborSolicitKw, Ne => SyntaxKind::NeOp,
TokenKind::NdNeighborAdvert => SyntaxKind::NdNeighborAdvertKw, Le => SyntaxKind::LeOp,
TokenKind::EchoRequest => SyntaxKind::EchoRequestKw, Ge => SyntaxKind::GeOp,
TokenKind::DestUnreachable => SyntaxKind::DestUnreachableKw, Lt => SyntaxKind::LtOp,
TokenKind::RouterAdvertisement => SyntaxKind::RouterAdvertisementKw, Gt => SyntaxKind::GtOp,
TokenKind::TimeExceeded => SyntaxKind::TimeExceededKw,
TokenKind::ParameterProblem => SyntaxKind::ParameterProblemKw,
TokenKind::PacketTooBig => SyntaxKind::PacketTooBigKw,
TokenKind::Eq => SyntaxKind::EqOp, // Punctuation - direct mapping
TokenKind::Ne => SyntaxKind::NeOp, LeftBrace => SyntaxKind::LeftBrace,
TokenKind::Le => SyntaxKind::LeOp, RightBrace => SyntaxKind::RightBrace,
TokenKind::Ge => SyntaxKind::GeOp, LeftParen => SyntaxKind::LeftParen,
TokenKind::Lt => SyntaxKind::LtOp, RightParen => SyntaxKind::RightParen,
TokenKind::Gt => SyntaxKind::GtOp, LeftBracket => SyntaxKind::LeftBracket,
RightBracket => SyntaxKind::RightBracket,
Comma => SyntaxKind::Comma,
Semicolon => SyntaxKind::Semicolon,
Colon => SyntaxKind::Colon,
Assign => SyntaxKind::Assign,
Dash => SyntaxKind::Dash,
Slash => SyntaxKind::Slash,
Dot => SyntaxKind::Dot,
TokenKind::LeftBrace => SyntaxKind::LeftBrace, // Literals - map data-carrying variants to their types
TokenKind::RightBrace => SyntaxKind::RightBrace, StringLiteral(_) => SyntaxKind::StringLiteral,
TokenKind::LeftParen => SyntaxKind::LeftParen, NumberLiteral(_) => SyntaxKind::NumberLiteral,
TokenKind::RightParen => SyntaxKind::RightParen, IpAddress(_) => SyntaxKind::IpAddress,
TokenKind::LeftBracket => SyntaxKind::LeftBracket, Ipv6Address(_) => SyntaxKind::Ipv6Address,
TokenKind::RightBracket => SyntaxKind::RightBracket, MacAddress(_) => SyntaxKind::MacAddress,
TokenKind::Comma => SyntaxKind::Comma, Identifier(_) => SyntaxKind::Identifier,
TokenKind::Semicolon => SyntaxKind::Semicolon,
TokenKind::Colon => SyntaxKind::Colon,
TokenKind::Assign => SyntaxKind::Assign,
TokenKind::Dash => SyntaxKind::Dash,
TokenKind::Slash => SyntaxKind::Slash,
TokenKind::Dot => SyntaxKind::Dot,
TokenKind::StringLiteral(_) => SyntaxKind::StringLiteral, // Special tokens
TokenKind::NumberLiteral(_) => SyntaxKind::NumberLiteral, Newline => SyntaxKind::Newline,
TokenKind::IpAddress(_) => SyntaxKind::IpAddress, CommentLine(_) => SyntaxKind::Comment,
TokenKind::Ipv6Address(_) => SyntaxKind::Ipv6Address, Shebang(_) => SyntaxKind::Shebang,
TokenKind::MacAddress(_) => SyntaxKind::MacAddress,
TokenKind::Identifier(_) => SyntaxKind::Identifier,
TokenKind::Newline => SyntaxKind::Newline, // Error fallback
TokenKind::CommentLine(_) => SyntaxKind::Comment, Error => SyntaxKind::Error,
TokenKind::Shebang(_) => SyntaxKind::Shebang,
TokenKind::Error => SyntaxKind::Error,
} }
} }
} }
@ -324,126 +340,7 @@ impl SyntaxKind {
} }
pub fn from_raw(raw: RawSyntaxKind) -> Self { pub fn from_raw(raw: RawSyntaxKind) -> Self {
match raw.0 { Self::try_from(raw.0 as u16).unwrap_or(SyntaxKind::Error)
0 => SyntaxKind::Root,
1 => SyntaxKind::Table,
2 => SyntaxKind::Chain,
3 => SyntaxKind::Rule,
4 => SyntaxKind::Set,
5 => SyntaxKind::Map,
6 => SyntaxKind::Element,
7 => SyntaxKind::Expression,
8 => SyntaxKind::BinaryExpr,
9 => SyntaxKind::UnaryExpr,
10 => SyntaxKind::CallExpr,
11 => SyntaxKind::SetExpr,
12 => SyntaxKind::RangeExpr,
13 => SyntaxKind::Statement,
14 => SyntaxKind::IncludeStmt,
15 => SyntaxKind::DefineStmt,
16 => SyntaxKind::FlushStmt,
17 => SyntaxKind::AddStmt,
18 => SyntaxKind::DeleteStmt,
19 => SyntaxKind::Identifier,
20 => SyntaxKind::StringLiteral,
21 => SyntaxKind::NumberLiteral,
22 => SyntaxKind::IpAddress,
23 => SyntaxKind::Ipv6Address,
24 => SyntaxKind::MacAddress,
25 => SyntaxKind::TableKw,
26 => SyntaxKind::ChainKw,
27 => SyntaxKind::RuleKw,
28 => SyntaxKind::SetKw,
29 => SyntaxKind::MapKw,
30 => SyntaxKind::ElementKw,
31 => SyntaxKind::IncludeKw,
32 => SyntaxKind::DefineKw,
33 => SyntaxKind::FlushKw,
34 => SyntaxKind::AddKw,
35 => SyntaxKind::DeleteKw,
36 => SyntaxKind::InsertKw,
37 => SyntaxKind::ReplaceKw,
38 => SyntaxKind::FilterKw,
39 => SyntaxKind::NatKw,
40 => SyntaxKind::RouteKw,
41 => SyntaxKind::InputKw,
42 => SyntaxKind::OutputKw,
43 => SyntaxKind::ForwardKw,
44 => SyntaxKind::PreroutingKw,
45 => SyntaxKind::PostroutingKw,
46 => SyntaxKind::IpKw,
47 => SyntaxKind::Ip6Kw,
48 => SyntaxKind::InetKw,
49 => SyntaxKind::ArpKw,
50 => SyntaxKind::BridgeKw,
51 => SyntaxKind::NetdevKw,
52 => SyntaxKind::TcpKw,
53 => SyntaxKind::UdpKw,
54 => SyntaxKind::IcmpKw,
55 => SyntaxKind::Icmpv6Kw,
56 => SyntaxKind::SportKw,
57 => SyntaxKind::DportKw,
58 => SyntaxKind::SaddrKw,
59 => SyntaxKind::DaddrKw,
60 => SyntaxKind::ProtocolKw,
61 => SyntaxKind::NexthdrKw,
62 => SyntaxKind::TypeKw,
63 => SyntaxKind::HookKw,
64 => SyntaxKind::PriorityKw,
65 => SyntaxKind::PolicyKw,
66 => SyntaxKind::IifnameKw,
67 => SyntaxKind::OifnameKw,
68 => SyntaxKind::CtKw,
69 => SyntaxKind::StateKw,
70 => SyntaxKind::AcceptKw,
71 => SyntaxKind::DropKw,
72 => SyntaxKind::RejectKw,
73 => SyntaxKind::ReturnKw,
74 => SyntaxKind::JumpKw,
75 => SyntaxKind::GotoKw,
76 => SyntaxKind::ContinueKw,
77 => SyntaxKind::LogKw,
78 => SyntaxKind::CommentKw,
79 => SyntaxKind::EstablishedKw,
80 => SyntaxKind::RelatedKw,
81 => SyntaxKind::NewKw,
82 => SyntaxKind::InvalidKw,
83 => SyntaxKind::EqOp,
84 => SyntaxKind::NeOp,
85 => SyntaxKind::LeOp,
86 => SyntaxKind::GeOp,
87 => SyntaxKind::LtOp,
88 => SyntaxKind::GtOp,
89 => SyntaxKind::LeftBrace,
90 => SyntaxKind::RightBrace,
91 => SyntaxKind::LeftParen,
92 => SyntaxKind::RightParen,
93 => SyntaxKind::LeftBracket,
94 => SyntaxKind::RightBracket,
95 => SyntaxKind::Comma,
96 => SyntaxKind::Semicolon,
97 => SyntaxKind::Colon,
98 => SyntaxKind::Assign,
99 => SyntaxKind::Dash,
100 => SyntaxKind::Slash,
101 => SyntaxKind::Dot,
102 => SyntaxKind::Whitespace,
103 => SyntaxKind::Newline,
104 => SyntaxKind::Comment,
105 => SyntaxKind::Shebang,
106 => SyntaxKind::Error,
107 => SyntaxKind::VmapKw,
108 => SyntaxKind::NdRouterAdvertKw,
109 => SyntaxKind::NdNeighborSolicitKw,
110 => SyntaxKind::NdNeighborAdvertKw,
111 => SyntaxKind::EchoRequestKw,
112 => SyntaxKind::DestUnreachableKw,
113 => SyntaxKind::RouterAdvertisementKw,
114 => SyntaxKind::TimeExceededKw,
115 => SyntaxKind::ParameterProblemKw,
116 => SyntaxKind::PacketTooBigKw,
_ => SyntaxKind::Error, // Fallback to Error for invalid values
}
} }
} }
@ -1350,7 +1247,7 @@ mod tests {
let mut lexer = NftablesLexer::new(source); let mut lexer = NftablesLexer::new(source);
let tokens = lexer.tokenize().expect("Tokenization should succeed"); let tokens = lexer.tokenize().expect("Tokenization should succeed");
// CST is now implemented - test that it works // Test CST construction with basic table syntax
let green_tree = CstBuilder::build_tree(&tokens); let green_tree = CstBuilder::build_tree(&tokens);
// Verify the tree was created successfully // Verify the tree was created successfully
@ -1367,4 +1264,88 @@ mod tests {
let cst_result = CstBuilder::parse_to_cst(&tokens); let cst_result = CstBuilder::parse_to_cst(&tokens);
assert!(cst_result.is_ok()); assert!(cst_result.is_ok());
} }
#[test]
fn test_num_enum_improvements() {
// Test that from_raw uses num_enum for conversion
// Invalid values fall back to Error variant
// Test valid conversions
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(0)), SyntaxKind::Root);
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(1)), SyntaxKind::Table);
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(25)), SyntaxKind::TableKw);
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(106)), SyntaxKind::Error);
assert_eq!(
SyntaxKind::from_raw(RawSyntaxKind(116)),
SyntaxKind::PacketTooBigKw
);
// Test invalid values automatically fall back to Error
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(999)), SyntaxKind::Error);
assert_eq!(SyntaxKind::from_raw(RawSyntaxKind(1000)), SyntaxKind::Error);
// Test bidirectional conversion
for variant in [
SyntaxKind::Root,
SyntaxKind::Table,
SyntaxKind::TableKw,
SyntaxKind::Error,
SyntaxKind::PacketTooBigKw,
] {
let raw = variant.to_raw();
let converted_back = SyntaxKind::from_raw(raw);
assert_eq!(variant, converted_back);
}
}
#[test]
fn test_token_kind_conversion_improvements() {
// Test that From<TokenKind> conversion is complete and correct
use crate::lexer::TokenKind;
// Test keyword mappings
assert_eq!(SyntaxKind::from(TokenKind::Table), SyntaxKind::TableKw);
assert_eq!(SyntaxKind::from(TokenKind::Chain), SyntaxKind::ChainKw);
assert_eq!(SyntaxKind::from(TokenKind::Accept), SyntaxKind::AcceptKw);
// Test operators
assert_eq!(SyntaxKind::from(TokenKind::Eq), SyntaxKind::EqOp);
assert_eq!(SyntaxKind::from(TokenKind::Lt), SyntaxKind::LtOp);
// Test punctuation
assert_eq!(
SyntaxKind::from(TokenKind::LeftBrace),
SyntaxKind::LeftBrace
);
assert_eq!(
SyntaxKind::from(TokenKind::Semicolon),
SyntaxKind::Semicolon
);
// Test literals (with data)
assert_eq!(
SyntaxKind::from(TokenKind::StringLiteral("test".to_string())),
SyntaxKind::StringLiteral
);
assert_eq!(
SyntaxKind::from(TokenKind::NumberLiteral(42)),
SyntaxKind::NumberLiteral
);
assert_eq!(
SyntaxKind::from(TokenKind::IpAddress("192.168.1.1".to_string())),
SyntaxKind::IpAddress
);
assert_eq!(
SyntaxKind::from(TokenKind::Identifier("test".to_string())),
SyntaxKind::Identifier
);
// Test special tokens
assert_eq!(SyntaxKind::from(TokenKind::Newline), SyntaxKind::Newline);
assert_eq!(
SyntaxKind::from(TokenKind::CommentLine("# comment".to_string())),
SyntaxKind::Comment
);
assert_eq!(SyntaxKind::from(TokenKind::Error), SyntaxKind::Error);
}
} }