1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45/// The functions in this module are common for parsing AT commands and responses and the
6/// arguments contained in them.
7///
8/// The next_* functions take a Pairs, an iterator over all the child syntax
9/// nodes of a given syntactic element, and check to make sure the next element is of the
10/// correct type or Rule. The rest of the functions recursively convert untyped pest trees to
11/// the appropriate typed definition types.
12///
13/// Additionally, there are functions for parsing common scalars such as integers, strings and
14/// command names.
15use {
16 pest::{
17 error::Error as PestError,
18 iterators::{Pair, Pairs},
19 RuleType,
20 },
21 std::num::ParseIntError,
22 thiserror::Error,
23};
2425#[derive(Debug, Error)]
26pub enum ParseError<Rule: RuleType> {
27#[error("Unable to use pest to parse {string:?}: {pest_error:?}")]
28PestParseFailure { string: String, pest_error: PestError<Rule> },
29#[error("Expected one of {expected_rules:?}, got nothing.")]
30NextRuleMissing { expected_rules: Vec<Rule> },
31#[error("Expected one of {expected_rules:?}, got {actual_rule:?}.")]
32NextRuleUnexpected { expected_rules: Vec<Rule>, actual_rule: Rule },
33#[error("Unable to parse \"{string:?}\" as an integer: {error:?}.")]
34InvalidInteger { string: String, error: ParseIntError },
35#[error("Unknown character after AT: \"{0}\"")]
36UnknownExtensionCharacter(String),
37}
3839pub type ParseResult<T, R> = std::result::Result<T, Box<ParseError<R>>>;
4041/// Get the next Pair syntax node out of an iterator if it is matched by one of the expected Rules.
42/// Otherwise, fail.
43pub fn next_match_one_of<'a, Rule: RuleType>(
44 pairs: &mut Pairs<'a, Rule>,
45 expected_rules: Vec<Rule>,
46) -> ParseResult<Pair<'a, Rule>, Rule> {
47let pair_result = pairs.next();
48let pair = pair_result
49 .ok_or_else(|| ParseError::NextRuleMissing { expected_rules: expected_rules.clone() })?;
5051let pair_rule = pair.as_rule();
52if !expected_rules.contains(&pair_rule) {
53return Err(Box::new(ParseError::NextRuleUnexpected {
54 expected_rules: expected_rules,
55 actual_rule: pair_rule,
56 }));
57 }
5859Ok(pair)
60}
6162/// Get the next Pair syntax node out of an iterator if it is matched by the expected Rule.
63/// Otherwise, fail.
64pub fn next_match<'a, Rule: RuleType>(
65 pairs: &mut Pairs<'a, Rule>,
66 expected_rule: Rule,
67) -> ParseResult<Pair<'a, Rule>, Rule> {
68 next_match_one_of(pairs, vec![expected_rule])
69}
7071/// Get the next Pair syntax node out of an interator if it exists. If it doesn't exist, return
72/// None. If it does exist and is not matched by the specified Rule, fail.
73pub fn next_match_option<'a, Rule: RuleType>(
74 pairs: &mut Pairs<'a, Rule>,
75 expected_rule: Rule,
76) -> ParseResult<Option<Pair<'a, Rule>>, Rule> {
77if !pairs.peek().is_some() {
78Ok(None)
79 } else {
80 next_match(pairs, expected_rule).map(|pair| Some(pair))
81 }
82}
8384/// Continue getting the next Pair syntax node of the iterator as long as they are matched by the
85/// expected Rule. Return a vector of matching Pairs.
86pub fn next_match_rep<'a, Rule: RuleType>(
87 pairs: &mut Pairs<'a, Rule>,
88 expected_rule: Rule,
89) -> Vec<Pair<'a, Rule>> {
90let is_correct_rule = |pair_option: Option<Pair<'a, Rule>>| match pair_option {
91Some(pair) => pair.as_rule() == expected_rule,
92None => false,
93 };
9495let mut vector = Vec::new();
96while is_correct_rule(pairs.peek()) {
97let pair = pairs.next().unwrap();
98 vector.push(pair);
99 }
100101 vector
102}
103104/// Parse a pair to a string. The caller must ensure that this is actually matched by a
105/// rule that can be parsed to a valid AT command string.
106pub fn parse_string<Rule: RuleType>(string: Pair<'_, Rule>) -> ParseResult<String, Rule> {
107Ok(string.as_span().as_str().to_string())
108}
109110/// Parse a pair to a string. The caller must ensure that this is actually matched by a
111/// rule that can be parsed to a valid integer.
112pub fn parse_integer<Rule: RuleType>(integer: Pair<'_, Rule>) -> ParseResult<i64, Rule> {
113let str = integer.as_span().as_str();
114 str.parse()
115 .map_err(|err| Box::new(ParseError::InvalidInteger { string: str.to_string(), error: err }))
116}
117118/// Parse a pair to a string. The caller must ensure that this is actually matched by a
119/// rule that can be parsed to a valid AT command name.
120pub fn parse_name<Rule: RuleType>(name: Pair<'_, Rule>) -> ParseResult<String, Rule> {
121Ok(name.as_span().as_str().to_string())
122}