aboutsummaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-03 17:49:12 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-03 17:49:12 +0200
commit9c45022422bc9826da36631bfe1184658956daaf (patch)
treef98bf7ef4ea82d34c4f05d7f452b840cfc77b0fe /build
parent6298f309bddaf3f279a724034e2d1d3ce58e0e1a (diff)
Implement new potential directive keyword test
Now we can use directive names as variables and targets type, for example: print = foo # variable print{foo}: # target
Diffstat (limited to 'build')
-rw-r--r--build/parser5
-rw-r--r--build/parser.cxx35
2 files changed, 36 insertions, 4 deletions
diff --git a/build/parser b/build/parser
index ca27890..f3f88d5 100644
--- a/build/parser
+++ b/build/parser
@@ -128,6 +128,11 @@ namespace build
void
skip_block (token&, token_type&);
+ // Return true if the name token can be considered a directive keyword.
+ //
+ bool
+ keyword (token&);
+
// Buildspec.
//
buildspec
diff --git a/build/parser.cxx b/build/parser.cxx
index de4cfdc..a4e2af0 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -99,10 +99,9 @@ namespace build
tt != type::colon) // Empty name: ': ...'
break; // Something else. Let our caller handle that.
- // See if this is one of the directives. This should be an
- // unquoted literal name.
+ // See if this is one of the directives.
//
- if (tt == type::name && !t.quoted)
+ if (tt == type::name && keyword (t))
{
const string& n (t.value);
@@ -985,7 +984,7 @@ namespace build
// See if we have another el* keyword.
//
- if (k != "else" && tt == type::name)
+ if (k != "else" && tt == type::name && keyword (t))
{
const string& n (t.value);
@@ -1739,6 +1738,34 @@ namespace build
}
}
+ bool parser::
+ keyword (token& t)
+ {
+ assert (t.type == type::name);
+
+ // The goal here is to allow using keywords as variable names and
+ // target types without imposing ugly restrictions/decorators on
+ // keywords (e.g., '.using' or 'USING'). A name is considered a
+ // potential keyword if:
+ //
+ // - it is not quoted [so a keyword can always be escaped] and
+ // - next token is separated or is '(' [so if(...) will work] and
+ // - next token is not '=' or '+=' [which means a "directive body"
+ // can never start with one of them].
+ //
+ // See tests/keyword.
+ //
+ if (!t.quoted)
+ {
+ type pt (peek ());
+
+ return pt == type::lparen ||
+ (pt != type::equal && pt != type::plus_equal && peeked ().separated);
+ }
+
+ return false;
+ }
+
// Buildspec parsing.
//