diff options
-rw-r--r-- | build2/parser | 11 | ||||
-rw-r--r-- | build2/parser.cxx | 73 | ||||
-rw-r--r-- | tests/if-else/buildfile | 26 | ||||
-rw-r--r-- | tests/if-else/test.out | 3 |
4 files changed, 86 insertions, 27 deletions
diff --git a/build2/parser b/build2/parser index 0962348..af5c500 100644 --- a/build2/parser +++ b/build2/parser @@ -56,8 +56,15 @@ namespace build2 // Recursive descent parser. // protected: - void - clause (token&, token_type&); + // If one is true then parse a single (logical) line (logical means it + // can actually be several lines, e.g., an if-block). Return false if + // nothing has been parsed (i.e., we are on the same token). + // + // Note that after this function returns, the token is the first token on + // the next line (or eos). + // + bool + clause (token&, token_type&, bool one = false); void print (token&, token_type&); diff --git a/build2/parser.cxx b/build2/parser.cxx index 1987945..04accd2 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -192,8 +192,8 @@ namespace build2 return make_pair (move (lhs), move (t)); } - void parser:: - clause (token& t, type& tt) + bool parser:: + clause (token& t, type& tt, bool one) { tracer trace ("parser::clause", &path_); @@ -203,7 +203,9 @@ namespace build2 // for if-else blocks, directory scopes, etc., that assume the } token // they see is on the new line. // - while (tt != type::eos) + bool parsed (false); + + while (tt != type::eos && !(one && parsed)) { // Extract attributes if any. // @@ -228,6 +230,11 @@ namespace build2 break; } + // Now we will either parse something or fail. + // + if (!parsed) + parsed = true; + // See if this is one of the directives. // if (tt == type::name && keyword (t)) @@ -689,6 +696,8 @@ namespace build2 fail (t) << "unexpected " << t; } + + return parsed; } void parser:: @@ -1286,33 +1295,51 @@ namespace build2 fail (t) << "expected newline instead of " << t << " after " << k << (k != "else" ? "-expression" : ""); - if (next (t, tt) != type::lcbrace) - fail (t) << "expected { instead of " << t << " at the beginning of " - << k << "-block"; + // This can be a block or a single line. + // + if (next (t, tt) == type::lcbrace) + { + if (next (t, tt) != type::newline) + fail (t) << "expected newline after {"; - if (next (t, tt) != type::newline) - fail (t) << "expected newline after {"; + next (t, tt); - next (t, tt); + if (take) + { + clause (t, tt); + taken = true; + } + else + skip_block (t, tt); - if (take) - { - clause (t, tt); - taken = true; + if (tt != type::rcbrace) + fail (t) << "expected } instead of " << t << " at the end of " << k + << "-block"; + + next (t, tt); + + if (tt == type::newline) + next (t, tt); + else if (tt != type::eos) + fail (t) << "expected newline after }"; } else - skip_block (t, tt); - - if (tt != type::rcbrace) - fail (t) << "expected } instead of " << t << " at the end of " << k - << "-block"; + { + if (take) + { + if (!clause (t, tt, true)) + fail (t) << "expected " << k << "-line instead of " << t; - next (t, tt); + taken = true; + } + else + { + skip_line (t, tt); - if (tt == type::newline) - next (t, tt); - else if (tt != type::eos) - fail (t) << "expected newline after }"; + if (tt == type::newline) + next (t, tt); + } + } // See if we have another el* keyword. // diff --git a/tests/if-else/buildfile b/tests/if-else/buildfile index a54092d..25fabf0 100644 --- a/tests/if-else/buildfile +++ b/tests/if-else/buildfile @@ -104,8 +104,6 @@ if! $f print 1 } -./: - # With eval context. # if (foo == foo) @@ -128,8 +126,32 @@ if ([uint64] 01 == [uint64] 1) print 1 } +# Single line. +# + +#if true +#} # expected if-line + +if true + print 1 + +if false + + print 0 +else + # Comment. + print 1 + +if true + if false + print 0 + else + print 1 + # EOF test. # +./: + if true { print 1 diff --git a/tests/if-else/test.out b/tests/if-else/test.out index 71c9a23..58501cb 100644 --- a/tests/if-else/test.out +++ b/tests/if-else/test.out @@ -11,3 +11,6 @@ 1 1 1 +1 +1 +1 |