ptx_parser/
lexer.rs

1use logos::Logos;
2
3pub use logos::Span;
4
5/// PTX specification token types for lexical analysis.
6#[derive(Logos, Debug, Clone, PartialEq, Eq)]
7#[logos(error = LexError)]
8#[logos(skip r"[ \t\r\n]+")]
9pub enum PtxToken {
10    #[regex(r"//[^\n]*", logos::skip)]
11    #[regex(r"/\*[^*]*\*+(?:[^/*][^*]*\*+)*/", logos::skip)]
12    #[token("::")]
13    DoubleColon,
14    #[token(".")]
15    Dot,
16    #[token(",")]
17    Comma,
18    #[token(";")]
19    Semicolon,
20    #[token(":")]
21    Colon,
22    #[token("(")]
23    LParen,
24    #[token(")")]
25    RParen,
26    #[token("[")]
27    LBracket,
28    #[token("]")]
29    RBracket,
30    #[token("{")]
31    LBrace,
32    #[token("}")]
33    RBrace,
34    #[token("+")]
35    Plus,
36    #[token("-")]
37    Minus,
38    #[token("*")]
39    Star,
40    #[token("/")]
41    Slash,
42    #[token("<")]
43    LAngle,
44    #[token(">")]
45    RAngle,
46    #[token("=")]
47    Equals,
48    #[token("%")]
49    Percent,
50    #[token("!")]
51    Exclaim,
52    #[token("|")]
53    Pipe,
54    #[token("&")]
55    Ampersand,
56    #[token("^")]
57    Caret,
58    #[token("~")]
59    Tilde,
60    #[token("@")]
61    At,
62    #[regex(r"0[fFdD][0-9a-fA-F]{8}", |lex| lex.slice().to_string())]
63    #[regex(r"0[fFdD][0-9a-fA-F]{16}", |lex| lex.slice().to_string())]
64    HexFloat(String),
65    #[regex(r"0[xX][0-9a-fA-F]+", |lex| lex.slice().to_string())]
66    HexInteger(String),
67    #[regex(r"0[bB][01]+", |lex| lex.slice().to_string())]
68    BinaryInteger(String),
69    #[regex(r"0[0-7]+", |lex| lex.slice().to_string())]
70    OctalInteger(String),
71    #[regex(r"[0-9]+\.[0-9]+[eE][+-]?[0-9]+", |lex| lex.slice().to_string())]
72    #[regex(r"[0-9]+[eE][+-]?[0-9]+", |lex| lex.slice().to_string())]
73    FloatExponent(String),
74    #[regex(r"[0-9]+\.[0-9]+", |lex| lex.slice().to_string())]
75    Float(String),
76    #[regex(r"[0-9]+", |lex| lex.slice().to_string())]
77    DecimalInteger(String),
78    #[regex(r"%[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_string())]
79    Register(String),
80    #[regex(r"[a-zA-Z_$][a-zA-Z0-9_$-]*", |lex| lex.slice().to_string())]
81    Identifier(String),
82    #[regex(r#""([^"\\]|\\.)*""#, |lex| {
83        let slice = lex.slice();
84        slice[1..slice.len() - 1].to_string()
85    })]
86    StringLiteral(String),
87}
88
89impl PtxToken {
90    /// Extract the string value from a token, if it has one
91    pub fn as_str(&self) -> &str {
92        match self {
93            PtxToken::Identifier(s) |
94            PtxToken::DecimalInteger(s) |
95            PtxToken::HexInteger(s) |
96            PtxToken::BinaryInteger(s) |
97            PtxToken::OctalInteger(s) |
98            PtxToken::Float(s) |
99            PtxToken::FloatExponent(s) |
100            PtxToken::HexFloat(s) |
101            PtxToken::Register(s) |
102            PtxToken::StringLiteral(s) => s.as_str(),
103            _ => "",
104        }
105    }
106}
107
108#[derive(Debug, Clone, PartialEq, Default)]
109pub struct LexError {
110    pub span: Span,
111}
112
113impl From<Span> for LexError {
114    fn from(span: Span) -> Self {
115        LexError { span }
116    }
117}
118
119pub fn tokenize(source: &str) -> Result<Vec<(PtxToken, Span)>, LexError> {
120    let mut lexer = PtxToken::lexer(source);
121    let mut tokens = Vec::new();
122
123    while let Some(item) = lexer.next() {
124        match item {
125            Ok(token) => tokens.push((token, lexer.span())),
126            Err(_) => return Err(LexError { span: lexer.span() }),
127        }
128    }
129
130    Ok(tokens)
131}