ptx_parser/
unlexer.rs

1use crate::lexer::PtxToken;
2use std::fmt::{self, Write};
3
4/// Utility that performs the inverse of the lexer: it writes textual PTX for a
5/// sequence of [`PtxSpecToken`] values.
6pub struct PtxUnlexer;
7
8impl PtxUnlexer {
9    /// Write the textual PTX representation of `tokens` to `writer`.
10    pub fn write_tokens<W>(writer: &mut W, tokens: &[PtxToken]) -> fmt::Result
11    where
12        W: Write,
13    {
14        let mut prev: Option<&PtxToken> = None;
15        for token in tokens {
16            if let Some(previous) = prev {
17                if needs_space(previous, token) {
18                    writer.write_char(' ')?;
19                }
20            }
21            write_token(writer, token)?;
22            prev = Some(token);
23        }
24        Ok(())
25    }
26
27    /// Convenience helper that produces a PTX string for `tokens`.
28    pub fn to_string(tokens: &[PtxToken]) -> Result<String, fmt::Error> {
29        let mut buffer = String::new();
30        Self::write_tokens(&mut buffer, tokens)?;
31        Ok(buffer)
32    }
33}
34
35fn write_token<W: Write>(writer: &mut W, token: &PtxToken) -> fmt::Result {
36    match token {
37        PtxToken::Identifier(name)
38        | PtxToken::DecimalInteger(name)
39        | PtxToken::HexInteger(name)
40        | PtxToken::BinaryInteger(name)
41        | PtxToken::OctalInteger(name)
42        | PtxToken::Float(name)
43        | PtxToken::FloatExponent(name)
44        | PtxToken::HexFloat(name)
45        | PtxToken::Register(name) => writer.write_str(name),
46        PtxToken::StringLiteral(name) => {
47            writer.write_char('"')?;
48            writer.write_str(name)?;
49            writer.write_char('"')
50        }
51        PtxToken::Dot => writer.write_char('.'),
52        PtxToken::Comma => writer.write_char(','),
53        PtxToken::Semicolon => writer.write_char(';'),
54        PtxToken::Colon => writer.write_char(':'),
55        PtxToken::DoubleColon => writer.write_str("::"),
56        PtxToken::LParen => writer.write_char('('),
57        PtxToken::RParen => writer.write_char(')'),
58        PtxToken::LBracket => writer.write_char('['),
59        PtxToken::RBracket => writer.write_char(']'),
60        PtxToken::LBrace => writer.write_char('{'),
61        PtxToken::RBrace => writer.write_char('}'),
62        PtxToken::Plus => writer.write_char('+'),
63        PtxToken::Minus => writer.write_char('-'),
64        PtxToken::Star => writer.write_char('*'),
65        PtxToken::Slash => writer.write_char('/'),
66        PtxToken::LAngle => writer.write_char('<'),
67        PtxToken::RAngle => writer.write_char('>'),
68        PtxToken::Equals => writer.write_char('='),
69        PtxToken::Percent => writer.write_char('%'),
70        PtxToken::Exclaim => writer.write_char('!'),
71        PtxToken::Pipe => writer.write_char('|'),
72        PtxToken::Ampersand => writer.write_char('&'),
73        PtxToken::Caret => writer.write_char('^'),
74        PtxToken::Tilde => writer.write_char('~'),
75        PtxToken::At => writer.write_char('@'),
76    }
77}
78
79fn needs_space(prev: &PtxToken, curr: &PtxToken) -> bool {
80    if no_space_after(prev) || no_space_before(curr) {
81        return false;
82    }
83    true
84}
85
86fn no_space_after(token: &PtxToken) -> bool {
87    matches!(
88        token,
89        PtxToken::LParen | PtxToken::LBracket | PtxToken::LBrace | PtxToken::Dot
90    )
91}
92
93fn no_space_before(token: &PtxToken) -> bool {
94    matches!(
95        token,
96        PtxToken::RParen
97            | PtxToken::RBracket
98            | PtxToken::RBrace
99            | PtxToken::Comma
100            | PtxToken::Semicolon
101            | PtxToken::Colon
102            | PtxToken::Dot
103    )
104}