pendzl_lang_codegen/
internal.rs1extern crate proc_macro;
24
25use quote::ToTokens;
26use std::collections::HashSet;
27use syn::{
28 ext::IdentExt,
29 parenthesized,
30 parse::{Parse, ParseStream},
31 punctuated::Punctuated,
32 token::Comma,
33 FnArg,
34};
35
36pub(crate) struct MetaList {
37 pub _path: syn::Path,
38 pub _paren_token: syn::token::Paren,
39 pub _nested: syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>,
40}
41#[derive(Debug)]
42pub struct InputsDiff {
43 pub added: HashSet<String>,
44 pub removed: HashSet<String>,
45}
46
47pub fn inputs_diff(
48 inputs_a: Punctuated<FnArg, Comma>,
49 inputs_b: Punctuated<FnArg, Comma>,
50) -> InputsDiff {
51 let set_a: HashSet<_> = inputs_a
52 .into_iter()
53 .map(|arg| arg.into_token_stream().to_string())
54 .collect();
55 let set_b: HashSet<_> = inputs_b
56 .into_iter()
57 .map(|arg| arg.into_token_stream().to_string())
58 .collect();
59
60 let added = &set_b - &set_a;
61 let removed = &set_a - &set_b;
62
63 InputsDiff {
64 added: added.into_iter().collect(),
65 removed: removed.into_iter().collect(),
66 }
67}
68
69pub fn format_arg_string(arg: &str) -> String {
70 let mut formatted = String::new();
71 let mut chars = arg.chars().peekable();
72
73 while let Some(ch) = chars.next() {
74
75 match ch {
76 '&' => {
77 if chars.peek() == Some(&' ') {
78 formatted.push('&');
79 chars.next(); }
81 }
82 _ => {
83 if chars.peek() == Some(&':') {
84 formatted.push(':');
85 chars.next();
86 }
87 else if chars.peek() == Some(&'>') {
88 formatted.push('>');
89 chars.next();
90 chars.next();
91 }
92 else if chars.peek() == Some(&'<') {
93 formatted.push('<');
94 chars.next();
95 chars.next();
96 }
97 else if chars.peek() == Some(&',') {
98 formatted.push(',');
99 chars.next();
100 }else {
101 formatted.push(ch);
102 }
103 }
104 }
105 }
106
107 formatted
108}
109
110fn parse_meta_path(input: ParseStream) -> syn::Result<syn::Path> {
112 Ok(syn::Path {
113 leading_colon: input.parse()?,
114 segments: {
115 let mut segments = syn::punctuated::Punctuated::new();
116 while input.peek(syn::Ident::peek_any) {
117 let ident = syn::Ident::parse_any(input)?;
118 segments.push_value(syn::PathSegment::from(ident));
119 if !input.peek(syn::Token![::]) {
120 break;
121 }
122 let punct = input.parse()?;
123 segments.push_punct(punct);
124 }
125 if segments.is_empty() {
126 return Err(input.error("expected path"));
127 } else if segments.trailing_punct() {
128 return Err(input.error("expected path segment"));
129 }
130 segments
131 },
132 })
133}
134
135fn parse_meta_list_after_path(path: syn::Path, input: ParseStream) -> syn::Result<MetaList> {
136 let content;
137 Ok(MetaList {
138 _path: path,
139 _paren_token: parenthesized!(content in input),
140 _nested: content.parse_terminated(syn::Expr::parse)?,
141 })
142}
143
144fn parse_meta_after_path(path: syn::Path, input: ParseStream) -> syn::Result<NestedMeta> {
145 if input.peek(syn::token::Paren) {
146 parse_meta_list_after_path(path, input).map(NestedMeta::List)
147 } else {
148 Ok(NestedMeta::Path(path))
149 }
150}
151
152impl Parse for MetaList {
153 fn parse(input: ParseStream) -> syn::Result<Self> {
154 let path = input.call(parse_meta_path)?;
155 parse_meta_list_after_path(path, input)
156 }
157}
158
159pub(crate) enum NestedMeta {
160 Path(syn::Path),
161 List(MetaList),
162}
163
164impl Parse for NestedMeta {
165 fn parse(input: ParseStream) -> syn::Result<Self> {
166 let path = input.call(parse_meta_path)?;
167 parse_meta_after_path(path, input)
168 }
169}
170
171pub(crate) struct AttributeArgs(Vec<NestedMeta>);
172
173impl Parse for AttributeArgs {
174 fn parse(input: ParseStream) -> syn::Result<Self> {
175 let mut attrs = Vec::new();
176 while input.peek(syn::Ident::peek_any) {
177 attrs.push(input.parse()?);
178 if input.is_empty() {
179 break;
180 }
181 let _: syn::token::Comma = input.parse()?;
182 }
183 Ok(AttributeArgs(attrs))
184 }
185}
186
187impl std::ops::Deref for AttributeArgs {
188 type Target = Vec<NestedMeta>;
189
190 fn deref(&self) -> &Self::Target {
191 &self.0
192 }
193}
194
195impl std::ops::DerefMut for AttributeArgs {
196 fn deref_mut(&mut self) -> &mut Vec<NestedMeta> {
197 &mut self.0
198 }
199}
200
201pub(crate) struct Attributes(Vec<syn::Attribute>);
202
203impl Parse for Attributes {
204 fn parse(input: ParseStream) -> syn::Result<Self> {
205 Ok(Self(syn::Attribute::parse_outer(input)?))
206 }
207}
208
209#[inline]
210pub(crate) fn is_attr(attrs: &[syn::Attribute], ident: &str) -> bool {
211 attrs.iter().any(|attr| {
212 attr.path
213 .segments
214 .last()
215 .expect("No segments in path")
216 .ident
217 == ident
218 })
219}
220
221pub(crate) const INK_PREFIX: &str = "ink=";
222
223#[inline]
224pub(crate) fn skip() -> bool {
225 !std::env::args().any(|arg| arg.contains(INK_PREFIX))
226}