Skip to content

Commit 616b6b6

Browse files
committed
expression: hide all Tree fields and encapsulate API
This removes the ability to randomly access children of tree nodes. You can get them in order using the `children` iterator, and get them recursively using the `TreeLike` iterator methods. (In the next commits we will specialize these a bit, providing a `pre_order_iter` and `rtl_post_order_iter` which let you efficiently skip over subtrees. We will need these to parse Taproot expression trees and they don't fit into the `TreeLike` trait, at least not efficiently.)
1 parent 4137a59 commit 616b6b6

File tree

8 files changed

+63
-36
lines changed

8 files changed

+63
-36
lines changed

src/descriptor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ impl Descriptor<DefiniteDescriptorKey> {
966966
impl<Pk: FromStrKey> crate::expression::FromTree for Descriptor<Pk> {
967967
/// Parse an expression tree into a descriptor.
968968
fn from_tree(top: &expression::Tree) -> Result<Descriptor<Pk>, Error> {
969-
Ok(match (top.name, top.args.len() as u32) {
969+
Ok(match (top.name(), top.n_children()) {
970970
("pkh", 1) => Descriptor::Pkh(Pkh::from_tree(top)?),
971971
("wpkh", 1) => Descriptor::Wpkh(Wpkh::from_tree(top)?),
972972
("sh", 1) => Descriptor::Sh(Sh::from_tree(top)?),

src/descriptor/segwitv0.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ impl<Pk: FromStrKey> crate::expression::FromTree for Wsh<Pk> {
253253
.map_err(From::from)
254254
.map_err(Error::Parse)?;
255255

256-
if top.name == "sortedmulti" {
256+
if top.name() == "sortedmulti" {
257257
return Ok(Wsh { inner: WshInner::SortedMulti(SortedMultiVec::from_tree(top)?) });
258258
}
259259
let sub = Miniscript::from_tree(top)?;

src/descriptor/sh.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<Pk: FromStrKey> crate::expression::FromTree for Sh<Pk> {
8787
.map_err(From::from)
8888
.map_err(Error::Parse)?;
8989

90-
let inner = match top.name {
90+
let inner = match top.name() {
9191
"wsh" => ShInner::Wsh(Wsh::from_tree(top)?),
9292
"wpkh" => ShInner::Wpkh(Wpkh::from_tree(top)?),
9393
"sortedmulti" => ShInner::SortedMulti(SortedMultiVec::from_tree(top)?),

src/descriptor/tr.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -532,20 +532,20 @@ impl<Pk: FromStrKey> crate::expression::FromTree for Tr<Pk> {
532532
} else {
533533
// From here on we are into the taptree.
534534
if item.n_children_yielded == 0 {
535-
match item.node.parens {
535+
match item.node.parens() {
536536
Parens::Curly => {
537-
if !item.node.name.is_empty() {
537+
if !item.node.name().is_empty() {
538538
return Err(Error::Parse(ParseError::Tree(
539539
ParseTreeError::IncorrectName {
540-
actual: item.node.name.to_owned(),
540+
actual: item.node.name().to_owned(),
541541
expected: "",
542542
},
543543
)));
544544
}
545545
if round_paren_depth > 0 {
546546
return Err(Error::Parse(ParseError::Tree(
547547
ParseTreeError::IllegalCurlyBrace {
548-
pos: item.node.children_pos,
548+
pos: item.node.children_pos(),
549549
},
550550
)));
551551
}
@@ -555,7 +555,7 @@ impl<Pk: FromStrKey> crate::expression::FromTree for Tr<Pk> {
555555
}
556556
}
557557
if item.is_complete {
558-
if item.node.parens == Parens::Curly {
558+
if item.node.parens() == Parens::Curly {
559559
if item.n_children_yielded == 2 {
560560
let rchild = tree_stack.pop().unwrap();
561561
let lchild = tree_stack.pop().unwrap();
@@ -571,7 +571,7 @@ impl<Pk: FromStrKey> crate::expression::FromTree for Tr<Pk> {
571571
)));
572572
}
573573
} else {
574-
if item.node.parens == Parens::Round {
574+
if item.node.parens() == Parens::Round {
575575
round_paren_depth -= 1;
576576
}
577577
if round_paren_depth == 0 {

src/expression/mod.rs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ pub const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVW
2222
/// A token of the form `x(...)` or `x`
2323
pub struct Tree<'a> {
2424
/// The name `x`
25-
pub name: &'a str,
25+
name: &'a str,
2626
/// Position one past the last character of the node's name. If it has
2727
/// children, the position of the '(' or '{'.
28-
pub children_pos: usize,
28+
children_pos: usize,
2929
/// The type of parentheses surrounding the node's children.
30-
pub parens: Parens,
30+
parens: Parens,
3131
/// The comma-separated contents of the `(...)`, if any
32-
pub args: Vec<Tree<'a>>,
32+
args: Vec<Tree<'a>>,
3333
}
3434

3535
impl PartialEq for Tree<'_> {
@@ -79,6 +79,32 @@ pub trait FromTree: Sized {
7979
}
8080

8181
impl<'a> Tree<'a> {
82+
/// The name of this tree node.
83+
pub fn name(&self) -> &str { self.name }
84+
85+
/// The 0-indexed byte-position of the name in the original expression tree.
86+
pub fn name_pos(&self) -> usize { self.children_pos - self.name.len() - 1 }
87+
88+
/// The 0-indexed byte-position of the '(' or '{' character which starts the
89+
/// expression's children.
90+
///
91+
/// If the expression has no children, returns one past the end of the name.
92+
pub fn children_pos(&self) -> usize { self.children_pos - self.name.len() - 1 }
93+
94+
/// The number of children this node has.
95+
pub fn n_children(&self) -> usize { self.args.len() }
96+
97+
/// The type of parenthesis surrounding this node's children.
98+
///
99+
/// If the node has no children, this will be `Parens::None`.
100+
pub fn parens(&self) -> Parens { self.parens }
101+
102+
/// An iterator over the direct children of this node.
103+
///
104+
/// If you want to iterate recursively, use the [`TreeLike`] API which
105+
/// provides methods `pre_order_iter` and `post_order_iter`.
106+
pub fn children(&self) -> impl ExactSizeIterator<Item = &Self> { self.args.iter() }
107+
82108
/// Split the name by a separating character.
83109
///
84110
/// If the separator is present, returns the prefix before the separator and
@@ -260,20 +286,21 @@ impl<'a> Tree<'a> {
260286
&self,
261287
mut map_child: F,
262288
) -> Result<Threshold<T, MAX>, E> {
289+
let mut child_iter = self.children();
290+
let kchild = match child_iter.next() {
291+
Some(k) => k,
292+
None => return Err(ParseThresholdError::NoChildren.into()),
293+
};
263294
// First, special case "no arguments" so we can index the first argument without panics.
264-
if self.args.is_empty() {
265-
return Err(ParseThresholdError::NoChildren.into());
266-
}
267-
268-
if !self.args[0].args.is_empty() {
295+
if kchild.n_children() > 0 {
269296
return Err(ParseThresholdError::KNotTerminal.into());
270297
}
271298

272-
let k = parse_num(self.args[0].name).map_err(ParseThresholdError::ParseK)? as usize;
273-
Threshold::new(k, vec![(); self.args.len() - 1])
299+
let k = parse_num(kchild.name()).map_err(ParseThresholdError::ParseK)? as usize;
300+
Threshold::new(k, vec![(); self.n_children() - 1])
274301
.map_err(ParseThresholdError::Threshold)
275302
.map_err(From::from)
276-
.and_then(|thresh| thresh.translate_by_index(|i| map_child(&self.args[1 + i])))
303+
.and_then(|thresh| thresh.translate_by_index(|_| map_child(child_iter.next().unwrap())))
277304
}
278305

279306
/// Check that a tree has no curly-brace children in it.

src/miniscript/astelem.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,14 @@ impl<Pk: FromStrKey, Ctx: ScriptContext> crate::expression::FromTree for Termina
112112
top.verify_n_children("andor", 3..=3)
113113
.map_err(From::from)
114114
.map_err(Error::Parse)?;
115-
let x = Arc::<Miniscript<Pk, Ctx>>::from_tree(&top.args[0])?;
116-
let y = Arc::<Miniscript<Pk, Ctx>>::from_tree(&top.args[1])?;
117-
let z = Arc::<Miniscript<Pk, Ctx>>::from_tree(&top.args[2])?;
118-
Ok(Terminal::AndOr(x, y, z))
115+
let mut child_iter = top
116+
.children()
117+
.map(|x| Arc::<Miniscript<Pk, Ctx>>::from_tree(x));
118+
Ok(Terminal::AndOr(
119+
child_iter.next().unwrap()?,
120+
child_iter.next().unwrap()?,
121+
child_iter.next().unwrap()?,
122+
))
119123
}
120124
"or_b" => binary(top, "or_b", Terminal::OrB),
121125
"or_d" => binary(top, "or_d", Terminal::OrD),
@@ -137,7 +141,7 @@ impl<Pk: FromStrKey, Ctx: ScriptContext> crate::expression::FromTree for Termina
137141

138142
if frag_wrap == Some("") {
139143
return Err(Error::Parse(crate::ParseError::Tree(
140-
crate::ParseTreeError::UnknownName { name: top.name.to_owned() },
144+
crate::ParseTreeError::UnknownName { name: top.name().to_owned() },
141145
)));
142146
}
143147
let ms = super::wrap_into_miniscript(unwrapped, frag_wrap.unwrap_or(""))?;

src/policy/concrete.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ impl<Pk: FromStrKey> Policy<Pk> {
856856
.map_err(From::from)
857857
.map_err(Error::Parse)?
858858
} else {
859-
(None, top.name)
859+
(None, top.name())
860860
};
861861

862862
let frag_prob = match frag_prob {
@@ -906,8 +906,7 @@ impl<Pk: FromStrKey> Policy<Pk> {
906906
.map_err(From::from)
907907
.map_err(Error::Parse)?;
908908
let subs = top
909-
.args
910-
.iter()
909+
.children()
911910
.map(|arg| Self::from_tree(arg).map(Arc::new))
912911
.collect::<Result<_, Error>>()?;
913912
Ok(Policy::And(subs))
@@ -917,8 +916,7 @@ impl<Pk: FromStrKey> Policy<Pk> {
917916
.map_err(From::from)
918917
.map_err(Error::Parse)?;
919918
let subs = top
920-
.args
921-
.iter()
919+
.children()
922920
.map(|arg| {
923921
Self::from_tree_prob(arg, true).map(|(prob, sub)| (prob, Arc::new(sub)))
924922
})

src/policy/semantic.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ serde_string_impl_pk!(Policy, "a miniscript semantic policy");
285285

286286
impl<Pk: FromStrKey> expression::FromTree for Policy<Pk> {
287287
fn from_tree(top: &expression::Tree) -> Result<Policy<Pk>, Error> {
288-
match top.name {
288+
match top.name() {
289289
"UNSATISFIABLE" => {
290290
top.verify_n_children("UNSATISFIABLE", 0..=0)
291291
.map_err(From::from)
@@ -325,8 +325,7 @@ impl<Pk: FromStrKey> expression::FromTree for Policy<Pk> {
325325
.map_err(From::from)
326326
.map_err(Error::Parse)?;
327327
let subs = top
328-
.args
329-
.iter()
328+
.children()
330329
.map(|arg| Self::from_tree(arg).map(Arc::new))
331330
.collect::<Result<Vec<_>, Error>>()?;
332331
Ok(Policy::Thresh(Threshold::new(subs.len(), subs).map_err(Error::Threshold)?))
@@ -336,8 +335,7 @@ impl<Pk: FromStrKey> expression::FromTree for Policy<Pk> {
336335
.map_err(From::from)
337336
.map_err(Error::Parse)?;
338337
let subs = top
339-
.args
340-
.iter()
338+
.children()
341339
.map(|arg| Self::from_tree(arg).map(Arc::new))
342340
.collect::<Result<Vec<_>, Error>>()?;
343341
Ok(Policy::Thresh(Threshold::new(1, subs).map_err(Error::Threshold)?))

0 commit comments

Comments
 (0)