From cdc4020eff1e49c03a7940f2c57b3525efb3299e Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 15:54:36 +0200 Subject: [PATCH 1/7] feat: derive Add, Sub, Mul, Div --- packages/macros/src/lib.rs | 56 +----- packages/macros/src/num_traits.rs | 168 ++++++++++++++++++ packages/macros/src/pow.rs | 54 ++++++ packages/macros_tests/src/lib.cairo | 16 +- .../macros_tests/src/test_num_traits.cairo | 95 ++++++++++ packages/macros_tests/src/test_pow.cairo | 12 ++ 6 files changed, 334 insertions(+), 67 deletions(-) create mode 100644 packages/macros/src/num_traits.rs create mode 100644 packages/macros/src/pow.rs create mode 100644 packages/macros_tests/src/test_num_traits.cairo create mode 100644 packages/macros_tests/src/test_pow.cairo diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs index 5ad557c5..85af4100 100644 --- a/packages/macros/src/lib.rs +++ b/packages/macros/src/lib.rs @@ -1,54 +1,2 @@ -use bigdecimal::{num_traits::pow, BigDecimal}; -use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; -use cairo_lang_parser::utils::SimpleParserDatabase; -use cairo_lang_syntax::node::kind::SyntaxKind::Arg; - -/// Compile-time power function. -/// -/// Takes two arguments, `x, y`, calculates the value of `x` raised to the power of `y`. -/// -/// ``` -/// const MEGABYTE: u64 = pow!(2, 20); -/// assert_eq!(MEGABYTE, 1048576); -/// ``` -#[inline_macro] -pub fn pow(token_stream: TokenStream) -> ProcMacroResult { - let db = SimpleParserDatabase::default(); - let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); - - let macro_args: Vec = parsed - .descendants(&db) - .filter_map(|node| { - if let Arg = node.kind(&db) { - Some(node.get_text(&db)) - } else { - None - } - }) - .collect(); - - if macro_args.len() != 2 { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid number of arguments").into()); - } - - let base: BigDecimal = match macro_args[0].parse() { - Ok(val) => val, - Err(_) => { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid base value").into()); - } - }; - - let exp: usize = match macro_args[1].parse() { - Ok(val) => val, - Err(_) => { - return ProcMacroResult::new(TokenStream::empty()) - .with_diagnostics(Diagnostic::error("Invalid exponent value").into()); - } - }; - - let result: BigDecimal = pow(base, exp); - - ProcMacroResult::new(TokenStream::new(result.to_string())) -} +mod num_traits; +mod pow; diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs new file mode 100644 index 00000000..59719365 --- /dev/null +++ b/packages/macros/src/num_traits.rs @@ -0,0 +1,168 @@ +use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; +use cairo_lang_parser::utils::SimpleParserDatabase; +use cairo_lang_syntax::node::kind::SyntaxKind::{ + Member, OptionWrappedGenericParamListEmpty, TerminalStruct, TokenIdentifier, + WrappedGenericParamList, +}; + +struct StructInfo { + name: String, + generic_params: Option>, + members: Vec, +} + +struct OpInfo { + trait_name: String, + fn_name: String, + operator: String, +} + +fn parse_tokenstream_struct(token_stream: TokenStream) -> StructInfo { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + let mut nodes = parsed.descendants(&db); + + // find struct name - the next TokenIdentifier after TeminalStruct + let mut struct_name = String::new(); + while let Some(node) = nodes.next() { + if node.kind(&db) == TerminalStruct { + struct_name = nodes + .find(|node| node.kind(&db) == TokenIdentifier) + .unwrap() + .get_text(&db); + break; + } + } + + // collect generic params or skip if there aren't any + let mut generic_params: Option> = None; + while let Some(node) = nodes.next() { + match node.kind(&db) { + WrappedGenericParamList => { + let params = node + .descendants(&db) + .filter(|node| node.kind(&db) == TokenIdentifier) + .map(|node| node.get_text(&db)) + .collect(); + generic_params = Some(params); + break; + } + OptionWrappedGenericParamListEmpty => { + break; + } + _ => {} + } + } + + // collect struct members - all TokenIdentifier nodes after each Member + let mut members = Vec::new(); + while let Some(node) = nodes.next() { + if node.kind(&db) == Member { + let member = node + .descendants(&db) + .find(|node| node.kind(&db) == TokenIdentifier) + .map(|node| node.get_text(&db)) + .unwrap(); + members.push(member); + } + } + + StructInfo { + name: struct_name, + generic_params, + members, + } +} + +fn generate_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { + let generic_params = s + .generic_params + .as_ref() + .map_or(String::new(), |params| format!("<{}>", params.join(", "))); + + let trait_bounds = s.generic_params.as_ref().map_or_else( + || String::new(), + |params| { + let bounds = params + .iter() + .flat_map(|param| { + vec![ + format!("+core::traits::{}<{}>", op_info.trait_name, param), + format!("+core::traits::Drop<{}>", param), + ] + }) + .collect::>() + .join(",\n"); + format!("<{},\n{}>", params.join(", "), bounds) + }, + ); + + let members_op = s + .members + .iter() + .map(|member| format!("{0}: lhs.{0} {1} rhs.{0}", member, op_info.operator)) + .collect::>() + .join(", "); + + format!( + "\n +impl {0}{1}{2} +of core::traits::{1}<{0}{3}> {{ + fn {4}(lhs: {0}{3}, rhs: {0}{3}) -> {0}{3} {{ + {0} {{ {5} }} + }} +}}\n", + s.name, op_info.trait_name, trait_bounds, generic_params, op_info.fn_name, members_op + ) +} + +// TODO: add macro docs so that they show in VSCode + +#[derive_macro] +pub fn add(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Add".to_string(), + fn_name: "add".to_string(), + operator: "+".to_string(), + }; + + let s = parse_tokenstream_struct(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) +} + +#[derive_macro] +pub fn sub(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Sub".to_string(), + fn_name: "sub".to_string(), + operator: "-".to_string(), + }; + let s = parse_tokenstream_struct(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) +} + +#[derive_macro] +pub fn mul(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Mul".to_string(), + fn_name: "mul".to_string(), + operator: "*".to_string(), + }; + let s = parse_tokenstream_struct(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) +} + +#[derive_macro] +pub fn div(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Div".to_string(), + fn_name: "div".to_string(), + operator: "/".to_string(), + }; + let s = parse_tokenstream_struct(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) +} diff --git a/packages/macros/src/pow.rs b/packages/macros/src/pow.rs new file mode 100644 index 00000000..5ad557c5 --- /dev/null +++ b/packages/macros/src/pow.rs @@ -0,0 +1,54 @@ +use bigdecimal::{num_traits::pow, BigDecimal}; +use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream}; +use cairo_lang_parser::utils::SimpleParserDatabase; +use cairo_lang_syntax::node::kind::SyntaxKind::Arg; + +/// Compile-time power function. +/// +/// Takes two arguments, `x, y`, calculates the value of `x` raised to the power of `y`. +/// +/// ``` +/// const MEGABYTE: u64 = pow!(2, 20); +/// assert_eq!(MEGABYTE, 1048576); +/// ``` +#[inline_macro] +pub fn pow(token_stream: TokenStream) -> ProcMacroResult { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + + let macro_args: Vec = parsed + .descendants(&db) + .filter_map(|node| { + if let Arg = node.kind(&db) { + Some(node.get_text(&db)) + } else { + None + } + }) + .collect(); + + if macro_args.len() != 2 { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid number of arguments").into()); + } + + let base: BigDecimal = match macro_args[0].parse() { + Ok(val) => val, + Err(_) => { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid base value").into()); + } + }; + + let exp: usize = match macro_args[1].parse() { + Ok(val) => val, + Err(_) => { + return ProcMacroResult::new(TokenStream::empty()) + .with_diagnostics(Diagnostic::error("Invalid exponent value").into()); + } + }; + + let result: BigDecimal = pow(base, exp); + + ProcMacroResult::new(TokenStream::new(result.to_string())) +} diff --git a/packages/macros_tests/src/lib.cairo b/packages/macros_tests/src/lib.cairo index 6023f41d..7f3e3029 100644 --- a/packages/macros_tests/src/lib.cairo +++ b/packages/macros_tests/src/lib.cairo @@ -1,15 +1,5 @@ -const TWO_TEN: u128 = pow!(2, 10); +#[cfg(test)] +mod test_pow; #[cfg(test)] -mod tests { - #[test] - fn test_pow_macro() { - assert_eq!(super::TWO_TEN, 1024); - assert_eq!(pow!(10, 2), 100); - assert_eq!(pow!(20, 30), 1073741824000000000000000000000000000000_felt252); - assert_eq!( - pow!(2, 255), - 57896044618658097711785492504343953926634992332820282019728792003956564819968_u256 - ); - } -} +mod test_num_traits; diff --git a/packages/macros_tests/src/test_num_traits.cairo b/packages/macros_tests/src/test_num_traits.cairo new file mode 100644 index 00000000..13acecea --- /dev/null +++ b/packages/macros_tests/src/test_num_traits.cairo @@ -0,0 +1,95 @@ +// a basic struct +#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +struct B { + pub a: u8, + b: u16 +} + +// a generic struct +#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +struct G { + x: T1, + pub y: T2, + z: T2 +} + +// a complex struct +#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +struct C { + pub g: G, + i: i64, + j: u32 +} + + +#[test] +fn test_add_derive() { + let b1 = B { a: 1, b: 2 }; + let b2 = B { a: 3, b: 4 }; + let b3 = b1 + b2; + assert_eq!(b3, B { a: 4, b: 6 }); + + let g1: G = G { x: 1, y: 2, z: 3 }; + let g2: G = G { x: 3, y: 4, z: 6 }; + let g3 = g1 + g2; + assert_eq!(g3, G { x: 4, y: 6, z: 9 }); + + let c1 = C { g: G { x: 1, y: 2, z: 3 }, i: 4, j: 5 }; + let c2 = C { g: G { x: 3, y: 4, z: 6 }, i: 8, j: 10 }; + let c3 = c1 + c2; + assert_eq!(c3, C { g: G { x: 4, y: 6, z: 9 }, i: 12, j: 15 }); +} + +#[test] +fn test_sub_derive() { + let b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + let b3 = b1 - b2; + assert_eq!(b3, B { a: 2, b: 0 }); + + let g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + let g3 = g1 - g2; + assert_eq!(g3, G { x: 2, y: 4, z: 0 }); + + let c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 16 }, i: 16, j: 60 }; + let c3 = c1 - c2; + assert_eq!(c3, C { g: G { x: 2, y: 4, z: 0 }, i: 16, j: 4 }); +} + +#[test] +fn test_mul_derive() { + let b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + let b3 = b1 * b2; + assert_eq!(b3, B { a: 8, b: 64 }); + + let g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + let g3 = g1 * g2; + assert_eq!(g3, G { x: 8, y: 32, z: 256 }); + + let c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 16 }, i: 16, j: 60 }; + let c3 = c1 * c2; + assert_eq!(c3, C { g: G { x: 8, y: 32, z: 256 }, i: 512, j: 3840 }); +} + +#[test] +fn test_div_derive() { + let b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + let b3 = b1 / b2; + assert_eq!(b3, B { a: 2, b: 1 }); + + let g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + let g3 = g1 / g2; + assert_eq!(g3, G { x: 2, y: 2, z: 1 }); + + let c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 1 }, i: 16, j: 32 }; + let c3 = c1 / c2; + assert_eq!(c3, C { g: G { x: 2, y: 2, z: 16 }, i: 2, j: 2 }); +} diff --git a/packages/macros_tests/src/test_pow.cairo b/packages/macros_tests/src/test_pow.cairo new file mode 100644 index 00000000..1ea1b6fe --- /dev/null +++ b/packages/macros_tests/src/test_pow.cairo @@ -0,0 +1,12 @@ +const TWO_TEN: u128 = pow!(2, 10); + +#[test] +fn test_pow_macro() { + assert_eq!(TWO_TEN, 1024); + assert_eq!(pow!(10, 2), 100); + assert_eq!(pow!(20, 30), 1073741824000000000000000000000000000000_felt252); + assert_eq!( + pow!(2, 255), + 57896044618658097711785492504343953926634992332820282019728792003956564819968_u256 + ); +} From b3d9b7c237ea323900fb24cb2e6ac10ec0ab0285 Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 17:05:29 +0200 Subject: [PATCH 2/7] feat: derive AddAssign, SubAssign, MulAssign, DivAssign --- packages/macros/src/num_traits.rs | 110 ++++++++++++++++-- .../macros_tests/src/test_num_traits.cairo | 82 ++++++++++++- 2 files changed, 177 insertions(+), 15 deletions(-) diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index 59719365..de27f653 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -17,7 +17,7 @@ struct OpInfo { operator: String, } -fn parse_tokenstream_struct(token_stream: TokenStream) -> StructInfo { +fn parse_struct_info(token_stream: TokenStream) -> StructInfo { let db = SimpleParserDatabase::default(); let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); let mut nodes = parsed.descendants(&db); @@ -74,7 +74,7 @@ fn parse_tokenstream_struct(token_stream: TokenStream) -> StructInfo { } } -fn generate_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { +fn generate_op_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { let generic_params = s .generic_params .as_ref() @@ -116,6 +116,48 @@ of core::traits::{1}<{0}{3}> {{ ) } +fn generate_op_assign_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { + let generic_params = s + .generic_params + .as_ref() + .map_or(String::new(), |params| format!("<{}>", params.join(", "))); + + let trait_bounds = s.generic_params.as_ref().map_or_else( + || String::new(), + |params| { + let bounds = params + .iter() + .flat_map(|param| { + vec![ + format!("+core::ops::{0}Assign<{1}, {1}>", op_info.trait_name, param), + format!("+core::traits::Drop<{}>", param), + ] + }) + .collect::>() + .join(",\n"); + format!("<{},\n{}>", params.join(", "), bounds) + }, + ); + + let members_op = s + .members + .iter() + .map(|member| format!("self.{0} {1}= rhs.{0}", member, op_info.operator)) + .collect::>() + .join(";\n "); + + format!( + "\n +impl {0}{1}Assign{2} +of core::ops::{1}Assign<{0}{3}, {0}{3}> {{ + fn {4}_assign(ref self: {0}{3}, rhs: {0}{3}) {{ + {5}; + }} +}}\n", + s.name, op_info.trait_name, trait_bounds, generic_params, op_info.fn_name, members_op + ) +} + // TODO: add macro docs so that they show in VSCode #[derive_macro] @@ -126,9 +168,9 @@ pub fn add(token_stream: TokenStream) -> ProcMacroResult { operator: "+".to_string(), }; - let s = parse_tokenstream_struct(token_stream); + let s = parse_struct_info(token_stream); - ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) + ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } #[derive_macro] @@ -138,9 +180,9 @@ pub fn sub(token_stream: TokenStream) -> ProcMacroResult { fn_name: "sub".to_string(), operator: "-".to_string(), }; - let s = parse_tokenstream_struct(token_stream); + let s = parse_struct_info(token_stream); - ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) + ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } #[derive_macro] @@ -150,9 +192,9 @@ pub fn mul(token_stream: TokenStream) -> ProcMacroResult { fn_name: "mul".to_string(), operator: "*".to_string(), }; - let s = parse_tokenstream_struct(token_stream); + let s = parse_struct_info(token_stream); - ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) + ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } #[derive_macro] @@ -162,7 +204,55 @@ pub fn div(token_stream: TokenStream) -> ProcMacroResult { fn_name: "div".to_string(), operator: "/".to_string(), }; - let s = parse_tokenstream_struct(token_stream); + let s = parse_struct_info(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) +} + +#[derive_macro] +fn add_assign(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Add".to_string(), + fn_name: "add".to_string(), + operator: "+".to_string(), + }; + let s = parse_struct_info(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) +} + +#[derive_macro] +fn sub_assign(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Sub".to_string(), + fn_name: "sub".to_string(), + operator: "-".to_string(), + }; + let s = parse_struct_info(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) +} + +#[derive_macro] +fn mul_assign(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Mul".to_string(), + fn_name: "mul".to_string(), + operator: "*".to_string(), + }; + let s = parse_struct_info(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) +} + +#[derive_macro] +fn div_assign(token_stream: TokenStream) -> ProcMacroResult { + let op = OpInfo { + trait_name: "Div".to_string(), + fn_name: "div".to_string(), + operator: "/".to_string(), + }; + let s = parse_struct_info(token_stream); - ProcMacroResult::new(TokenStream::new(generate_trait_impl(&op, &s))) + ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } diff --git a/packages/macros_tests/src/test_num_traits.cairo b/packages/macros_tests/src/test_num_traits.cairo index 13acecea..6e9492dd 100644 --- a/packages/macros_tests/src/test_num_traits.cairo +++ b/packages/macros_tests/src/test_num_traits.cairo @@ -1,27 +1,27 @@ // a basic struct -#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +#[derive(Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Debug, Drop, PartialEq)] struct B { pub a: u8, b: u16 } // a generic struct -#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +#[derive(Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Debug, Drop, PartialEq)] struct G { x: T1, pub y: T2, z: T2 } + // a complex struct -#[derive(Add, Sub, Mul, Div, Debug, Drop, PartialEq)] +#[derive(Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Debug, Drop, PartialEq)] struct C { pub g: G, - i: i64, + i: u64, j: u32 } - #[test] fn test_add_derive() { let b1 = B { a: 1, b: 2 }; @@ -93,3 +93,75 @@ fn test_div_derive() { let c3 = c1 / c2; assert_eq!(c3, C { g: G { x: 2, y: 2, z: 16 }, i: 2, j: 2 }); } + +#[test] +fn test_addassign_derive() { + let mut b1 = B { a: 1, b: 2 }; + let b2 = B { a: 3, b: 4 }; + b1 += b2; + assert_eq!(b1, B { a: 4, b: 6 }); + + let mut g1: G = G { x: 1, y: 2, z: 3 }; + let g2: G = G { x: 3, y: 4, z: 6 }; + g1 += g2; + assert_eq!(g1, G { x: 4, y: 6, z: 9 }); + + let mut c1 = C { g: G { x: 1, y: 2, z: 3 }, i: 4, j: 5 }; + let c2 = C { g: G { x: 3, y: 4, z: 6 }, i: 8, j: 10 }; + c1 += c2; + assert_eq!(c1, C { g: G { x: 4, y: 6, z: 9 }, i: 12, j: 15 }); +} + +#[test] +fn test_subassign_derive() { + let mut b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + b1 -= b2; + assert_eq!(b1, B { a: 2, b: 0 }); + + let mut g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + g1 -= g2; + assert_eq!(g1, G { x: 2, y: 4, z: 0 }); + + let mut c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 16 }, i: 16, j: 60 }; + c1 -= c2; + assert_eq!(c1, C { g: G { x: 2, y: 4, z: 0 }, i: 16, j: 4 }); +} + +#[test] +fn test_mulassign_derive() { + let mut b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + b1 *= b2; + assert_eq!(b1, B { a: 8, b: 64 }); + + let mut g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + g1 *= g2; + assert_eq!(g1, G { x: 8, y: 32, z: 256 }); + + let mut c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 16 }, i: 16, j: 60 }; + c1 *= c2; + assert_eq!(c1, C { g: G { x: 8, y: 32, z: 256 }, i: 512, j: 3840 }); +} + +#[test] +fn test_divassign_derive() { + let mut b1 = B { a: 4, b: 8 }; + let b2 = B { a: 2, b: 8 }; + b1 /= b2; + assert_eq!(b1, B { a: 2, b: 1 }); + + let mut g1: G = G { x: 4, y: 8, z: 16 }; + let g2: G = G { x: 2, y: 4, z: 16 }; + g1 /= g2; + assert_eq!(g1, G { x: 2, y: 2, z: 1 }); + + let mut c1 = C { g: G { x: 4, y: 8, z: 16 }, i: 32, j: 64 }; + let c2 = C { g: G { x: 2, y: 4, z: 1 }, i: 16, j: 32 }; + c1 /= c2; + assert_eq!(c1, C { g: G { x: 2, y: 2, z: 16 }, i: 2, j: 2 }); +} From 229724ae174f0387289c9b0aa47d71e975ed1f9b Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 17:05:55 +0200 Subject: [PATCH 3/7] docs: num trait derives inline docs --- packages/macros/src/num_traits.rs | 34 +++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index de27f653..5ecbb84d 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -158,8 +158,10 @@ of core::ops::{1}Assign<{0}{3}, {0}{3}> {{ ) } -// TODO: add macro docs so that they show in VSCode - +/// Adds implementation for the `Add` trait. +/// +/// Allows you to use the `+` oprator on a type. All members of +/// the struct must already implement the `Add` trait. #[derive_macro] pub fn add(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -173,6 +175,10 @@ pub fn add(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } +/// Adds implementation for the `Sub` trait. +/// +/// Allows you to use the `-` operator on a type. All members of +/// the struct must already implement the `Sub` trait. #[derive_macro] pub fn sub(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -185,6 +191,10 @@ pub fn sub(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } +/// Adds implementation for the `Mul` trait. +/// +/// Allows you to use the `*` operator on a type. All members of +/// the struct must already implement the `Mul` trait. #[derive_macro] pub fn mul(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -197,6 +207,10 @@ pub fn mul(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } +/// Adds implementation for the `Div` trait. +/// +/// Allows you to use the `/` operator on a type. All members of +/// the struct must already implement the `Div` trait. #[derive_macro] pub fn div(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -209,6 +223,10 @@ pub fn div(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } +/// Adds implementation for the `AddAssign` trait. +/// +/// Allows you to use the `+=` operator on a type. All members of +/// the struct must already implement the `AddAssign` trait. #[derive_macro] fn add_assign(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -221,6 +239,10 @@ fn add_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } +/// Adds implementation for the `SubAssign` trait. +/// +/// Allows you to use the `-=` operator on a type. All members of +/// the struct must already implement the `SubAssign` trait. #[derive_macro] fn sub_assign(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -233,6 +255,10 @@ fn sub_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } +/// Adds implementation for the `MulAssign` trait. +/// +/// Allows you to use the `*=` operator on a type. All members of +/// the struct must already implement the `MulAssign` trait. #[derive_macro] fn mul_assign(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { @@ -245,6 +271,10 @@ fn mul_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } +/// Adds implementation for the `DivAssign` trait. +/// +/// Allows you to use the `/=` operator on a type. All members of +/// the struct must already implement the `DivAssign` trait. #[derive_macro] fn div_assign(token_stream: TokenStream) -> ProcMacroResult { let op = OpInfo { From c1dc474e24c90f26f556cdf285e8b49f31e06a8a Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 17:46:01 +0200 Subject: [PATCH 4/7] feat: Zero derive --- packages/macros/src/lib.rs | 3 + packages/macros/src/num_traits.rs | 68 +--------------- packages/macros/src/parse.rs | 69 ++++++++++++++++ packages/macros/src/zero_trait.rs | 81 +++++++++++++++++++ packages/macros_tests/src/lib.cairo | 3 + .../macros_tests/src/test_zero_trait.cairo | 56 +++++++++++++ 6 files changed, 213 insertions(+), 67 deletions(-) create mode 100644 packages/macros/src/parse.rs create mode 100644 packages/macros/src/zero_trait.rs create mode 100644 packages/macros_tests/src/test_zero_trait.cairo diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs index 85af4100..950a643c 100644 --- a/packages/macros/src/lib.rs +++ b/packages/macros/src/lib.rs @@ -1,2 +1,5 @@ mod num_traits; +mod zero_trait; mod pow; + +mod parse; diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index 5ecbb84d..a1d670bb 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -1,15 +1,6 @@ use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; -use cairo_lang_parser::utils::SimpleParserDatabase; -use cairo_lang_syntax::node::kind::SyntaxKind::{ - Member, OptionWrappedGenericParamListEmpty, TerminalStruct, TokenIdentifier, - WrappedGenericParamList, -}; -struct StructInfo { - name: String, - generic_params: Option>, - members: Vec, -} +use crate::parse::{StructInfo, parse_struct_info}; struct OpInfo { trait_name: String, @@ -17,63 +8,6 @@ struct OpInfo { operator: String, } -fn parse_struct_info(token_stream: TokenStream) -> StructInfo { - let db = SimpleParserDatabase::default(); - let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); - let mut nodes = parsed.descendants(&db); - - // find struct name - the next TokenIdentifier after TeminalStruct - let mut struct_name = String::new(); - while let Some(node) = nodes.next() { - if node.kind(&db) == TerminalStruct { - struct_name = nodes - .find(|node| node.kind(&db) == TokenIdentifier) - .unwrap() - .get_text(&db); - break; - } - } - - // collect generic params or skip if there aren't any - let mut generic_params: Option> = None; - while let Some(node) = nodes.next() { - match node.kind(&db) { - WrappedGenericParamList => { - let params = node - .descendants(&db) - .filter(|node| node.kind(&db) == TokenIdentifier) - .map(|node| node.get_text(&db)) - .collect(); - generic_params = Some(params); - break; - } - OptionWrappedGenericParamListEmpty => { - break; - } - _ => {} - } - } - - // collect struct members - all TokenIdentifier nodes after each Member - let mut members = Vec::new(); - while let Some(node) = nodes.next() { - if node.kind(&db) == Member { - let member = node - .descendants(&db) - .find(|node| node.kind(&db) == TokenIdentifier) - .map(|node| node.get_text(&db)) - .unwrap(); - members.push(member); - } - } - - StructInfo { - name: struct_name, - generic_params, - members, - } -} - fn generate_op_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { let generic_params = s .generic_params diff --git a/packages/macros/src/parse.rs b/packages/macros/src/parse.rs new file mode 100644 index 00000000..5586fe32 --- /dev/null +++ b/packages/macros/src/parse.rs @@ -0,0 +1,69 @@ +use cairo_lang_macro::TokenStream; +use cairo_lang_parser::utils::SimpleParserDatabase; +use cairo_lang_syntax::node::kind::SyntaxKind::{ + Member, OptionWrappedGenericParamListEmpty, TerminalStruct, TokenIdentifier, + WrappedGenericParamList, +}; + +pub(crate) struct StructInfo { + pub(crate) name: String, + pub(crate) generic_params: Option>, + pub(crate) members: Vec, +} + +pub(crate) fn parse_struct_info(token_stream: TokenStream) -> StructInfo { + let db = SimpleParserDatabase::default(); + let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream); + let mut nodes = parsed.descendants(&db); + + // find struct name - the next TokenIdentifier after TeminalStruct + let mut struct_name = String::new(); + while let Some(node) = nodes.next() { + if node.kind(&db) == TerminalStruct { + struct_name = nodes + .find(|node| node.kind(&db) == TokenIdentifier) + .unwrap() + .get_text(&db); + break; + } + } + + // collect generic params or skip if there aren't any + let mut generic_params: Option> = None; + while let Some(node) = nodes.next() { + match node.kind(&db) { + WrappedGenericParamList => { + let params = node + .descendants(&db) + .filter(|node| node.kind(&db) == TokenIdentifier) + .map(|node| node.get_text(&db)) + .collect(); + generic_params = Some(params); + break; + } + OptionWrappedGenericParamListEmpty => { + break; + } + _ => {} + } + } + + // collect struct members - all TokenIdentifier nodes after each Member + let mut members = Vec::new(); + while let Some(node) = nodes.next() { + if node.kind(&db) == Member { + let member = node + .descendants(&db) + .find(|node| node.kind(&db) == TokenIdentifier) + .map(|node| node.get_text(&db)) + .unwrap(); + members.push(member); + } + } + + StructInfo { + name: struct_name, + generic_params, + members, + } +} diff --git a/packages/macros/src/zero_trait.rs b/packages/macros/src/zero_trait.rs new file mode 100644 index 00000000..3b71d25e --- /dev/null +++ b/packages/macros/src/zero_trait.rs @@ -0,0 +1,81 @@ +use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; +use crate::parse::{parse_struct_info, StructInfo}; + +fn generate_zero_trait_impl(s: &StructInfo) -> String { + let generic_params = s + .generic_params + .as_ref() + .map_or(String::new(), |params| format!("<{}>", params.join(", "))); + + let trait_bounds = s.generic_params.as_ref().map_or_else( + || String::new(), + |params| { + let bounds = params + .iter() + .flat_map(|param| { + vec![ + format!("+core::num::traits::Zero<{}>", param), + format!("+core::traits::Drop<{}>", param), + ] + }) + .collect::>() + .join(",\n"); + format!("<{},\n{}>", params.join(", "), bounds) + }, + ); + + let zero_fn = s + .members + .iter() + .map(|member| format!("{}: core::num::traits::Zero::zero()", member)) + .collect::>() + .join(", "); + + let is_zero_fn = s + .members + .iter() + .map(|member| format!("self.{}.is_zero()", member)) + .collect::>() + .join(" && "); + + format!( + "\n +impl {0}ZeroImpl{1} +of core::num::traits::Zero<{0}{2}> {{ + fn zero() -> {0}{2} {{ + {0} {{ {3} }} + }} + + fn is_zero(self: @{0}{2}) -> bool {{ + {4} + }} + + fn is_non_zero(self: @{0}{2}) -> bool {{ + !self.is_zero() + }} +}}\n", + s.name, trait_bounds, generic_params, zero_fn, is_zero_fn + ) +} + +/// Adds implementation of the `Zero` trait. +/// +/// All members of the struct must already implement the `Zero` trait. +/// +/// ``` +/// #[derive(Zero, PartialEq, Debug)] +/// struct Point { +/// x: u64, +/// y: u64, +/// } +/// +/// assert_eq!(Point { x: 0, y: 0 }, Zero::zero()); +/// assert!(Point { x: 0, y: 0 }.is_zero()); +/// assert!(Point { x: 1, y: 0 }.is_non_zero()); +/// ``` +#[derive_macro] +pub fn zero(token_stream: TokenStream) -> ProcMacroResult { + let s = parse_struct_info(token_stream); + + ProcMacroResult::new(TokenStream::new(generate_zero_trait_impl(&s))) +} diff --git a/packages/macros_tests/src/lib.cairo b/packages/macros_tests/src/lib.cairo index 7f3e3029..c76e302c 100644 --- a/packages/macros_tests/src/lib.cairo +++ b/packages/macros_tests/src/lib.cairo @@ -3,3 +3,6 @@ mod test_pow; #[cfg(test)] mod test_num_traits; + +#[cfg(test)] +mod test_zero_trait; diff --git a/packages/macros_tests/src/test_zero_trait.cairo b/packages/macros_tests/src/test_zero_trait.cairo new file mode 100644 index 00000000..9854bf17 --- /dev/null +++ b/packages/macros_tests/src/test_zero_trait.cairo @@ -0,0 +1,56 @@ +use core::num::traits::Zero; + +// a basic struct +#[derive(Zero, Debug, Drop, PartialEq)] +struct B { + pub a: u8, + b: u16 +} + +// a generic struct +#[derive(Zero, Debug, Drop, PartialEq)] +struct G { + x: T1, + pub y: T2, + z: T2 +} + +// a complex struct +#[derive(Zero, Debug, Drop, PartialEq)] +struct C { + pub g: G, + i: u64, + j: u32 +} + + + +#[test] +fn test_zero_derive() { + let b0: B = B { a: 0, b: 0 }; + let b1: B = B { a: 1, b: 2 }; + + assert_eq!(b0, Zero::zero()); + assert!(b0.is_zero()); + assert!(b0.is_non_zero() == false); + assert!(b1.is_zero() == false); + assert!(b1.is_non_zero()); + + let g0: G = G { x: 0, y: 0, z: 0 }; + let g1: G = G { x: 1, y: 2, z: 3 }; + + assert_eq!(g0, Zero::zero()); + assert!(g0.is_zero()); + assert!(g0.is_non_zero() == false); + assert!(g1.is_zero() == false); + assert!(g1.is_non_zero()); + + let c0: C = C { g: G { x: 0, y: 0, z: 0 }, i: 0, j: 0 }; + let c1: C = C { g: G { x: 0, y: 0, z: 0 }, i: 4, j: 5 }; + + assert_eq!(c0, Zero::zero()); + assert!(c0.is_zero()); + assert!(c0.is_non_zero() == false); + assert!(c1.is_zero() == false); + assert!(c1.is_non_zero()); +} From 312f4812b990b6b8753cb90a1b0f47657c05f200 Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 18:11:09 +0200 Subject: [PATCH 5/7] doc: new macros --- packages/macros/README.md | 62 ++++++++++++++++++++++++++++++- packages/macros/src/num_traits.rs | 16 ++++---- packages/macros/src/zero_trait.rs | 2 +- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/packages/macros/README.md b/packages/macros/README.md index 1a8aefbe..d310fafc 100644 --- a/packages/macros/README.md +++ b/packages/macros/README.md @@ -2,12 +2,70 @@ A collection of useful macros. -- [`pow!`](#pow) +- [Add, Sub, Mul, Div derives](#add-sub-mul-div-derives) +- [AddAssign, SubAssign, MulAssign, DivAssign derives](#addassign-subassign-mulassign-divassign-derives) +- [pow!](#pow) +- [Zero derive](#zero-derive) -## `pow!` +## Add, Sub, Mul, Div derives + +These macros add the ability to use addition `+`, subtraction `-`, multiplication `*` and division `/` operators on the type that derives them. All individual members of the struct must already support a particular operation for a derive to work. + +```rust +#[derive(Add, Sub, Mul, Div)] +struct Point { + x: u32, + y: u32 +} + +let a = Point { x: 6, y: 32 }; +let b = Point { x: 2, y: 2 }; +let c = a + b; // Point { x: 8, y: 34 } +let d = a - b; // Point { x: 4, y: 30 } +let e = a * b; // Point { x: 12, y: 64 } +let f = a / b; // Point { x: 3, y: 16 } +``` + +## AddAssign, SubAssign, MulAssign, DivAssign derives + +These macros add the ability to use add and assign `+=`, subtract and assign `-=`, multiply and assign `*=` and divide and assign `/=` operators on the type that derives them. All individual members of the struct must already support the particular operation for a derive to work. + +```rust +#[derive(AddAssign, SubAssign, MulAssign, DivAssign)] +struct Point { + x: u32, + y: u32 +} + +let mut a = Point { x: 6, y: 32 }; +let b = Point { x: 2, y: 2 }; +a += b; // Point { x: 8, y: 34 } +a -= b; // Point { x: 6, y: 32 } +a *= b; // Point { x: 12, y: 64 } +a /= b; // Point { x: 6, y: 32 }; +``` + +## pow! Power function. Takes two arguments, `x, y`, calculates the value of `x` raised to the power of `y`. ```cairo const MEGABYTE: u64 = pow!(2, 20); // will be set to 1048576 ``` + +## Zero derive + +Adds implementation of the `core::num::traits::Zero` trait. + +All members of the struct must already implement the `Zero` trait. + +```rust +#[derive(Zero, PartialEq, Debug)] +struct Point { + x: u64, + y: u64, +} +assert_eq!(Point { x: 0, y: 0 }, Zero::zero()); +assert!(Point { x: 0, y: 0 }.is_zero()); +assert!(Point { x: 1, y: 0 }.is_non_zero()); +``` diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index a1d670bb..dc455ace 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -92,7 +92,7 @@ of core::ops::{1}Assign<{0}{3}, {0}{3}> {{ ) } -/// Adds implementation for the `Add` trait. +/// Adds implementation for the `core::traits::Add` trait. /// /// Allows you to use the `+` oprator on a type. All members of /// the struct must already implement the `Add` trait. @@ -109,7 +109,7 @@ pub fn add(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } -/// Adds implementation for the `Sub` trait. +/// Adds implementation for the `core::traits::Sub` trait. /// /// Allows you to use the `-` operator on a type. All members of /// the struct must already implement the `Sub` trait. @@ -125,7 +125,7 @@ pub fn sub(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } -/// Adds implementation for the `Mul` trait. +/// Adds implementation for the `core::traits::Mul` trait. /// /// Allows you to use the `*` operator on a type. All members of /// the struct must already implement the `Mul` trait. @@ -141,7 +141,7 @@ pub fn mul(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } -/// Adds implementation for the `Div` trait. +/// Adds implementation for the `core::traits::Div` trait. /// /// Allows you to use the `/` operator on a type. All members of /// the struct must already implement the `Div` trait. @@ -157,7 +157,7 @@ pub fn div(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_trait_impl(&op, &s))) } -/// Adds implementation for the `AddAssign` trait. +/// Adds implementation for the `core::ops::AddAssign` trait. /// /// Allows you to use the `+=` operator on a type. All members of /// the struct must already implement the `AddAssign` trait. @@ -173,7 +173,7 @@ fn add_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } -/// Adds implementation for the `SubAssign` trait. +/// Adds implementation for the `core::ops::SubAssign` trait. /// /// Allows you to use the `-=` operator on a type. All members of /// the struct must already implement the `SubAssign` trait. @@ -189,7 +189,7 @@ fn sub_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } -/// Adds implementation for the `MulAssign` trait. +/// Adds implementation for the `core::ops::MulAssign` trait. /// /// Allows you to use the `*=` operator on a type. All members of /// the struct must already implement the `MulAssign` trait. @@ -205,7 +205,7 @@ fn mul_assign(token_stream: TokenStream) -> ProcMacroResult { ProcMacroResult::new(TokenStream::new(generate_op_assign_trait_impl(&op, &s))) } -/// Adds implementation for the `DivAssign` trait. +/// Adds implementation for the `core::ops::DivAssign` trait. /// /// Allows you to use the `/=` operator on a type. All members of /// the struct must already implement the `DivAssign` trait. diff --git a/packages/macros/src/zero_trait.rs b/packages/macros/src/zero_trait.rs index 3b71d25e..8b46db3a 100644 --- a/packages/macros/src/zero_trait.rs +++ b/packages/macros/src/zero_trait.rs @@ -58,7 +58,7 @@ of core::num::traits::Zero<{0}{2}> {{ ) } -/// Adds implementation of the `Zero` trait. +/// Adds implementation of the `core::num::traits::Zero` trait. /// /// All members of the struct must already implement the `Zero` trait. /// From 3e76b4f6da564fc6137d7da6e3f97a74761ee884 Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 21:02:26 +0200 Subject: [PATCH 6/7] fix: lint --- packages/macros/src/lib.rs | 2 +- packages/macros/src/num_traits.rs | 2 +- packages/macros/src/zero_trait.rs | 2 +- packages/macros_tests/src/test_zero_trait.cairo | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs index 950a643c..cbea9c56 100644 --- a/packages/macros/src/lib.rs +++ b/packages/macros/src/lib.rs @@ -1,5 +1,5 @@ mod num_traits; -mod zero_trait; mod pow; +mod zero_trait; mod parse; diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index dc455ace..d0fd4f0d 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -1,6 +1,6 @@ use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; -use crate::parse::{StructInfo, parse_struct_info}; +use crate::parse::{parse_struct_info, StructInfo}; struct OpInfo { trait_name: String, diff --git a/packages/macros/src/zero_trait.rs b/packages/macros/src/zero_trait.rs index 8b46db3a..c86b8a8e 100644 --- a/packages/macros/src/zero_trait.rs +++ b/packages/macros/src/zero_trait.rs @@ -1,5 +1,5 @@ -use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; use crate::parse::{parse_struct_info, StructInfo}; +use cairo_lang_macro::{derive_macro, ProcMacroResult, TokenStream}; fn generate_zero_trait_impl(s: &StructInfo) -> String { let generic_params = s diff --git a/packages/macros_tests/src/test_zero_trait.cairo b/packages/macros_tests/src/test_zero_trait.cairo index 9854bf17..a2b7b087 100644 --- a/packages/macros_tests/src/test_zero_trait.cairo +++ b/packages/macros_tests/src/test_zero_trait.cairo @@ -24,7 +24,6 @@ struct C { } - #[test] fn test_zero_derive() { let b0: B = B { a: 0, b: 0 }; From 006783d9f1a32e0609c89538c4fddef978225010 Mon Sep 17 00:00:00 2001 From: Milan Cermak Date: Fri, 23 Aug 2024 21:10:21 +0200 Subject: [PATCH 7/7] dev: satisfying clippy --- packages/macros/src/num_traits.rs | 20 ++++++++++---------- packages/macros/src/parse.rs | 6 +++--- packages/macros/src/zero_trait.rs | 10 +++++----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/macros/src/num_traits.rs b/packages/macros/src/num_traits.rs index d0fd4f0d..48be4578 100644 --- a/packages/macros/src/num_traits.rs +++ b/packages/macros/src/num_traits.rs @@ -14,9 +14,10 @@ fn generate_op_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { .as_ref() .map_or(String::new(), |params| format!("<{}>", params.join(", "))); - let trait_bounds = s.generic_params.as_ref().map_or_else( - || String::new(), - |params| { + let trait_bounds = s + .generic_params + .as_ref() + .map_or_else(String::new, |params| { let bounds = params .iter() .flat_map(|param| { @@ -28,8 +29,7 @@ fn generate_op_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { .collect::>() .join(",\n"); format!("<{},\n{}>", params.join(", "), bounds) - }, - ); + }); let members_op = s .members @@ -56,9 +56,10 @@ fn generate_op_assign_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { .as_ref() .map_or(String::new(), |params| format!("<{}>", params.join(", "))); - let trait_bounds = s.generic_params.as_ref().map_or_else( - || String::new(), - |params| { + let trait_bounds = s + .generic_params + .as_ref() + .map_or_else(String::new, |params| { let bounds = params .iter() .flat_map(|param| { @@ -70,8 +71,7 @@ fn generate_op_assign_trait_impl(op_info: &OpInfo, s: &StructInfo) -> String { .collect::>() .join(",\n"); format!("<{},\n{}>", params.join(", "), bounds) - }, - ); + }); let members_op = s .members diff --git a/packages/macros/src/parse.rs b/packages/macros/src/parse.rs index 5586fe32..57ac0d42 100644 --- a/packages/macros/src/parse.rs +++ b/packages/macros/src/parse.rs @@ -18,7 +18,7 @@ pub(crate) fn parse_struct_info(token_stream: TokenStream) -> StructInfo { // find struct name - the next TokenIdentifier after TeminalStruct let mut struct_name = String::new(); - while let Some(node) = nodes.next() { + for node in nodes.by_ref() { if node.kind(&db) == TerminalStruct { struct_name = nodes .find(|node| node.kind(&db) == TokenIdentifier) @@ -30,7 +30,7 @@ pub(crate) fn parse_struct_info(token_stream: TokenStream) -> StructInfo { // collect generic params or skip if there aren't any let mut generic_params: Option> = None; - while let Some(node) = nodes.next() { + for node in nodes.by_ref() { match node.kind(&db) { WrappedGenericParamList => { let params = node @@ -50,7 +50,7 @@ pub(crate) fn parse_struct_info(token_stream: TokenStream) -> StructInfo { // collect struct members - all TokenIdentifier nodes after each Member let mut members = Vec::new(); - while let Some(node) = nodes.next() { + for node in nodes { if node.kind(&db) == Member { let member = node .descendants(&db) diff --git a/packages/macros/src/zero_trait.rs b/packages/macros/src/zero_trait.rs index c86b8a8e..8a66312c 100644 --- a/packages/macros/src/zero_trait.rs +++ b/packages/macros/src/zero_trait.rs @@ -7,9 +7,10 @@ fn generate_zero_trait_impl(s: &StructInfo) -> String { .as_ref() .map_or(String::new(), |params| format!("<{}>", params.join(", "))); - let trait_bounds = s.generic_params.as_ref().map_or_else( - || String::new(), - |params| { + let trait_bounds = s + .generic_params + .as_ref() + .map_or_else(String::new, |params| { let bounds = params .iter() .flat_map(|param| { @@ -21,8 +22,7 @@ fn generate_zero_trait_impl(s: &StructInfo) -> String { .collect::>() .join(",\n"); format!("<{},\n{}>", params.join(", "), bounds) - }, - ); + }); let zero_fn = s .members