aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-06-03 08:39:36 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-06-03 08:39:36 +0200
commitbc3c8492f129d9295c9ef6c325bf2c99e88ca73e (patch)
tree79fa0ccfbf030568caa2d521f3bc3dbc613d4796
parent7368566619bc990b69f90a4828be2966854fa785 (diff)
Factor implementation-specific ad hoc recipe parsing to adhoc_*_rule
-rw-r--r--libbuild2/forward.hxx5
-rw-r--r--libbuild2/parser.cxx108
-rw-r--r--libbuild2/parser.hxx34
-rw-r--r--libbuild2/rule.cxx42
-rw-r--r--libbuild2/rule.hxx32
5 files changed, 128 insertions, 93 deletions
diff --git a/libbuild2/forward.hxx b/libbuild2/forward.hxx
index 1679b4a..4443610 100644
--- a/libbuild2/forward.hxx
+++ b/libbuild2/forward.hxx
@@ -70,6 +70,11 @@ namespace build2
// <libbuild2/context.hxx>
//
class context;
+
+ // <libbuild2/parser.hxx>
+ //
+ struct attribute;
+ struct attributes;
}
#endif // LIBBUILD2_FORWARD_HXX
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 72d189e..65a42fe 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -20,9 +20,6 @@
#include <libbuild2/diagnostics.hxx>
#include <libbuild2/prerequisite.hxx>
-#include <libbuild2/build/script/parser.hxx>
-#include <libbuild2/build/script/script.hxx>
-
#include <libbuild2/config/utility.hxx> // lookup_config
using namespace std;
@@ -33,7 +30,7 @@ namespace build2
using type = token_type;
ostream&
- operator<< (ostream& o, const parser::attribute& a)
+ operator<< (ostream& o, const attribute& a)
{
o << a.name;
@@ -1111,24 +1108,9 @@ namespace build2
else
fail (t) << "expected recipe language instead of " << t;
- mode (lexer_mode::foreign, '\0', st.value.size ());
- next_after_newline (t, tt, st); // Should be on its own line.
-
- if (tt != type::word)
- {
- diag_record dr;
-
- dr << fail (t) << "unterminated recipe ";
- if (kind.empty ()) dr << "block"; else dr << kind << "-block";
-
- dr << info (st) << "recipe ";
- if (kind.empty ()) dr << "block"; else dr << kind << "-block";
- dr << " starts here" << endf;
- }
-
+ shared_ptr<adhoc_rule> ar;
if (!skip)
{
- shared_ptr<adhoc_rule> ar;
if (d.first)
{
// Note that this is always the location of the opening multi-
@@ -1138,72 +1120,62 @@ namespace build2
//
location loc (get_location (st));
- // Buildscript
- //
if (!lang)
{
- // Handle and erase recipe-specific attributes.
+ // Buildscript
//
- optional<string> diag;
- for (auto i (d.as.begin ()); i != d.as.end (); )
- {
- attribute& a (*i);
- const string& n (a.name);
-
- if (n == "diag")
- try
- {
- diag = convert<string> (move (a.value));
- }
- catch (const invalid_argument& e)
- {
- fail (d.as.loc) << "invalid " << n << " attribute value: "
- << e;
- }
- else
- {
- ++i;
- continue;
- }
-
- i = d.as.erase (i);
- }
-
- auto* asr (new adhoc_script_rule (loc, st.value.size ()));
- ar.reset (asr);
-
- asr->checksum = sha256 (t.value).string ();
-
- istringstream is (move (t.value));
- build::script::parser p (ctx);
- asr->script = p.pre_parse (
- is, asr->loc.file, loc.line + 1, move (diag));
+ ar.reset (new adhoc_script_rule (loc, st.value.size ()));
}
- //
- // C++
- //
else if (*lang == "c++")
{
- ar.reset (new adhoc_cxx_rule (
- move (t.value), loc, st.value.size ()));
- d.clean = true;
+ // C++
+ //
+ ar.reset (new adhoc_cxx_rule (loc, st.value.size ()));
}
else
fail (lloc) << "unknown recipe language '" << *lang << "'";
- // Verify we have no unhandled attributes.
- //
- for (attribute& a: d.as)
- fail (d.as.loc) << "unknown recipe attribute " << a << endf;
-
assert (d.recipes[d.i] == nullptr);
d.recipes[d.i] = ar;
}
else
{
+ skip_line (t, tt);
+
assert (d.recipes[d.i] != nullptr);
ar = d.recipes[d.i];
}
+ }
+ else
+ skip_line (t, tt);
+
+ mode (lexer_mode::foreign, '\0', st.value.size ());
+ next_after_newline (t, tt, st); // Should be on its own line.
+
+ if (tt != type::word)
+ {
+ diag_record dr;
+
+ dr << fail (t) << "unterminated recipe ";
+ if (kind.empty ()) dr << "block"; else dr << kind << "-block";
+
+ dr << info (st) << "recipe ";
+ if (kind.empty ()) dr << "block"; else dr << kind << "-block";
+ dr << " starts here" << endf;
+ }
+
+ if (!skip)
+ {
+ if (d.first)
+ {
+ if (ar->recipe_text (ctx, move (t.value), d.as))
+ d.clean = true;
+
+ // Verify we have no unhandled attributes.
+ //
+ for (attribute& a: d.as)
+ fail (d.as.loc) << "unknown recipe attribute " << a << endf;
+ }
target_->adhoc_recipes.push_back (
adhoc_recipe {perform_update_id, move (ar)});
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 66a985a..88b4ad9 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -19,6 +19,23 @@
namespace build2
{
+ struct attribute
+ {
+ string name;
+ build2::value value;
+ };
+
+ ostream&
+ operator<< (ostream&, const attribute&);
+
+ struct attributes: small_vector<attribute, 1>
+ {
+ location loc; // Start location.
+
+ explicit
+ attributes (location l = {}): loc (move (l)) {}
+ };
+
class LIBBUILD2_SYMEXPORT parser
{
public:
@@ -261,23 +278,6 @@ namespace build2
//
// In this example we only apply the value attributes after evaluating
// the context, which has its own attributes.
- //
- struct attribute
- {
- string name;
- build2::value value;
- };
-
- friend ostream&
- operator<< (ostream&, const attribute&);
-
- struct attributes: small_vector<attribute, 1>
- {
- location loc; // Start location.
-
- explicit
- attributes (location l = {}): loc (move (l)) {}
- };
// Push a new entry into the attributes_ stack. If the next token is `[`
// then parse the attribute sequence until ']' storing the result in the
diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx
index 5f532ef..7f9c357 100644
--- a/libbuild2/rule.cxx
+++ b/libbuild2/rule.cxx
@@ -3,6 +3,8 @@
#include <libbuild2/rule.hxx>
+#include <sstream>
+
#include <libbuild2/file.hxx>
#include <libbuild2/depdb.hxx>
#include <libbuild2/scope.hxx>
@@ -12,6 +14,8 @@
#include <libbuild2/filesystem.hxx>
#include <libbuild2/diagnostics.hxx>
+#include <libbuild2/parser.hxx> // attributes
+
#include <libbuild2/build/script/parser.hxx>
#include <libbuild2/build/script/runner.hxx>
@@ -360,6 +364,44 @@ namespace build2
// adhoc_script_rule
//
+ bool adhoc_script_rule::
+ recipe_text (context& ctx, string&& t, attributes& as)
+ {
+ // Handle and erase recipe-specific attributes.
+ //
+ optional<string> diag;
+ for (auto i (as.begin ()); i != as.end (); )
+ {
+ attribute& a (*i);
+ const string& n (a.name);
+
+ if (n == "diag")
+ try
+ {
+ diag = convert<string> (move (a.value));
+ }
+ catch (const invalid_argument& e)
+ {
+ fail (as.loc) << "invalid " << n << " attribute value: " << e;
+ }
+ else
+ {
+ ++i;
+ continue;
+ }
+
+ i = as.erase (i);
+ }
+
+ checksum = sha256 (t).string ();
+
+ istringstream is (move (t));
+ build::script::parser p (ctx);
+ script = p.pre_parse (is, loc.file, loc.line + 1, move (diag));
+
+ return false;
+ }
+
void adhoc_script_rule::
dump (ostream& os, string& ind) const
{
diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx
index 36e4733..05be9eb 100644
--- a/libbuild2/rule.hxx
+++ b/libbuild2/rule.hxx
@@ -116,7 +116,7 @@ namespace build2
// Ad hoc rule.
//
- // Note: not exported
+ // Note: not exported.
//
class adhoc_rule: public rule
{
@@ -129,6 +129,13 @@ namespace build2
braces (b),
rule_match ("adhoc", static_cast<const rule&> (*this)) {}
+ // Set the rule text, handle any recipe-specific attributes, and return
+ // true if the recipe builds anything in the build/recipes/ directory and
+ // therefore requires cleanup.
+ //
+ virtual bool
+ recipe_text (context&, string&&, attributes&) = 0;
+
public:
// Some of the operations come in compensating pairs, such as update and
// clean, install and uninstall. An ad hoc rule implementation may choose
@@ -184,13 +191,16 @@ namespace build2
virtual void
dump (ostream&, string&) const override;
- using script_type = build::script::script;
-
adhoc_script_rule (const location& l, size_t b): adhoc_rule (l, b) {}
+ virtual bool
+ recipe_text (context&, string&&, attributes&) override;
+
public:
+ using script_type = build::script::script;
+
script_type script;
- string checksum; // Script text hashsum.
+ string checksum; // Script text hash.
};
// Ad hoc C++ rule.
@@ -200,7 +210,6 @@ namespace build2
class LIBBUILD2_SYMEXPORT cxx_rule: public rule
{
public:
-
// A robust recipe may want to incorporate the recipe_state into its
// up-to-date decision as if the recipe library was a prerequisite (it
// cannot be injected as a real prerequisite since it's from a different
@@ -232,8 +241,15 @@ namespace build2
virtual void
dump (ostream&, string&) const override;
- adhoc_cxx_rule (string c, const location& l, size_t b)
- : adhoc_rule (l, b), code (move (c)), impl (nullptr) {}
+ adhoc_cxx_rule (const location& l, size_t b)
+ : adhoc_rule (l, b), impl (nullptr) {}
+
+ virtual bool
+ recipe_text (context&, string&& t, attributes&) override
+ {
+ code = move (t);
+ return true;
+ }
virtual
~adhoc_cxx_rule () override;
@@ -242,7 +258,7 @@ namespace build2
// Note that this recipe (rule instance) can be shared between multiple
// targets which could all be matched in parallel.
//
- const string code;
+ string code;
mutable atomic<cxx_rule*> impl;
};
}