From 82ee575b32bc57598cec5eaaa3a170ac36de9af0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 20 May 2020 14:00:32 +0200 Subject: Add ability to notice variable expansions in pre-parse mode --- libbuild2/build/script/parser.cxx | 3 +- libbuild2/parser.cxx | 110 ++++++++++++++++++++++---------------- libbuild2/parser.hxx | 6 +++ libbuild2/test/script/parser.cxx | 3 +- 4 files changed, 74 insertions(+), 48 deletions(-) diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx index 9c397f1..6649777 100644 --- a/libbuild2/build/script/parser.cxx +++ b/libbuild2/build/script/parser.cxx @@ -327,7 +327,8 @@ namespace build2 lookup parser:: lookup_variable (name&& qual, string&& name, const location& loc) { - assert (!pre_parse_); + if (pre_parse_) + return lookup (); if (!qual.empty ()) fail (loc) << "qualified variable name"; diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index 93da22a..ff32340 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -3702,11 +3702,8 @@ namespace build2 values parser:: parse_eval (token& t, type& tt, pattern_mode pmode) { - // enter: lparen - // leave: rparen - - mode (lexer_mode::eval, '@'); // Auto-expires at rparen. - next_with_attributes (t, tt); + // enter: token after lparen (lexed in the eval mode with attributes). + // leave: rparen (eval mode auto-expires at rparen). if (tt == type::rparen) return values (); @@ -5522,56 +5519,72 @@ namespace build2 ; // Leave the name empty to fail below. else if (tt == type::word) { - if (!pre_parse_) - name = move (t.value); + name = move (t.value); } else if (tt == type::lparen) { expire_mode (); - values vs (parse_eval (t, tt, pmode)); //@@ OUT will parse @-pair and do well? + mode (lexer_mode::eval, '@'); + next_with_attributes (t, tt); - if (!pre_parse_) + // Handle the $(x) case ad hoc. We do it this way in order to get + // the variable name even during pre-parse. It should also be + // faster. + // + if (tt == type::word && peek () == type::rparen) + { + name = move (t.value); + next (t, tt); // Get `)`. + } + else { - if (vs.size () != 1) - fail (loc) << "expected single variable/function name"; + //@@ OUT will parse @-pair and do well? + // + values vs (parse_eval (t, tt, pmode)); - value& v (vs[0]); + if (!pre_parse_) + { + if (vs.size () != 1) + fail (loc) << "expected single variable/function name"; - if (!v) - fail (loc) << "null variable/function name"; + value& v (vs[0]); - names storage; - vector_view ns (reverse (v, storage)); // Movable. - size_t n (ns.size ()); + if (!v) + fail (loc) << "null variable/function name"; - // We cannot handle scope-qualification in the eval context as - // we do for target-qualification (see eval-qual) since then we - // would be treating all paths as qualified variables. So we - // have to do it here. - // - if (n == 2 && ns[0].pair == ':') // $(foo: x) - { - qual = move (ns[0]); + names storage; + vector_view ns (reverse (v, storage)); // Movable. + size_t n (ns.size ()); - if (qual.empty ()) - fail (loc) << "empty variable/function qualification"; - } - else if (n == 2 && ns[0].directory ()) // $(foo/ x) - { - qual = move (ns[0]); - qual.pair = '/'; - } - else if (n > 1) - fail (loc) << "expected variable/function name instead of '" - << ns << "'"; + // We cannot handle scope-qualification in the eval context as + // we do for target-qualification (see eval-qual) since then + // we would be treating all paths as qualified variables. So + // we have to do it here. + // + if (n == 2 && ns[0].pair == ':') // $(foo: x) + { + qual = move (ns[0]); - // Note: checked for empty below. - // - if (!ns[n - 1].simple ()) - fail (loc) << "expected variable/function name instead of '" - << ns[n - 1] << "'"; + if (qual.empty ()) + fail (loc) << "empty variable/function qualification"; + } + else if (n == 2 && ns[0].directory ()) // $(foo/ x) + { + qual = move (ns[0]); + qual.pair = '/'; + } + else if (n > 1) + fail (loc) << "expected variable/function name instead of '" + << ns << "'"; - name = move (ns[n - 1].value); + // Note: checked for empty below. + // + if (!ns[n - 1].simple ()) + fail (loc) << "expected variable/function name instead of '" + << ns[n - 1] << "'"; + + name = move (ns[n - 1].value); + } } } else @@ -5592,8 +5605,9 @@ namespace build2 { // Function call. // - next (t, tt); // Get '('. + mode (lexer_mode::eval, '@'); + next_with_attributes (t, tt); // @@ Should we use (target/scope) qualification (of name) as the // context in which to call the function? Hm, interesting... @@ -5613,12 +5627,11 @@ namespace build2 { // Variable expansion. // + lookup l (lookup_variable (move (qual), move (name), loc)); if (pre_parse_) continue; // As if empty value. - lookup l (lookup_variable (move (qual), move (name), loc)); - if (l.defined ()) result = l.value; // Otherwise leave as NULL result_data. @@ -5629,8 +5642,10 @@ namespace build2 { // Context evaluation. // - loc = get_location (t); + mode (lexer_mode::eval, '@'); + next_with_attributes (t, tt); + values vs (parse_eval (t, tt, pmode)); tt = peek (); @@ -6266,6 +6281,9 @@ namespace build2 lookup parser:: lookup_variable (name&& qual, string&& name, const location& loc) { + if (pre_parse_) + return lookup (); + tracer trace ("parser::lookup_variable", &path_); const scope* s (nullptr); diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx index 7a44e65..bc01e08 100644 --- a/libbuild2/parser.hxx +++ b/libbuild2/parser.hxx @@ -489,6 +489,12 @@ namespace build2 // If qual is not empty, then its pair member should indicate the kind // of qualification: ':' -- target, '/' -- scope. // + // Note that this function is called even during pre-parse with the result + // unused. In this case a valid name will only be provided for variables + // with literal names (for example, $x, $(x)). For computed variables (for + // example, $($x ? X : Y)) it will be empty (along with qual, which can + // only be non-empty for a computed variable). + // virtual lookup lookup_variable (name&& qual, string&& name, const location&); diff --git a/libbuild2/test/script/parser.cxx b/libbuild2/test/script/parser.cxx index 77f791e..798b743 100644 --- a/libbuild2/test/script/parser.cxx +++ b/libbuild2/test/script/parser.cxx @@ -1600,7 +1600,8 @@ namespace build2 lookup parser:: lookup_variable (name&& qual, string&& name, const location& loc) { - assert (!pre_parse_); + if (pre_parse_) + return lookup (); if (!qual.empty ()) fail (loc) << "qualified variable name"; -- cgit v1.1