use rucc_base::Symbol;
use rucc_diag::Span;
use rucc_lex::{PpToken, PpTokenKind, Punct, TokenFlags};
use crate::hide::HideSet;
use crate::trace::TraceId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Tok {
pub kind: PpTokenKind,
pub flags: TokenFlags,
pub value: Option<Symbol>,
pub span: Span,
pub expansion: Span,
pub hides: HideSet,
pub trace: TraceId,
pub(crate) placemarker: bool,
}
impl Tok {
#[inline]
pub fn new(pp: PpToken) -> Tok {
Tok {
kind: pp.kind,
flags: pp.flags,
value: pp.value,
span: pp.span,
expansion: Span::DUMMY,
trace: TraceId::NONE,
hides: HideSet::EMPTY,
placemarker: false,
}
}
#[inline]
pub fn punct(self) -> Option<Punct> {
match self.kind {
PpTokenKind::Punct(p) if !self.placemarker => Some(p),
_ => None,
}
}
#[inline]
pub fn is(self, p: Punct) -> bool {
self.punct() == Some(p)
}
#[inline]
pub fn ident(self) -> Option<Symbol> {
match self.kind {
PpTokenKind::Ident => self.value,
_ => None,
}
}
#[inline]
pub fn is_placemarker(self) -> bool {
self.placemarker
}
#[inline]
pub fn report_span(self) -> Span {
if self.expansion.is_dummy() { self.span } else { self.expansion }
}
pub(crate) fn synthetic(
kind: PpTokenKind,
value: Option<Symbol>,
flags: TokenFlags,
span: Span,
) -> Tok {
Tok {
kind,
flags,
value,
span,
expansion: Span::DUMMY,
trace: TraceId::NONE,
hides: HideSet::EMPTY,
placemarker: false,
}
}
pub(crate) fn placemarker_at(span: Span) -> Tok {
Tok {
kind: PpTokenKind::Other,
flags: TokenFlags::EMPTY,
value: None,
span,
expansion: Span::DUMMY,
trace: TraceId::NONE,
hides: HideSet::EMPTY,
placemarker: true,
}
}
}
#[cfg(test)]
mod tests {
use rucc_diag::Span;
use super::*;
fn pp(kind: PpTokenKind) -> PpToken {
PpToken { kind, flags: TokenFlags::EMPTY, value: None, span: Span::new(0, 1) }
}
#[test]
fn a_lexed_token_starts_with_an_empty_hide_set() {
let t = Tok::new(pp(PpTokenKind::Punct(Punct::Plus)));
assert_eq!(t.hides, HideSet::EMPTY);
assert!(t.expansion.is_dummy());
assert!(!t.is_placemarker());
}
#[test]
fn a_placemarker_is_not_a_punctuator() {
let t = Tok::placemarker_at(Span::new(3, 3));
assert!(t.is_placemarker());
assert_eq!(t.punct(), None);
assert_eq!(t.ident(), None);
}
#[test]
fn a_token_from_a_macro_is_reported_at_the_call() {
let mut t = Tok::new(pp(PpTokenKind::Ident));
assert_eq!(t.report_span(), Span::new(0, 1));
t.expansion = Span::new(40, 44);
assert_eq!(t.report_span(), Span::new(40, 44));
}
}