|
2 | 2 |
|
3 | 3 | //! # Function-like Expression Language |
4 | 4 | //! |
| 5 | +
|
| 6 | +mod error; |
| 7 | + |
5 | 8 | use core::fmt; |
6 | 9 | use core::str::FromStr; |
7 | 10 |
|
| 11 | +pub use self::error::ParseThresholdError; |
8 | 12 | use crate::prelude::*; |
9 | | -use crate::{errstr, Error, MAX_RECURSION_DEPTH}; |
| 13 | +use crate::{errstr, Error, Threshold, MAX_RECURSION_DEPTH}; |
10 | 14 |
|
11 | 15 | /// Allowed characters are descriptor strings. |
12 | 16 | pub const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; |
@@ -185,6 +189,35 @@ impl<'a> Tree<'a> { |
185 | 189 | Err(errstr(rem)) |
186 | 190 | } |
187 | 191 | } |
| 192 | + |
| 193 | + /// Parses an expression tree as a threshold (a term with at least one child, |
| 194 | + /// the first of which is a positive integer k). |
| 195 | + /// |
| 196 | + /// This sanity-checks that the threshold is well-formed (begins with a valid |
| 197 | + /// threshold value, etc.) but does not parse the children of the threshold. |
| 198 | + /// Instead it returns a threshold holding the empty type `()`, which is |
| 199 | + /// constructed without any allocations, and expects the caller to convert |
| 200 | + /// this to the "real" threshold type by calling [`Threshold::translate`]. |
| 201 | + /// |
| 202 | + /// (An alternate API which does the conversion inline turned out to be |
| 203 | + /// too messy; it needs to take a closure, have multiple generic parameters, |
| 204 | + /// and be able to return multiple error types.) |
| 205 | + pub fn to_null_threshold<const MAX: usize>( |
| 206 | + &self, |
| 207 | + ) -> Result<Threshold<(), MAX>, ParseThresholdError> { |
| 208 | + // First, special case "no arguments" so we can index the first argument without panics. |
| 209 | + if self.args.is_empty() { |
| 210 | + return Err(ParseThresholdError::NoChildren); |
| 211 | + } |
| 212 | + |
| 213 | + if !self.args[0].args.is_empty() { |
| 214 | + return Err(ParseThresholdError::KNotTerminal); |
| 215 | + } |
| 216 | + |
| 217 | + let k = parse_num(self.args[0].name) |
| 218 | + .map_err(|e| ParseThresholdError::ParseK(e.to_string()))? as usize; |
| 219 | + Threshold::new(k, vec![(); self.args.len() - 1]).map_err(ParseThresholdError::Threshold) |
| 220 | + } |
188 | 221 | } |
189 | 222 |
|
190 | 223 | /// Filter out non-ASCII because we byte-index strings all over the |
|
0 commit comments