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#[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#[derive(PartialEq, Debug, Eq, Clone)]
94pub enum ValuePiece<'a> {
95 Reference(&'a str),
97 Plain(&'a [u8]),
99}
100
101#[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#[derive(Debug, PartialEq, Eq, Clone)]
253pub struct Binding<'a> {
254 pub name: Identifier<'a>,
256 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 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#[derive(Debug)]
426pub struct Rule<'a> {
427 pub name: Identifier<'a>,
429 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#[derive(Debug, PartialEq, Eq, Clone)]
466pub struct Build<'a> {
467 pub outputs: Vec<Value<'a>>,
473 pub implicit_outputs: Vec<Value<'a>>,
479 pub rule: Identifier<'a>,
484 pub inputs: Vec<Value<'a>>,
490 pub implicit_inputs: Vec<Value<'a>>,
494 pub order_only_inputs: Vec<Value<'a>>,
499 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#[derive(Debug, PartialEq, Eq, Clone)]
627pub struct Default<'a> {
628 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#[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#[derive(Debug, PartialEq, Eq, Clone)]
741pub struct Pool<'a> {
742 pub name: Identifier<'a>,
744 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 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#[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#[derive(Debug)]
827pub enum Statement<'a> {
828 Rule(Rule<'a>),
830 Build(Build<'a>),
832 Binding(Binding<'a>),
834 Default(Default<'a>),
836 Include(Include<'a>),
838 Pool(Pool<'a>),
840 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}