diff options
Diffstat (limited to 'build/parser.cxx')
-rw-r--r-- | build/parser.cxx | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/build/parser.cxx b/build/parser.cxx index 74b41cc..c7687d3 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -19,6 +19,7 @@ #include <build/target> #include <build/prerequisite> #include <build/variable> +#include <build/module> #include <build/diagnostics> #include <build/context> @@ -49,7 +50,13 @@ namespace build default_target_ = nullptr; out_root_ = &root["out_root"].as<const path&> (); - src_root_ = &root["src_root"].as<const path&> (); + + // During bootstrap we may not know src_root yet. + // + { + auto v (root["src_root"]); + src_root_ = v ? &v.as<const path&> () : nullptr; + } token t (type::eos, false, 0, 0); type tt; @@ -105,6 +112,12 @@ namespace build include (t, tt); continue; } + else if (n == "load") + { + next (t, tt); + load (t, tt); + continue; + } } // ': foo' is equvalent to '{}: foo' and to 'dir{}: foo'. @@ -388,9 +401,24 @@ namespace build // If the path is relative then use the src directory corresponding // to the current directory scope. // - if (p.relative ()) + if (src_root_ != nullptr && p.relative ()) p = src_out (scope_->path (), *out_root_, *src_root_) / p; + p.normalize (); + + // See if there is a trigger for this path. + // + if (src_root_ != nullptr && p.sub (*src_root_)) + { + auto i (root_->triggers.find (p.leaf (*src_root_))); + + if (i != root_->triggers.end () && !i->second (*root_, p)) + { + level4 ([&]{trace (l) << "trigger instructed to skip " << p;}); + continue; + } + } + ifstream ifs (p.string ()); if (!ifs.is_open ()) @@ -420,6 +448,21 @@ namespace build lexer_ = ol; path_ = op; + + // If src_root is unknown (happens during bootstrap), reload it + // in case the just sourced buildfile set it. This way, once it + // is set, all the parser mechanism that were disabled (like + // relative file source'ing) will start working. Note that they + // will still be disabled inside the file that set src_root. For + // this to work we would need to keep a reference to the value + // stored in the variable plus the update would need to update + // the value in place (see value_proxy). + // + if (src_root_ == nullptr) + { + auto v ((*root_)["src_root"]); + src_root_ = v ? &v.as<const path&> () : nullptr; + } } if (tt == type::newline) @@ -433,6 +476,9 @@ namespace build { tracer trace ("parser::include", &path_); + if (src_root_ == nullptr) + fail (t) << "inclusion during bootstrap"; + // The rest should be a list of buildfiles. Parse them as names // to get variable expansion and directory prefixes. // @@ -551,6 +597,41 @@ namespace build } void parser:: + load (token& t, token_type& tt) + { + tracer trace ("parser::load", &path_); + + // The rest should be a list of module names. Parse them as names + // to get variable expansion, etc. + // + location l (get_location (t, &path_)); + names_type ns (tt != type::newline && tt != type::eos + ? names (t, tt) + : names_type ()); + + for (name& n: ns) + { + // For now it should be a simple name. + // + if (!n.type.empty () || !n.dir.empty ()) + fail (l) << "module name expected instead of " << n; + + const string& name (n.value); + auto i (modules.find (name)); + + if (i == modules.end ()) + fail (l) << "unknown module " << name; + + i->second (*root_, *scope_, l); + } + + 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) { for (; tt != type::newline && tt != type::eos; next (t, tt)) |