-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Mateusz Kowalski <mateusz.kowalski@swmansion.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> commit-id:face0a80 --- **Stack**: - #1811 - #1810 ⬅⚠️ *Part of a stack created by [spr](https://github.com/ejoffe/spr). Do not merge manually using the UI - doing so may have unexpected results.*
- Loading branch information
Showing
9 changed files
with
600 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "cairo-lang-quote" | ||
version = "0.1.0" | ||
edition.workspace = true | ||
|
||
authors.workspace = true | ||
categories = ["development-tools"] | ||
description = "Cairo procedural macro helper for constructing procedural macro results." | ||
homepage.workspace = true | ||
keywords = ["scarb"] | ||
license.workspace = true | ||
repository.workspace = true | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
proc-macro2.workspace = true | ||
quote.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
use std::iter::Peekable; | ||
|
||
use proc_macro::{Delimiter, TokenStream as RustTokenStream, TokenTree as RustTokenTree}; | ||
use proc_macro2::{Ident, Span}; | ||
|
||
extern crate proc_macro; | ||
use quote::quote as rust_quote; | ||
|
||
#[derive(Debug)] | ||
enum QuoteToken { | ||
Var(Ident), | ||
Content(String), | ||
Whitespace, | ||
} | ||
|
||
enum DelimiterVariant { | ||
Open, | ||
Close, | ||
} | ||
|
||
impl QuoteToken { | ||
pub fn from_delimiter(delimiter: Delimiter, variant: DelimiterVariant) -> Self { | ||
match (delimiter, variant) { | ||
(Delimiter::Brace, DelimiterVariant::Open) => Self::Content("{".to_string()), | ||
(Delimiter::Brace, DelimiterVariant::Close) => Self::Content("}".to_string()), | ||
(Delimiter::Bracket, DelimiterVariant::Open) => Self::Content("[".to_string()), | ||
(Delimiter::Bracket, DelimiterVariant::Close) => Self::Content("]".to_string()), | ||
(Delimiter::Parenthesis, DelimiterVariant::Open) => Self::Content("(".to_string()), | ||
(Delimiter::Parenthesis, DelimiterVariant::Close) => Self::Content(")".to_string()), | ||
(Delimiter::None, _) => Self::Content(String::default()), | ||
} | ||
} | ||
} | ||
|
||
fn process_token_stream( | ||
mut token_stream: Peekable<impl Iterator<Item = RustTokenTree>>, | ||
output: &mut Vec<QuoteToken>, | ||
) { | ||
// Rust proc macro parser to TokenStream gets rid of all whitespaces. | ||
// Here we just make sure no two identifiers are without a space between them. | ||
let mut was_previous_ident: bool = false; | ||
while let Some(token_tree) = token_stream.next() { | ||
match token_tree { | ||
RustTokenTree::Group(group) => { | ||
let token_iter = group.stream().into_iter().peekable(); | ||
let delimiter = group.delimiter(); | ||
output.push(QuoteToken::from_delimiter( | ||
delimiter, | ||
DelimiterVariant::Open, | ||
)); | ||
process_token_stream(token_iter, output); | ||
output.push(QuoteToken::from_delimiter( | ||
delimiter, | ||
DelimiterVariant::Close, | ||
)); | ||
was_previous_ident = false; | ||
} | ||
RustTokenTree::Punct(punct) => { | ||
if punct.as_char() == '#' { | ||
if let Some(RustTokenTree::Ident(ident)) = token_stream.next() { | ||
let var_ident = Ident::new(&ident.to_string(), Span::call_site()); | ||
output.push(QuoteToken::Var(var_ident)) | ||
} | ||
} else { | ||
output.push(QuoteToken::Content(punct.to_string())); | ||
} | ||
was_previous_ident = false; | ||
} | ||
RustTokenTree::Ident(ident) => { | ||
if was_previous_ident { | ||
output.push(QuoteToken::Whitespace); | ||
} | ||
output.push(QuoteToken::Content(ident.to_string())); | ||
was_previous_ident = true; | ||
} | ||
RustTokenTree::Literal(literal) => { | ||
output.push(QuoteToken::Content(literal.to_string())); | ||
was_previous_ident = false; | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[proc_macro] | ||
pub fn quote(input: RustTokenStream) -> RustTokenStream { | ||
let mut parsed_input: Vec<QuoteToken> = Vec::new(); | ||
let mut output_token_stream = rust_quote! { | ||
let mut quote_macro_result = ::cairo_lang_macro::TokenStream::empty(); | ||
}; | ||
|
||
let token_iter = input.into_iter().peekable(); | ||
process_token_stream(token_iter, &mut parsed_input); | ||
|
||
for quote_token in parsed_input.iter() { | ||
match quote_token { | ||
QuoteToken::Content(content) => { | ||
output_token_stream.extend(rust_quote! { | ||
quote_macro_result.push_token(::cairo_lang_macro::TokenTree::Ident(::cairo_lang_macro::Token::new(::std::string::ToString::to_string(#content), ::cairo_lang_macro::TextSpan::call_site()))); | ||
}); | ||
} | ||
QuoteToken::Var(ident) => { | ||
output_token_stream.extend(rust_quote! { | ||
quote_macro_result.extend(::cairo_lang_macro::TokenStream::from_primitive_token_stream(::cairo_lang_primitive_token::ToPrimitiveTokenStream::to_primitive_token_stream(&#ident)).into_iter()); | ||
}); | ||
} | ||
QuoteToken::Whitespace => output_token_stream.extend(rust_quote! { | ||
quote_macro_result.push_token(::cairo_lang_macro::TokenTree::Ident(::cairo_lang_macro::Token::new(" ".to_string(), ::cairo_lang_macro::TextSpan::call_site()))); | ||
}), | ||
} | ||
} | ||
RustTokenStream::from(rust_quote!({ | ||
#output_token_stream | ||
quote_macro_result | ||
})) | ||
} |
Oops, something went wrong.