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
10macro_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 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 #[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 pub struct DefaultBuilder,
204 RcCoreBuilder,
205 TopLevelWord,
206 TopLevelCommand,
207 ShellPipeableCommand,
208}
209
210default_builder! {
211 pub struct AtomicDefaultBuilder,
214 ArcCoreBuilder,
215 AtomicTopLevelWord,
216 AtomicTopLevelCommand,
217 AtomicShellPipeableCommand,
218}
219
220pub type StringBuilder = DefaultBuilder<String>;
223
224pub type RcBuilder = DefaultBuilder<Rc<String>>;
227
228pub type ArcBuilder = AtomicDefaultBuilder<Arc<String>>;
231
232pub 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#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 fn comments(&mut self, _comments: Vec<Newline>) -> Result<(), Self::Error> {
539 Ok(())
540 }
541
542 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 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 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}