Skip to content

Commit a4da316

Browse files
committed
spaned errors
1 parent 4805529 commit a4da316

File tree

2 files changed

+96
-43
lines changed

2 files changed

+96
-43
lines changed

crates/felt-macro/src/lib.rs

Lines changed: 92 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro::TokenStream;
22
use quote::quote;
33
use std::ops::Neg;
4-
use syn::{Expr, ExprLit, ExprUnary, Lit, parse_macro_input};
4+
use syn::{Error, Expr, ExprLit, ExprUnary, Lit, Result, parse_macro_input};
55

66
use lambdaworks_math::{
77
field::{
@@ -23,16 +23,17 @@ pub fn felt(input: TokenStream) -> TokenStream {
2323
let expr = parse_macro_input!(input as Expr);
2424

2525
match handle_expr(&expr) {
26-
HandleExprOutput::ComptimeFelt(field_element) => {
26+
Ok(HandleExprOutput::ComptimeFelt(field_element)) => {
2727
generate_const_felt_token_stream_from_lambda_field_element(field_element).into()
2828
}
29-
HandleExprOutput::Runtime => quote! {
29+
Ok(HandleExprOutput::Runtime) => quote! {
3030
match Felt::try_from(#expr) {
3131
Ok(f) => f,
32-
Err(_) => panic!("Invalid Felt value"),
32+
Err(e) => panic!("Invalid Felt value: {}", e),
3333
}
3434
}
3535
.into(),
36+
Err(error) => error.to_compile_error().into(),
3637
}
3738
}
3839

@@ -54,19 +55,27 @@ fn generate_const_felt_token_stream_from_lambda_field_element(
5455
}
5556
}
5657

57-
fn handle_expr(expr: &syn::Expr) -> HandleExprOutput {
58+
fn handle_expr(expr: &syn::Expr) -> Result<HandleExprOutput> {
5859
match expr {
5960
Expr::Lit(expr_lit) => match &expr_lit.lit {
60-
Lit::Bool(lit_bool) => HandleExprOutput::ComptimeFelt(match lit_bool.value() {
61-
false => LambdaFieldElement::from_hex_unchecked("0x0"),
62-
true => LambdaFieldElement::from_hex_unchecked("0x1"),
63-
}),
61+
Lit::Bool(lit_bool) => Ok(HandleExprOutput::ComptimeFelt(match lit_bool.value() {
62+
false => LambdaFieldElement::from(&UnsignedInteger::from_u64(0)),
63+
true => LambdaFieldElement::from(&UnsignedInteger::from_u64(1)),
64+
})),
6465

6566
Lit::Int(lit_int) => {
66-
let value = lit_int.base10_parse::<u128>().unwrap();
67+
let value = match lit_int.base10_parse::<u128>() {
68+
Ok(v) => v,
69+
Err(_) => {
70+
return Err(Error::new_spanned(
71+
lit_int,
72+
"Invalid integer literal for Felt conversion",
73+
));
74+
}
75+
};
6776

68-
HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(&UnsignedInteger::from(
69-
value,
77+
Ok(HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(
78+
&UnsignedInteger::from(value),
7079
)))
7180
}
7281

@@ -83,64 +92,103 @@ fn handle_expr(expr: &syn::Expr) -> HandleExprOutput {
8392
UnsignedInteger::from_hex(value).map(|x| LambdaFieldElement::from(&x))
8493
} else {
8594
UnsignedInteger::from_dec_str(value).map(|x| LambdaFieldElement::from(&x))
86-
}
87-
.unwrap();
95+
};
96+
97+
let lfe = match lfe {
98+
Ok(v) => v,
99+
Err(_) => {
100+
return Err(Error::new_spanned(
101+
lit_str,
102+
"Invalid string literal for Felt conversion",
103+
));
104+
}
105+
};
88106

89-
HandleExprOutput::ComptimeFelt(if is_neg { lfe.neg() } else { lfe })
107+
Ok(HandleExprOutput::ComptimeFelt(if is_neg {
108+
lfe.neg()
109+
} else {
110+
lfe
111+
}))
90112
}
91113

92114
Lit::ByteStr(lit_byte_str) => {
93115
let bytes = lit_byte_str.value();
94116

95-
assert!(
96-
bytes.len() <= 31,
97-
"Short string must be at most 31 characters"
98-
);
99-
assert!(
100-
bytes.is_ascii(),
101-
"Short string must contain only ASCII characters"
102-
);
117+
if bytes.len() > 31 {
118+
return Err(Error::new_spanned(
119+
lit_byte_str,
120+
"Short string must be at most 31 characters",
121+
));
122+
}
123+
124+
if !bytes.is_ascii() {
125+
return Err(Error::new_spanned(
126+
lit_byte_str,
127+
"Short string must contain only ASCII characters",
128+
));
129+
}
103130

104131
let mut buffer = [0u8; 32];
105132
buffer[(32 - bytes.len())..].copy_from_slice(&bytes);
106133

107-
HandleExprOutput::ComptimeFelt(LambdaFieldElement::from_bytes_be(&buffer).unwrap())
134+
match LambdaFieldElement::from_bytes_be(&buffer) {
135+
Ok(field_element) => Ok(HandleExprOutput::ComptimeFelt(field_element)),
136+
Err(_) => Err(Error::new_spanned(
137+
lit_byte_str,
138+
"Failed to convert byte string to Felt",
139+
)),
140+
}
108141
}
142+
109143
Lit::Char(lit_char) => {
110144
let char = lit_char.value();
111145

112-
assert!(char.is_ascii(), "Only ASCII characters are handled");
146+
if !char.is_ascii() {
147+
return Err(Error::new_spanned(
148+
lit_char,
149+
"Only ASCII characters are supported",
150+
));
151+
}
113152

114153
let mut buffer = [0u8];
115154
char.encode_utf8(&mut buffer);
116155

117-
HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(&UnsignedInteger::from(
118-
u16::from(buffer[0]),
156+
Ok(HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(
157+
&UnsignedInteger::from(u16::from(buffer[0])),
119158
)))
120159
}
160+
121161
Lit::Byte(lit_byte) => {
122162
let char = lit_byte.value();
123163

124-
HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(&UnsignedInteger::from(
125-
u16::from(char),
164+
Ok(HandleExprOutput::ComptimeFelt(LambdaFieldElement::from(
165+
&UnsignedInteger::from(u16::from(char)),
126166
)))
127167
}
128-
Lit::CStr(_) | Lit::Float(_) | Lit::Verbatim(_) => panic!("Literal type not handled"),
168+
169+
Lit::CStr(_) | Lit::Float(_) | Lit::Verbatim(_) => {
170+
Err(Error::new_spanned(expr_lit, "Unsupported literal type"))
171+
}
172+
129173
// `Lit` is a non-exhaustive enum
130-
_ => panic!("Unkown literal type. Not handled"),
174+
_ => Err(Error::new_spanned(expr_lit, "Unknown literal type")),
131175
},
132176

133177
// Negative (`-`) prefixed values
178+
// Can be used before any other expression
134179
Expr::Unary(ExprUnary {
135180
attrs: _attrs,
136181
op: syn::UnOp::Neg(_),
137182
expr,
138-
}) => match handle_expr(expr) {
183+
}) => match handle_expr(expr)? {
139184
HandleExprOutput::ComptimeFelt(field_element) => {
140-
HandleExprOutput::ComptimeFelt(field_element.neg())
185+
Ok(HandleExprOutput::ComptimeFelt(field_element.neg()))
141186
}
142-
HandleExprOutput::Runtime => HandleExprOutput::Runtime,
187+
HandleExprOutput::Runtime => Ok(HandleExprOutput::Runtime),
143188
},
189+
190+
// Oposite (`!`) prefixed values
191+
// Can only be used before literal bool expression and any runtime expression where it is semanticaly valid
144192
Expr::Unary(ExprUnary {
145193
attrs: _attrs,
146194
op: syn::UnOp::Not(_),
@@ -149,16 +197,17 @@ fn handle_expr(expr: &syn::Expr) -> HandleExprOutput {
149197
Expr::Lit(ExprLit {
150198
lit: Lit::Bool(lit_bool),
151199
..
152-
}) => HandleExprOutput::ComptimeFelt(match lit_bool.value() {
153-
false => LambdaFieldElement::from_hex_unchecked("0x1"),
154-
true => LambdaFieldElement::from_hex_unchecked("0x0"),
155-
}),
156-
Expr::Lit(_) => panic!(
157-
"The `!` logical inversion operatior in only allowed before booleans in literal expressions."
158-
),
159-
_ => HandleExprOutput::Runtime,
200+
}) => Ok(HandleExprOutput::ComptimeFelt(match lit_bool.value() {
201+
false => LambdaFieldElement::from(&UnsignedInteger::from_u64(1)),
202+
true => LambdaFieldElement::from(&UnsignedInteger::from_u64(0)),
203+
})),
204+
Expr::Lit(_) => Err(Error::new_spanned(
205+
expr,
206+
"The `!` logical inversion operator is only allowed before booleans in literal expressions",
207+
)),
208+
_ => Ok(HandleExprOutput::Runtime),
160209
},
161210

162-
_ => HandleExprOutput::Runtime,
211+
_ => Ok(HandleExprOutput::Runtime),
163212
}
164213
}

crates/starknet-types-core/src/felt/macro_impl.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ mod tests {
115115
assert_eq!(felt!(-{ 40 + 2 }), Felt::from(-42));
116116
let x = 42;
117117
assert_eq!(felt!({ (40 + 2 == x) | true }), Felt::ONE);
118+
let x = "105".to_string();
119+
assert_eq!(felt!(x), Felt::from(105));
120+
let x = true;
121+
assert_eq!(felt!(!x), Felt::from(0));
118122

119123
// Constants
120124
const X: &str = "42";

0 commit comments

Comments
 (0)