1use crate::lexer::PtxToken;
2use std::fmt::{self, Write};
3
4pub struct PtxUnlexer;
7
8impl PtxUnlexer {
9 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 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}