aboutsummaryrefslogtreecommitdiff
path: root/build2/parser.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-11-20 13:11:59 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-11-20 18:29:45 +0200
commit9964a9aca03b38c2959994e0fdc91014da252cb8 (patch)
tree4c263c8f9ee422de9f27aecdb05a040ee116ddae /build2/parser.cxx
parent4184f61e2b795dd4c4b4a974a890bdaf98906b82 (diff)
Implement dump directive
It can be used to print (to stderr) a human-readable representation of the current scope or a list of targets. For example: dump # Dump current scope. dump lib{foo} details/exe{bar} # Dump two targets. This is primarily useful for debugging as well as to write build system tests.
Diffstat (limited to 'build2/parser.cxx')
-rw-r--r--build2/parser.cxx109
1 files changed, 100 insertions, 9 deletions
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 1863f67..7c8695a 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -9,6 +9,7 @@
#include <libbutl/filesystem.mxx> // path_search(), path_match()
+#include <build2/dump.hxx>
#include <build2/file.hxx>
#include <build2/scope.hxx>
#include <build2/module.hxx>
@@ -112,6 +113,40 @@ namespace build2
tracer& tr)
: p_ (&p), t_ (p.target_)
{
+ // Find or insert.
+ //
+ auto r (process_target (p, n, o, loc));
+ p.target_ = &targets.insert (*r.first, // target type
+ move (n.dir),
+ move (o.dir),
+ move (n.value),
+ move (r.second), // extension
+ implied,
+ tr).first;
+ }
+
+ static const target*
+ find_target (parser& p,
+ name& n, // If n.pair, then o is out dir.
+ name& o,
+ const location& loc,
+ tracer& tr)
+ {
+ auto r (process_target (p, n, o, loc));
+ return targets.find (*r.first, // target type
+ n.dir,
+ o.dir,
+ n.value,
+ r.second, // extension
+ tr);
+ }
+
+ static pair<const target_type*, optional<string>>
+ process_target (parser& p,
+ name& n, // If n.pair, then o is out dir.
+ name& o,
+ const location& loc)
+ {
optional<string> e;
const target_type* ti (p.scope_->find_target_type (n, e));
@@ -148,16 +183,9 @@ namespace build2
out = o.dir.relative () ? od / o.dir : move (o.dir);
out.normalize ();
}
+ o.dir = move (out); // Result.
- // Find or insert.
- //
- p.target_ = &targets.insert (*ti,
- move (d),
- move (out),
- move (n.value),
- move (e),
- implied,
- tr).first;
+ return make_pair (ti, move (e));
}
~enter_target ()
@@ -348,6 +376,10 @@ namespace build2
{
f = &parser::parse_diag;
}
+ else if (n == "dump")
+ {
+ f = &parser::parse_dump;
+ }
else if (n == "source")
{
f = &parser::parse_source;
@@ -1823,6 +1855,65 @@ namespace build2
next (t, tt); // Swallow newline.
}
+ void parser::
+ parse_dump (token& t, type& tt)
+ {
+ // dump [<target>...]
+ //
+ // If there are no targets, then we dump the current scope.
+ //
+ tracer trace ("parser::parse_dump", &path_);
+
+ const location l (get_location (t));
+ next (t, tt);
+ names ns (tt != type::newline && tt != type::eos
+ ? parse_names (t, tt, pattern_mode::ignore)
+ : names ());
+
+ text (l) << "dump:";
+
+ // Dump directly into diag_stream.
+ //
+ ostream& os (*diag_stream);
+
+ // Print directories as absolute.
+ //
+ const dir_path* orb (relative_base);
+ relative_base = &empty_dir_path;
+
+ if (ns.empty ())
+ {
+ if (scope_ != nullptr)
+ dump (*scope_, " "); // Indent two spaces.
+ else
+ os << " <no current scope>" << endl;
+ }
+ else
+ {
+ for (auto i (ns.begin ()), e (ns.end ()); i != e; ++i)
+ {
+ name& n (*i);
+ name o (n.pair ? move (*++i) : name ());
+
+ const target* t (enter_target::find_target (*this, n, o, l, trace));
+
+ if (t != nullptr)
+ dump (*t, " "); // Indent two spaces.
+ else
+ {
+ os << " <no target " << n;
+ if (n.pair && !o.dir.empty ()) os << '@' << o.dir;
+ os << '>' << endl;
+ }
+ }
+ }
+
+ relative_base = orb;
+
+ if (tt != type::eos)
+ next (t, tt); // Swallow newline.
+ }
+
string parser::
parse_variable_name (names&& ns, const location& l)
{