at_commands/parser/
response_parser.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/// The functions in this module convert the untyped pest Pair syntax nodes to typed AT response AST nodes.
///
/// These functions should not fail, but report failures from the next_* methods if the
/// expected element is not found.  This should only happen if the code here does not correctly
/// match the parse tree defined in response_grammar.rs.
use {
    crate::lowlevel::{HardcodedError, Response},
    crate::parser::{
        arguments_parser::ArgumentsParser,
        common::{
            next_match, next_match_one_of, parse_integer, parse_name, parse_string, ParseError,
            ParseResult,
        },
        response_grammar::{Grammar, Rule},
    },
    pest::{iterators::Pair, Parser},
};

static ARGUMENTS_PARSER: ArgumentsParser<Rule> = ArgumentsParser {
    argument_list: Rule::argument_list,
    argument: Rule::argument,
    arguments: Rule::arguments,
    key_value_argument: Rule::key_value_argument,
    optional_argument_delimiter: Rule::optional_argument_delimiter,
    optional_argument_terminator: Rule::optional_argument_terminator,
    parenthesized_argument_lists: Rule::parenthesized_argument_lists,
    primitive_argument: Rule::primitive_argument,
};

pub fn parse(string: &String) -> ParseResult<Response, Rule> {
    let mut parsed = Grammar::parse(Rule::input, string).map_err(|pest_error| {
        ParseError::PestParseFailure { string: string.clone(), pest_error }
    })?;

    let input = next_match(&mut parsed, Rule::input)?;
    let mut input_elements = input.into_inner();
    let response = next_match(&mut input_elements, Rule::response)?;

    parse_response(response)
}

fn parse_response(response: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
    let mut response_elements = response.into_inner();
    let response_variant = next_match_one_of(
        &mut response_elements,
        vec![Rule::ok, Rule::error, Rule::hardcoded_error, Rule::cme_error, Rule::success],
    )?;

    let parsed_response = match response_variant.as_rule() {
        Rule::ok => Response::Ok,
        Rule::error => Response::Error,
        Rule::hardcoded_error => parse_hardcoded_error(response_variant)?,
        Rule::cme_error => parse_cme_error(response_variant)?,
        Rule::success => parse_success(response_variant)?,
        // This is unreachable since next_match_one_of only returns success if one of the rules
        // passed into it matches; otherwise it returns Err and this method will return early
        // before reaching this point.
        _ => unreachable!(),
    };

    Ok(parsed_response)
}

fn parse_hardcoded_error(hardcoded_error: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
    let error_string = parse_string(hardcoded_error)?;

    let parsed_error = match error_string.as_str() {
        "NO CARRIER" => HardcodedError::NoCarrier,
        "BUSY" => HardcodedError::Busy,
        "NO ANSWER" => HardcodedError::NoAnswer,
        "DELAYED" => HardcodedError::Delayed,
        "BLACKLIST" => HardcodedError::Blacklist,
        // This is unreachable since these are the only strings that match the harcoded_error rule.
        // For parse_response to call this method, hardcoded_error must have matched this span of the
        // parsed response, so only the above strings are possible matches.
        _ => unreachable!(),
    };

    Ok(Response::HardcodedError(parsed_error))
}

fn parse_cme_error(cme_error: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
    let mut cme_error_elements = cme_error.into_inner();

    let error_code = next_match(&mut cme_error_elements, Rule::integer)?;
    let parsed_error_code = parse_integer(error_code)?;

    Ok(Response::CmeError(parsed_error_code))
}

fn parse_success(success: Pair<'_, Rule>) -> ParseResult<Response, Rule> {
    let mut success_elements = success.into_inner();

    let optional_extension = next_match(&mut success_elements, Rule::optional_extension)?;
    let parsed_optional_extension = parse_optional_extension(optional_extension)?;

    let name = next_match(&mut success_elements, Rule::command_name)?;
    let parsed_name = parse_name(name)?;

    let delimited_arguments = next_match(&mut success_elements, Rule::delimited_arguments)?;
    let parsed_delimited_arguments =
        ARGUMENTS_PARSER.parse_delimited_arguments(delimited_arguments)?;

    Ok(Response::Success {
        name: parsed_name,
        is_extension: parsed_optional_extension,
        arguments: parsed_delimited_arguments,
    })
}

fn parse_optional_extension(optional_extension: Pair<'_, Rule>) -> ParseResult<bool, Rule> {
    let extension_str = optional_extension.as_span().as_str();

    match extension_str {
        "" => Ok(false),
        "+" => Ok(true),
        c => Err(ParseError::UnknownExtensionCharacter(c.to_string())),
    }
}