diff --git a/Cargo.lock b/Cargo.lock index 1b11d7f..cd5a4c2 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,6 +281,7 @@ dependencies = [ "cstree", "glob", "logos", + "num_enum", "regex", "serde", "serde_json", @@ -288,6 +289,27 @@ dependencies = [ "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]] name = "parking_lot" version = "0.12.3" @@ -311,6 +333,15 @@ dependencies = [ "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]] name = "proc-macro2" version = "1.0.95" @@ -487,6 +518,23 @@ dependencies = [ "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]] name = "triomphe" version = "0.1.14" @@ -573,3 +621,12 @@ name = "windows_x86_64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 4bb2743..afd902e 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,6 @@ cstree = "0.12" text-size = "1.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -regex = "1.11.1" +regex = "1.11" glob = "0.3" +num_enum = "0.7" diff --git a/src/cst.rs b/src/cst.rs index 412b379..b36cad0 100644 --- a/src/cst.rs +++ b/src/cst.rs @@ -4,11 +4,15 @@ use crate::lexer::{Token, TokenKind}; use cstree::{RawSyntaxKind, green::GreenNode, util::NodeOrToken}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::fmt; use thiserror::Error; /// 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)] pub enum SyntaxKind { // Root and containers @@ -161,116 +165,128 @@ pub enum SyntaxKind { impl From for SyntaxKind { fn from(kind: TokenKind) -> Self { + use TokenKind::*; match kind { - TokenKind::Table => SyntaxKind::TableKw, - TokenKind::Chain => SyntaxKind::ChainKw, - TokenKind::Rule => SyntaxKind::RuleKw, - TokenKind::Set => SyntaxKind::SetKw, - TokenKind::Map => SyntaxKind::MapKw, - TokenKind::Element => SyntaxKind::ElementKw, - TokenKind::Include => SyntaxKind::IncludeKw, - TokenKind::Define => SyntaxKind::DefineKw, - TokenKind::Flush => SyntaxKind::FlushKw, - TokenKind::Add => SyntaxKind::AddKw, - TokenKind::Delete => SyntaxKind::DeleteKw, - TokenKind::Insert => SyntaxKind::InsertKw, - TokenKind::Replace => SyntaxKind::ReplaceKw, + // Keywords -> Kw variants + Table => SyntaxKind::TableKw, + Chain => SyntaxKind::ChainKw, + Rule => SyntaxKind::RuleKw, + Set => SyntaxKind::SetKw, + Map => SyntaxKind::MapKw, + Element => SyntaxKind::ElementKw, + Include => SyntaxKind::IncludeKw, + Define => SyntaxKind::DefineKw, + Flush => SyntaxKind::FlushKw, + Add => SyntaxKind::AddKw, + Delete => SyntaxKind::DeleteKw, + Insert => SyntaxKind::InsertKw, + Replace => SyntaxKind::ReplaceKw, - TokenKind::Filter => SyntaxKind::FilterKw, - TokenKind::Nat => SyntaxKind::NatKw, - TokenKind::Route => SyntaxKind::RouteKw, + // Chain types and hooks + Filter => SyntaxKind::FilterKw, + 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, - TokenKind::Output => SyntaxKind::OutputKw, - TokenKind::Forward => SyntaxKind::ForwardKw, - TokenKind::Prerouting => SyntaxKind::PreroutingKw, - TokenKind::Postrouting => SyntaxKind::PostroutingKw, + // Protocols and families + Ip => SyntaxKind::IpKw, + Ip6 => SyntaxKind::Ip6Kw, + Inet => SyntaxKind::InetKw, + 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, - TokenKind::Ip6 => SyntaxKind::Ip6Kw, - TokenKind::Inet => SyntaxKind::InetKw, - TokenKind::Arp => SyntaxKind::ArpKw, - TokenKind::Bridge => SyntaxKind::BridgeKw, - TokenKind::Netdev => SyntaxKind::NetdevKw, - TokenKind::Tcp => SyntaxKind::TcpKw, - TokenKind::Udp => SyntaxKind::UdpKw, - TokenKind::Icmp => SyntaxKind::IcmpKw, - TokenKind::Icmpv6 => SyntaxKind::Icmpv6Kw, + // Match keywords + Sport => SyntaxKind::SportKw, + Dport => SyntaxKind::DportKw, + Saddr => SyntaxKind::SaddrKw, + Daddr => SyntaxKind::DaddrKw, + Protocol => SyntaxKind::ProtocolKw, + Nexthdr => SyntaxKind::NexthdrKw, + Type => SyntaxKind::TypeKw, + Hook => SyntaxKind::HookKw, + Priority => SyntaxKind::PriorityKw, + Policy => SyntaxKind::PolicyKw, + Iifname => SyntaxKind::IifnameKw, + Oifname => SyntaxKind::OifnameKw, + Ct => SyntaxKind::CtKw, + State => SyntaxKind::StateKw, - TokenKind::Sport => SyntaxKind::SportKw, - TokenKind::Dport => SyntaxKind::DportKw, - TokenKind::Saddr => SyntaxKind::SaddrKw, - TokenKind::Daddr => SyntaxKind::DaddrKw, - TokenKind::Protocol => SyntaxKind::ProtocolKw, - TokenKind::Nexthdr => SyntaxKind::NexthdrKw, - TokenKind::Type => SyntaxKind::TypeKw, - TokenKind::Hook => SyntaxKind::HookKw, - TokenKind::Priority => SyntaxKind::PriorityKw, - TokenKind::Policy => SyntaxKind::PolicyKw, - TokenKind::Iifname => SyntaxKind::IifnameKw, - TokenKind::Oifname => SyntaxKind::OifnameKw, - TokenKind::Ct => SyntaxKind::CtKw, - TokenKind::State => SyntaxKind::StateKw, + // Actions + Accept => SyntaxKind::AcceptKw, + Drop => SyntaxKind::DropKw, + Reject => SyntaxKind::RejectKw, + Return => SyntaxKind::ReturnKw, + Jump => SyntaxKind::JumpKw, + Goto => SyntaxKind::GotoKw, + Continue => SyntaxKind::ContinueKw, + Log => SyntaxKind::LogKw, + Comment => SyntaxKind::CommentKw, - TokenKind::Accept => SyntaxKind::AcceptKw, - TokenKind::Drop => SyntaxKind::DropKw, - TokenKind::Reject => SyntaxKind::RejectKw, - TokenKind::Return => SyntaxKind::ReturnKw, - TokenKind::Jump => SyntaxKind::JumpKw, - TokenKind::Goto => SyntaxKind::GotoKw, - TokenKind::Continue => SyntaxKind::ContinueKw, - TokenKind::Log => SyntaxKind::LogKw, - TokenKind::Comment => SyntaxKind::CommentKw, + // States + Established => SyntaxKind::EstablishedKw, + Related => SyntaxKind::RelatedKw, + New => SyntaxKind::NewKw, + Invalid => SyntaxKind::InvalidKw, - TokenKind::Established => SyntaxKind::EstablishedKw, - TokenKind::Related => SyntaxKind::RelatedKw, - TokenKind::New => SyntaxKind::NewKw, - TokenKind::Invalid => SyntaxKind::InvalidKw, + // Additional protocol keywords + Vmap => SyntaxKind::VmapKw, + NdRouterAdvert => SyntaxKind::NdRouterAdvertKw, + 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, - TokenKind::NdRouterAdvert => SyntaxKind::NdRouterAdvertKw, - TokenKind::NdNeighborSolicit => SyntaxKind::NdNeighborSolicitKw, - TokenKind::NdNeighborAdvert => SyntaxKind::NdNeighborAdvertKw, - TokenKind::EchoRequest => SyntaxKind::EchoRequestKw, - TokenKind::DestUnreachable => SyntaxKind::DestUnreachableKw, - TokenKind::RouterAdvertisement => SyntaxKind::RouterAdvertisementKw, - TokenKind::TimeExceeded => SyntaxKind::TimeExceededKw, - TokenKind::ParameterProblem => SyntaxKind::ParameterProblemKw, - TokenKind::PacketTooBig => SyntaxKind::PacketTooBigKw, + // Operators - direct mapping + Eq => SyntaxKind::EqOp, + Ne => SyntaxKind::NeOp, + Le => SyntaxKind::LeOp, + Ge => SyntaxKind::GeOp, + Lt => SyntaxKind::LtOp, + Gt => SyntaxKind::GtOp, - TokenKind::Eq => SyntaxKind::EqOp, - TokenKind::Ne => SyntaxKind::NeOp, - TokenKind::Le => SyntaxKind::LeOp, - TokenKind::Ge => SyntaxKind::GeOp, - TokenKind::Lt => SyntaxKind::LtOp, - TokenKind::Gt => SyntaxKind::GtOp, + // Punctuation - direct mapping + LeftBrace => SyntaxKind::LeftBrace, + RightBrace => SyntaxKind::RightBrace, + LeftParen => SyntaxKind::LeftParen, + RightParen => SyntaxKind::RightParen, + 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, - TokenKind::RightBrace => SyntaxKind::RightBrace, - TokenKind::LeftParen => SyntaxKind::LeftParen, - TokenKind::RightParen => SyntaxKind::RightParen, - TokenKind::LeftBracket => SyntaxKind::LeftBracket, - TokenKind::RightBracket => SyntaxKind::RightBracket, - TokenKind::Comma => SyntaxKind::Comma, - TokenKind::Semicolon => SyntaxKind::Semicolon, - TokenKind::Colon => SyntaxKind::Colon, - TokenKind::Assign => SyntaxKind::Assign, - TokenKind::Dash => SyntaxKind::Dash, - TokenKind::Slash => SyntaxKind::Slash, - TokenKind::Dot => SyntaxKind::Dot, + // Literals - map data-carrying variants to their types + StringLiteral(_) => SyntaxKind::StringLiteral, + NumberLiteral(_) => SyntaxKind::NumberLiteral, + IpAddress(_) => SyntaxKind::IpAddress, + Ipv6Address(_) => SyntaxKind::Ipv6Address, + MacAddress(_) => SyntaxKind::MacAddress, + Identifier(_) => SyntaxKind::Identifier, - TokenKind::StringLiteral(_) => SyntaxKind::StringLiteral, - TokenKind::NumberLiteral(_) => SyntaxKind::NumberLiteral, - TokenKind::IpAddress(_) => SyntaxKind::IpAddress, - TokenKind::Ipv6Address(_) => SyntaxKind::Ipv6Address, - TokenKind::MacAddress(_) => SyntaxKind::MacAddress, - TokenKind::Identifier(_) => SyntaxKind::Identifier, + // Special tokens + Newline => SyntaxKind::Newline, + CommentLine(_) => SyntaxKind::Comment, + Shebang(_) => SyntaxKind::Shebang, - TokenKind::Newline => SyntaxKind::Newline, - TokenKind::CommentLine(_) => SyntaxKind::Comment, - TokenKind::Shebang(_) => SyntaxKind::Shebang, - - TokenKind::Error => SyntaxKind::Error, + // Error fallback + Error => SyntaxKind::Error, } } } @@ -324,126 +340,7 @@ impl SyntaxKind { } pub fn from_raw(raw: RawSyntaxKind) -> Self { - match raw.0 { - 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 - } + Self::try_from(raw.0 as u16).unwrap_or(SyntaxKind::Error) } } @@ -1350,7 +1247,7 @@ mod tests { let mut lexer = NftablesLexer::new(source); 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); // Verify the tree was created successfully @@ -1367,4 +1264,88 @@ mod tests { let cst_result = CstBuilder::parse_to_cst(&tokens); 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 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); + } }