Skip to content

Commit 4bae87a

Browse files
committed
allow $\n in most contexts when parsing
The Ninja rules here aren't super clear, like I think this might be legal build $ foo$ :$ bar baz$ =$ blah and at least that kind of thing appears to be possible output of ninja_syntax.py. Fixes #89.
1 parent 593a81a commit 4bae87a

1 file changed

Lines changed: 40 additions & 11 deletions

File tree

src/parse.rs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl<'text> Parser<'text> {
9393
' ' | '\t' => return self.scanner.parse_error("unexpected whitespace"),
9494
_ => {
9595
let ident = self.read_ident()?;
96-
self.scanner.skip_spaces();
96+
self.skip_spaces();
9797
match ident {
9898
"rule" => return Ok(Some(Statement::Rule(self.read_rule()?))),
9999
"build" => return Ok(Some(Statement::Build(self.read_build(loader)?))),
@@ -125,19 +125,21 @@ impl<'text> Parser<'text> {
125125
}
126126
}
127127

128+
/// Read the `= ...` part of a variable definition.
128129
fn read_vardef(&mut self) -> ParseResult<EvalString<&'text str>> {
129-
self.scanner.skip_spaces();
130+
self.skip_spaces();
130131
self.scanner.expect('=')?;
131-
self.scanner.skip_spaces();
132+
self.skip_spaces();
132133
self.read_eval()
133134
}
134135

136+
/// Read a collection of ` foo = bar` variables, with leading indent.
135137
fn read_scoped_vars(&mut self) -> ParseResult<VarList<'text>> {
136138
let mut vars = VarList::default();
137139
while self.scanner.peek() == ' ' {
138140
self.scanner.skip_spaces();
139141
let name = self.read_ident()?;
140-
self.scanner.skip_spaces();
142+
self.skip_spaces();
141143
let val = self.read_vardef()?;
142144
vars.insert(name, val.into_owned());
143145
}
@@ -184,10 +186,10 @@ impl<'text> Parser<'text> {
184186
loader: &mut L,
185187
v: &mut Vec<L::Path>,
186188
) -> ParseResult<()> {
187-
self.scanner.skip_spaces();
189+
self.skip_spaces();
188190
while let Some(path) = self.read_path(loader)? {
189191
v.push(path);
190-
self.scanner.skip_spaces();
192+
self.skip_spaces();
191193
}
192194
Ok(())
193195
}
@@ -204,7 +206,7 @@ impl<'text> Parser<'text> {
204206
}
205207

206208
self.scanner.expect(':')?;
207-
self.scanner.skip_spaces();
209+
self.skip_spaces();
208210
let rule = self.read_ident()?;
209211

210212
let mut ins = Vec::new();
@@ -246,10 +248,7 @@ impl<'text> Parser<'text> {
246248

247249
fn read_default<L: Loader>(&mut self, loader: &mut L) -> ParseResult<Vec<L::Path>> {
248250
let mut defaults = Vec::new();
249-
while let Some(path) = self.read_path(loader)? {
250-
defaults.push(path);
251-
self.scanner.skip_spaces();
252-
}
251+
self.read_paths_to(loader, &mut defaults)?;
253252
if defaults.is_empty() {
254253
return self.scanner.parse_error("expected path");
255254
}
@@ -407,6 +406,25 @@ impl<'text> Parser<'text> {
407406
}
408407
})
409408
}
409+
410+
fn skip_spaces(&mut self) {
411+
loop {
412+
match self.scanner.read() {
413+
' ' => {}
414+
'$' => {
415+
if self.scanner.peek() != '\n' {
416+
self.scanner.back();
417+
return;
418+
}
419+
self.scanner.next();
420+
}
421+
_ => {
422+
self.scanner.back();
423+
return;
424+
}
425+
}
426+
}
427+
}
410428
}
411429

412430
#[cfg(test)]
@@ -466,4 +484,15 @@ mod tests {
466484
})
467485
));
468486
}
487+
488+
#[test]
489+
fn parse_trailing_newline() {
490+
let mut buf = "build$\n foo$\n : $\n touch $\n\n".as_bytes().to_vec();
491+
let mut parser = Parser::new(&mut buf);
492+
let stmt = parser.read(&mut StringLoader {}).unwrap().unwrap();
493+
assert!(matches!(
494+
stmt,
495+
Statement::Build(Build { rule: "touch", .. })
496+
));
497+
}
469498
}

0 commit comments

Comments
 (0)