@@ -44,94 +44,34 @@ impl Eq for Tree<'_> {}
44
44
// or_b()
45
45
// pk(A), pk(B)
46
46
47
+ /// Whether to treat `{` and `}` as deliminators when parsing an expression.
48
+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
49
+ pub enum Delimiter {
50
+ /// Use `(` and `)` as parentheses.
51
+ NonTaproot ,
52
+ /// Use `{` and `}` as parentheses.
53
+ Taproot ,
54
+ }
55
+
47
56
/// A trait for extracting a structure from a Tree representation in token form
48
57
pub trait FromTree : Sized {
49
58
/// Extract a structure from Tree representation
50
59
fn from_tree ( top : & Tree ) -> Result < Self , Error > ;
51
60
}
52
61
53
- enum Found {
54
- Nothing ,
55
- LBracket ( usize ) , // Either a left ( or {
56
- Comma ( usize ) ,
57
- RBracket ( usize ) , // Either a right ) or }
58
- }
59
-
60
- fn next_expr ( sl : & str , delim : char ) -> Found {
61
- let mut found = Found :: Nothing ;
62
- if delim == '(' {
63
- for ( n, ch) in sl. char_indices ( ) {
64
- match ch {
65
- '(' => {
66
- found = Found :: LBracket ( n) ;
67
- break ;
68
- }
69
- ',' => {
70
- found = Found :: Comma ( n) ;
71
- break ;
72
- }
73
- ')' => {
74
- found = Found :: RBracket ( n) ;
75
- break ;
76
- }
77
- _ => { }
78
- }
79
- }
80
- } else if delim == '{' {
81
- let mut new_count = 0 ;
82
- for ( n, ch) in sl. char_indices ( ) {
83
- match ch {
84
- '{' => {
85
- found = Found :: LBracket ( n) ;
86
- break ;
87
- }
88
- '(' => {
89
- new_count += 1 ;
90
- }
91
- ',' => {
92
- if new_count == 0 {
93
- found = Found :: Comma ( n) ;
94
- break ;
95
- }
96
- }
97
- ')' => {
98
- new_count -= 1 ;
99
- }
100
- '}' => {
101
- found = Found :: RBracket ( n) ;
102
- break ;
103
- }
104
- _ => { }
105
- }
106
- }
107
- } else {
108
- unreachable ! ( "{}" , "Internal: delimiters in parsing must be '(' or '{'" ) ;
109
- }
110
- found
111
- }
112
-
113
- // Get the corresponding delim
114
- fn closing_delim ( delim : char ) -> char {
115
- match delim {
116
- '(' => ')' ,
117
- '{' => '}' ,
118
- _ => unreachable ! ( "Unknown delimiter" ) ,
119
- }
120
- }
121
-
122
62
impl < ' a > Tree < ' a > {
123
63
/// Parse an expression with round brackets
124
- pub fn from_slice ( sl : & ' a str ) -> Result < ( Tree < ' a > , & ' a str ) , Error > {
125
- // Parsing TapTree or just miniscript
126
- Self :: from_slice_delim ( sl, 0u32 , '(' )
64
+ pub fn from_slice ( sl : & ' a str ) -> Result < Tree < ' a > , ParseTreeError > {
65
+ Self :: from_slice_delim ( sl, Delimiter :: NonTaproot )
127
66
}
128
67
129
68
/// Check that a string is a well-formed expression string, with optional
130
69
/// checksum.
131
70
///
132
- /// Returns the string with the checksum removed.
133
- fn parse_pre_check ( s : & str , open : u8 , close : u8 ) -> Result < & str , ParseTreeError > {
134
- // Do ASCII check first; after this we can use .bytes().enumerate() rather
71
+ /// Returns the string with the checksum removed and its tree depth.
72
+ fn parse_pre_check ( s : & str , open : u8 , close : u8 ) -> Result < ( & str , usize ) , ParseTreeError > {
73
+ // First, scan through string to make sure it is well-formed.
74
+ // Do ASCII/checksum check first; after this we can use .bytes().enumerate() rather
135
75
// than .char_indices(), which is *significantly* faster.
136
76
let s = verify_checksum ( s) ?;
137
77
@@ -211,68 +151,64 @@ impl<'a> Tree<'a> {
211
151
} ) ;
212
152
}
213
153
214
- Ok ( s )
154
+ Ok ( ( s , max_depth ) )
215
155
}
216
156
217
- pub ( crate ) fn from_slice_delim (
218
- mut sl : & ' a str ,
219
- depth : u32 ,
220
- delim : char ,
221
- ) -> Result < ( Tree < ' a > , & ' a str ) , Error > {
222
- if depth == 0 {
223
- if delim == '{' {
224
- sl = Self :: parse_pre_check ( sl, b'{' , b'}' ) . map_err ( Error :: ParseTree ) ?;
225
- } else {
226
- sl = Self :: parse_pre_check ( sl, b'(' , b')' ) . map_err ( Error :: ParseTree ) ?;
157
+ pub ( crate ) fn from_slice_delim ( s : & ' a str , delim : Delimiter ) -> Result < Self , ParseTreeError > {
158
+ let ( oparen, cparen) = match delim {
159
+ Delimiter :: NonTaproot => ( b'(' , b')' ) ,
160
+ Delimiter :: Taproot => ( b'{' , b'}' ) ,
161
+ } ;
162
+
163
+ // First, scan through string to make sure it is well-formed.
164
+ let ( s, max_depth) = Self :: parse_pre_check ( s, oparen, cparen) ?;
165
+
166
+ // Now, knowing it is sane and well-formed, we can easily parse it backward,
167
+ // which will yield a post-order right-to-left iterator of its nodes.
168
+ let mut stack = Vec :: with_capacity ( max_depth) ;
169
+ let mut children = None ;
170
+ let mut node_name_end = s. len ( ) ;
171
+ let mut tapleaf_depth = 0 ;
172
+ for ( pos, ch) in s. bytes ( ) . enumerate ( ) . rev ( ) {
173
+ if ch == cparen {
174
+ stack. push ( vec ! [ ] ) ;
175
+ node_name_end = pos;
176
+ } else if tapleaf_depth == 0 && ch == b',' {
177
+ let top = stack. last_mut ( ) . unwrap ( ) ;
178
+ let mut new_tree = Tree {
179
+ name : & s[ pos + 1 ..node_name_end] ,
180
+ args : children. take ( ) . unwrap_or ( vec ! [ ] ) ,
181
+ } ;
182
+ new_tree. args . reverse ( ) ;
183
+ top. push ( new_tree) ;
184
+ node_name_end = pos;
185
+ } else if ch == oparen {
186
+ let mut top = stack. pop ( ) . unwrap ( ) ;
187
+ let mut new_tree = Tree {
188
+ name : & s[ pos + 1 ..node_name_end] ,
189
+ args : children. take ( ) . unwrap_or ( vec ! [ ] ) ,
190
+ } ;
191
+ new_tree. args . reverse ( ) ;
192
+ top. push ( new_tree) ;
193
+ children = Some ( top) ;
194
+ node_name_end = pos;
195
+ } else if delim == Delimiter :: Taproot && ch == b'(' {
196
+ tapleaf_depth += 1 ;
197
+ } else if delim == Delimiter :: Taproot && ch == b')' {
198
+ tapleaf_depth -= 1 ;
227
199
}
228
200
}
229
201
230
- match next_expr ( sl, delim) {
231
- // String-ending terminal
232
- Found :: Nothing => Ok ( ( Tree { name : sl, args : vec ! [ ] } , "" ) ) ,
233
- // Terminal
234
- Found :: Comma ( n) | Found :: RBracket ( n) => {
235
- Ok ( ( Tree { name : & sl[ ..n] , args : vec ! [ ] } , & sl[ n..] ) )
236
- }
237
- // Function call
238
- Found :: LBracket ( n) => {
239
- let mut ret = Tree { name : & sl[ ..n] , args : vec ! [ ] } ;
240
-
241
- sl = & sl[ n + 1 ..] ;
242
- loop {
243
- let ( arg, new_sl) = Tree :: from_slice_delim ( sl, depth + 1 , delim) ?;
244
- ret. args . push ( arg) ;
245
-
246
- if new_sl. is_empty ( ) {
247
- unreachable ! ( )
248
- }
249
-
250
- sl = & new_sl[ 1 ..] ;
251
- match new_sl. as_bytes ( ) [ 0 ] {
252
- b',' => { }
253
- last_byte => {
254
- if last_byte == closing_delim ( delim) as u8 {
255
- break ;
256
- } else {
257
- unreachable ! ( )
258
- }
259
- }
260
- }
261
- }
262
- Ok ( ( ret, sl) )
263
- }
264
- }
202
+ assert_eq ! ( stack. len( ) , 0 ) ;
203
+ let mut children = children. take ( ) . unwrap_or ( vec ! [ ] ) ;
204
+ children. reverse ( ) ;
205
+ Ok ( Tree { name : & s[ ..node_name_end] , args : children } )
265
206
}
266
207
267
208
/// Parses a tree from a string
268
209
#[ allow( clippy:: should_implement_trait) ] // Cannot use std::str::FromStr because of lifetimes.
269
210
pub fn from_str ( s : & ' a str ) -> Result < Tree < ' a > , Error > {
270
- let ( top, rem) = Tree :: from_slice ( s) ?;
271
- if rem. is_empty ( ) {
272
- Ok ( top)
273
- } else {
274
- unreachable ! ( )
275
- }
211
+ Self :: from_slice_delim ( s, Delimiter :: NonTaproot ) . map_err ( Error :: ParseTree )
276
212
}
277
213
278
214
/// Parses an expression tree as a threshold (a term with at least one child,
0 commit comments