ninja_build_syntax/
parsers.rs

1use std::convert::identity;
2use std::str::from_utf8;
3
4use nom::{
5    branch::alt,
6    bytes::complete::{is_a, is_not, tag, take_while, take_while1},
7    character::{complete::line_ending, is_alphanumeric},
8    combinator::{map, map_opt, opt, verify},
9    multi::{many0, many1},
10    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
11};
12
13#[cfg(test)]
14#[macro_use]
15mod test_macros;
16
17use crate::IResult;
18
19fn maybe_whitespace(input: &[u8]) -> IResult<()> {
20    map(many0(alt((tag("$\r\n"), tag("$\n"), tag(" ")))), |_| ())(input)
21}
22
23#[cfg(test)]
24#[test]
25fn test_maybe_whitespace() {
26    test_parse!(maybe_whitespace(b""), ());
27    test_parse!(maybe_whitespace(b"        "), ());
28    test_parse!(maybe_whitespace(b"    $\n    "), ());
29    test_parse!(maybe_whitespace(b"    $\r\n    "), ());
30    test_parse!(maybe_whitespace(b"    \t    "), (), b"\t    ");
31    test_parse!(maybe_whitespace(b"abc"), (), b"abc");
32}
33
34fn maybe_surrounded_by_whitespace<'a, O, F>(f: F) -> impl Fn(&'a [u8]) -> IResult<O>
35where
36    F: Fn(&'a [u8]) -> IResult<O>,
37{
38    delimited(maybe_whitespace, f, maybe_whitespace)
39}
40
41fn word<'a, Input: 'a>(w: &'a str) -> impl Fn(Input) -> nom::IResult<Input, ()> + 'a
42where
43    Input: nom::InputTake + nom::Compare<&'a str> + Clone,
44{
45    map(
46        pair(tag(w), alt((tag("$\r\n"), tag("$\n"), tag(" ")))),
47        |_| (),
48    )
49}
50
51fn is_simple_identifier_character(c: u8) -> bool {
52    is_alphanumeric(c) || c == b'_' || c == b'-'
53}
54
55fn is_identifier_character(c: u8) -> bool {
56    is_simple_identifier_character(c) || c == b'.'
57}
58
59/// Identifier.
60///
61/// Used for variable names, rule names and pool names.
62#[derive(Debug, PartialEq, Eq, Clone)]
63pub struct Identifier<'a>(pub &'a str);
64
65fn identifier(input: &[u8]) -> IResult<Identifier> {
66    map(take_while1(is_identifier_character), |s| {
67        Identifier(from_utf8(s).unwrap())
68    })(input)
69}
70
71fn simple_identifier(input: &[u8]) -> IResult<Identifier> {
72    map(take_while1(is_simple_identifier_character), |s| {
73        Identifier(from_utf8(s).unwrap())
74    })(input)
75}
76
77#[cfg(test)]
78#[test]
79fn test_identifier() {
80    test_parse!(identifier(b"abc"), id!("abc"));
81    test_parse!(identifier(b"ab.c"), id!("ab.c"));
82    test_parse!(identifier(b"ab_c"), id!("ab_c"));
83    test_parse!(identifier(b"ab-c"), id!("ab-c"));
84    test_parse!(identifier(b"3-1"), id!("3-1"));
85    test_parse!(identifier(b"3+1"), id!("3"), b"+1");
86    test_parse!(identifier(b"0.1"), id!("0.1"));
87    test_parse!(identifier(b"abc def"), id!("abc"), b" def");
88    test_parse!(identifier(b"abc_def"), id!("abc_def"));
89    test_parse_error!(identifier(b""));
90}
91
92/// Piece of a value.
93#[derive(PartialEq, Debug, Eq, Clone)]
94pub enum ValuePiece<'a> {
95    /// Reference to a variable.
96    Reference(&'a str),
97    /// Plain value.
98    Plain(&'a [u8]),
99}
100
101/// An unevaluated value.
102///
103/// Used for variable values and paths. A `Value` can contain references to
104/// variables in which case it's represented as multiple pieces, plain ones and
105/// evaluated ones. To get the evaluated value of a `Value` the plain pieces and
106/// variable references must be concatenated.
107#[derive(Debug, PartialEq, Eq, Clone)]
108pub struct Value<'a>(Vec<ValuePiece<'a>>);
109
110impl<'a> IntoIterator for Value<'a> {
111    type Item = ValuePiece<'a>;
112    type IntoIter = std::vec::IntoIter<Self::Item>;
113
114    fn into_iter(self) -> Self::IntoIter {
115        self.0.into_iter()
116    }
117}
118
119impl<'a> IntoIterator for &'a Value<'a> {
120    type Item = &'a ValuePiece<'a>;
121    type IntoIter = std::slice::Iter<'a, ValuePiece<'a>>;
122
123    fn into_iter(self) -> Self::IntoIter {
124        self.0.iter()
125    }
126}
127
128fn value(input: &[u8]) -> IResult<Value> {
129    map(
130        many0(alt((
131            map(verify(is_not("$\r\n"), |s: &[u8]| !s.is_empty()), |s| {
132                Some(ValuePiece::Plain(s))
133            }),
134            map(preceded(tag("$"), is_a("$ |:")), |s| {
135                Some(ValuePiece::Plain(s))
136            }),
137            map(
138                preceded(alt((tag("$\n"), tag("$\r\n"))), opt(is_a(" "))),
139                |_| None,
140            ),
141            map(
142                delimited(tag("${"), identifier, tag("}")),
143                |Identifier(x)| Some(ValuePiece::Reference(x)),
144            ),
145            map(preceded(tag("$"), simple_identifier), |Identifier(x)| {
146                Some(ValuePiece::Reference(x))
147            }),
148        ))),
149        |pieces| Value(pieces.into_iter().filter_map(identity).collect()),
150    )(input)
151}
152
153#[cfg(test)]
154#[test]
155fn test_value() {
156    test_parse!(value(b""), value![]);
157    test_parse!(value(b"abc"), value![plain!(b"abc")]);
158    test_parse!(value(b"$$abc"), value![plain!(b"$"), plain!(b"abc")]);
159    test_parse!(value(b"abc def"), value![plain!(b"abc def")]);
160    test_parse!(
161        value(b"abc$ def"),
162        value![plain!(b"abc"), plain!(b" "), plain!(b"def"),]
163    );
164    test_parse!(
165        value(b"abc$ def"),
166        value![plain!(b"abc"), plain!(b" "), plain!(b"def"),]
167    );
168    test_parse!(
169        value(b"abc$:def"),
170        value![plain!(b"abc"), plain!(b":"), plain!(b"def"),]
171    );
172    test_parse!(
173        value(b"abc$|def"),
174        value![plain!(b"abc"), plain!(b"|"), plain!(b"def"),]
175    );
176    test_parse!(value(b"abc$\ndef"), value![plain!(b"abc"), plain!(b"def"),]);
177    test_parse!(
178        value(b"abc$\n    def"),
179        value![plain!(b"abc"), plain!(b"def"),]
180    );
181    test_parse!(
182        value(b"ab${cd}ef"),
183        value![plain!(b"ab"), reference!("cd"), plain!(b"ef"),]
184    );
185    test_parse!(
186        value(b"abc$def.ghi"),
187        value![plain!(b"abc"), reference!("def"), plain!(b".ghi"),]
188    );
189    test_parse!(value(b"abc$/def"), value![plain!(b"abc")], &b"$/def");
190    test_parse!(value(b"a | b"), value![plain!(b"a | b")]);
191    test_parse!(value(b"a : b"), value![plain!(b"a : b")]);
192    test_parse!(value(b"abc\n"), value![plain!(b"abc")], b"\n");
193}
194
195fn path(input: &[u8]) -> IResult<Value> {
196    map(
197        many1(alt((
198            map(
199                verify(is_not("$ :\r\n|\0"), |s: &[u8]| !s.is_empty()),
200                |s| Some(ValuePiece::Plain(s)),
201            ),
202            map(preceded(tag("$"), is_a("$ |:")), |s| {
203                Some(ValuePiece::Plain(s))
204            }),
205            map(
206                preceded(alt((tag("$\n"), tag("$\r\n"))), opt(is_a(" "))),
207                |_| None,
208            ),
209            map(
210                delimited(tag("${"), identifier, tag("}")),
211                |Identifier(x)| Some(ValuePiece::Reference(x)),
212            ),
213            map(preceded(tag("$"), simple_identifier), |Identifier(x)| {
214                Some(ValuePiece::Reference(x))
215            }),
216        ))),
217        |pieces| Value(pieces.into_iter().filter_map(identity).collect()),
218    )(input)
219}
220
221fn paths0(input: &[u8]) -> IResult<Vec<Value>> {
222    terminated(many0(preceded(maybe_whitespace, path)), maybe_whitespace)(input)
223}
224
225fn paths1(input: &[u8]) -> IResult<Vec<Value>> {
226    terminated(many1(preceded(maybe_whitespace, path)), maybe_whitespace)(input)
227}
228
229#[cfg(test)]
230#[test]
231fn test_path() {
232    test_parse_error!(path(b""));
233    test_parse!(path(b"foo.c"), value![plain!(b"foo.c")]);
234    test_parse!(path(b"foo.c bar.c"), value![plain!(b"foo.c")], b" bar.c");
235    test_parse!(path(b"foo.c\n"), value![plain!(b"foo.c")], b"\n");
236
237    test_parse!(paths0(b""), vec![]);
238    test_parse!(paths0(b"foo.c"), vec![value![plain!(b"foo.c")]]);
239    test_parse!(
240        paths0(b" foo.c bar.c "),
241        vec![value![plain!(b"foo.c")], value![plain!(b"bar.c")]]
242    );
243    test_parse!(paths0(b"foo.c\n"), vec![value![plain!(b"foo.c")]], b"\n");
244}
245
246/// Variable assignment.
247///
248/// Example:
249/// ```notrust
250/// a = 1
251/// ```
252#[derive(Debug, PartialEq, Eq, Clone)]
253pub struct Binding<'a> {
254    /// Left-hand side of the assignment.
255    pub name: Identifier<'a>,
256    /// Right-hand side of the assignment.
257    pub value: Value<'a>,
258}
259
260impl Binding<'_> {
261    fn parse(input: &[u8]) -> IResult<Binding> {
262        map(
263            terminated(
264                separated_pair(
265                    identifier,
266                    tuple((maybe_whitespace, tag("="), maybe_whitespace)),
267                    value,
268                ),
269                line_ending,
270            ),
271            |(name, value)| Binding { name, value },
272        )(input)
273    }
274}
275
276#[cfg(test)]
277#[test]
278fn test_binding() {
279    let binding = Binding::parse;
280    test_parse!(
281        binding(b"abc=def\n"),
282        Binding {
283            name: id!("abc"),
284            value: value![plain!(b"def")],
285        }
286    );
287    test_parse_error!(binding(b"abc=def"));
288    test_parse!(
289        binding(b"abc = def\n"),
290        Binding {
291            name: id!("abc"),
292            value: value![plain!(b"def")],
293        }
294    );
295    test_parse_error!(binding(b" abc = def\n"));
296    test_parse!(
297        binding(b"abc = \n"),
298        Binding {
299            name: id!("abc"),
300            value: value![],
301        }
302    );
303    test_parse!(
304        binding(b"abc = def ghi\n"),
305        Binding {
306            name: id!("abc"),
307            value: value![plain!(b"def ghi")],
308        }
309    );
310    test_parse!(
311        binding(b"abc = def $ghi\n"),
312        Binding {
313            name: id!("abc"),
314            value: value![plain!(b"def "), reference!("ghi")],
315        }
316    );
317    test_parse!(
318        binding(b"abc $\n = $\n    def\n"),
319        Binding {
320            name: id!("abc"),
321            value: value![plain!(b"def")],
322        }
323    );
324    // TODO: check against ninja
325    test_parse!(
326        binding(b"abc = def # comment\n"),
327        Binding {
328            name: id!("abc"),
329            value: value![plain!(b"def # comment")],
330        }
331    );
332}
333
334fn bindings(input: &[u8]) -> IResult<Vec<Binding>> {
335    many1(preceded(indent, Binding::parse))(input)
336}
337
338#[cfg(test)]
339#[test]
340fn test_bindings() {
341    test_parse_error!(bindings(b""));
342    test_parse!(
343        bindings(b" a = b\n"),
344        vec![Binding {
345            name: id!("a"),
346            value: value![plain!(b"b")],
347        }]
348    );
349    test_parse!(
350        bindings(
351            &br#"
352  a = b
353  c = d
354  x = $y
355"#[1..]
356        ),
357        vec![
358            Binding {
359                name: id!("a"),
360                value: value![plain!(b"b")],
361            },
362            Binding {
363                name: id!("c"),
364                value: value![plain!(b"d")],
365            },
366            Binding {
367                name: id!("x"),
368                value: value![reference!("y")],
369            },
370        ]
371    );
372    test_parse!(
373        bindings(
374            &br#"
375  a = b
376     c = d
377       x = $y
378"#[1..]
379        ),
380        vec![
381            Binding {
382                name: id!("a"),
383                value: value![plain!(b"b")],
384            },
385            Binding {
386                name: id!("c"),
387                value: value![plain!(b"d")],
388            },
389            Binding {
390                name: id!("x"),
391                value: value![reference!("y")],
392            },
393        ]
394    );
395    test_parse!(
396        bindings(
397            &br#"
398       a = b
399     c = d
400   x = $y
401"#[1..]
402        ),
403        vec![
404            Binding {
405                name: id!("a"),
406                value: value![plain!(b"b")],
407            },
408            Binding {
409                name: id!("c"),
410                value: value![plain!(b"d")],
411            },
412            Binding {
413                name: id!("x"),
414                value: value![reference!("y")],
415            },
416        ]
417    );
418    test_parse_error!(bindings(b"a = b\n"));
419}
420
421/// Rule definition.
422///
423/// This defines the command to execute to produce the outputs of a `build`
424/// instruction.
425#[derive(Debug)]
426pub struct Rule<'a> {
427    /// Rule name.
428    pub name: Identifier<'a>,
429    /// Rule variables.
430    ///
431    /// Only certain variable names are allowed here while some are required.
432    /// Please refer to the ninja documentation.
433    pub bindings: Vec<Binding<'a>>,
434}
435
436impl Rule<'_> {
437    fn parse(input: &[u8]) -> IResult<Rule> {
438        map(
439            pair(
440                delimited(
441                    word("rule"),
442                    maybe_surrounded_by_whitespace(identifier),
443                    line_ending,
444                ),
445                bindings,
446            ),
447            |(name, bindings)| Rule { name, bindings },
448        )(input)
449    }
450}
451
452// TODO: add test_rule
453
454/// Build instruction.
455///
456/// The build instructions describe commands that have to be executed in order
457/// to produce the outputs. They are called "edges" in ninja jargon while the
458/// inputs and outputs are called "nodes".
459///
460/// Example:
461/// ```notrust
462/// build foo.o : c foo.c || generated_header.h
463///   cflags = -DHAVE_BAR=1
464/// ```
465#[derive(Debug, PartialEq, Eq, Clone)]
466pub struct Build<'a> {
467    /// Outputs.
468    ///
469    /// This is what the build instruction produces. There can be many outputs
470    /// but having at least one is mandatory. These are populated into the
471    /// implicit `$out` variable by ninja.
472    pub outputs: Vec<Value<'a>>,
473    /// Implicit outputs.
474    ///
475    /// Also produced by the build instruction. The difference to the `outputs`
476    /// is that they are optional and are not populated into the `$out` variable
477    /// by ninja.
478    pub implicit_outputs: Vec<Value<'a>>,
479    /// Rule name.
480    ///
481    /// The name of the rule that is used to generate the command to execute to
482    /// generate an output.
483    pub rule: Identifier<'a>,
484    /// Inputs.
485    ///
486    /// These are used to produce the outputs. During rebuilding when any of
487    /// these are considered out-of-date the outputs will have to rebuild. They
488    /// are populated into the `$in` variable by ninja.
489    pub inputs: Vec<Value<'a>>,
490    /// Implicit inputs.
491    ///
492    /// Similar to inputs but not populated into the `$in` variable by ninja.
493    pub implicit_inputs: Vec<Value<'a>>,
494    /// Order-only inputs.
495    ///
496    /// These are inputs that have to exist for this build instruction to run.
497    /// They are not checked for being up-to-date when rebuilding.
498    pub order_only_inputs: Vec<Value<'a>>,
499    /// Variable assignments.
500    ///
501    /// These can be used to customize the commands set forth by the rule.
502    pub bindings: Vec<Binding<'a>>,
503}
504
505fn opt_default<I: Clone, O: std::default::Default, E: nom::error::ParseError<I>, F>(
506    f: F,
507) -> impl Fn(I) -> nom::IResult<I, O, E>
508where
509    F: Fn(I) -> nom::IResult<I, O, E>,
510{
511    map(opt(f), Option::unwrap_or_default)
512}
513
514impl Build<'_> {
515    fn parse(input: &[u8]) -> IResult<Build> {
516        map(
517            tuple((
518                preceded(word("build"), paths1),
519                opt_default(preceded(tag("|"), paths1)),
520                preceded(tag(":"), maybe_surrounded_by_whitespace(identifier)),
521                paths0,
522                opt_default(preceded(tag("|"), paths1)),
523                opt_default(preceded(tag("||"), paths1)),
524                line_ending,
525                opt_default(bindings),
526            )),
527            |(
528                outputs,
529                implicit_outputs,
530                rule,
531                inputs,
532                implicit_inputs,
533                order_only_inputs,
534                _newline,
535                bindings,
536            )| {
537                Build {
538                    outputs,
539                    implicit_outputs,
540                    rule,
541                    inputs,
542                    implicit_inputs,
543                    order_only_inputs,
544                    bindings,
545                }
546            },
547        )(input)
548    }
549}
550
551#[cfg(test)]
552#[test]
553fn test_build() {
554    let build = Build::parse;
555    test_parse!(
556        build(b"build foo.o:cc foo.c\n"),
557        Build {
558            outputs: vec![value![plain!(b"foo.o")]],
559            implicit_outputs: vec![],
560            rule: id!("cc"),
561            inputs: vec![value![plain!(b"foo.c")]],
562            implicit_inputs: vec![],
563            order_only_inputs: vec![],
564            bindings: vec![],
565        }
566    );
567    test_parse_error!(build(b"build : cc foo.c\n"));
568    test_parse_error!(build(b"buildfoo.o : cc foo.c\n"));
569    test_parse!(
570        build(b"build foo.o : cc foo.c    \n"),
571        Build {
572            outputs: vec![value![plain!(b"foo.o")]],
573            implicit_outputs: vec![],
574            rule: id!("cc"),
575            inputs: vec![value![plain!(b"foo.c")]],
576            implicit_inputs: vec![],
577            order_only_inputs: vec![],
578            bindings: vec![],
579        }
580    );
581    test_parse!(
582        build(
583            b"\
584build foo.o | foo.o.d foo.s : cc foo.c | foo.h || bar.so
585    restat = 1
586    pool = expensive
587"
588        ),
589        Build {
590            outputs: vec![value![plain!(b"foo.o")]],
591            implicit_outputs: vec![value![plain!(b"foo.o.d")], value![plain!(b"foo.s")]],
592            rule: id!("cc"),
593            inputs: vec![value![plain!(b"foo.c")]],
594            implicit_inputs: vec![value![plain!(b"foo.h")]],
595            order_only_inputs: vec![value![plain!(b"bar.so")]],
596            bindings: vec![
597                Binding {
598                    name: id!("restat"),
599                    value: value![plain!(b"1")],
600                },
601                Binding {
602                    name: id!("pool"),
603                    value: value![plain!(b"expensive")],
604                },
605            ],
606        }
607    );
608    test_parse!(
609        build(b"build nothing : nil\n"),
610        Build {
611            outputs: vec![value![plain!(b"nothing")]],
612            implicit_outputs: vec![],
613            rule: id!("nil"),
614            inputs: vec![],
615            implicit_inputs: vec![],
616            order_only_inputs: vec![],
617            bindings: vec![],
618        }
619    );
620}
621
622/// Default instruction.
623///
624/// Defines the targets to build when no arguments are given to the `ninja`
625/// command.
626#[derive(Debug, PartialEq, Eq, Clone)]
627pub struct Default<'a> {
628    /// Default targets.
629    pub targets: Vec<Value<'a>>,
630}
631
632impl<'a> Default<'a> {
633    fn parse(input: &[u8]) -> IResult<Default> {
634        map(
635            terminated(
636                preceded(word("default"), maybe_surrounded_by_whitespace(paths1)),
637                line_ending,
638            ),
639            |targets| Default { targets },
640        )(input)
641    }
642}
643
644#[cfg(test)]
645#[test]
646fn test_default() {
647    let default = Default::parse;
648    test_parse!(
649        default(b"default all\n"),
650        Default {
651            targets: vec![value![plain!(b"all")]],
652        }
653    );
654    test_parse_error!(default(b"default\n"));
655    test_parse_error!(default(b"defaultall\n"));
656    test_parse!(
657        default(b"default all nothing $special with$ space\n"),
658        Default {
659            targets: vec![
660                value![plain!(b"all")],
661                value![plain!(b"nothing")],
662                value![reference!("special")],
663                value![plain!(b"with"), plain!(b" "), plain!(b"space")],
664            ],
665        }
666    );
667}
668
669/// Include instruction.
670///
671/// Instructs ninja to include another file. This comes in two flavors `include`
672/// and `subninja`. `include` instructs ninja to include a file as-is while
673/// `subninja` instructs ninja to open another "scope" such that rule
674/// definitions and variable bindings are not propagated up to the file that
675/// contains the `subninja` instruction.
676#[derive(Debug, PartialEq, Eq, Clone)]
677pub struct Include<'a> {
678    pub path: Value<'a>,
679    pub new_scope: bool,
680}
681
682impl<'a> Include<'a> {
683    fn parse(input: &[u8]) -> IResult<Include> {
684        terminated(
685            alt((
686                map(
687                    preceded(word("include"), maybe_surrounded_by_whitespace(path)),
688                    |path| Include {
689                        path,
690                        new_scope: false,
691                    },
692                ),
693                map(
694                    preceded(word("subninja"), maybe_surrounded_by_whitespace(path)),
695                    |path| Include {
696                        path,
697                        new_scope: true,
698                    },
699                ),
700            )),
701            line_ending,
702        )(input)
703    }
704}
705
706#[cfg(test)]
707#[test]
708fn test_include() {
709    let include = Include::parse;
710    test_parse!(
711        include(b"include rules.ninja\n"),
712        Include {
713            path: value![plain!(b"rules.ninja")],
714            new_scope: false,
715        }
716    );
717    test_parse!(
718        include(b"include $dir/rules.ninja\n"),
719        Include {
720            path: value![reference!("dir"), plain!(b"/rules.ninja"),],
721            new_scope: false,
722        }
723    );
724    test_parse!(
725        include(b"subninja dir/build.ninja\n"),
726        Include {
727            path: value![plain!(b"dir/build.ninja"),],
728            new_scope: true,
729        }
730    );
731    test_parse_error!(include(b"include\n"));
732    test_parse_error!(include(b"subninja\n"));
733    test_parse_error!(include(b"includerules.ninja\n"));
734    test_parse_error!(include(b"subninjarules.ninja\n"));
735}
736
737/// Pool definition.
738///
739/// A pool definition is used to limit parallel execution of build commands.
740#[derive(Debug, PartialEq, Eq, Clone)]
741pub struct Pool<'a> {
742    /// Pool name.
743    pub name: Identifier<'a>,
744    /// Pool depth.
745    pub depth: Value<'a>,
746}
747
748fn indent(input: &[u8]) -> IResult<usize> {
749    map(is_a(" "), <[u8]>::len)(input)
750}
751
752impl<'a> Pool<'a> {
753    fn parse(input: &[u8]) -> IResult<Pool> {
754        map(
755            separated_pair(
756                delimited(
757                    word("pool"),
758                    maybe_surrounded_by_whitespace(identifier),
759                    line_ending,
760                ),
761                indent,
762                // Technically ninja allows multiple depth values and just takes the
763                // last one.
764                map_opt(Binding::parse, |Binding { name, value }| {
765                    if name == Identifier("depth") {
766                        Some(value)
767                    } else {
768                        None
769                    }
770                }),
771            ),
772            |(name, value)| Pool { name, depth: value },
773        )(input)
774    }
775}
776
777#[cfg(test)]
778#[test]
779fn test_pool() {
780    let pool = Pool::parse;
781    test_parse!(
782        pool(b"pool link\n    depth = 3\n"),
783        Pool {
784            name: Identifier(&"link"[..]),
785            depth: value![plain!(b"3")],
786        }
787    );
788    test_parse_error!(pool(b"poollink\n    depth = 3\n"));
789    test_parse_error!(pool(b"pool link\n    command = rm -rf /\n"));
790    test_parse_error!(pool(b"pool link\n"));
791    test_parse_error!(pool(b"pool link\n\n"));
792    test_parse_error!(pool(b"pool link\ndepth = 3\n"));
793}
794
795/// Comment.
796///
797/// A single comment line, that is everything after a `#`.
798#[derive(Debug, PartialEq, Eq, Clone)]
799pub struct Comment<'a>(pub &'a [u8]);
800
801impl<'a> Comment<'a> {
802    fn parse(input: &[u8]) -> IResult<Comment> {
803        map(
804            delimited(tag("#"), take_while(|c| c != b'\n'), line_ending),
805            Comment,
806        )(input)
807    }
808}
809
810#[cfg(test)]
811#[test]
812fn test_comment() {
813    let comment = Comment::parse;
814    test_parse!(
815        comment(&b"# this is a comment\n"[..]),
816        Comment(&b" this is a comment"[..])
817    );
818    test_parse!(comment(&b"#\n"[..]), Comment(&b""[..]));
819}
820
821/// Statement.
822///
823/// Sum type of any of the statements that are allowed in a ninja file. Note
824/// that this doesn't include the empty statement consisting of a single empty
825/// line.
826#[derive(Debug)]
827pub enum Statement<'a> {
828    /// Rule definition.
829    Rule(Rule<'a>),
830    /// Build instruction.
831    Build(Build<'a>),
832    /// Variable definition.
833    Binding(Binding<'a>),
834    /// Default instruction.
835    Default(Default<'a>),
836    /// Include instruction.
837    Include(Include<'a>),
838    /// Pool definition.
839    Pool(Pool<'a>),
840    /// Comment.
841    Comment(Comment<'a>),
842}
843
844impl Statement<'_> {
845    pub(crate) fn parse(input: &[u8]) -> IResult<Statement> {
846        alt((
847            map(Rule::parse, Statement::Rule),
848            map(Build::parse, Statement::Build),
849            map(Binding::parse, Statement::Binding),
850            map(Default::parse, Statement::Default),
851            map(Include::parse, Statement::Include),
852            map(Pool::parse, Statement::Pool),
853            map(Comment::parse, Statement::Comment),
854        ))(input)
855    }
856}