aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-06-10 10:01:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-06-10 10:01:45 +0200
commit1ea33ab70f88fcfebf388a9a438e3c1e56fbdf0f (patch)
tree359f61dc51fee77abd1f376b45418501de549104
parentd5faeeab1d2115c02a330ac9c95d63ba225faabc (diff)
Handle special variable names when spelled as $(<char>) rather than $<char>
-rw-r--r--libbuild2/lexer.cxx3
-rw-r--r--libbuild2/lexer.hxx3
-rw-r--r--libbuild2/parser.cxx43
-rw-r--r--libbuild2/parser.hxx25
-rw-r--r--libbuild2/token.hxx1
5 files changed, 69 insertions, 6 deletions
diff --git a/libbuild2/lexer.cxx b/libbuild2/lexer.cxx
index 2f2ace4..4256422 100644
--- a/libbuild2/lexer.cxx
+++ b/libbuild2/lexer.cxx
@@ -111,6 +111,9 @@ namespace build2
}
case lexer_mode::eval:
{
+ // NOTE: remember to update special() lambda in parse_names() if
+ // adding any new single-character tokens to the eval mode.
+ //
s1 = ":<>=!&|?, $(){}#\t\n";
s2 = " = &| ";
break;
diff --git a/libbuild2/lexer.hxx b/libbuild2/lexer.hxx
index f577828..6c2b90b 100644
--- a/libbuild2/lexer.hxx
+++ b/libbuild2/lexer.hxx
@@ -161,6 +161,9 @@ namespace build2
lexer_mode
mode () const {return state_.top ().mode;}
+ uintptr_t
+ mode_data () const {return state_.top ().data;}
+
char
pair_separator () const {return state_.top ().sep_pair;}
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index db00633..36e75a3 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -5815,7 +5815,44 @@ namespace build2
// token is a paren or a word, we turn it on and switch to the eval
// mode if what we get next is a paren.
//
+ // Also sniff out the special variables string from mode data for
+ // the ad hoc $() handling below.
+ //
mode (lexer_mode::variable);
+
+ auto special = [s = reinterpret_cast<const char*> (mode_data ())]
+ (const token& t) -> char
+ {
+ char r ('\0');
+
+ if (s != nullptr)
+ {
+ switch (t.type)
+ {
+ case type::less: r = '<'; break;
+ case type::greater: r = '>'; break;
+ case type::colon: r = ':'; break;
+ case type::dollar: r = '$'; break;
+ case type::question: r = '?'; break;
+ case type::comma: r = ','; break;
+ case type::log_not: r = '!'; break;
+ case type::lparen: r = '('; break;
+ case type::rparen: r = ')'; break;
+ case type::lcbrace: r = '{'; break;
+ case type::rcbrace: r = '}'; break;
+ case type::lsbrace: r = '['; break;
+ case type::rsbrace: r = ']'; break;
+ case type::pair_separator: r = t.value[0]; break;
+ default: break;
+ }
+
+ if (r != '\0' && strchr (s, r) == nullptr)
+ r = '\0';
+ }
+
+ return r;
+ };
+
next (t, tt);
loc = get_location (t);
@@ -5838,9 +5875,11 @@ namespace build2
// the variable name even during pre-parse. It should also be
// faster.
//
- if (tt == type::word && peek () == type::rparen)
+ char c;
+ if ((tt == type::word || (c = special (t))) &&
+ peek () == type::rparen)
{
- name = move (t.value);
+ name = (tt == type::word ? move (t.value) : string (1, c));
next (t, tt); // Get `)`.
}
else
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 78c7d17..2db7ade 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -611,8 +611,9 @@ namespace build2
lexer_->mode (m, ps, nullopt, d);
else
// As a sanity check, make sure the mode matches the next token. Note
- // that we don't check the attributes flags or the pair separator
- // since they can be overridden by the lexer's mode() implementation.
+ // that we don't check the attributes flags, the pair separator, or
+ // the mode data since they can be overridden by the lexer's mode()
+ // implementation.
//
assert (replay_i_ != replay_data_.size () &&
replay_data_[replay_i_].mode == m);
@@ -630,6 +631,18 @@ namespace build2
}
}
+ uintptr_t
+ mode_data () const
+ {
+ if (replay_ != replay::play)
+ return lexer_->mode_data ();
+ else
+ {
+ assert (replay_i_ != replay_data_.size ());
+ return replay_data_[replay_i_].mode_data;
+ }
+ }
+
void
enable_attributes ()
{
@@ -753,8 +766,12 @@ namespace build2
replay_token
lexer_next ()
{
- lexer_mode m (lexer_->mode ()); // Get it first since it may expire.
- return replay_token {lexer_->next (), path_, m};
+ // Get these first since the mode may expire.
+ //
+ lexer_mode m (lexer_->mode ());
+ uintptr_t d (lexer_->mode_data ());
+
+ return replay_token {lexer_->next (), path_, m, d};
}
const replay_token&
diff --git a/libbuild2/token.hxx b/libbuild2/token.hxx
index 156e428..7344ecd 100644
--- a/libbuild2/token.hxx
+++ b/libbuild2/token.hxx
@@ -206,6 +206,7 @@ namespace build2
build2::token token;
const path_name* file;
lexer_mode_base mode;
+ uintptr_t mode_data;
using location_type = build2::location;