miniscript_debug/
expression.rs1use core::str::FromStr;
18
19use crate::prelude::*;
20use crate::{errstr, Error, MAX_RECURSION_DEPTH};
21
22#[derive(Debug)]
23pub struct Tree<'a> {
25 pub name: &'a str,
27 pub args: Vec<Tree<'a>>,
29}
30pub trait FromTree: Sized {
38 fn from_tree(top: &Tree) -> Result<Self, Error>;
40}
41
42enum Found {
43 Nothing,
44 LBracket(usize), Comma(usize),
46 RBracket(usize), }
48
49fn next_expr(sl: &str, delim: char) -> Found {
50 let mut found = Found::Nothing;
51 if delim == '(' {
52 for (n, ch) in sl.char_indices() {
53 match ch {
54 '(' => {
55 found = Found::LBracket(n);
56 break;
57 }
58 ',' => {
59 found = Found::Comma(n);
60 break;
61 }
62 ')' => {
63 found = Found::RBracket(n);
64 break;
65 }
66 _ => {}
67 }
68 }
69 } else if delim == '{' {
70 let mut new_count = 0;
71 for (n, ch) in sl.char_indices() {
72 match ch {
73 '{' => {
74 found = Found::LBracket(n);
75 break;
76 }
77 '(' => {
78 new_count += 1;
79 }
80 ',' => {
81 if new_count == 0 {
82 found = Found::Comma(n);
83 break;
84 }
85 }
86 ')' => {
87 new_count -= 1;
88 }
89 '}' => {
90 found = Found::RBracket(n);
91 break;
92 }
93 _ => {}
94 }
95 }
96 } else {
97 unreachable!("{}", "Internal: delimiters in parsing must be '(' or '{'");
98 }
99 found
100}
101
102fn closing_delim(delim: char) -> char {
104 match delim {
105 '(' => ')',
106 '{' => '}',
107 _ => unreachable!("Unknown delimiter"),
108 }
109}
110
111impl<'a> Tree<'a> {
112 pub fn from_slice(sl: &'a str) -> Result<(Tree<'a>, &'a str), Error> {
114 Self::from_slice_delim(sl, 0u32, '(')
116 }
117
118 pub(crate) fn from_slice_delim(
119 mut sl: &'a str,
120 depth: u32,
121 delim: char,
122 ) -> Result<(Tree<'a>, &'a str), Error> {
123 if depth >= MAX_RECURSION_DEPTH {
124 return Err(Error::MaxRecursiveDepthExceeded);
125 }
126
127 match next_expr(sl, delim) {
128 Found::Nothing => Ok((
130 Tree {
131 name: sl,
132 args: vec![],
133 },
134 "",
135 )),
136 Found::Comma(n) | Found::RBracket(n) => Ok((
138 Tree {
139 name: &sl[..n],
140 args: vec![],
141 },
142 &sl[n..],
143 )),
144 Found::LBracket(n) => {
146 let mut ret = Tree {
147 name: &sl[..n],
148 args: vec![],
149 };
150
151 sl = &sl[n + 1..];
152 loop {
153 let (arg, new_sl) = Tree::from_slice_delim(sl, depth + 1, delim)?;
154 ret.args.push(arg);
155
156 if new_sl.is_empty() {
157 return Err(Error::ExpectedChar(closing_delim(delim)));
158 }
159
160 sl = &new_sl[1..];
161 match new_sl.as_bytes()[0] {
162 b',' => {}
163 last_byte => {
164 if last_byte == closing_delim(delim) as u8 {
165 break;
166 } else {
167 return Err(Error::ExpectedChar(closing_delim(delim)));
168 }
169 }
170 }
171 }
172 Ok((ret, sl))
173 }
174 }
175 }
176
177 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &'a str) -> Result<Tree<'a>, Error> {
180 for ch in s.bytes() {
183 if !ch.is_ascii() {
184 return Err(Error::Unprintable(ch));
185 }
186 }
187
188 let (top, rem) = Tree::from_slice(s)?;
189 if rem.is_empty() {
190 Ok(top)
191 } else {
192 Err(errstr(rem))
193 }
194 }
195}
196
197pub fn parse_num(s: &str) -> Result<u32, Error> {
199 if s.len() > 1 {
200 let ch = s.chars().next().unwrap();
201 if !('1'..='9').contains(&ch) {
202 return Err(Error::Unexpected(
203 "Number must start with a digit 1-9".to_string(),
204 ));
205 }
206 }
207 u32::from_str(s).map_err(|_| errstr(s))
208}
209
210pub fn terminal<T, F, Err>(term: &Tree, convert: F) -> Result<T, Error>
212where
213 F: FnOnce(&str) -> Result<T, Err>,
214 Err: ToString,
215{
216 if term.args.is_empty() {
217 convert(term.name).map_err(|e| Error::Unexpected(e.to_string()))
218 } else {
219 Err(errstr(term.name))
220 }
221}
222
223pub fn unary<L, T, F>(term: &Tree, convert: F) -> Result<T, Error>
225where
226 L: FromTree,
227 F: FnOnce(L) -> T,
228{
229 if term.args.len() == 1 {
230 let left = FromTree::from_tree(&term.args[0])?;
231 Ok(convert(left))
232 } else {
233 Err(errstr(term.name))
234 }
235}
236
237pub fn binary<L, R, T, F>(term: &Tree, convert: F) -> Result<T, Error>
239where
240 L: FromTree,
241 R: FromTree,
242 F: FnOnce(L, R) -> T,
243{
244 if term.args.len() == 2 {
245 let left = FromTree::from_tree(&term.args[0])?;
246 let right = FromTree::from_tree(&term.args[1])?;
247 Ok(convert(left, right))
248 } else {
249 Err(errstr(term.name))
250 }
251}
252
253#[cfg(test)]
254mod tests {
255
256 use super::parse_num;
257
258 #[test]
259 fn test_parse_num() {
260 assert!(parse_num("0").is_ok());
261 assert!(parse_num("00").is_err());
262 assert!(parse_num("0000").is_err());
263 assert!(parse_num("06").is_err());
264 assert!(parse_num("+6").is_err());
265 assert!(parse_num("-6").is_err());
266 }
267}