From 1c9a65505781dd81d757f236e43db121b7475b27 Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 18 May 2023 16:23:13 +0200 Subject: [PATCH 1/5] fix expect![[]] --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 877241b..03c818e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -359,7 +359,7 @@ fn locate_end(arg_start_to_eof: &str) -> Option { // expect![[]] '[' => { let str_start_to_eof = arg_start_to_eof[1..].trim_start(); - let str_len = find_str_lit_len(str_start_to_eof)?; + let str_len = find_str_lit_len(str_start_to_eof).unwrap_or(0); let str_end_to_eof = &str_start_to_eof[str_len..]; let closing_brace_offset = str_end_to_eof.find(']')?; Some((arg_start_to_eof.len() - str_end_to_eof.len()) + closing_brace_offset + 1) From afda7ac0a6a7dc84236ca48e0550396efbca8c1a Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 18 May 2023 16:52:48 +0200 Subject: [PATCH 2/5] add comments --- src/lib.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 03c818e..8918a04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -338,6 +338,7 @@ impl Expect { } line_start += line.len(); } + // `literal_start` points to the first character after `expect![` let (literal_start, line_indent) = target_line.unwrap(); let lit_to_eof = &file[literal_start..]; @@ -352,6 +353,9 @@ impl Expect { } } +/// Returns the byte index of the closing delimiter. +/// +/// `arg_start_to_eof` is the part after `expect![`, with leading whitespaces trimmed. fn locate_end(arg_start_to_eof: &str) -> Option { match arg_start_to_eof.chars().next()? { c if c.is_whitespace() => panic!("skip whitespace before calling `locate_end`"), @@ -837,8 +841,9 @@ line1 macro_rules! check_locate { ($( [[$s:literal]] ),* $(,)?) => {$({ let lit = stringify!($s); - let with_trailer = format!("{} \t]]\n", lit); - assert_eq!(locate_end(&with_trailer), Some(lit.len())); + let with_trailer = format!("[{} \t]]\n", lit); + // ^ ^^ ^^ 5 additional chars + assert_eq!(locate_end(&with_trailer), Some(4+lit.len())); })*}; } @@ -851,7 +856,7 @@ line1 ); // Check `expect![[ ]]` as well. - assert_eq!(locate_end("]]"), Some(0)); + assert_eq!(locate_end("[]]"), Some(2)); } #[test] From 5d4cb8efa998976c76a0232303554399179e501b Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 16 May 2024 22:28:05 +0800 Subject: [PATCH 3/5] update test Signed-off-by: xxchan --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 8918a04..cad5405 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -857,6 +857,9 @@ line1 // Check `expect![[ ]]` as well. assert_eq!(locate_end("[]]"), Some(2)); + // For `expect![]]`, this will be invalid syntax: Syntax Error: expected SEMICOLON + // In `locate_end`, we just find the first `]` is the end position and ignores the rest. + assert_eq!(locate_end("]]"), Some(0)); } #[test] From 0416fe200e30fb6630e03b8e1b90c866e6149567 Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 16 May 2024 22:46:21 +0800 Subject: [PATCH 4/5] update test Signed-off-by: xxchan --- src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cad5405..9f40c73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -855,11 +855,10 @@ line1 [[r#""]]"#]], ); - // Check `expect![[ ]]` as well. + // Check `expect![[ ]]` assert_eq!(locate_end("[]]"), Some(2)); - // For `expect![]]`, this will be invalid syntax: Syntax Error: expected SEMICOLON - // In `locate_end`, we just find the first `]` is the end position and ignores the rest. - assert_eq!(locate_end("]]"), Some(0)); + // Check `expect![ ]` + assert_eq!(locate_end("]"), Some(0)); } #[test] From 7178666e2f1e5e1140a3f3255c2791c49ac2bedd Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 16 May 2024 23:10:55 +0800 Subject: [PATCH 5/5] refactor Signed-off-by: xxchan --- src/lib.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9f40c73..d5568cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -346,8 +346,7 @@ impl Expect { let literal_start = literal_start + (lit_to_eof.len() - lit_to_eof_trimmed.len()); - let literal_len = - locate_end(lit_to_eof_trimmed).expect("Couldn't find closing delimiter for `expect!`."); + let literal_len = locate_end(lit_to_eof_trimmed); let literal_range = literal_start..literal_start + literal_len; Location { line_indent, literal_range } } @@ -355,25 +354,34 @@ impl Expect { /// Returns the byte index of the closing delimiter. /// -/// `arg_start_to_eof` is the part after `expect![`, with leading whitespaces trimmed. -fn locate_end(arg_start_to_eof: &str) -> Option { - match arg_start_to_eof.chars().next()? { +/// `arg_start_to_eof` is the part after `expect![` until the closing delimiter +/// with leading whitespaces trimmed. +/// Note that we can actually assume the syntax is valid according to `macro_rules`. +fn locate_end(arg_start_to_eof: &str) -> usize { + let mut chars = arg_start_to_eof.chars(); + match chars.next().expect("after `expect![` there should be a char") { c if c.is_whitespace() => panic!("skip whitespace before calling `locate_end`"), // expect![[]] '[' => { let str_start_to_eof = arg_start_to_eof[1..].trim_start(); - let str_len = find_str_lit_len(str_start_to_eof).unwrap_or(0); + let str_len = if ']' == chars.next().expect("after `expect![[` there should be a char") + { + 0 + } else { + find_str_lit_len(str_start_to_eof).expect("invalid string literal in `expect![[`") + }; let str_end_to_eof = &str_start_to_eof[str_len..]; - let closing_brace_offset = str_end_to_eof.find(']')?; - Some((arg_start_to_eof.len() - str_end_to_eof.len()) + closing_brace_offset + 1) + let closing_brace_offset = + str_end_to_eof.find(']').expect("closing `]` not found after `expect![[`"); + (arg_start_to_eof.len() - str_end_to_eof.len()) + closing_brace_offset + 1 } // expect![] | expect!{} | expect!() - ']' | '}' | ')' => Some(0), + ']' | '}' | ')' => 0, // expect!["..."] | expect![r#"..."#] - _ => find_str_lit_len(arg_start_to_eof), + _ => find_str_lit_len(arg_start_to_eof).expect("invalid string literal after `expect![`"), } } @@ -843,7 +851,7 @@ line1 let lit = stringify!($s); let with_trailer = format!("[{} \t]]\n", lit); // ^ ^^ ^^ 5 additional chars - assert_eq!(locate_end(&with_trailer), Some(4+lit.len())); + assert_eq!(locate_end(&with_trailer), 4+lit.len()); })*}; } @@ -856,9 +864,14 @@ line1 ); // Check `expect![[ ]]` - assert_eq!(locate_end("[]]"), Some(2)); + assert_eq!(locate_end("[]]"), 2); // Check `expect![ ]` - assert_eq!(locate_end("]"), Some(0)); + assert_eq!(locate_end("]"), 0); + + // `locate_end` returns after the closing delimiter. + assert_eq!(locate_end("]abc"), 0); + // This is actually invalid syntax. + assert_eq!(locate_end("]]abc"), 0); } #[test]