oxc_parser/lexer/
token.rs1use std::{fmt, mem, ptr::NonNull};
4
5use oxc_span::Span;
6
7use super::kind::Kind;
8
9const START_SHIFT: usize = 0;
20const END_SHIFT: usize = 32;
21const KIND_SHIFT: usize = 64;
22const IS_ON_NEW_LINE_SHIFT: usize = 72;
23const ESCAPED_SHIFT: usize = 80;
24const LONE_SURROGATES_SHIFT: usize = 88;
25const HAS_SEPARATOR_SHIFT: usize = 96;
26
27const START_MASK: u128 = 0xFFFF_FFFF; const END_MASK: u128 = 0xFFFF_FFFF; const KIND_MASK: u128 = 0xFF; #[expect(dead_code)]
31const BOOL_MASK: u128 = 0xFF; const _: () = {
34 const fn is_valid_shift<T>(shift: usize) -> bool {
35 let align_bits = align_of::<T>() * 8;
36 shift.is_multiple_of(align_bits) && shift < u128::BITS as usize
37 }
38
39 assert!(is_valid_shift::<u32>(START_SHIFT));
41 assert!(is_valid_shift::<u32>(END_SHIFT));
42
43 assert!(size_of::<Kind>() == 1);
45 assert!(align_of::<Kind>() == 1);
46 assert!(is_valid_shift::<Kind>(KIND_SHIFT));
47
48 assert!(is_valid_shift::<bool>(IS_ON_NEW_LINE_SHIFT));
50 assert!(is_valid_shift::<bool>(ESCAPED_SHIFT));
51 assert!(is_valid_shift::<bool>(LONE_SURROGATES_SHIFT));
52 assert!(is_valid_shift::<bool>(HAS_SEPARATOR_SHIFT));
53};
54
55#[derive(Clone, Copy)]
56#[repr(transparent)]
57pub struct Token(u128);
58
59impl Default for Token {
60 #[inline]
61 fn default() -> Self {
62 const _: () = assert!(Kind::Eof as u8 == 0);
71 Self(0)
72 }
73}
74
75impl fmt::Debug for Token {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.debug_struct("Token")
78 .field("kind", &self.kind())
79 .field("start", &self.start())
80 .field("end", &self.end())
81 .field("is_on_new_line", &self.is_on_new_line())
82 .field("escaped", &self.escaped())
83 .field("lone_surrogates", &self.lone_surrogates())
84 .field("has_separator", &self.has_separator())
85 .finish()
86 }
87}
88
89impl Token {
90 #[inline]
91 pub(super) fn new_on_new_line() -> Self {
92 let mut token = Self::default();
94 token.set_is_on_new_line(true);
95 token
96 }
97}
98
99impl Token {
110 #[inline]
111 pub fn span(&self) -> Span {
112 Span::new(self.start(), self.end())
113 }
114
115 #[cfg(feature = "mutate_tokens")]
118 #[inline]
119 pub fn set_span(&mut self, span: Span) {
120 self.set_span_impl(span);
121 }
122
123 #[cfg(not(feature = "mutate_tokens"))]
124 #[inline]
125 #[allow(dead_code, clippy::allow_attributes)]
126 pub(super) fn set_span(&mut self, span: Span) {
127 self.set_span_impl(span);
128 }
129
130 #[inline]
131 fn set_span_impl(&mut self, span: Span) {
132 self.set_start(span.start);
136 self.set_end(span.end);
137 }
138
139 #[inline]
140 pub fn start(&self) -> u32 {
141 ((self.0 >> START_SHIFT) & START_MASK) as u32
142 }
143
144 #[inline]
145 pub(super) fn set_start(&mut self, start: u32) {
146 unsafe { self.write_u32(START_SHIFT, start) };
154 }
155
156 #[inline]
157 pub fn end(&self) -> u32 {
158 ((self.0 >> END_SHIFT) & END_MASK) as u32
159 }
160
161 #[inline]
162 pub(super) fn set_end(&mut self, end: u32) {
163 let start = self.start();
164 debug_assert!(end >= start, "Token end ({end}) cannot be less than start ({start})");
165
166 unsafe { self.write_u32(END_SHIFT, end) };
174 }
175
176 #[inline]
177 pub fn kind(&self) -> Kind {
178 unsafe { mem::transmute::<u8, Kind>(((self.0 >> KIND_SHIFT) & KIND_MASK) as u8) }
182 }
183
184 #[cfg(feature = "mutate_tokens")]
187 #[inline]
188 pub fn set_kind(&mut self, kind: Kind) {
189 self.set_kind_impl(kind);
190 }
191
192 #[cfg(not(feature = "mutate_tokens"))]
193 #[inline]
194 pub(super) fn set_kind(&mut self, kind: Kind) {
195 self.set_kind_impl(kind);
196 }
197
198 #[inline]
199 fn set_kind_impl(&mut self, kind: Kind) {
200 const OFFSET: usize =
207 if cfg!(target_endian = "little") { KIND_SHIFT / 8 } else { 15 - (KIND_SHIFT / 8) };
208 unsafe { *NonNull::from(self).cast::<Kind>().add(OFFSET).as_mut() = kind };
212 }
213
214 #[inline]
220 pub fn is_on_new_line(&self) -> bool {
221 unsafe { self.read_bool(IS_ON_NEW_LINE_SHIFT) }
225 }
226
227 #[inline]
228 pub(super) fn set_is_on_new_line(&mut self, value: bool) {
229 unsafe { self.write_bool(IS_ON_NEW_LINE_SHIFT, value) };
237 }
238
239 #[inline]
240 pub fn escaped(&self) -> bool {
241 unsafe { self.read_bool(ESCAPED_SHIFT) }
245 }
246
247 #[inline]
248 pub(super) fn set_escaped(&mut self, escaped: bool) {
249 unsafe { self.write_bool(ESCAPED_SHIFT, escaped) };
257 }
258
259 #[inline]
260 pub fn lone_surrogates(&self) -> bool {
261 unsafe { self.read_bool(LONE_SURROGATES_SHIFT) }
265 }
266
267 #[inline]
268 pub(super) fn set_lone_surrogates(&mut self, value: bool) {
269 unsafe { self.write_bool(LONE_SURROGATES_SHIFT, value) };
277 }
278
279 #[inline]
280 pub fn has_separator(&self) -> bool {
281 unsafe { self.read_bool(HAS_SEPARATOR_SHIFT) }
285 }
286
287 #[inline]
288 pub(super) fn set_has_separator(&mut self, value: bool) {
289 unsafe { self.write_bool(HAS_SEPARATOR_SHIFT, value) };
297 }
298
299 #[expect(clippy::inline_always)]
334 #[inline(always)] unsafe fn read_bool(&self, shift: usize) -> bool {
336 let offset = if cfg!(target_endian = "little") { shift / 8 } else { 15 - (shift / 8) };
338 unsafe {
341 let field_ptr = NonNull::from_ref(self).cast::<bool>().add(offset);
342 debug_assert!(field_ptr.cast::<u8>().read() <= 1);
343 *field_ptr.as_ref()
344 }
345 }
346
347 #[expect(clippy::inline_always)]
360 #[inline(always)] unsafe fn write_bool(&mut self, shift: usize, value: bool) {
362 let offset = if cfg!(target_endian = "little") { shift / 8 } else { 15 - (shift / 8) };
364 unsafe { *NonNull::from(self).cast::<bool>().add(offset).as_mut() = value };
368 }
369
370 #[expect(clippy::inline_always)]
380 #[inline(always)] unsafe fn write_u32(&mut self, shift: usize, value: u32) {
382 let offset = if cfg!(target_endian = "little") { shift / 32 } else { 3 - (shift / 32) };
384 unsafe { *NonNull::from(self).cast::<u32>().add(offset).as_mut() = value };
389 }
390}
391
392#[cfg(test)]
393mod test {
394 use super::{Kind, Span, Token};
395
396 const _: () = assert!(size_of::<Token>() == 16);
398
399 #[test]
401 fn default_token_values() {
402 let token = Token::default();
403 assert_eq!(token.start(), 0);
404 assert_eq!(token.end(), 0);
405 assert_eq!(token.kind(), Kind::Eof); assert!(!token.is_on_new_line());
407 assert!(!token.escaped());
408 assert!(!token.lone_surrogates());
409 assert!(!token.has_separator());
410 }
411
412 #[test]
413 fn new_on_new_line_token_values() {
414 let token = Token::new_on_new_line();
415 assert_eq!(token.start(), 0);
416 assert_eq!(token.end(), 0);
417 assert_eq!(token.kind(), Kind::Eof);
418 assert!(token.is_on_new_line());
419 assert!(!token.escaped());
420 assert!(!token.lone_surrogates());
421 assert!(!token.has_separator());
422 }
423
424 #[test]
425 fn token_creation_and_retrieval() {
426 let kind = Kind::Ident;
427 let start = 100u32;
428 let end = start + 5u32;
429 let is_on_new_line = true;
430 let escaped = false;
431 let lone_surrogates = true;
432 let has_separator = false;
433
434 let mut token = Token::default();
435 token.set_kind(kind);
436 token.set_start(start);
437 token.set_end(end);
438 token.set_is_on_new_line(is_on_new_line);
439 token.set_escaped(escaped);
440 token.set_lone_surrogates(lone_surrogates);
441 if has_separator {
442 token.set_has_separator(true);
444 }
445
446 assert_eq!(token.kind(), kind);
447 assert_eq!(token.start(), start);
448 assert_eq!(token.end(), end);
449 assert_eq!(token.is_on_new_line(), is_on_new_line);
450 assert_eq!(token.escaped(), escaped);
451 assert_eq!(token.lone_surrogates(), lone_surrogates);
452 assert_eq!(token.has_separator(), has_separator);
453 }
454
455 #[test]
456 fn token_setters() {
457 let mut token = Token::default();
458 token.set_kind(Kind::Ident);
459 token.set_span(Span::new(10, 15));
460 assert_eq!(token.start(), 10);
463 assert_eq!(token.end(), 15);
464 assert!(!token.escaped());
465 assert!(!token.is_on_new_line());
466 assert!(!token.lone_surrogates());
467
468 let mut token_for_set_end = Token::default();
470 token_for_set_end.set_kind(Kind::Ident);
471 token_for_set_end.set_start(10);
472 token_for_set_end.set_end(15);
473
474 assert_eq!(token_for_set_end.end(), 15);
475 token_for_set_end.set_end(30);
476 assert_eq!(token_for_set_end.start(), 10);
477 assert_eq!(token_for_set_end.end(), 30);
478
479 let mut token_with_flags = Token::default();
481 token_with_flags.set_kind(Kind::Str);
482 token_with_flags.set_start(30);
483 token_with_flags.set_end(33);
484 token_with_flags.set_is_on_new_line(true);
485 token_with_flags.set_escaped(true);
486 token_with_flags.set_lone_surrogates(true);
487 token_with_flags.set_has_separator(true);
488
489 token_with_flags.set_start(40);
490 assert_eq!(token_with_flags.start(), 40);
491 assert!(token_with_flags.is_on_new_line());
492 assert!(token_with_flags.escaped());
493 assert!(token_with_flags.lone_surrogates());
494 assert!(token_with_flags.has_separator());
495
496 let mut token_with_flags2 = Token::default();
498 token_with_flags2.set_kind(Kind::Str);
499 token_with_flags2.set_start(50);
500 token_with_flags2.set_end(52);
501 token_with_flags2.set_is_on_new_line(true);
502 token_with_flags2.set_lone_surrogates(true);
504 token_with_flags2.set_has_separator(true);
505
506 token_with_flags2.set_escaped(true);
507 assert_eq!(token_with_flags2.start(), 50);
508 assert!(token_with_flags2.is_on_new_line());
509 assert!(token_with_flags2.escaped());
510 assert!(token_with_flags2.lone_surrogates());
511 assert!(token_with_flags2.has_separator());
512 token_with_flags2.set_escaped(false);
513 assert!(!token_with_flags2.escaped());
514 assert!(token_with_flags2.is_on_new_line()); assert!(token_with_flags2.lone_surrogates()); assert!(token_with_flags2.has_separator()); let mut token_flags_test_newline = Token::default();
520 token_flags_test_newline.set_kind(Kind::Str);
521 token_flags_test_newline.set_start(60);
522 token_flags_test_newline.set_end(62);
523 token_flags_test_newline.set_escaped(true);
525 token_flags_test_newline.set_lone_surrogates(true);
526 token_flags_test_newline.set_has_separator(true);
527
528 token_flags_test_newline.set_is_on_new_line(true);
529 assert!(token_flags_test_newline.is_on_new_line());
530 assert_eq!(token_flags_test_newline.start(), 60);
531 assert!(token_flags_test_newline.escaped());
532 assert!(token_flags_test_newline.lone_surrogates());
533 assert!(token_flags_test_newline.has_separator());
534 token_flags_test_newline.set_is_on_new_line(false);
535 assert!(!token_flags_test_newline.is_on_new_line());
536 assert!(token_flags_test_newline.escaped());
537 assert!(token_flags_test_newline.lone_surrogates());
538 assert!(token_flags_test_newline.has_separator());
539
540 let mut token_flags_test_lone_surrogates = Token::default();
542 token_flags_test_lone_surrogates.set_kind(Kind::Str);
543 token_flags_test_lone_surrogates.set_start(70);
544 token_flags_test_lone_surrogates.set_end(72);
545 token_flags_test_lone_surrogates.set_is_on_new_line(true);
546 token_flags_test_lone_surrogates.set_escaped(true);
547 token_flags_test_lone_surrogates.set_has_separator(true);
549
550 token_flags_test_lone_surrogates.set_lone_surrogates(true);
551 assert!(token_flags_test_lone_surrogates.lone_surrogates());
552 assert_eq!(token_flags_test_lone_surrogates.start(), 70);
553 assert!(token_flags_test_lone_surrogates.is_on_new_line());
554 assert!(token_flags_test_lone_surrogates.escaped());
555 assert!(token_flags_test_lone_surrogates.has_separator());
556 token_flags_test_lone_surrogates.set_lone_surrogates(false);
557 assert!(!token_flags_test_lone_surrogates.lone_surrogates());
558 assert!(token_flags_test_lone_surrogates.is_on_new_line());
559 assert!(token_flags_test_lone_surrogates.escaped());
560 assert!(token_flags_test_lone_surrogates.has_separator());
561 }
562
563 #[test]
564 fn is_on_new_line() {
565 let mut token = Token::default();
566 assert!(!token.is_on_new_line());
567 token.set_is_on_new_line(true);
568 assert!(token.is_on_new_line());
569 token.set_is_on_new_line(false);
570 assert!(!token.is_on_new_line());
571 }
572
573 #[test]
574 fn escaped() {
575 let mut token = Token::default();
576 assert!(!token.escaped());
577 token.set_escaped(true);
578 assert!(token.escaped());
579 token.set_escaped(false);
580 assert!(!token.escaped());
581 }
582
583 #[test]
584 fn lone_surrogates() {
585 let mut token = Token::default();
586 assert!(!token.lone_surrogates());
587 token.set_lone_surrogates(true);
588 assert!(token.lone_surrogates());
589 token.set_lone_surrogates(false);
590 assert!(!token.lone_surrogates());
591 }
592
593 #[test]
594 fn has_separator() {
595 let mut token = Token::default();
596 assert!(!token.has_separator());
597 token.set_has_separator(true);
598 assert!(token.has_separator());
599 token.set_has_separator(false);
600 assert!(!token.has_separator());
601 }
602}