mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
c3ba832444
* Refactor annotation system * Move tests to different location * Limit annotations per line (15) * Write initial benchmark * Optimize * More optimizations * Rewrite with 3x speed! * Remove benchmarks They were in wrong place and for development * Polishing * Remove unused leftover * Integrate new annotation system * Add comment explanation * Remove `hashe-based matching` Turned to be it is impure and non-deterministic method * Add `tracing::error` for `// native` without `deno_core` If you build backend without `deno_core` feature flag, and add //native annotation to ts script, it would just silently exit. This commit prints error to logs * add more tests * Update annotations.rs --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
96 lines
3.2 KiB
Rust
96 lines
3.2 KiB
Rust
use proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use syn::{parse_macro_input, Ident, ItemStruct, Lit};
|
|
|
|
#[proc_macro_attribute]
|
|
pub fn annotations(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
let input = parse_macro_input!(item as ItemStruct);
|
|
let name = input.ident.clone();
|
|
let fields = input
|
|
.fields
|
|
.iter()
|
|
.map(|f| f.ident.clone().unwrap())
|
|
.collect::<Vec<Ident>>();
|
|
|
|
// Match on the literal to extract the string value
|
|
let comm_lit = match parse_macro_input!(attr as Lit) {
|
|
Lit::Str(lit_str) => lit_str.value(), // This will give "#" without quotes
|
|
_ => panic!("Expected a string literal"),
|
|
};
|
|
|
|
// Generate regex
|
|
let mut reg = format!("^{}|", &comm_lit);
|
|
{
|
|
for field in fields.iter() {
|
|
reg.push_str(&(field.to_string()));
|
|
reg.push_str("\\b");
|
|
}
|
|
|
|
reg.push_str(r#"|\w+"#);
|
|
}
|
|
// Example of generated regex:
|
|
// ^#
|
|
// |ann1\b|ann2\b|ann3\b|ann4\b
|
|
// |\w+
|
|
|
|
TokenStream::from(quote! {
|
|
#[derive(Default, Debug)]
|
|
#input
|
|
|
|
impl std::ops::BitOrAssign for #name{
|
|
fn bitor_assign(&mut self, rhs: Self) {
|
|
// Unfold fields
|
|
// Read more: https://docs.rs/quote/latest/quote/macro.quote.html#interpolation
|
|
#( self.#fields |= rhs.#fields; )*
|
|
}
|
|
}
|
|
|
|
impl #name {
|
|
/// Autogenerated by windmill-macros
|
|
pub fn parse(inner_content: &str) -> Self{
|
|
let mut res = Self::default();
|
|
lazy_static::lazy_static! {
|
|
static ref RE: regex::Regex = regex::Regex::new(#reg).unwrap();
|
|
}
|
|
// Create lines stream
|
|
let mut lines = inner_content.lines();
|
|
'outer: while let Some(line) = lines.next() {
|
|
// If comment sign(s) on the right place
|
|
let mut comms = false;
|
|
// New instance
|
|
// We will apply it if in line only annotations
|
|
let mut new = Self::default();
|
|
|
|
'inner: for (i, mat) in RE.find_iter(line).enumerate() {
|
|
|
|
match mat.as_str(){
|
|
#comm_lit if i == 0 => {
|
|
comms = true;
|
|
continue 'inner;
|
|
},
|
|
|
|
// Will expand into something like:
|
|
// "ann1" => new.ann1 = true,
|
|
// "ann2" => new.ann2 = true,
|
|
// "ann3" => new.ann3 = true,
|
|
#( stringify!(#fields) => new.#fields = true, )*
|
|
// Non annotations
|
|
_ => continue 'outer,
|
|
};
|
|
}
|
|
|
|
if !comms {
|
|
// We dont want to continue if line does not start with #
|
|
return res;
|
|
}
|
|
|
|
// Apply changes
|
|
res |= new;
|
|
}
|
|
|
|
res
|
|
}
|
|
}
|
|
})
|
|
}
|