whitespace/
whitespace.rs

1use pom::parser::*;
2
3#[derive(Clone, Debug, PartialEq)]
4struct Container {
5	containers: Vec<Container>,
6	contents: Vec<String>,
7}
8
9enum TmpContainerOrContent {
10	Container(Container),
11	Content(String),
12}
13
14fn whitespace<'a>() -> Parser<'a, u8, ()> {
15	one_of(b" \t\r\n").repeat(0..).discard()
16}
17
18fn linebreak<'a>() -> Parser<'a, u8, ()> {
19	sym(b'\r').opt() * sym(b'\n').discard()
20}
21
22fn indented<'a>() -> Parser<'a, u8, Vec<u8>> {
23	sym(b'\t') * none_of(b"\n\r").repeat(1..) - linebreak()
24}
25
26fn empty<'a>() -> Parser<'a, u8, ()> {
27	one_of(b" \t").repeat(0..).discard() - linebreak()
28}
29
30fn content<'a>() -> Parser<'a, u8, String> {
31	none_of(b" \t\r\n").repeat(1..).convert(String::from_utf8) - linebreak()
32}
33
34fn subcontainer<'a>() -> Parser<'a, u8, (Vec<Container>, Vec<String>)> {
35	(
36		call(container).map(|ctr| TmpContainerOrContent::Container(ctr)) |
37		content().map(|ctn| TmpContainerOrContent::Content(ctn))
38	).repeat(1..).map(
39		|tmp| {
40			tmp.into_iter().fold(
41				(vec![], vec![]),
42				|acc, x| match x {
43					TmpContainerOrContent::Container(ct) => (
44						acc.0.into_iter().chain(vec![ct].into_iter()).collect(),
45						acc.1,
46					),
47					TmpContainerOrContent::Content(cn) => (
48						acc.0,
49						acc.1.into_iter().chain(vec![cn].into_iter()).collect(),
50					),
51				}
52			)
53		}
54	)
55}
56
57fn container<'a>() -> Parser<'a, u8, Container> {
58	seq(b"Container\n") *
59	(
60		indented() |
61		empty().map(|()| vec![])
62	).repeat(1..).map(
63		|lines| lines.into_iter().filter(
64			|line| line.len() > 0
65		).fold(
66			vec![],
67			|accum, line| accum.into_iter().chain(
68				line.into_iter().chain(vec![b'\n'].into_iter())
69			).collect()
70		)
71	).map(|deden| {
72		subcontainer().parse(&deden).expect("subcont")
73	}).map(|(containers, contents)| Container { containers, contents })
74}
75
76fn mylang<'a>() -> Parser<'a, u8, Vec<Container>> {
77	(
78		whitespace() *
79		list(
80			call(container),
81			whitespace()
82		)
83	)
84}
85
86fn main() -> Result<(), ()> {
87	let input = br#"
88Container
89	Container
90		a
91		b
92		c
93
94	1
95	2
96	3
97
98	Container
99		q
100
101Container
102	foo
103	bar
104
105	Container
106		baz
107		quux
108		"#;
109
110	assert_eq!(
111		mylang().parse(input),
112		Ok(
113			vec![
114				Container {
115					containers: vec![
116						Container {
117							containers: vec![],
118							contents: vec![
119								"a".into(),
120								"b".into(),
121								"c".into(),
122							]
123						},
124						Container {
125							containers: vec![],
126							contents: vec![
127								"q".into(),
128							]
129						}
130					],
131					contents: vec![
132						"1".into(),
133						"2".into(),
134						"3".into(),
135					]
136				},
137				Container {
138					containers: vec![
139						Container {
140							contents: vec![
141								"baz".into(),
142								"quux".into(),
143							],
144							containers: vec![],
145						},
146					],
147					contents: vec![
148						"foo".into(),
149						"bar".into(),
150					]
151				},
152			]
153		)
154	);
155
156	Ok(())
157}