aboutsummaryrefslogtreecommitdiff
path: root/build/parser.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-01 13:39:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-01 13:42:10 +0200
commit7996c2bfc2d7e998e2f9f1236d457ec7bea8ad8a (patch)
treedca79d3657bec47d4cd5db85899a70d3d49c079e /build/parser.cxx
parentf355a4379f035df61a7702f5ff805eefb004fb20 (diff)
Implement support for definition target type aliases
For example: define cli=file Currently, the semantics is that of a real alias with only name differences that are used for display. See tests/define/buildfile for more use cases.
Diffstat (limited to 'build/parser.cxx')
-rw-r--r--build/parser.cxx76
1 files changed, 75 insertions, 1 deletions
diff --git a/build/parser.cxx b/build/parser.cxx
index bc6caa9..4981347 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -12,6 +12,9 @@
#include <iterator> // make_move_iterator()
#include <iostream>
+#include <build/types>
+#include <build/utility>
+
#include <build/token>
#include <build/lexer>
@@ -130,6 +133,11 @@ namespace build
using_ (t, tt);
continue;
}
+ else if (n == "define")
+ {
+ define (t, tt);
+ continue;
+ }
}
// ': foo' is equvalent to '{}: foo' and to 'dir{}: foo'.
@@ -343,7 +351,7 @@ namespace build
const target_type* ti (
n.untyped ()
? &target::static_type
- : scope_->find_target_type (n.type.c_str ()));
+ : scope_->find_target_type (n.type));
if (ti == nullptr)
fail (nloc) << "unknown target type " << n.type;
@@ -799,6 +807,72 @@ namespace build
fail (t) << "expected newline instead of " << t;
}
+ static target*
+ alias_factory (const target_type& tt, dir_path d, string n, const string* e)
+ {
+ assert (tt.origin != nullptr);
+ target* r (tt.origin->factory (*tt.origin, move (d), move (n), e));
+ r->alias_type = &tt;
+ return r;
+ }
+
+ void parser::
+ define (token& t, token_type& tt)
+ {
+ // define <alias>=<name>
+ //
+ // See tests/define/buildfile.
+ //
+ if (next (t, tt) != type::name)
+ fail (t) << "expected name instead of " << t << " in target type "
+ << "definition";
+
+ string a (move (t.value));
+ const location al (get_location (t, &path_));
+
+ if (next (t, tt) != type::equal)
+ fail (t) << "expected '=' instead of " << t << " in target type "
+ << "definition";
+
+ next (t, tt);
+
+ if (tt == type::name)
+ {
+ // Alias.
+ //
+ const string& n (t.value);
+ const target_type* ntt (scope_->find_target_type (n));
+
+ if (ntt == nullptr)
+ fail (t) << "unknown target type " << n;
+
+ unique_ptr<target_type> att (new target_type (*ntt));
+ att->factory = &alias_factory;
+ att->origin = ntt->origin != nullptr ? ntt->origin : ntt;
+
+ target_type& ratt (*att); // Save non-const reference to the object.
+
+ auto pr (scope_->target_types.emplace (a, target_type_ref (move (att))));
+
+ if (!pr.second)
+ fail (al) << "target type " << a << " already define in this scope";
+
+ // Patch the alias name to use the map's key storage.
+ //
+ ratt.name = pr.first->first.c_str ();
+
+ next (t, tt); // Get newline.
+ }
+ else
+ fail (t) << "expected name instead of " << t << " in target type "
+ << "definition";
+
+ if (tt == type::newline)
+ next (t, tt);
+ else if (tt != type::eos)
+ fail (t) << "expected newline instead of " << t;
+ }
+
void parser::
print (token& t, token_type& tt)
{