@@ -44,94 +44,34 @@ impl Eq for Tree<'_> {}
4444// or_b()
4545// pk(A), pk(B)
4646
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+
4756/// A trait for extracting a structure from a Tree representation in token form
4857pub trait FromTree : Sized {
4958 /// Extract a structure from Tree representation
5059 fn from_tree ( top : & Tree ) -> Result < Self , Error > ;
5160}
5261
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-
12262impl < ' a > Tree < ' a > {
12363 /// 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 )
12766 }
12867
12968 /// Check that a string is a well-formed expression string, with optional
13069 /// checksum.
13170 ///
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
13575 // than .char_indices(), which is *significantly* faster.
13676 let s = verify_checksum ( s) ?;
13777
@@ -211,68 +151,64 @@ impl<'a> Tree<'a> {
211151 } ) ;
212152 }
213153
214- Ok ( s )
154+ Ok ( ( s , max_depth ) )
215155 }
216156
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 ;
227199 }
228200 }
229201
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 } )
265206 }
266207
267208 /// Parses a tree from a string
268209 #[ allow( clippy:: should_implement_trait) ] // Cannot use std::str::FromStr because of lifetimes.
269210 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 )
276212 }
277213
278214 /// Parses an expression tree as a threshold (a term with at least one child,
0 commit comments