conch_parser/ast/builder/
default_builder.rs

1use ast::*;
2use ast::builder::*;
3use std::default::Default;
4use std::fmt;
5use std::marker::PhantomData;
6use std::rc::Rc;
7use std::sync::Arc;
8use void::Void;
9
10/// A macro for defining a default builder, its boilerplate, and delegating
11/// the `Builder` trait to its respective `CoreBuilder` type.
12///
13/// This allows us to create concrete atomic/non-atomic builders which
14/// wrap a concrete `CoreBuilder` implementation so we can hide its type
15/// complexity from the consumer.
16///
17/// We could accomplish this by using a public type alias to the private
18/// builder type, however, rustdoc will only generate docs for the alias
19/// definition is, and the docs for the inner builder will be rendered in
20/// their entire complexity.
21// FIXME: might be good to revisit this complexity/indirection
22macro_rules! default_builder {
23    ($(#[$attr:meta])*
24     pub struct $Builder:ident,
25     $CoreBuilder:ident,
26     $Word:ident,
27     $Cmd:ident,
28     $PipeableCmd:ident,
29    ) => {
30        $(#[$attr])*
31        pub struct $Builder<T>($CoreBuilder<T, $Word<T>, $Cmd<T>>);
32
33        impl<T> $Builder<T> {
34            /// Constructs a builder.
35            pub fn new() -> Self {
36                $Builder($CoreBuilder::new())
37            }
38        }
39
40        impl<T> fmt::Debug for $Builder<T> {
41            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
42                fmt.debug_struct(stringify!($Builder))
43                    .finish()
44            }
45        }
46
47        impl<T> Default for $Builder<T> {
48            fn default() -> Self {
49                Self::new()
50            }
51        }
52
53        // See https://github.com/Manishearth/rust-clippy/issues/1254
54        #[cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy))]
55        impl<T> Clone for $Builder<T> {
56            fn clone(&self) -> Self {
57                *self
58            }
59        }
60
61        impl<T> Copy for $Builder<T> {}
62
63        impl<T: From<String>> Builder for $Builder<T> {
64            type Command         = $Cmd<T>;
65            type CommandList     = AndOrList<Self::ListableCommand>;
66            type ListableCommand = ListableCommand<Self::PipeableCommand>;
67            type PipeableCommand = $PipeableCmd<T, Self::Word, Self::Command>;
68            type CompoundCommand = ShellCompoundCommand<T, Self::Word, Self::Command>;
69            type Word            = $Word<T>;
70            type Redirect        = Redirect<Self::Word>;
71            type Error           = Void;
72
73            fn complete_command(&mut self,
74                                pre_cmd_comments: Vec<Newline>,
75                                list: Self::CommandList,
76                                separator: SeparatorKind,
77                                cmd_comment: Option<Newline>)
78                -> Result<Self::Command, Self::Error>
79            {
80                self.0.complete_command(pre_cmd_comments, list, separator, cmd_comment)
81            }
82
83            fn and_or_list(&mut self,
84                      first: Self::ListableCommand,
85                      rest: Vec<(Vec<Newline>, AndOr<Self::ListableCommand>)>)
86                -> Result<Self::CommandList, Self::Error>
87            {
88                self.0.and_or_list(first, rest)
89            }
90
91            fn pipeline(&mut self,
92                        bang: bool,
93                        cmds: Vec<(Vec<Newline>, Self::PipeableCommand)>)
94                -> Result<Self::ListableCommand, Self::Error>
95            {
96                self.0.pipeline(bang, cmds)
97            }
98
99            fn simple_command(
100                &mut self,
101                redirects_or_env_vars: Vec<RedirectOrEnvVar<Self::Redirect, String, Self::Word>>,
102                redirects_or_cmd_words: Vec<RedirectOrCmdWord<Self::Redirect, Self::Word>>
103            ) -> Result<Self::PipeableCommand, Self::Error>
104            {
105                self.0.simple_command(redirects_or_env_vars, redirects_or_cmd_words)
106            }
107
108            fn brace_group(&mut self,
109                           cmds: CommandGroup<Self::Command>,
110                           redirects: Vec<Self::Redirect>)
111                -> Result<Self::CompoundCommand, Self::Error>
112            {
113                self.0.brace_group(cmds, redirects)
114            }
115
116            fn subshell(&mut self,
117                        cmds: CommandGroup<Self::Command>,
118                        redirects: Vec<Self::Redirect>)
119                -> Result<Self::CompoundCommand, Self::Error>
120            {
121                self.0.subshell(cmds, redirects)
122            }
123
124            fn loop_command(&mut self,
125                            kind: LoopKind,
126                            guard_body_pair: GuardBodyPairGroup<Self::Command>,
127                            redirects: Vec<Self::Redirect>)
128                -> Result<Self::CompoundCommand, Self::Error>
129            {
130                self.0.loop_command(kind, guard_body_pair, redirects)
131            }
132
133            fn if_command(&mut self,
134                          fragments: IfFragments<Self::Command>,
135                          redirects: Vec<Self::Redirect>)
136                -> Result<Self::CompoundCommand, Self::Error>
137            {
138                self.0.if_command(fragments, redirects)
139            }
140
141            fn for_command(&mut self,
142                           fragments: ForFragments<Self::Word, Self::Command>,
143                           redirects: Vec<Self::Redirect>)
144                -> Result<Self::CompoundCommand, Self::Error>
145            {
146                self.0.for_command(fragments, redirects)
147            }
148
149            fn case_command(&mut self,
150                            fragments: CaseFragments<Self::Word, Self::Command>,
151                            redirects: Vec<Self::Redirect>)
152                -> Result<Self::CompoundCommand, Self::Error>
153            {
154                self.0.case_command(fragments, redirects)
155            }
156
157            fn compound_command_into_pipeable(&mut self,
158                                              cmd: Self::CompoundCommand)
159                -> Result<Self::PipeableCommand, Self::Error>
160            {
161                self.0.compound_command_into_pipeable(cmd)
162            }
163
164            fn function_declaration(&mut self,
165                                    name: String,
166                                    post_name_comments: Vec<Newline>,
167                                    body: Self::CompoundCommand)
168                -> Result<Self::PipeableCommand, Self::Error>
169            {
170                self.0.function_declaration(name, post_name_comments, body)
171            }
172
173            fn comments(&mut self,
174                        comments: Vec<Newline>)
175                -> Result<(), Self::Error>
176            {
177                self.0.comments(comments)
178            }
179
180            fn word(&mut self,
181                    kind: ComplexWordKind<Self::Command>)
182                -> Result<Self::Word, Self::Error>
183            {
184                self.0.word(kind)
185            }
186
187            fn redirect(&mut self,
188                        kind: RedirectKind<Self::Word>)
189                -> Result<Self::Redirect, Self::Error>
190            {
191                self.0.redirect(kind)
192            }
193        }
194    };
195}
196
197type RcCoreBuilder<T, W, C> = CoreBuilder<T, W, C, Rc<ShellCompoundCommand<T, W, C>>>;
198type ArcCoreBuilder<T, W, C> = CoreBuilder<T, W, C, Arc<ShellCompoundCommand<T, W, C>>>;
199
200default_builder! {
201    /// A `Builder` implementation which builds shell commands
202    /// using the (non-atomic) AST definitions in the `ast` module.
203    pub struct DefaultBuilder,
204    RcCoreBuilder,
205    TopLevelWord,
206    TopLevelCommand,
207    ShellPipeableCommand,
208}
209
210default_builder! {
211    /// A `Builder` implementation which builds shell commands
212    /// using the (atomic) AST definitions in the `ast` module.
213    pub struct AtomicDefaultBuilder,
214    ArcCoreBuilder,
215    AtomicTopLevelWord,
216    AtomicTopLevelCommand,
217    AtomicShellPipeableCommand,
218}
219
220/// A `DefaultBuilder` implementation which uses regular `String`s when
221/// representing shell words.
222pub type StringBuilder = DefaultBuilder<String>;
223
224/// A `DefaultBuilder` implementation which uses `Rc<String>`s when
225/// representing shell words.
226pub type RcBuilder = DefaultBuilder<Rc<String>>;
227
228/// A `DefaultBuilder` implementation which uses `Arc<String>`s when
229/// representing shell words.
230pub type ArcBuilder = AtomicDefaultBuilder<Arc<String>>;
231
232/// The actual provided `Builder` implementation.
233/// The various type parameters are used to swap out atomic/non-atomic AST versions.
234pub struct CoreBuilder<T, W, C, F> {
235    phantom_data: PhantomData<(T, W, C, F)>,
236}
237
238impl<T, W, C, F> fmt::Debug for CoreBuilder<T, W, C, F> {
239    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
240        fmt.debug_struct("CoreBuilder")
241            .finish()
242    }
243}
244
245// See https://github.com/Manishearth/rust-clippy/issues/1254
246#[cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy))]
247impl<T, W, C, F> Clone for CoreBuilder<T, W, C, F> {
248    fn clone(&self) -> Self {
249        *self
250    }
251}
252
253impl<T, W, C, F> Copy for CoreBuilder<T, W, C, F> {}
254
255impl<T, W, C, F> Default for CoreBuilder<T, W, C, F> {
256    fn default() -> Self {
257        Self::new()
258    }
259}
260
261impl<T, W, C, F> CoreBuilder<T, W, C, F> {
262    /// Constructs a builder.
263    pub fn new() -> Self {
264        CoreBuilder {
265            phantom_data: PhantomData,
266        }
267    }
268}
269
270type BuilderPipeableCommand<T, W, C, F> = PipeableCommand<
271    T,
272    Box<SimpleCommand<T, W, Redirect<W>>>,
273    Box<ShellCompoundCommand<T, W, C>>,
274    F,
275>;
276
277impl<T, W, C, F> Builder for CoreBuilder<T, W, C, F>
278    where T: From<String>,
279          W: From<ShellWord<T, W, C>>,
280          C: From<Command<AndOrList<ListableCommand<BuilderPipeableCommand<T, W, C, F>>>>>,
281          F: From<ShellCompoundCommand<T, W, C>>,
282{
283    type Command         = C;
284    type CommandList     = AndOrList<Self::ListableCommand>;
285    type ListableCommand = ListableCommand<Self::PipeableCommand>;
286    type PipeableCommand = BuilderPipeableCommand<T, W, C, F>;
287    type CompoundCommand = ShellCompoundCommand<T, Self::Word, Self::Command>;
288    type Word            = W;
289    type Redirect        = Redirect<Self::Word>;
290    type Error           = Void;
291
292    /// Constructs a `Command::Job` node with the provided inputs if the command
293    /// was delimited by an ampersand or the command itself otherwise.
294    fn complete_command(&mut self,
295                        _pre_cmd_comments: Vec<Newline>,
296                        list: Self::CommandList,
297                        separator: SeparatorKind,
298                        _cmd_comment: Option<Newline>)
299        -> Result<Self::Command, Self::Error>
300    {
301        let cmd = match separator {
302            SeparatorKind::Semi  |
303            SeparatorKind::Other |
304            SeparatorKind::Newline => Command::List(list),
305            SeparatorKind::Amp => Command::Job(list),
306        };
307
308        Ok(cmd.into())
309    }
310
311    /// Constructs a `Command::List` node with the provided inputs.
312    fn and_or_list(&mut self,
313              first: Self::ListableCommand,
314              rest: Vec<(Vec<Newline>, AndOr<Self::ListableCommand>)>)
315        -> Result<Self::CommandList, Self::Error>
316    {
317        Ok(AndOrList {
318            first: first,
319            rest: rest.into_iter().map(|(_, c)| c).collect(),
320        })
321    }
322
323    /// Constructs a `Command::Pipe` node with the provided inputs or a `Command::Simple`
324    /// node if only a single command with no status inversion is supplied.
325    fn pipeline(&mut self,
326                bang: bool,
327                cmds: Vec<(Vec<Newline>, Self::PipeableCommand)>)
328        -> Result<Self::ListableCommand, Self::Error>
329    {
330        debug_assert_eq!(cmds.is_empty(), false);
331        let mut cmds: Vec<_> = cmds.into_iter().map(|(_, c)| c).collect();
332
333        // Pipe is the only AST node which allows for a status
334        // negation, so we are forced to use it even if we have a single
335        // command. Otherwise there is no need to wrap it further.
336        if bang || cmds.len() > 1 {
337            cmds.shrink_to_fit();
338            Ok(ListableCommand::Pipe(bang, cmds))
339        } else {
340            Ok(ListableCommand::Single(cmds.pop().unwrap()))
341        }
342    }
343
344    /// Constructs a `Command::Simple` node with the provided inputs.
345    fn simple_command(
346        &mut self,
347        redirects_or_env_vars: Vec<RedirectOrEnvVar<Self::Redirect, String, Self::Word>>,
348        mut redirects_or_cmd_words: Vec<RedirectOrCmdWord<Self::Redirect, Self::Word>>
349    ) -> Result<Self::PipeableCommand, Self::Error>
350    {
351        let redirects_or_env_vars = redirects_or_env_vars.into_iter()
352            .map(|roev| match roev {
353                RedirectOrEnvVar::Redirect(red) => RedirectOrEnvVar::Redirect(red),
354                RedirectOrEnvVar::EnvVar(k, v) => RedirectOrEnvVar::EnvVar(k.into(), v),
355            })
356            .collect();
357
358        redirects_or_cmd_words.shrink_to_fit();
359
360        Ok(PipeableCommand::Simple(Box::new(SimpleCommand {
361            redirects_or_env_vars: redirects_or_env_vars,
362            redirects_or_cmd_words: redirects_or_cmd_words,
363        })))
364    }
365
366    /// Constructs a `CompoundCommand::Brace` node with the provided inputs.
367    fn brace_group(&mut self,
368                   cmd_group: CommandGroup<Self::Command>,
369                   mut redirects: Vec<Self::Redirect>)
370        -> Result<Self::CompoundCommand, Self::Error>
371    {
372        let mut cmds = cmd_group.commands;
373        cmds.shrink_to_fit();
374        redirects.shrink_to_fit();
375        Ok(CompoundCommand {
376            kind: CompoundCommandKind::Brace(cmds),
377            io: redirects,
378        })
379    }
380
381    /// Constructs a `CompoundCommand::Subshell` node with the provided inputs.
382    fn subshell(&mut self,
383                cmd_group: CommandGroup<Self::Command>,
384                mut redirects: Vec<Self::Redirect>)
385        -> Result<Self::CompoundCommand, Self::Error>
386    {
387        let mut cmds = cmd_group.commands;
388        cmds.shrink_to_fit();
389        redirects.shrink_to_fit();
390        Ok(CompoundCommand {
391            kind: CompoundCommandKind::Subshell(cmds),
392            io: redirects,
393        })
394    }
395
396    /// Constructs a `CompoundCommand::Loop` node with the provided inputs.
397    fn loop_command(&mut self,
398                    kind: LoopKind,
399                    guard_body_pair: GuardBodyPairGroup<Self::Command>,
400                    mut redirects: Vec<Self::Redirect>)
401        -> Result<Self::CompoundCommand, Self::Error>
402    {
403        let mut guard = guard_body_pair.guard.commands;
404        let mut body = guard_body_pair.body.commands;
405
406        guard.shrink_to_fit();
407        body.shrink_to_fit();
408        redirects.shrink_to_fit();
409
410        let guard_body_pair = GuardBodyPair {
411            guard: guard,
412            body: body,
413        };
414
415        let loop_cmd = match kind {
416            LoopKind::While => CompoundCommandKind::While(guard_body_pair),
417            LoopKind::Until => CompoundCommandKind::Until(guard_body_pair),
418        };
419
420        Ok(CompoundCommand {
421            kind: loop_cmd,
422            io: redirects,
423        })
424    }
425
426    /// Constructs a `CompoundCommand::If` node with the provided inputs.
427    fn if_command(&mut self,
428                  fragments: IfFragments<Self::Command>,
429                  mut redirects: Vec<Self::Redirect>)
430        -> Result<Self::CompoundCommand, Self::Error>
431    {
432        let IfFragments { conditionals, else_branch } = fragments;
433
434        let conditionals = conditionals.into_iter()
435            .map(|gbp| {
436                let mut guard = gbp.guard.commands;
437                let mut body = gbp.body.commands;
438
439                guard.shrink_to_fit();
440                body.shrink_to_fit();
441
442                GuardBodyPair {
443                    guard: guard,
444                    body: body,
445                }
446            })
447            .collect();
448
449        let else_branch = else_branch.map(|CommandGroup { commands: mut els, .. }| {
450            els.shrink_to_fit();
451            els
452        });
453
454        redirects.shrink_to_fit();
455
456        Ok(CompoundCommand {
457            kind: CompoundCommandKind::If {
458                conditionals: conditionals,
459                else_branch: else_branch,
460            },
461            io: redirects,
462        })
463    }
464
465    /// Constructs a `CompoundCommand::For` node with the provided inputs.
466    fn for_command(&mut self,
467                   fragments: ForFragments<Self::Word, Self::Command>,
468                   mut redirects: Vec<Self::Redirect>)
469        -> Result<Self::CompoundCommand, Self::Error>
470    {
471        let words = fragments.words.map(|(_, mut words, _)| {
472            words.shrink_to_fit();
473            words
474        });
475
476        let mut body = fragments.body.commands;
477        body.shrink_to_fit();
478        redirects.shrink_to_fit();
479
480        Ok(CompoundCommand {
481            kind: CompoundCommandKind::For {
482                var: fragments.var.into(),
483                words: words,
484                body: body,
485            },
486            io: redirects
487        })
488    }
489
490    /// Constructs a `CompoundCommand::Case` node with the provided inputs.
491    fn case_command(&mut self,
492                    fragments: CaseFragments<Self::Word, Self::Command>,
493                    mut redirects: Vec<Self::Redirect>)
494        -> Result<Self::CompoundCommand, Self::Error>
495    {
496        let arms = fragments.arms.into_iter().map(|arm| {
497            let mut patterns = arm.patterns.pattern_alternatives;
498            patterns.shrink_to_fit();
499
500            let mut body = arm.body.commands;
501            body.shrink_to_fit();
502
503            PatternBodyPair {
504                patterns: patterns,
505                body: body,
506            }
507        }).collect();
508
509        redirects.shrink_to_fit();
510        Ok(CompoundCommand {
511            kind: CompoundCommandKind::Case {
512                word: fragments.word,
513                arms: arms,
514            },
515            io: redirects,
516        })
517    }
518
519    /// Converts a `CompoundCommand` into a `PipeableCommand`.
520    fn compound_command_into_pipeable(&mut self,
521                                      cmd: Self::CompoundCommand)
522        -> Result<Self::PipeableCommand, Self::Error>
523    {
524        Ok(PipeableCommand::Compound(Box::new(cmd)))
525    }
526
527    /// Constructs a `Command::FunctionDef` node with the provided inputs.
528    fn function_declaration(&mut self,
529                            name: String,
530                            _post_name_comments: Vec<Newline>,
531                            body: Self::CompoundCommand)
532        -> Result<Self::PipeableCommand, Self::Error>
533    {
534        Ok(PipeableCommand::FunctionDef(name.into(), body.into()))
535    }
536
537    /// Ignored by the builder.
538    fn comments(&mut self, _comments: Vec<Newline>) -> Result<(), Self::Error> {
539        Ok(())
540    }
541
542    /// Constructs a `ast::Word` from the provided input.
543    fn word(&mut self, kind: ComplexWordKind<Self::Command>) -> Result<Self::Word, Self::Error>
544    {
545        macro_rules! map {
546            ($pat:expr) => {
547                match $pat {
548                    Some(w) => Some(try!(self.word(w))),
549                    None => None,
550                }
551            }
552        }
553
554        fn map_arith<T: From<String>>(kind: DefaultArithmetic) -> Arithmetic<T> {
555            use ast::Arithmetic::*;
556            match kind {
557                Var(v)           => Var(v.into()),
558                Literal(l)       => Literal(l.into()),
559                Pow(a, b)        => Pow(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
560                PostIncr(p)      => PostIncr(p.into()),
561                PostDecr(p)      => PostDecr(p.into()),
562                PreIncr(p)       => PreIncr(p.into()),
563                PreDecr(p)       => PreDecr(p.into()),
564                UnaryPlus(a)     => UnaryPlus(Box::new(map_arith(*a))),
565                UnaryMinus(a)    => UnaryMinus(Box::new(map_arith(*a))),
566                LogicalNot(a)    => LogicalNot(Box::new(map_arith(*a))),
567                BitwiseNot(a)    => BitwiseNot(Box::new(map_arith(*a))),
568                Mult(a, b)       => Mult(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
569                Div(a, b)        => Div(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
570                Modulo(a, b)     => Modulo(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
571                Add(a, b)        => Add(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
572                Sub(a, b)        => Sub(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
573                ShiftLeft(a, b)  => ShiftLeft(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
574                ShiftRight(a, b) => ShiftRight(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
575                Less(a, b)       => Less(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
576                LessEq(a, b)     => LessEq(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
577                Great(a, b)      => Great(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
578                GreatEq(a, b)    => GreatEq(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
579                Eq(a, b)         => Eq(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
580                NotEq(a, b)      => NotEq(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
581                BitwiseAnd(a, b) => BitwiseAnd(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
582                BitwiseXor(a, b) => BitwiseXor(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
583                BitwiseOr(a, b)  => BitwiseOr(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
584                LogicalAnd(a, b) => LogicalAnd(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
585                LogicalOr(a, b)  => LogicalOr(Box::new(map_arith(*a)), Box::new(map_arith(*b))),
586                Ternary(a, b, c) =>
587                    Ternary(Box::new(map_arith(*a)), Box::new(map_arith(*b)), Box::new(map_arith(*c))),
588                Assign(v, a) => Assign(v.into(), Box::new(map_arith(*a))),
589                Sequence(ariths) => Sequence(ariths.into_iter().map(map_arith).collect()),
590            }
591        }
592
593        let map_param = |kind: DefaultParameter| -> Parameter<T> {
594            use ast::Parameter::*;
595            match kind {
596                At            => At,
597                Star          => Star,
598                Pound         => Pound,
599                Question      => Question,
600                Dash          => Dash,
601                Dollar        => Dollar,
602                Bang          => Bang,
603                Positional(p) => Positional(p),
604                Var(v)        => Var(v.into()),
605            }
606        };
607
608        let mut map_simple = |kind| {
609            use ast::builder::ParameterSubstitutionKind::*;
610
611            let simple = match kind {
612                SimpleWordKind::Literal(s)      => SimpleWord::Literal(s.into()),
613                SimpleWordKind::Escaped(s)      => SimpleWord::Escaped(s.into()),
614                SimpleWordKind::Param(p)        => SimpleWord::Param(map_param(p)),
615                SimpleWordKind::Star            => SimpleWord::Star,
616                SimpleWordKind::Question        => SimpleWord::Question,
617                SimpleWordKind::SquareOpen      => SimpleWord::SquareOpen,
618                SimpleWordKind::SquareClose     => SimpleWord::SquareClose,
619                SimpleWordKind::Tilde           => SimpleWord::Tilde,
620                SimpleWordKind::Colon           => SimpleWord::Colon,
621
622                SimpleWordKind::CommandSubst(c) => SimpleWord::Subst(
623                    Box::new(ParameterSubstitution::Command(c.commands))
624                ),
625
626                SimpleWordKind::Subst(s) => {
627                    // Force a move out of the boxed substitution. For some reason doing
628                    // the deref in the match statment gives a strange borrow failure
629                    let s = *s;
630                    let subst = match s {
631                        Len(p) => ParameterSubstitution::Len(map_param(p)),
632                        Command(c) => ParameterSubstitution::Command(c.commands),
633                        Arith(a) => ParameterSubstitution::Arith(a.map(map_arith)),
634                        Default(c, p, w) =>
635                            ParameterSubstitution::Default(c, map_param(p), map!(w)),
636                        Assign(c, p, w) =>
637                            ParameterSubstitution::Assign(c, map_param(p), map!(w)),
638                        Error(c, p, w) =>
639                            ParameterSubstitution::Error(c, map_param(p), map!(w)),
640                        Alternative(c, p, w) =>
641                            ParameterSubstitution::Alternative(c, map_param(p), map!(w)),
642                        RemoveSmallestSuffix(p, w) =>
643                            ParameterSubstitution::RemoveSmallestSuffix(map_param(p), map!(w)),
644                        RemoveLargestSuffix(p, w)  =>
645                            ParameterSubstitution::RemoveLargestSuffix(map_param(p), map!(w)),
646                        RemoveSmallestPrefix(p, w) =>
647                            ParameterSubstitution::RemoveSmallestPrefix(map_param(p), map!(w)),
648                        RemoveLargestPrefix(p, w)  =>
649                            ParameterSubstitution::RemoveLargestPrefix(map_param(p), map!(w)),
650                    };
651                    SimpleWord::Subst(Box::new(subst))
652                },
653            };
654            Ok(simple)
655        };
656
657        let mut map_word = |kind| {
658            let word = match kind {
659                WordKind::Simple(s)       => Word::Simple(try!(map_simple(s))),
660                WordKind::SingleQuoted(s) => Word::SingleQuoted(s.into()),
661                WordKind::DoubleQuoted(v) => Word::DoubleQuoted(try!(
662                    v.into_iter()
663                     .map(&mut map_simple)
664                     .collect::<Result<Vec<_>, _>>()
665                )),
666            };
667            Ok(word)
668        };
669
670        let word = match compress(kind) {
671            ComplexWordKind::Single(s)     => ComplexWord::Single(try!(map_word(s))),
672            ComplexWordKind::Concat(words) => ComplexWord::Concat(try!(
673                    words.into_iter()
674                         .map(map_word)
675                         .collect::<Result<Vec<_>, _>>()
676            )),
677        };
678
679        Ok(word.into())
680    }
681
682    /// Constructs a `ast::Redirect` from the provided input.
683    fn redirect(&mut self,
684                kind: RedirectKind<Self::Word>)
685        -> Result<Self::Redirect, Self::Error>
686    {
687        let io = match kind {
688            RedirectKind::Read(fd, path)      => Redirect::Read(fd, path),
689            RedirectKind::Write(fd, path)     => Redirect::Write(fd, path),
690            RedirectKind::ReadWrite(fd, path) => Redirect::ReadWrite(fd, path),
691            RedirectKind::Append(fd, path)    => Redirect::Append(fd, path),
692            RedirectKind::Clobber(fd, path)   => Redirect::Clobber(fd, path),
693            RedirectKind::Heredoc(fd, body)   => Redirect::Heredoc(fd, body),
694            RedirectKind::DupRead(src, dst)   => Redirect::DupRead(src, dst),
695            RedirectKind::DupWrite(src, dst)  => Redirect::DupWrite(src, dst),
696        };
697
698        Ok(io)
699    }
700}
701
702#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
703struct Coalesce<I: Iterator, F> {
704    iter: I,
705    cur: Option<I::Item>,
706    func: F,
707}
708
709impl<I: Iterator, F> Coalesce<I, F> {
710    fn new<T>(iter: T, func: F) -> Self
711        where T: IntoIterator<IntoIter = I, Item = I::Item>
712    {
713        Coalesce {
714            iter: iter.into_iter(),
715            cur: None,
716            func: func,
717        }
718    }
719}
720
721type CoalesceResult<T> = Result<T, (T, T)>;
722impl<I, F> Iterator for Coalesce<I, F>
723    where I: Iterator,
724          F: FnMut(I::Item, I::Item) -> CoalesceResult<I::Item>
725{
726    type Item = I::Item;
727
728    fn next(&mut self) -> Option<Self::Item> {
729        let cur = self.cur.take().or_else(|| self.iter.next());
730        let (mut left, mut right) = match (cur, self.iter.next()) {
731            (Some(l), Some(r)) => (l, r),
732            (Some(l), None) |
733            (None, Some(l)) => return Some(l),
734            (None, None) => return None,
735        };
736
737        loop {
738            match (self.func)(left, right) {
739                Ok(combined) => match self.iter.next() {
740                    Some(next) => {
741                        left = combined;
742                        right = next;
743                    },
744                    None => return Some(combined),
745                },
746
747                Err((left, right)) => {
748                    debug_assert!(self.cur.is_none());
749                    self.cur = Some(right);
750                    return Some(left);
751                },
752            }
753        }
754    }
755}
756
757fn compress<C>(word: ComplexWordKind<C>) -> ComplexWordKind<C> {
758    use ast::builder::ComplexWordKind::*;
759    use ast::builder::SimpleWordKind::*;
760    use ast::builder::WordKind::*;
761
762    fn coalesce_simple<C>(a: SimpleWordKind<C>, b: SimpleWordKind<C>)
763        -> CoalesceResult<SimpleWordKind<C>>
764    {
765        match (a, b) {
766            (Literal(mut a), Literal(b)) => {
767                a.push_str(&b);
768                Ok(Literal(a))
769            },
770            (a, b) => Err((a, b)),
771        }
772    }
773
774    fn coalesce_word<C>(a: WordKind<C>, b: WordKind<C>) -> CoalesceResult<WordKind<C>> {
775        match (a, b) {
776            (Simple(a), Simple(b)) => coalesce_simple(a, b)
777                .map(Simple)
778                .map_err(|(a, b)| (Simple(a), Simple(b))),
779            (SingleQuoted(mut a), SingleQuoted(b)) => {
780                a.push_str(&b);
781                Ok(SingleQuoted(a))
782            },
783            (DoubleQuoted(a), DoubleQuoted(b)) => {
784                let quoted = Coalesce::new(a.into_iter().chain(b), coalesce_simple).collect();
785                Ok(DoubleQuoted(quoted))
786            },
787            (a, b) => Err((a, b)),
788        }
789    }
790
791    match word {
792        Single(s) => Single(match s {
793            s@Simple(_) |
794            s@SingleQuoted(_) => s,
795            DoubleQuoted(v) => DoubleQuoted(Coalesce::new(v, coalesce_simple).collect()),
796        }),
797        Concat(v) => {
798            let mut body: Vec<_> = Coalesce::new(v.into_iter(), coalesce_word).collect();
799            if body.len() == 1 {
800                Single(body.pop().unwrap())
801            } else {
802                Concat(body)
803            }
804        }
805    }
806}