1use std::fmt;
4
5use crate::error::*;
6use crate::parser::*;
7use crate::splicer::Span;
8
9use enquote::unquote;
10use snafu::ResultExt;
11
12pub(crate) fn parse_string_array(array: Pair) -> Result<StringArray> {
15 let span = Span::from_pair(&array);
16 let mut elements = Vec::new();
17
18 for field in array.into_inner() {
19 match field.as_rule() {
20 Rule::string => {
21 elements.push(parse_string(&field)?);
22 },
23 Rule::comment => continue,
24 _ => return Err(unexpected_token(field))
25 }
26 }
27
28 Ok(StringArray {
29 span,
30 elements,
31 })
32}
33
34pub(crate) fn parse_string(field: &Pair) -> Result<SpannedString> {
35 let str_span = Span::from_pair(field);
36 let field_str = field.as_str();
37 let content = if matches!(field_str.chars().next(), Some('"' | '\'' | '`')) {
38 unquote(field_str).context(UnescapeError)?
39 } else {
40 field_str.to_string()
41 };
42
43 Ok(SpannedString {
44 span: str_span,
45 content,
46 })
47}
48
49pub(crate) fn clean_escaped_breaks(s: &str) -> String {
53 s.replace("\\\n", "")
54}
55
56#[derive(Debug, PartialEq, Eq, Clone)]
58pub enum ShellOrExecExpr {
59 Shell(BreakableString),
60 Exec(StringArray),
61}
62
63impl ShellOrExecExpr {
64 pub fn into_shell(self) -> Option<BreakableString> {
67 if let ShellOrExecExpr::Shell(s) = self {
68 Some(s)
69 } else {
70 None
71 }
72 }
73
74 pub fn as_shell(&self) -> Option<&BreakableString> {
77 if let ShellOrExecExpr::Shell(s) = self {
78 Some(s)
79 } else {
80 None
81 }
82 }
83
84 pub fn into_exec(self) -> Option<StringArray> {
87 if let ShellOrExecExpr::Exec(s) = self {
88 Some(s)
89 } else {
90 None
91 }
92 }
93
94 pub fn as_exec(&self) -> Option<&StringArray> {
97 if let ShellOrExecExpr::Exec(s) = self {
98 Some(s)
99 } else {
100 None
101 }
102 }
103}
104
105#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
107pub struct StringArray {
108 pub span: Span,
109 pub elements: Vec<SpannedString>,
110}
111
112impl StringArray {
113 pub fn as_str_vec(&self) -> Vec<&str> {
114 self.elements.iter().map(|c| c.as_ref()).collect()
115 }
116}
117
118#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
120pub struct SpannedComment {
121 pub span: Span,
122 pub content: String,
123}
124
125#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
127pub struct SpannedString {
128 pub span: Span,
129 pub content: String,
130}
131
132impl AsRef<str> for SpannedString {
133 fn as_ref(&self) -> &str {
134 &self.content
135 }
136}
137
138impl fmt::Display for SpannedString {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 self.content.fmt(f)
141 }
142}
143
144#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
146pub enum BreakableStringComponent {
147 String(SpannedString),
148 Comment(SpannedComment),
149}
150
151impl From<SpannedString> for BreakableStringComponent {
152 fn from(s: SpannedString) -> Self {
153 BreakableStringComponent::String(s)
154 }
155}
156
157impl From<((usize, usize), &str)> for BreakableStringComponent {
158 fn from(s: ((usize, usize), &str)) -> Self {
159 let ((start, end), content) = s;
160
161 BreakableStringComponent::String(SpannedString {
162 span: (start, end).into(),
163 content: content.to_string(),
164 })
165 }
166}
167
168impl From<SpannedComment> for BreakableStringComponent {
169 fn from(c: SpannedComment) -> Self {
170 BreakableStringComponent::Comment(c)
171 }
172}
173
174#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
187pub struct BreakableString {
188 pub span: Span,
189 pub components: Vec<BreakableStringComponent>,
190}
191
192impl fmt::Display for BreakableString {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 for component in &self.components {
197 if let BreakableStringComponent::String(s) = &component {
198 write!(f, "{}", s.content)?;
199 }
200 }
201
202 Ok(())
203 }
204}
205
206impl BreakableString {
207 pub fn new(span: impl Into<Span>) -> Self {
208 BreakableString {
209 span: span.into(),
210 components: Vec::new(),
211 }
212 }
213
214 pub fn add(mut self, c: impl Into<BreakableStringComponent>) -> Self {
215 self.components.push(c.into());
216
217 self
218 }
219
220 pub fn add_string(mut self, s: impl Into<Span>, c: impl Into<String>) -> Self {
221 self.components.push(SpannedString {
222 span: s.into(),
223 content: c.into(),
224 }.into());
225
226 self
227 }
228
229 pub fn add_comment(mut self, s: impl Into<Span>, c: impl Into<String>) -> Self {
230 self.components.push(SpannedComment {
231 span: s.into(),
232 content: c.into(),
233 }.into());
234
235 self
236 }
237
238 pub fn iter_components(&self) -> impl Iterator<Item = &BreakableStringComponent> {
239 self.components.iter()
240 }
241}
242
243impl From<((usize, usize), &str)> for BreakableString {
244 fn from(s: ((usize, usize), &str)) -> Self {
245 let ((start, end), content) = s;
246
247 BreakableString::new((start, end))
248 .add_string((start, end), content)
249 }
250}
251
252fn parse_any_breakable_inner(pair: Pair) -> Result<Vec<BreakableStringComponent>> {
253 let mut components = Vec::new();
254
255 for field in pair.into_inner() {
256 match field.as_rule() {
257 Rule::any_breakable => components.extend(parse_any_breakable_inner(field)?),
258 Rule::comment => components.push(SpannedComment {
259 span: (&field).into(),
260 content: field.as_str().to_string(),
261 }.into()),
262 Rule::any_content => components.push(SpannedString {
263 span: (&field).into(),
264 content: field.as_str().to_string(),
265 }.into()),
266 _ => return Err(unexpected_token(field))
267 }
268 }
269
270 Ok(components)
271}
272
273pub(crate) fn parse_any_breakable(pair: Pair) -> Result<BreakableString> {
274 Ok(BreakableString {
275 span: (&pair).into(),
276 components: parse_any_breakable_inner(pair)?,
277 })
278}