aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--build/parser5
-rw-r--r--build/parser.cxx35
-rw-r--r--tests/directive/buildfile8
-rw-r--r--tests/directive/test.out1
-rw-r--r--tests/keyword/buildfile23
-rw-r--r--tests/keyword/test.out2
-rwxr-xr-xtests/keyword/test.sh (renamed from tests/directive/test.sh)0
7 files changed, 61 insertions, 13 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.
//
diff --git a/tests/directive/buildfile b/tests/directive/buildfile
deleted file mode 100644
index 0f83717..0000000
--- a/tests/directive/buildfile
+++ /dev/null
@@ -1,8 +0,0 @@
-"print" = a
-'print' += b
-pr"int" += c
-print'' += d
-
-print $print
-
-./:
diff --git a/tests/directive/test.out b/tests/directive/test.out
deleted file mode 100644
index 8e13e46..0000000
--- a/tests/directive/test.out
+++ /dev/null
@@ -1 +0,0 @@
-a b c d
diff --git a/tests/keyword/buildfile b/tests/keyword/buildfile
new file mode 100644
index 0000000..cd91d33
--- /dev/null
+++ b/tests/keyword/buildfile
@@ -0,0 +1,23 @@
+# Quoting.
+#
+"print" = a
+'print' += b
+pr"int" += c
+print'' += d
+
+# Not = or +=.
+#
+print += e
+
+print $print
+
+# <name>(
+#
+print(test)
+
+# Separated.
+#
+define print: file
+print{foo}:
+
+./:
diff --git a/tests/keyword/test.out b/tests/keyword/test.out
new file mode 100644
index 0000000..729af10
--- /dev/null
+++ b/tests/keyword/test.out
@@ -0,0 +1,2 @@
+a b c d e
+test
diff --git a/tests/directive/test.sh b/tests/keyword/test.sh
index b898b3c..b898b3c 100755
--- a/tests/directive/test.sh
+++ b/tests/keyword/test.sh