From c76fe316122969986103d243706dc7fa7ab6ddc1 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 3 Mar 2015 12:53:37 +0200 Subject: Use names() to handle include/source, support include of directories This gives us variable expansion and directory prefixes. Also, in include, if the path is a directory (either ends with / or has dir{} type), then we append 'buildfile'. --- build/parser.cxx | 71 ++++++++++++++++++++++++---------- tests/build/buildfile | 4 ++ tests/build/semantics/include/includer | 1 + tests/build/semantics/source/sourcer | 1 + 4 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 tests/build/buildfile diff --git a/build/parser.cxx b/build/parser.cxx index d5b07b1..1ff841b 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -435,14 +435,20 @@ namespace build { tracer trace ("parser::source", &path_); - // The rest should be a list of paths to buildfiles. + // The rest should be a list of buildfiles. Parse them as names + // to get variable expansion and directory prefixes. // - for (; tt != type::newline && tt != type::eos; next (t, tt)) - { - if (tt != type::name) - fail (t) << "expected buildfile to source instead of " << t; + location l (get_location (t, &path_)); + names_type ns (tt != type::newline && tt != type::eos + ? names (t, tt) + : names_type ()); - path p (t.name ()); + for (name& n: ns) + { + // Construct the buildfile path. + // + path p (move (n.dir)); + p /= path (move (n.value)); // If the path is relative then use the src directory corresponding // to the current directory scope. @@ -453,7 +459,7 @@ namespace build ifstream ifs (p.string ()); if (!ifs.is_open ()) - fail (t) << "unable to open " << p; + fail (l) << "unable to open " << p; ifs.exceptions (ifstream::failbit | ifstream::badbit); @@ -467,6 +473,8 @@ namespace build lexer* ol (lexer_); lexer_ = &l; + token t (type::eos, false, 0, 0); + type tt; next (t, tt); clause (t, tt); @@ -479,8 +487,10 @@ namespace build path_ = op; } - if (tt != type::eos) - next (t, tt); // Swallow newline. + if (tt == type::newline) + next (t, tt); + else if (tt != type::eos) + fail (t) << "expected newline instead of " << t; } void parser:: @@ -488,16 +498,33 @@ namespace build { tracer trace ("parser::include", &path_); - // The rest should be a list of paths to buildfiles. + // The rest should be a list of buildfiles. Parse them as names + // to get variable expansion and directory prefixes. // - for (; tt != type::newline && tt != type::eos; next (t, tt)) + location l (get_location (t, &path_)); + names_type ns (tt != type::newline && tt != type::eos + ? names (t, tt) + : names_type ()); + + for (name& n: ns) { - if (tt != type::name) - fail (t) << "expected buildfile to include instead of " << t; + // Construct the buildfile path. If it is a directory, then append + // 'buildfile'. + // + path p (move (n.dir)); + if (n.value.empty ()) + p /= path ("buildfile"); + else + { + bool d (path::traits::is_separator (n.value.back ()) + || n.type == "dir"); - path p (t.name ()); - bool in_out (false); + p /= path (move (n.value)); + if (d) + p /= path ("buildfile"); + } + bool in_out (false); if (p.absolute ()) { p.normalize (); @@ -506,7 +533,7 @@ namespace build // to be used for intra-project inclusion. // if (!p.sub (src_root) && !(in_out = p.sub (out_root))) - fail (t) << "out of project include " << p; + fail (l) << "out of project include " << p; } else { @@ -518,14 +545,14 @@ namespace build if (!include_.insert (p).second) { - level4 ([&]{trace (t) << "skipping already included " << p;}); + level4 ([&]{trace (l) << "skipping already included " << p;}); continue; } ifstream ifs (p.string ()); if (!ifs.is_open ()) - fail (t) << "unable to open " << p; + fail (l) << "unable to open " << p; ifs.exceptions (ifstream::failbit | ifstream::badbit); @@ -545,6 +572,8 @@ namespace build target* odt (default_target_); default_target_ = nullptr; + token t (type::eos, false, 0, 0); + type tt; next (t, tt); clause (t, tt); @@ -561,8 +590,10 @@ namespace build path_ = op; } - if (tt != type::eos) - next (t, tt); // Swallow newline. + if (tt == type::newline) + next (t, tt); + else if (tt != type::eos) + fail (t) << "expected newline instead of " << t; } void parser:: diff --git a/tests/build/buildfile b/tests/build/buildfile new file mode 100644 index 0000000..99a0a6f --- /dev/null +++ b/tests/build/buildfile @@ -0,0 +1,4 @@ +d=path/ prefix-map/ + +.: $d +include $d diff --git a/tests/build/semantics/include/includer b/tests/build/semantics/include/includer index c129e33..70527a5 100644 --- a/tests/build/semantics/include/includer +++ b/tests/build/semantics/include/includer @@ -7,3 +7,4 @@ nested/: include includee5 include ../includee2 # skipped } +: diff --git a/tests/build/semantics/source/sourcer b/tests/build/semantics/source/sourcer index e8b9558..eb1310e 100644 --- a/tests/build/semantics/source/sourcer +++ b/tests/build/semantics/source/sourcer @@ -6,3 +6,4 @@ nested/: source sourcee3 source ../sourcee1 } +: -- cgit v1.1