aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-05-20 14:00:32 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-05-27 08:35:29 +0200
commit82ee575b32bc57598cec5eaaa3a170ac36de9af0 (patch)
tree68274e597b5d378b0b0209b5dedf9451d2c940b1
parent7c8e544b520cc46c174a952e63ccd2d71002516d (diff)
Add ability to notice variable expansions in pre-parse mode
-rw-r--r--libbuild2/build/script/parser.cxx3
-rw-r--r--libbuild2/parser.cxx110
-rw-r--r--libbuild2/parser.hxx6
-rw-r--r--libbuild2/test/script/parser.cxx3
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<build2::name> 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<build2::name> 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";