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::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}