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::HexFloatSingle(name)
45        | PtxToken::HexFloatDouble(name)
46        | PtxToken::Register(name) => writer.write_str(name),
47        PtxToken::StringLiteral(name) => {
48            writer.write_char('"')?;
49            writer.write_str(name)?;
50            writer.write_char('"')
51        }
52        PtxToken::Dot => writer.write_char('.'),
53        PtxToken::Comma => writer.write_char(','),
54        PtxToken::Semicolon => writer.write_char(';'),
55        PtxToken::Colon => writer.write_char(':'),
56        PtxToken::DoubleColon => writer.write_str("::"),
57        PtxToken::LParen => writer.write_char('('),
58        PtxToken::RParen => writer.write_char(')'),
59        PtxToken::LBracket => writer.write_char('['),
60        PtxToken::RBracket => writer.write_char(']'),
61        PtxToken::LBrace => writer.write_char('{'),
62        PtxToken::RBrace => writer.write_char('}'),
63        PtxToken::Plus => writer.write_char('+'),
64        PtxToken::Minus => writer.write_char('-'),
65        PtxToken::Star => writer.write_char('*'),
66        PtxToken::Slash => writer.write_char('/'),
67        PtxToken::LAngle => writer.write_char('<'),
68        PtxToken::RAngle => writer.write_char('>'),
69        PtxToken::Equals => writer.write_char('='),
70        PtxToken::Percent => writer.write_char('%'),
71        PtxToken::Exclaim => writer.write_char('!'),
72        PtxToken::Pipe => writer.write_char('|'),
73        PtxToken::Ampersand => writer.write_char('&'),
74        PtxToken::Caret => writer.write_char('^'),
75        PtxToken::Tilde => writer.write_char('~'),
76        PtxToken::At => writer.write_char('@'),
77    }
78}
79
80fn needs_space(prev: &PtxToken, curr: &PtxToken) -> bool {
81    if no_space_after(prev) || no_space_before(curr) {
82        return false;
83    }
84    true
85}
86
87fn no_space_after(token: &PtxToken) -> bool {
88    matches!(
89        token,
90        PtxToken::LParen | PtxToken::LBracket | PtxToken::LBrace | PtxToken::Dot
91    )
92}
93
94fn no_space_before(token: &PtxToken) -> bool {
95    matches!(
96        token,
97        PtxToken::RParen
98            | PtxToken::RBracket
99            | PtxToken::RBrace
100            | PtxToken::Comma
101            | PtxToken::Semicolon
102            | PtxToken::Colon
103            | PtxToken::Dot
104    )
105}