From bc78974fd2b03d195735f119db026bd4cd36f1c7 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 2 May 2019 09:07:38 +0200 Subject: [PATCH] =?UTF-8?q?Ignore=20escaped=20brackets=20for=20body=20meas?= =?UTF-8?q?ure=20=F0=9F=90=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parsing.rs | 70 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/parsing.rs b/src/parsing.rs index 85949e579..924c3ddec 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -504,16 +504,22 @@ impl<'s> Parser<'s> { } } -/// Find the index of the first unbalanced closing bracket. +/// Find the index of the first unbalanced (unescaped) closing bracket. fn find_closing_bracket(src: &str) -> Option { let mut parens = 0; + let mut escaped = false; for (index, c) in src.char_indices() { match c { - ']' if parens == 0 => return Some(index), - '[' => parens += 1, - ']' => parens -= 1, + '\\' => { + escaped = !escaped; + continue; + }, + ']' if !escaped && parens == 0 => return Some(index), + '[' if !escaped => parens += 1, + ']' if !escaped => parens -= 1, _ => {}, } + escaped = false; } None } @@ -856,45 +862,53 @@ mod parse_tests { T("of"), S, T("a"), S, T("function"), S, T("invocation.") ]); test_scoped(&scope, "[func][Hello][modifier][Here][end]", tree! [ - F(func! { - name => "func", - body => tree! [ T("Hello") ], - }), - F(func! { - name => "modifier", - body => tree! [ T("Here") ], - }), - F(func! { - name => "end", - body => None, - }), - ]); - test_scoped(&scope, "[func][]", tree! [ - F(func! { - name => "func", - body => tree! [], - }) + F(func! { name => "func", body => tree! [ T("Hello") ] }), + F(func! { name => "modifier", body => tree! [ T("Here") ] }), + F(func! { name => "end", body => None }), ]); + test_scoped(&scope, "[func][]", tree! [ F(func! { name => "func", body => tree! [] }) ]); test_scoped(&scope, "[modifier][[func][call]] outside", tree! [ F(func! { name => "modifier", - body => tree! [ - F(func! { - name => "func", - body => tree! [ T("call") ], - }), - ], + body => tree! [ F(func! { name => "func", body => tree! [ T("call") ] }) ], }), S, T("outside") ]); } + /// Test if escaped, but unbalanced parens are correctly parsed. + #[test] + fn parse_unbalanced_body_parens() { + let mut scope = Scope::new(); + scope.add::("code"); + + test_scoped(&scope, r"My [code][Close \]] end", tree! [ + T("My"), S, F(func! { + name => "code", + body => tree! [ T("Close"), S, T("]") ] + }), S, T("end") + ]); + test_scoped(&scope, r"My [code][\[ Open] end", tree! [ + T("My"), S, F(func! { + name => "code", + body => tree! [ T("["), S, T("Open") ] + }), S, T("end") + ]); + test_scoped(&scope, r"My [code][Open \] and \[ close]end", tree! [ + T("My"), S, F(func! { + name => "code", + body => tree! [ T("Open"), S, T("]"), S, T("and"), S, T("["), S, T("close") ] + }), T("end") + ]); + } + /// Tests if the parser handles non-ASCII stuff correctly. #[test] fn parse_unicode() { let mut scope = Scope::new(); scope.add::("func"); scope.add::("bold"); + test_scoped(&scope, "[func] ⺐.", tree! [ F(func! { name => "func",