From f98b9c87438d40888a6b8d60436a4f644a5364d4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 27 May 2020 07:25:05 +0200 Subject: Handle recipes in dependency declarations with prerequisites --- libbuild2/parser.cxx | 82 ++++++++++++++++++++++++++------------ tests/dependency/recipe/testscript | 50 +++++++++++++++++------ 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 7a4efcd..94f597d 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -701,7 +701,7 @@ namespace build2 if (tt == type::newline) { - // See if this is a target-specific variable and/or recipe block. + // See if this is a target-specific variable and/or recipe block(s). // // Note that we cannot just let parse_dependency() handle this case // because we can have (a mixture of) target type/patterns. @@ -716,8 +716,6 @@ namespace build2 tt == type::multi_lcbrace || (tt == type::lcbrace && peek () == type::newline)) { - token st (t); // Save start token. - // Parse the block(s) for each target. // // Note that because we have to peek past the closing brace(s) to @@ -725,9 +723,11 @@ namespace build2 // that token part of the replay (we cannot peek past the replay // sequence). // + // Note: similar code to the version in parse_dependency(). + // auto parse = [ this, - &st, + st = token (t), // Save start token (will be gone on replay). recipes = small_vector, 1> ()] (token& t, type& tt, const target_type* type, string pat) mutable @@ -782,7 +782,7 @@ namespace build2 // Target-specific variable assignment or dependency declaration, // including a dependency chain and/or prerequisite-specific variable - // assignment. + // assignment and/or recipe block(s). // auto at (attributes_push (t, tt)); @@ -796,6 +796,10 @@ namespace build2 // Target-specific variable assignment. // + // Note that neither here nor in parse_dependency() below we allow + // specifying recipes following a target-specified variable assignment + // (but we do allow them following a target-specific variable block). + // if (tt == type::assign || tt == type::prepend || tt == type::append) { type akind (tt); @@ -827,7 +831,8 @@ namespace build2 next_after_newline (t, tt); } // Dependency declaration potentially followed by a chain and/or a - // target/prerequisite-specific variable assignment/block. + // target/prerequisite-specific variable assignment/block and/or + // recipe block(s). // else { @@ -1323,9 +1328,9 @@ namespace build2 bool chain) { // Parse a dependency chain and/or a target/prerequisite-specific variable - // assignment/block. Return true if the following block (if any) has been - // "claimed" (the block "belongs" to targets/prerequisites before the last - // colon). + // assignment/block and/or recipe block(s). Return true if the following + // block(s) (if any) have been "claimed", meaning they "belong" to + // targets/prerequisites before the last colon. // // enter: colon (anything else is not handled) // leave: - first token on the next line if returning true @@ -1403,7 +1408,8 @@ namespace build2 // each target (for_each_p). // // We handle multiple targets and/or prerequisites by replaying the tokens - // (see the target-specific case for details). The function signature is: + // (see the target-specific case comments for details). The function + // signature is: // // void (token& t, type& tt) // @@ -1449,9 +1455,9 @@ namespace build2 }; // Do we have a dependency chain and/or prerequisite-specific variable - // assignment? If not, check for the target-specific variable block unless - // this is a chained call (in which case the block, if any, "belongs" to - // prerequisites). + // assignment? If not, check for the target-specific variable block and/or + // recipe block(s) unless this is a chained call (in which case the block, + // if any, "belongs" to prerequisites). // if (tt != type::colon) { @@ -1460,24 +1466,48 @@ namespace build2 next_after_newline (t, tt); // Must be a newline then. - if (tt == type::lcbrace && peek () == type::newline) + if (tt == type::percent || + tt == type::multi_lcbrace || + (tt == type::lcbrace && peek () == type::newline)) { - next (t, tt); // Newline. - - // Parse the block for each target. + // Parse the block(s) for each target. // - for_each_t ([this] (token& t, token_type& tt) - { - next (t, tt); // First token inside the block. + // Note: similar code to the version in parse_clause(). + // + auto parse = [ + this, + st = token (t), // Save start token (will be gone on replay). + recipes = small_vector, 1> ()] + (token& t, type& tt) mutable + { + token rt; // Recipe start token. - parse_variable_block (t, tt); + // The variable block, if any, should be first. + // + if (st.type == type::lcbrace) + { + next (t, tt); // Newline. + next (t, tt); // First token inside the variable block. + parse_variable_block (t, tt); - if (tt != type::rcbrace) - fail (t) << "expected '}' instead of " << t; - }); + if (tt != type::rcbrace) + fail (t) << "expected '}' instead of " << t; - next (t, tt); // Presumably newline after '}'. - next_after_newline (t, tt, '}'); // Should be on its own line. + next (t, tt); // Newline. + next_after_newline (t, tt, '}'); // Should be on its own line. + + if (tt != type::percent && tt != type::multi_lcbrace) + return; + + rt = t; + } + else + rt = st; + + parse_recipe (t, tt, rt, recipes); + }; + + for_each_t (parse); } return true; // Claimed or isn't any. diff --git a/tests/dependency/recipe/testscript b/tests/dependency/recipe/testscript index 503ad7e..5510e3c 100644 --- a/tests/dependency/recipe/testscript +++ b/tests/dependency/recipe/testscript @@ -3,17 +3,20 @@ .include ../../common.testscript +# Note: in the parser we have to handle recipes for the with/without +# prerequisites cases separately. So we try to cover both here. + : basics : $* <>/~%EOE% -alias{x}: +alias{x}: alias{z} {{ cmd }} dump alias{x} EOI :5:1: dump: -% .+/alias\{x\}:% +% .+/alias\{x\}: .+/:alias\{z\}% {{ cmd }} @@ -22,14 +25,14 @@ EOE : basics-replay : $* <>/~%EOE% -alias{x y}: +alias{x y}: alias{z} {{ cmd }} dump alias{y} EOI :5:1: dump: -% .+/alias\{y\}:% +% .+/alias\{y\}: .+/:alias\{z\}% {{ cmd }} @@ -110,7 +113,7 @@ EOE : with-vars-replay : $* <>/~%EOE% -alias{x y}: +alias{x y}: alias{z} { var = x } @@ -120,7 +123,7 @@ alias{x y}: dump alias{y} EOI :8:1: dump: -% .+/alias\{y\}:% +% .+/alias\{y\}: .+/:alias\{z\}% { var = x } @@ -132,7 +135,7 @@ EOE : with-vars-header : $* <>/~%EOE% -alias{x}: +alias{x}: alias{z} { var = x } @@ -143,7 +146,30 @@ alias{x}: dump alias{x} EOI :9:1: dump: -% .+/alias\{x\}:% +% .+/alias\{x\}: .+/:alias\{z\}% + { + var = x + } + {{ + cmd + }} +EOE + +: with-vars-header-replay +: +$* <>/~%EOE% +alias{x y}: +{ + var = x +} +% +{{ + cmd +}} +dump alias{y} +EOI +:9:1: dump: +% .+/alias\{y\}:% { var = x } @@ -177,7 +203,7 @@ EOE : chain-replay : $* <>/~%EOE% -alias{x y}: +alias{x y}: alias{z} {{ cmd1 }} @@ -187,7 +213,7 @@ alias{x y}: dump alias{y} EOI :8:1: dump: -% .+/alias\{y\}:% +% .+/alias\{y\}: .+/:alias\{z\}% {{ cmd1 }} @@ -199,7 +225,7 @@ EOE : chain-header : $* <>/~%EOE% -alias{x}: +alias{x}: alias{z} {{ cmd1 @@ -212,7 +238,7 @@ alias{x}: dump alias{x} EOI :11:1: dump: -% .+/alias\{x\}:% +% .+/alias\{x\}: .+/:alias\{z\}% {{ cmd1 }} -- cgit v1.1