1use crate::types::Span;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct Token {
15 pub kind: TokenKind,
17 pub span: Span,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27#[repr(u8)]
28pub enum TokenKind {
29 Error,
32 Eof,
34 ForbiddenKeyword,
37 Comment,
39
40 UppercaseIdent,
43 LowercaseIdent,
45
46 Number,
49 NegativeNumber,
51 QuotedString,
53 HexString,
55 BinString,
57
58 LBracket,
61 RBracket,
63 LBrace,
65 RBrace,
67 LParen,
69 RParen,
71 Colon,
73 Semicolon,
75 Comma,
77 Dot,
79 Pipe,
81 Minus,
83
84 DotDot,
87 ColonColonEqual,
89
90 KwDefinitions,
93 KwBegin,
95 KwEnd,
97 KwImports,
99 KwExports,
101 KwFrom,
103 KwObject,
105 KwIdentifier,
107 KwSequence,
109 KwOf,
111 KwChoice,
113 KwMacro,
115
116 KwSyntax,
119 KwMaxAccess,
121 KwMinAccess,
123 KwAccess,
125 KwStatus,
127 KwDescription,
129 KwReference,
131 KwIndex,
133 KwDefval,
135 KwAugments,
137 KwUnits,
139 KwDisplayHint,
141 KwObjects,
143 KwNotifications,
145 KwModule,
147 KwMandatoryGroups,
149 KwGroup,
151 KwWriteSyntax,
153 KwProductRelease,
155 KwSupports,
157 KwIncludes,
159 KwVariation,
161 KwCreationRequires,
163 KwRevision,
165 KwLastUpdated,
167 KwOrganization,
169 KwContactInfo,
171 KwImplied,
173 KwSize,
175 KwEnterprise,
177 KwVariables,
179
180 KwModuleIdentity,
183 KwModuleCompliance,
185 KwObjectGroup,
187 KwNotificationGroup,
189 KwAgentCapabilities,
191 KwObjectType,
193 KwObjectIdentity,
195 KwNotificationType,
197 KwTextualConvention,
199 KwTrapType,
201
202 KwInteger,
205 KwUnsigned32,
207 KwCounter32,
209 KwCounter64,
211 KwGauge32,
213 KwIpAddress,
215 KwOpaque,
217 KwTimeTicks,
219 KwBits,
221 KwOctet,
223 KwString,
225
226 KwCounter,
229 KwGauge,
231 KwNetworkAddress,
233
234 KwApplication,
237 KwImplicit,
239 KwUniversal,
241
242 KwCurrent,
245 KwDeprecated,
247 KwObsolete,
249 KwMandatory,
251 KwOptional,
253 KwReadOnly,
255 KwReadWrite,
257 KwReadCreate,
259 KwWriteOnly,
261 KwNotAccessible,
263 KwAccessibleForNotify,
265 KwNotImplemented,
267}
268
269impl TokenKind {
270 pub fn is_keyword(self) -> bool {
273 self.is_structural_keyword()
274 || self.is_clause_keyword()
275 || self.is_macro_keyword()
276 || self.is_type_keyword()
277 || self.is_tag_keyword()
278 || self.is_status_access_keyword()
279 }
280
281 pub fn is_identifier(self) -> bool {
284 matches!(self, TokenKind::UppercaseIdent | TokenKind::LowercaseIdent)
285 }
286
287 pub fn is_type_keyword(self) -> bool {
290 matches!(
291 self,
292 TokenKind::KwInteger
293 | TokenKind::KwUnsigned32
294 | TokenKind::KwCounter32
295 | TokenKind::KwCounter64
296 | TokenKind::KwGauge32
297 | TokenKind::KwIpAddress
298 | TokenKind::KwOpaque
299 | TokenKind::KwTimeTicks
300 | TokenKind::KwBits
301 | TokenKind::KwOctet
302 | TokenKind::KwString
303 | TokenKind::KwCounter
304 | TokenKind::KwGauge
305 | TokenKind::KwNetworkAddress
306 )
307 }
308
309 pub fn is_macro_keyword(self) -> bool {
312 matches!(
313 self,
314 TokenKind::KwModuleIdentity
315 | TokenKind::KwModuleCompliance
316 | TokenKind::KwObjectGroup
317 | TokenKind::KwNotificationGroup
318 | TokenKind::KwAgentCapabilities
319 | TokenKind::KwObjectType
320 | TokenKind::KwObjectIdentity
321 | TokenKind::KwNotificationType
322 | TokenKind::KwTextualConvention
323 | TokenKind::KwTrapType
324 )
325 }
326
327 pub fn is_clause_keyword(self) -> bool {
330 matches!(
331 self,
332 TokenKind::KwSyntax
333 | TokenKind::KwMaxAccess
334 | TokenKind::KwMinAccess
335 | TokenKind::KwAccess
336 | TokenKind::KwStatus
337 | TokenKind::KwDescription
338 | TokenKind::KwReference
339 | TokenKind::KwIndex
340 | TokenKind::KwDefval
341 | TokenKind::KwAugments
342 | TokenKind::KwUnits
343 | TokenKind::KwDisplayHint
344 | TokenKind::KwObjects
345 | TokenKind::KwNotifications
346 | TokenKind::KwModule
347 | TokenKind::KwMandatoryGroups
348 | TokenKind::KwGroup
349 | TokenKind::KwWriteSyntax
350 | TokenKind::KwProductRelease
351 | TokenKind::KwSupports
352 | TokenKind::KwIncludes
353 | TokenKind::KwVariation
354 | TokenKind::KwCreationRequires
355 | TokenKind::KwRevision
356 | TokenKind::KwLastUpdated
357 | TokenKind::KwOrganization
358 | TokenKind::KwContactInfo
359 | TokenKind::KwImplied
360 | TokenKind::KwSize
361 | TokenKind::KwEnterprise
362 | TokenKind::KwVariables
363 )
364 }
365
366 pub fn is_tag_keyword(self) -> bool {
369 matches!(
370 self,
371 TokenKind::KwApplication | TokenKind::KwImplicit | TokenKind::KwUniversal
372 )
373 }
374
375 pub fn is_status_access_keyword(self) -> bool {
378 matches!(
379 self,
380 TokenKind::KwCurrent
381 | TokenKind::KwDeprecated
382 | TokenKind::KwObsolete
383 | TokenKind::KwMandatory
384 | TokenKind::KwOptional
385 | TokenKind::KwReadOnly
386 | TokenKind::KwReadWrite
387 | TokenKind::KwReadCreate
388 | TokenKind::KwWriteOnly
389 | TokenKind::KwNotAccessible
390 | TokenKind::KwAccessibleForNotify
391 | TokenKind::KwNotImplemented
392 )
393 }
394
395 pub fn is_structural_keyword(self) -> bool {
398 matches!(
399 self,
400 TokenKind::KwDefinitions
401 | TokenKind::KwBegin
402 | TokenKind::KwEnd
403 | TokenKind::KwImports
404 | TokenKind::KwExports
405 | TokenKind::KwFrom
406 | TokenKind::KwObject
407 | TokenKind::KwIdentifier
408 | TokenKind::KwSequence
409 | TokenKind::KwOf
410 | TokenKind::KwChoice
411 | TokenKind::KwMacro
412 )
413 }
414
415 pub fn display_name(self) -> &'static str {
421 match self {
422 TokenKind::Error => "<error>",
423 TokenKind::Eof => "end of file",
424 TokenKind::ForbiddenKeyword => "reserved keyword",
425 TokenKind::Comment => "comment",
426 TokenKind::UppercaseIdent => "identifier",
427 TokenKind::LowercaseIdent => "identifier",
428 TokenKind::Number => "number",
429 TokenKind::NegativeNumber => "negative number",
430 TokenKind::QuotedString => "quoted string",
431 TokenKind::HexString => "hex string",
432 TokenKind::BinString => "binary string",
433 TokenKind::LBracket => "'['",
434 TokenKind::RBracket => "']'",
435 TokenKind::LBrace => "'{'",
436 TokenKind::RBrace => "'}'",
437 TokenKind::LParen => "'('",
438 TokenKind::RParen => "')'",
439 TokenKind::Colon => "':'",
440 TokenKind::Semicolon => "';'",
441 TokenKind::Comma => "','",
442 TokenKind::Dot => "'.'",
443 TokenKind::Pipe => "'|'",
444 TokenKind::Minus => "'-'",
445 TokenKind::DotDot => "'..'",
446 TokenKind::ColonColonEqual => "'::='",
447 _ => self.libsmi_name(),
448 }
449 }
450
451 pub fn libsmi_name(self) -> &'static str {
457 match self {
458 TokenKind::Error => "ERROR",
459 TokenKind::Eof => "EOF",
460 TokenKind::ForbiddenKeyword => "FORBIDDEN_KEYWORD",
461 TokenKind::Comment => "COMMENT",
462 TokenKind::UppercaseIdent => "UPPERCASE_IDENTIFIER",
463 TokenKind::LowercaseIdent => "LOWERCASE_IDENTIFIER",
464 TokenKind::Number => "NUMBER",
465 TokenKind::NegativeNumber => "NEGATIVENUMBER",
466 TokenKind::QuotedString => "QUOTED_STRING",
467 TokenKind::HexString => "HEX_STRING",
468 TokenKind::BinString => "BIN_STRING",
469 TokenKind::LBracket => "LBRACKET",
470 TokenKind::RBracket => "RBRACKET",
471 TokenKind::LBrace => "LBRACE",
472 TokenKind::RBrace => "RBRACE",
473 TokenKind::LParen => "LPAREN",
474 TokenKind::RParen => "RPAREN",
475 TokenKind::Colon => "COLON",
476 TokenKind::Semicolon => "SEMICOLON",
477 TokenKind::Comma => "COMMA",
478 TokenKind::Dot => "DOT",
479 TokenKind::Pipe => "PIPE",
480 TokenKind::Minus => "MINUS",
481 TokenKind::DotDot => "DOT_DOT",
482 TokenKind::ColonColonEqual => "COLON_COLON_EQUAL",
483 TokenKind::KwDefinitions => "DEFINITIONS",
484 TokenKind::KwBegin => "BEGIN",
485 TokenKind::KwEnd => "END",
486 TokenKind::KwImports => "IMPORTS",
487 TokenKind::KwExports => "EXPORTS",
488 TokenKind::KwFrom => "FROM",
489 TokenKind::KwObject => "OBJECT",
490 TokenKind::KwIdentifier => "IDENTIFIER",
491 TokenKind::KwSequence => "SEQUENCE",
492 TokenKind::KwOf => "OF",
493 TokenKind::KwChoice => "CHOICE",
494 TokenKind::KwMacro => "MACRO",
495 TokenKind::KwSyntax => "SYNTAX",
496 TokenKind::KwMaxAccess => "MAX_ACCESS",
497 TokenKind::KwMinAccess => "MIN_ACCESS",
498 TokenKind::KwAccess => "ACCESS",
499 TokenKind::KwStatus => "STATUS",
500 TokenKind::KwDescription => "DESCRIPTION",
501 TokenKind::KwReference => "REFERENCE",
502 TokenKind::KwIndex => "INDEX",
503 TokenKind::KwDefval => "DEFVAL",
504 TokenKind::KwAugments => "AUGMENTS",
505 TokenKind::KwUnits => "UNITS",
506 TokenKind::KwDisplayHint => "DISPLAY_HINT",
507 TokenKind::KwObjects => "OBJECTS",
508 TokenKind::KwNotifications => "NOTIFICATIONS",
509 TokenKind::KwModule => "MODULE",
510 TokenKind::KwMandatoryGroups => "MANDATORY_GROUPS",
511 TokenKind::KwGroup => "GROUP",
512 TokenKind::KwWriteSyntax => "WRITE_SYNTAX",
513 TokenKind::KwProductRelease => "PRODUCT_RELEASE",
514 TokenKind::KwSupports => "SUPPORTS",
515 TokenKind::KwIncludes => "INCLUDES",
516 TokenKind::KwVariation => "VARIATION",
517 TokenKind::KwCreationRequires => "CREATION_REQUIRES",
518 TokenKind::KwRevision => "REVISION",
519 TokenKind::KwLastUpdated => "LAST_UPDATED",
520 TokenKind::KwOrganization => "ORGANIZATION",
521 TokenKind::KwContactInfo => "CONTACT_INFO",
522 TokenKind::KwImplied => "IMPLIED",
523 TokenKind::KwSize => "SIZE",
524 TokenKind::KwEnterprise => "ENTERPRISE",
525 TokenKind::KwVariables => "VARIABLES",
526 TokenKind::KwModuleIdentity => "MODULE_IDENTITY",
527 TokenKind::KwModuleCompliance => "MODULE_COMPLIANCE",
528 TokenKind::KwObjectGroup => "OBJECT_GROUP",
529 TokenKind::KwNotificationGroup => "NOTIFICATION_GROUP",
530 TokenKind::KwAgentCapabilities => "AGENT_CAPABILITIES",
531 TokenKind::KwObjectType => "OBJECT_TYPE",
532 TokenKind::KwObjectIdentity => "OBJECT_IDENTITY",
533 TokenKind::KwNotificationType => "NOTIFICATION_TYPE",
534 TokenKind::KwTextualConvention => "TEXTUAL_CONVENTION",
535 TokenKind::KwTrapType => "TRAP_TYPE",
536 TokenKind::KwInteger => "INTEGER",
537 TokenKind::KwUnsigned32 => "UNSIGNED32",
538 TokenKind::KwCounter32 => "COUNTER32",
539 TokenKind::KwCounter64 => "COUNTER64",
540 TokenKind::KwGauge32 => "GAUGE32",
541 TokenKind::KwIpAddress => "IPADDRESS",
542 TokenKind::KwOpaque => "OPAQUE",
543 TokenKind::KwTimeTicks => "TIMETICKS",
544 TokenKind::KwBits => "BITS",
545 TokenKind::KwOctet => "OCTET",
546 TokenKind::KwString => "STRING",
547 TokenKind::KwCounter => "COUNTER",
548 TokenKind::KwGauge => "GAUGE",
549 TokenKind::KwNetworkAddress => "NETWORKADDRESS",
550 TokenKind::KwApplication => "APPLICATION",
551 TokenKind::KwImplicit => "IMPLICIT",
552 TokenKind::KwUniversal => "UNIVERSAL",
553 TokenKind::KwCurrent => "CURRENT",
554 TokenKind::KwDeprecated => "DEPRECATED",
555 TokenKind::KwObsolete => "OBSOLETE",
556 TokenKind::KwMandatory => "MANDATORY",
557 TokenKind::KwOptional => "OPTIONAL",
558 TokenKind::KwReadOnly => "READ_ONLY",
559 TokenKind::KwReadWrite => "READ_WRITE",
560 TokenKind::KwReadCreate => "READ_CREATE",
561 TokenKind::KwWriteOnly => "WRITE_ONLY",
562 TokenKind::KwNotAccessible => "NOT_ACCESSIBLE",
563 TokenKind::KwAccessibleForNotify => "ACCESSIBLE_FOR_NOTIFY",
564 TokenKind::KwNotImplemented => "NOT_IMPLEMENTED",
565 }
566 }
567}
568
569impl std::fmt::Display for TokenKind {
570 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 f.write_str(self.libsmi_name())
573 }
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 #[test]
581 fn keyword_classification() {
582 assert!(TokenKind::KwDefinitions.is_keyword());
583 assert!(TokenKind::KwNotImplemented.is_keyword());
584 assert!(TokenKind::KwMacro.is_structural_keyword());
585 assert!(!TokenKind::KwSyntax.is_structural_keyword());
586 assert!(TokenKind::KwSyntax.is_clause_keyword());
587 assert!(TokenKind::KwVariables.is_clause_keyword());
588 assert!(!TokenKind::KwModuleIdentity.is_clause_keyword());
589 assert!(TokenKind::KwModuleIdentity.is_macro_keyword());
590 assert!(TokenKind::KwTrapType.is_macro_keyword());
591 assert!(TokenKind::KwInteger.is_type_keyword());
592 assert!(TokenKind::KwNetworkAddress.is_type_keyword());
593 assert!(TokenKind::KwApplication.is_tag_keyword());
594 assert!(TokenKind::KwUniversal.is_tag_keyword());
595 assert!(TokenKind::KwCurrent.is_status_access_keyword());
596 assert!(TokenKind::KwNotImplemented.is_status_access_keyword());
597 }
598
599 #[test]
600 fn non_keywords_are_not_keywords() {
601 assert!(!TokenKind::Error.is_keyword());
602 assert!(!TokenKind::UppercaseIdent.is_keyword());
603 assert!(!TokenKind::Number.is_keyword());
604 assert!(!TokenKind::LBrace.is_keyword());
605 assert!(!TokenKind::ColonColonEqual.is_keyword());
606 }
607
608 #[test]
609 fn identifier_classification() {
610 assert!(TokenKind::UppercaseIdent.is_identifier());
611 assert!(TokenKind::LowercaseIdent.is_identifier());
612 assert!(!TokenKind::KwObject.is_identifier());
613 assert!(!TokenKind::Number.is_identifier());
614 }
615
616 #[test]
617 fn libsmi_names() {
618 assert_eq!(TokenKind::Eof.libsmi_name(), "EOF");
619 assert_eq!(TokenKind::KwObjectType.libsmi_name(), "OBJECT_TYPE");
620 assert_eq!(
621 TokenKind::ColonColonEqual.libsmi_name(),
622 "COLON_COLON_EQUAL"
623 );
624 assert_eq!(TokenKind::KwReadOnly.libsmi_name(), "READ_ONLY");
625 }
626}