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.
45/// The functions in this module convert the untyped pest Pair syntax nodes to typed AT command argument nodes.
6///
7/// The types in the arguments module represent the arguments of either AT commands and responses. However, the
8/// pest grammar macros generate different Rule types for the arguments of AT commands or responses. Thus, the
9/// argument parser must be abstracted over the Rule types. In addition, the actual enum variants of the Rule
10/// type differ between different generated macros, so we also abstract over the Rule enum values by storing them
11/// in a struct.
12///
13/// These functions should not fail, but report failures from the next_* methods if the
14/// expected element is not found. This should only happen if the code here does not correctly
15/// match the parse tree defined in argument_grammar.rs.
16use {
17crate::{
18 lowlevel::{Argument, Arguments, DelimitedArguments},
19 parser::common::{
20 next_match, next_match_one_of, next_match_option, next_match_rep, parse_string,
21 ParseResult,
22 },
23 },
24 pest::{iterators::Pair, RuleType},
25};
2627pub struct ArgumentsParser<Rule: RuleType> {
28pub argument_list: Rule,
29pub argument: Rule,
30pub arguments: Rule,
31pub key_value_argument: Rule,
32pub optional_argument_delimiter: Rule,
33pub optional_argument_terminator: Rule,
34pub parenthesized_argument_lists: Rule,
35pub primitive_argument: Rule,
36}
3738impl<Rule: RuleType> ArgumentsParser<Rule> {
39#[allow(clippy::large_result_err)]
40pub fn parse_delimited_arguments(
41&self,
42 delimited_arguments: Pair<'_, Rule>,
43 ) -> ParseResult<DelimitedArguments, Rule> {
44let mut delimited_arguments_elements = delimited_arguments.into_inner();
4546let delimited_argument_delimiter_option =
47 next_match_option(&mut delimited_arguments_elements, self.optional_argument_delimiter)?;
48let parsed_delimited_argument_delimiter_option = match delimited_argument_delimiter_option {
49Some(delimiter) => {
50let string = parse_string(delimiter)?;
51 (!string.is_empty()).then_some(string)
52 }
53None => None,
54 };
5556let arguments = next_match(&mut delimited_arguments_elements, self.arguments)?;
57let parsed_arguments = self.parse_arguments(arguments)?;
5859let delimited_argument_terminator_option = next_match_option(
60&mut delimited_arguments_elements,
61self.optional_argument_terminator,
62 )?;
63let parsed_delimited_argument_terminator_option = match delimited_argument_terminator_option
64 {
65Some(terminator) => {
66let string = parse_string(terminator)?;
67 (!string.is_empty()).then_some(string)
68 }
69None => None,
70 };
7172Ok(DelimitedArguments {
73 delimiter: parsed_delimited_argument_delimiter_option,
74 arguments: parsed_arguments,
75 terminator: parsed_delimited_argument_terminator_option,
76 })
77 }
7879fn parse_arguments(&self, arguments: Pair<'_, Rule>) -> ParseResult<Arguments, Rule> {
80let mut arguments_elements = arguments.into_inner();
81let arguments_variant = next_match_one_of(
82&mut arguments_elements,
83vec![self.parenthesized_argument_lists, self.argument_list],
84 )?;
85let arguments_variant_rule = arguments_variant.as_rule();
86let parsed_arguments = if arguments_variant_rule == self.parenthesized_argument_lists {
87self.parse_parenthesized_argument_lists(arguments_variant)?
88} else if arguments_variant_rule == self.argument_list {
89self.parse_argument_list(arguments_variant)?
90} else {
91// This is unreachable since next_match_one_of only returns success if one of the rules
92 // passed into it matches; otherwise it returns Err and this method will return early
93 // before reaching this point.
94unreachable!()
95 };
9697Ok(parsed_arguments)
98 }
99100fn parse_parenthesized_argument_lists(
101&self,
102 parenthesized_argument_lists: Pair<'_, Rule>,
103 ) -> ParseResult<Arguments, Rule> {
104let mut parenthesized_argument_lists_elements = parenthesized_argument_lists.into_inner();
105let argument_list_vec =
106 next_match_rep(&mut parenthesized_argument_lists_elements, self.argument_list);
107108let parsed_argument_list_vec = argument_list_vec
109 .into_iter()
110 .map(|argument_list_pair| self.parse_argument_list_to_vec(argument_list_pair))
111 .collect::<ParseResult<Vec<Vec<Argument>>, Rule>>()?;
112113Ok(Arguments::ParenthesisDelimitedArgumentLists(parsed_argument_list_vec))
114 }
115116fn parse_argument_list(&self, argument_list: Pair<'_, Rule>) -> ParseResult<Arguments, Rule> {
117let parsed_argument_list = self.parse_argument_list_to_vec(argument_list)?;
118Ok(Arguments::ArgumentList(parsed_argument_list))
119 }
120121fn parse_argument_list_to_vec(
122&self,
123 argument_list: Pair<'_, Rule>,
124 ) -> ParseResult<Vec<Argument>, Rule> {
125let mut argument_list_elements = argument_list.into_inner();
126let argument_vec = next_match_rep(&mut argument_list_elements, self.argument);
127128let parsed_argument_vec = argument_vec
129 .into_iter()
130 .map(|argument_pair| self.parse_argument(argument_pair))
131 .collect::<ParseResult<Vec<Argument>, Rule>>()?;
132133// This is a hack. There's no way for the parser to tell if "AT+CMD=" contains zero
134 // arguments or one empty argument. The parser eagerly assumes that it's one empty
135 // argument. However, if the AT command definition expects zero arguments this is an
136 // error. On the other hand, missing optional argunments at the end of an AT command
137 // are considered empty. Forcing this to be zero arguments here allows the raise step
138 // to handle both the zero arguments case and the empty optional argument case.
139let parsed_argument_vec_maybe_empty =
140if parsed_argument_vec == vec![Argument::PrimitiveArgument(String::from(""))] {
141 Vec::new()
142 } else {
143 parsed_argument_vec
144 };
145146Ok(parsed_argument_vec_maybe_empty)
147 }
148149fn parse_argument(&self, argument: Pair<'_, Rule>) -> ParseResult<Argument, Rule> {
150let mut argument_elements = argument.into_inner();
151152let argument_variant = next_match_one_of(
153&mut argument_elements,
154vec![self.key_value_argument, self.primitive_argument],
155 )?;
156157let argument_variant_rule = argument_variant.as_rule();
158let parsed_argument = if argument_variant_rule == self.key_value_argument {
159self.parse_key_value_argument(argument_variant)?
160} else if argument_variant_rule == self.primitive_argument {
161 Argument::PrimitiveArgument(parse_string(argument_variant)?)
162 } else {
163// This is unreachable since next_match_one_of only returns success if one of the rules
164 // passed into it matches; otherwise it returns Err and this method will return early
165 // before reaching this point.
166unreachable!()
167 };
168169Ok(parsed_argument)
170 }
171172fn parse_key_value_argument(
173&self,
174 key_value_argument: Pair<'_, Rule>,
175 ) -> ParseResult<Argument, Rule> {
176let mut argument_elements = key_value_argument.into_inner();
177178let key = next_match(&mut argument_elements, self.primitive_argument)?;
179let parsed_key = parse_string(key)?;
180181let value = next_match(&mut argument_elements, self.primitive_argument)?;
182let parsed_value = parse_string(value)?;
183184Ok(Argument::KeyValueArgument { key: parsed_key, value: parsed_value })
185 }
186}