Skip to content

Commit d3490d8

Browse files
committed
Improve parsing code in expression.rs
1 parent f621bbf commit d3490d8

File tree

2 files changed

+58
-94
lines changed

2 files changed

+58
-94
lines changed

src/descriptor/tr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ fn parse_tr_tree(s: &str) -> Result<expression::Tree, Error> {
483483
args: vec![internal_key],
484484
});
485485
}
486-
let (tree, rest) = expression::Tree::from_slice_helper_curly(script, 1)?;
486+
let (tree, rest) = expression::Tree::from_slice_delim(script, 1, '{')?;
487487
if rest.is_empty() {
488488
Ok(expression::Tree {
489489
name: "tr",

src/expression.rs

Lines changed: 57 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -37,110 +37,39 @@ pub trait FromTree: Sized {
3737
fn from_tree(top: &Tree) -> Result<Self, Error>;
3838
}
3939

40-
impl<'a> Tree<'a> {
41-
/// Parse an expression with round brackets
42-
pub fn from_slice(sl: &'a str) -> Result<(Tree<'a>, &'a str), Error> {
43-
// Parsing TapTree or just miniscript
44-
Self::from_slice_helper_round(sl, 0u32)
45-
}
46-
47-
fn from_slice_helper_round(mut sl: &'a str, depth: u32) -> Result<(Tree<'a>, &'a str), Error> {
48-
if depth >= MAX_RECURSION_DEPTH {
49-
return Err(Error::MaxRecursiveDepthExceeded);
50-
}
51-
enum Found {
52-
Nothing,
53-
Lparen(usize),
54-
Comma(usize),
55-
Rparen(usize),
56-
}
40+
enum Found {
41+
Nothing,
42+
LBracket(usize), // Either a left ( or {
43+
Comma(usize),
44+
RBracket(usize), // Either a right ) or }
45+
}
5746

58-
let mut found = Found::Nothing;
47+
fn next_expr(sl: &str, delim: char) -> Found {
48+
let mut found = Found::Nothing;
49+
if delim == '(' {
5950
for (n, ch) in sl.char_indices() {
6051
match ch {
6152
'(' => {
62-
found = Found::Lparen(n);
53+
found = Found::LBracket(n);
6354
break;
6455
}
6556
',' => {
6657
found = Found::Comma(n);
6758
break;
6859
}
6960
')' => {
70-
found = Found::Rparen(n);
61+
found = Found::RBracket(n);
7162
break;
7263
}
7364
_ => {}
7465
}
7566
}
76-
77-
match found {
78-
// String-ending terminal
79-
Found::Nothing => Ok((
80-
Tree {
81-
name: &sl[..],
82-
args: vec![],
83-
},
84-
"",
85-
)),
86-
// Terminal
87-
Found::Comma(n) | Found::Rparen(n) => Ok((
88-
Tree {
89-
name: &sl[..n],
90-
args: vec![],
91-
},
92-
&sl[n..],
93-
)),
94-
// Function call
95-
Found::Lparen(n) => {
96-
let mut ret = Tree {
97-
name: &sl[..n],
98-
args: vec![],
99-
};
100-
101-
sl = &sl[n + 1..];
102-
loop {
103-
let (arg, new_sl) = Tree::from_slice_helper_round(sl, depth + 1)?;
104-
ret.args.push(arg);
105-
106-
if new_sl.is_empty() {
107-
return Err(Error::ExpectedChar(')'));
108-
}
109-
110-
sl = &new_sl[1..];
111-
match new_sl.as_bytes()[0] {
112-
b',' => {}
113-
b')' => break,
114-
_ => return Err(Error::ExpectedChar(',')),
115-
}
116-
}
117-
Ok((ret, sl))
118-
}
119-
}
120-
}
121-
122-
// Helper function to parse expressions with curly braces
123-
pub(crate) fn from_slice_helper_curly(
124-
mut sl: &'a str,
125-
depth: u32,
126-
) -> Result<(Tree<'a>, &'a str), Error> {
127-
// contain the context of brackets
128-
if depth >= MAX_RECURSION_DEPTH {
129-
return Err(Error::MaxRecursiveDepthExceeded);
130-
}
131-
enum Found {
132-
Nothing,
133-
Lbrace(usize),
134-
Comma(usize),
135-
Rbrace(usize),
136-
}
137-
138-
let mut found = Found::Nothing;
67+
} else if delim == '{' {
13968
let mut new_count = 0;
14069
for (n, ch) in sl.char_indices() {
14170
match ch {
14271
'{' => {
143-
found = Found::Lbrace(n);
72+
found = Found::LBracket(n);
14473
break;
14574
}
14675
'(' => {
@@ -156,14 +85,44 @@ impl<'a> Tree<'a> {
15685
new_count -= 1;
15786
}
15887
'}' => {
159-
found = Found::Rbrace(n);
88+
found = Found::RBracket(n);
16089
break;
16190
}
16291
_ => {}
16392
}
16493
}
94+
} else {
95+
unreachable!("Internal: delimiters in parsing must be '(' or '{'");
96+
}
97+
found
98+
}
99+
100+
// Get the corresponding delim
101+
fn closing_delim(delim: char) -> char {
102+
match delim {
103+
'(' => ')',
104+
'{' => '}',
105+
_ => unreachable!("Unknown delimiter"),
106+
}
107+
}
165108

166-
match found {
109+
impl<'a> Tree<'a> {
110+
/// Parse an expression with round brackets
111+
pub fn from_slice(sl: &'a str) -> Result<(Tree<'a>, &'a str), Error> {
112+
// Parsing TapTree or just miniscript
113+
Self::from_slice_delim(sl, 0u32, '(')
114+
}
115+
116+
pub(crate) fn from_slice_delim(
117+
mut sl: &'a str,
118+
depth: u32,
119+
delim: char,
120+
) -> Result<(Tree<'a>, &'a str), Error> {
121+
if depth >= MAX_RECURSION_DEPTH {
122+
return Err(Error::MaxRecursiveDepthExceeded);
123+
}
124+
125+
match next_expr(sl, delim) {
167126
// String-ending terminal
168127
Found::Nothing => Ok((
169128
Tree {
@@ -173,34 +132,39 @@ impl<'a> Tree<'a> {
173132
"",
174133
)),
175134
// Terminal
176-
Found::Comma(n) | Found::Rbrace(n) => Ok((
135+
Found::Comma(n) | Found::RBracket(n) => Ok((
177136
Tree {
178137
name: &sl[..n],
179138
args: vec![],
180139
},
181140
&sl[n..],
182141
)),
183142
// Function call
184-
Found::Lbrace(n) => {
143+
Found::LBracket(n) => {
185144
let mut ret = Tree {
186-
name: &sl[..n], // Would be empty for left and right assignments
145+
name: &sl[..n],
187146
args: vec![],
188147
};
189148

190149
sl = &sl[n + 1..];
191150
loop {
192-
let (arg, new_sl) = Tree::from_slice_helper_curly(sl, depth + 1)?;
151+
let (arg, new_sl) = Tree::from_slice_delim(sl, depth + 1, delim)?;
193152
ret.args.push(arg);
194153

195154
if new_sl.is_empty() {
196-
return Err(Error::ExpectedChar('}'));
155+
return Err(Error::ExpectedChar(closing_delim(delim)));
197156
}
198157

199158
sl = &new_sl[1..];
200159
match new_sl.as_bytes()[0] {
201160
b',' => {}
202-
b'}' => break,
203-
_ => return Err(Error::ExpectedChar(',')),
161+
last_byte => {
162+
if last_byte == closing_delim(delim) as u8 {
163+
break;
164+
} else {
165+
return Err(Error::ExpectedChar(closing_delim(delim)));
166+
}
167+
}
204168
}
205169
}
206170
Ok((ret, sl))

0 commit comments

Comments
 (0)