blob: 5cf98afa6ddd1e7fdadd049e93240e9541674666 [file] [log] [blame]
Marcel Hlopko3164eee2021-08-24 20:09:22 +00001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5use anyhow::Result;
6use proc_macro2::TokenStream;
7use proc_macro2::TokenTree;
8
9use std::fmt::Write;
10
11/// Produces C++ source code out of the token stream.
12///
13/// Notable features:
14/// * quote! cannot produce a single `#` token (that is not immediately followed by `(`, `[`, `{`,
15/// or variable interpolation). For cases when we need `#` to be produced in the C++ source code
16/// use the placeholder `__HASH_TOKEN__`.
17/// * Rust tokenizer ignores newlines as they are not significant for Rust. For C++ they are (for
18/// example there needs to be a newline after `#include "foo/bar.h"`). Use the placeholder
19/// `__NEWLINE__` to insert a newline character.
20pub fn cc_tokens_to_string(tokens: TokenStream) -> Result<String> {
21 let mut result = "".to_string();
22 let mut first = true;
23 for tt in tokens.into_iter() {
24 if !first {
25 write!(result, " ")?;
26 }
27 first = false;
28 match tt {
29 TokenTree::Ident(ref tt) if tt == "__NEWLINE__" => writeln!(result)?,
30 TokenTree::Ident(ref tt) if tt == "__HASH_TOKEN__" => write!(result, "#")?,
31
32 _ => write!(result, "{}", tt)?,
33 }
34 }
35 Ok(result)
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 use super::Result;
43 use quote::quote;
44
45 #[test]
46 fn test_simple_token_stream() -> Result<()> {
47 let token_stream = quote! {
48 struct Foo {}
49
50 impl Bar for Foo {
51 fn bar(&self) {}
52 }
53 };
54 assert_eq!(cc_tokens_to_string(token_stream.clone())?, token_stream.to_string());
55 Ok(())
56 }
57
58 #[test]
59 fn test_newline_token() -> Result<()> {
60 let token_stream = quote! { a __NEWLINE__ b };
61 assert_eq!(cc_tokens_to_string(token_stream.clone())?, "a \n b");
62 Ok(())
63 }
64
65 #[test]
66 fn test_hash_token() -> Result<()> {
67 let token_stream = quote! { a __HASH_TOKEN__ b };
68 assert_eq!(cc_tokens_to_string(token_stream.clone())?, "a # b");
69 Ok(())
70 }
71}