at_commands/parser/
response_parser.rs

1// Copyright 2020 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.
4
5/// The functions in this module convert the untyped pest Pair syntax nodes to typed AT response AST nodes.
6///
7/// These functions should not fail, but report failures from the next_* methods if the
8/// expected element is not found.  This should only happen if the code here does not correctly
9/// match the parse tree defined in response_grammar.rs.
10use {
11    crate::lowlevel::{HardcodedError, Response},
12    crate::parser::{
13        arguments_parser::ArgumentsParser,
14        common::{
15            next_match, next_match_one_of, parse_integer, parse_name, parse_string, ParseError,
16            ParseResult,
17        },
18        response_grammar::{Grammar, Rule},
19    },
20    pest::{iterators::Pair, Parser},
21};
22
23static ARGUMENTS_PARSER: ArgumentsParser<Rule> = ArgumentsParser {
24    argument_list: Rule::argument_list,
25    argument: Rule::argument,
26    arguments: Rule::arguments,
27    key_value_argument: Rule::key_value_argument,
28    optional_argument_delimiter: Rule::optional_argument_delimiter,
29    optional_argument_terminator: Rule::optional_argument_terminator,
30    parenthesized_argument_lists: Rule::parenthesized_argument_lists,
31    primitive_argument: Rule::primitive_argument,
32};
33
34pub fn parse(string: &str) -> ParseResult<Response, Rule> {
35    let mut parsed = Grammar::parse(Rule::input, string)
36        .map_err(|pest_error| ParseError::PestParseFailure { string: string.into(), pest_error })?;
37
38    let input = next_match(&mut parsed, Rule::input)?;
39    let mut input_elements = input.into_inner();
40    let response = next_match(&mut input_elements, Rule::response)?;
41
42    parse_response(response)
43}
44
45fn parse_response(response: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
46    let mut response_elements = response.into_inner();
47    let response_variant = next_match_one_of(
48        &mut response_elements,
49        vec![Rule::ok, Rule::error, Rule::hardcoded_error, Rule::cme_error, Rule::success],
50    )?;
51
52    let parsed_response = match response_variant.as_rule() {
53        Rule::ok => Response::Ok,
54        Rule::error => Response::Error,
55        Rule::hardcoded_error => parse_hardcoded_error(response_variant)?,
56        Rule::cme_error => parse_cme_error(response_variant)?,
57        Rule::success => parse_success(response_variant)?,
58        // This is unreachable since next_match_one_of only returns success if one of the rules
59        // passed into it matches; otherwise it returns Err and this method will return early
60        // before reaching this point.
61        _ => unreachable!(),
62    };
63
64    Ok(parsed_response)
65}
66
67fn parse_hardcoded_error(hardcoded_error: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
68    let error_string = parse_string(hardcoded_error)?;
69
70    let parsed_error = match error_string.as_str() {
71        "NO CARRIER" => HardcodedError::NoCarrier,
72        "BUSY" => HardcodedError::Busy,
73        "NO ANSWER" => HardcodedError::NoAnswer,
74        "DELAYED" => HardcodedError::Delayed,
75        "BLACKLIST" => HardcodedError::Blacklist,
76        // This is unreachable since these are the only strings that match the harcoded_error rule.
77        // For parse_response to call this method, hardcoded_error must have matched this span of the
78        // parsed response, so only the above strings are possible matches.
79        _ => unreachable!(),
80    };
81
82    Ok(Response::HardcodedError(parsed_error))
83}
84
85fn parse_cme_error(cme_error: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
86    let mut cme_error_elements = cme_error.into_inner();
87
88    let error_code = next_match(&mut cme_error_elements, Rule::integer)?;
89    let parsed_error_code = parse_integer(error_code)?;
90
91    Ok(Response::CmeError(parsed_error_code))
92}
93
94fn parse_success(success: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
95    let mut success_elements = success.into_inner();
96
97    let optional_extension = next_match(&mut success_elements, Rule::optional_extension)?;
98    let parsed_optional_extension = parse_optional_extension(optional_extension)?;
99
100    let name = next_match(&mut success_elements, Rule::command_name)?;
101    let parsed_name = parse_name(name)?;
102
103    let delimited_arguments = next_match(&mut success_elements, Rule::delimited_arguments)?;
104    let parsed_delimited_arguments =
105        ARGUMENTS_PARSER.parse_delimited_arguments(delimited_arguments)?;
106
107    Ok(Response::Success {
108        name: parsed_name,
109        is_extension: parsed_optional_extension,
110        arguments: parsed_delimited_arguments,
111    })
112}
113
114fn parse_optional_extension(optional_extension: Pair<'_, Rule>) -> ParseResult<bool, Rule> {
115    let extension_str = optional_extension.as_span().as_str();
116
117    match extension_str {
118        "" => Ok(false),
119        "+" => Ok(true),
120        c => Err(ParseError::UnknownExtensionCharacter(c.to_string()).into()),
121    }
122}