aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-06-05 06:36:30 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-06-05 06:36:30 +0200
commit9ec2bdd87659438b4aa021a10c4a4977ef77118e (patch)
tree12580b4d0b82bce80047b067c3bb221b49be7449
parentd280946474568925016359be742b59fd6c000c52 (diff)
Add ability to specify ad hoc recipe actions
We are reusing the buildspec syntax for that.
-rw-r--r--build2/b.cli5
-rw-r--r--build2/b.cxx2
-rw-r--r--libbuild2/algorithm.cxx36
-rw-r--r--libbuild2/build/script/parser.cxx2
-rw-r--r--libbuild2/buildspec.cxx (renamed from libbuild2/spec.cxx)4
-rw-r--r--libbuild2/buildspec.hxx (renamed from libbuild2/spec.hxx)14
-rw-r--r--libbuild2/config/operation.cxx2
-rw-r--r--libbuild2/dump.cxx13
-rw-r--r--libbuild2/forward.hxx2
-rw-r--r--libbuild2/lexer.cxx8
-rw-r--r--libbuild2/parser.cxx130
-rw-r--r--libbuild2/parser.hxx4
-rw-r--r--libbuild2/recipe.hxx6
-rw-r--r--libbuild2/rule.cxx34
-rw-r--r--libbuild2/rule.hxx22
-rw-r--r--tests/dependency/recipe/testscript108
16 files changed, 284 insertions, 108 deletions
diff --git a/build2/b.cli b/build2/b.cli
index c6a4e3e..355e2d9 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -48,8 +48,9 @@ namespace build2
omitted, then it defaults to \cb{perform}. If <operation> is omitted,
then it defaults to the default operation for this meta-operation. For
\cb{perform} it is \cb{update}. Finally, if <target> is omitted, then it
- defaults to the current working directory. Some operations and
- meta-operations may take additional <parameters>. For example:
+ defaults to the current working directory. A meta-operation on operation
+ is called an \i{action}. Some operations and meta-operations may take
+ additional <parameters>. For example:
\
$ b # perform(update(./))
diff --git a/build2/b.cxx b/build2/b.cxx
index fdd1b1c..bae40b6 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -28,13 +28,13 @@
#include <libbuild2/dump.hxx>
#include <libbuild2/file.hxx>
#include <libbuild2/rule.hxx>
-#include <libbuild2/spec.hxx>
#include <libbuild2/scope.hxx>
#include <libbuild2/module.hxx>
#include <libbuild2/target.hxx>
#include <libbuild2/context.hxx>
#include <libbuild2/variable.hxx>
#include <libbuild2/algorithm.hxx>
+#include <libbuild2/buildspec.hxx>
#include <libbuild2/operation.hxx>
#include <libbuild2/filesystem.hxx>
#include <libbuild2/diagnostics.hxx>
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 0924540..6ea1e1f 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -335,20 +335,32 @@ namespace build2
// the correct semantics.
auto b (t.adhoc_recipes.begin ()), e (t.adhoc_recipes.end ());
- auto i (find_if (b, e,
- [a, &t] (const adhoc_recipe& r)
- {
- return r.action == a &&
- r.rule->match (a, t, string () /* hint */, nullopt);
- }));
+ auto i (find_if (
+ b, e,
+ [a, &t] (const adhoc_recipe& r)
+ {
+ auto& as (r.actions);
+ return (find (as.begin (), as.end (), a) != as.end () &&
+ r.rule->match (a, t, string () /* hint */, nullopt));
+ }));
if (i == e)
- i = find_if (b, e,
- [a, &t] (const adhoc_recipe& r)
- {
- return r.action != a &&
- r.rule->match (a, t, string () /* hint */, r.action);
- });
+ i = find_if (
+ b, e,
+ [a, &t] (const adhoc_recipe& r)
+ {
+ // See the adhoc_rule::match() documentation for details.
+ //
+ auto& as (r.actions);
+ if (find (as.begin (), as.end (), a) == as.end ())
+ {
+ for (auto ra: as)
+ if (r.rule->match (a, t, string () /* hint */, ra))
+ return true;
+ }
+ return false;
+ });
+
if (i != e)
return &i->rule->rule_match;
}
diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx
index 72c99ad..274faf0 100644
--- a/libbuild2/build/script/parser.cxx
+++ b/libbuild2/build/script/parser.cxx
@@ -385,7 +385,7 @@ namespace build2
<< "the 'diag' recipe attribute";
dr << info << "or provide custom low-verbosity diagnostics "
- << " with the 'diag' builtin";
+ << "with the 'diag' builtin";
};
parse_names_result pr;
diff --git a/libbuild2/spec.cxx b/libbuild2/buildspec.cxx
index d1a39ab..bd580ca 100644
--- a/libbuild2/spec.cxx
+++ b/libbuild2/buildspec.cxx
@@ -1,7 +1,7 @@
-// file : libbuild2/spec.cxx -*- C++ -*-
+// file : libbuild2/buildspec.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <libbuild2/spec.hxx>
+#include <libbuild2/buildspec.hxx>
#include <libbuild2/diagnostics.hxx>
diff --git a/libbuild2/spec.hxx b/libbuild2/buildspec.hxx
index d2ed609..b181d15 100644
--- a/libbuild2/spec.hxx
+++ b/libbuild2/buildspec.hxx
@@ -1,8 +1,8 @@
-// file : libbuild2/spec.hxx -*- C++ -*-
+// file : libbuild2/buildspec.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef LIBBUILD2_SPEC_HXX
-#define LIBBUILD2_SPEC_HXX
+#ifndef LIBBUILD2_BUILDSPEC_HXX
+#define LIBBUILD2_BUILDSPEC_HXX
#include <libbuild2/types.hxx>
#include <libbuild2/forward.hxx>
@@ -34,7 +34,7 @@ namespace build2
bool forwarded = false;
};
- struct opspec: vector<targetspec>
+ struct opspec: small_vector<targetspec, 1>
{
opspec () = default;
opspec (string n): name (move (n)) {}
@@ -43,7 +43,7 @@ namespace build2
values params;
};
- struct metaopspec: vector<opspec>
+ struct metaopspec: small_vector<opspec, 1>
{
metaopspec () = default;
metaopspec (string n): name (move (n)) {}
@@ -52,7 +52,7 @@ namespace build2
values params;
};
- using buildspec = vector<metaopspec>;
+ using buildspec = small_vector<metaopspec, 1>;
LIBBUILD2_SYMEXPORT ostream&
operator<< (ostream&, const targetspec&);
@@ -67,4 +67,4 @@ namespace build2
operator<< (ostream&, const buildspec&);
}
-#endif // LIBBUILD2_SPEC_HXX
+#endif // LIBBUILD2_BUILDSPEC_HXX
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx
index 41d982b..6e28b0a 100644
--- a/libbuild2/config/operation.cxx
+++ b/libbuild2/config/operation.cxx
@@ -4,11 +4,11 @@
#include <libbuild2/config/operation.hxx>
#include <libbuild2/file.hxx>
-#include <libbuild2/spec.hxx>
#include <libbuild2/scope.hxx>
#include <libbuild2/target.hxx>
#include <libbuild2/context.hxx>
#include <libbuild2/algorithm.hxx>
+#include <libbuild2/buildspec.hxx> // opspec
#include <libbuild2/filesystem.hxx>
#include <libbuild2/diagnostics.hxx>
diff --git a/libbuild2/dump.cxx b/libbuild2/dump.cxx
index 9f60900..11eb4b3 100644
--- a/libbuild2/dump.cxx
+++ b/libbuild2/dump.cxx
@@ -350,10 +350,21 @@ namespace build2
//
if (!t.adhoc_recipes.empty ())
{
+ auto& re (*s.root_scope ()->root_extra);
+
for (const adhoc_recipe r: t.adhoc_recipes)
{
+ os << endl
+ << ind << '%';
+
+ r.rule->dump_attributes (os);
+
+ for (action a: r.actions)
+ os << ' ' << re.meta_operations[a.meta_operation ()]->name <<
+ '(' << re.operations[a.operation ()]->name << ')';
+
os << endl;
- r.rule->dump (os, ind); // @@ TODO: pass action(s).
+ r.rule->dump_text (os, ind);
}
used = true;
diff --git a/libbuild2/forward.hxx b/libbuild2/forward.hxx
index 4443610..94eb006 100644
--- a/libbuild2/forward.hxx
+++ b/libbuild2/forward.hxx
@@ -14,7 +14,7 @@ namespace build2
//
struct action;
- // <libbuild2/spec.hxx>
+ // <libbuild2/buildspec.hxx>
//
struct opspec;
diff --git a/libbuild2/lexer.cxx b/libbuild2/lexer.cxx
index 7149d45..e50ec16 100644
--- a/libbuild2/lexer.cxx
+++ b/libbuild2/lexer.cxx
@@ -125,13 +125,13 @@ namespace build2
//
// 2. Recognizes comma.
//
- // 3. Treat newline as an ordinary space.
- //
- // Also note that we don't have buildspec attributes.
+ // Note that because we use this mode for both the command line
+ // buildspec and ad hoc recipe actions, we control the recognition of
+ // newlines as tokens via the auxiliary data.
//
s1 = " $(){},\t\n";
s2 = " ";
- n = false;
+ n = (data != 0);
break;
}
case lexer_mode::foreign:
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index d8baf06..6fb20fe 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -1046,11 +1046,12 @@ namespace build2
{
// Parse a recipe chain.
//
- // % [<attrs>]
+ // % [<attrs>] [<buildspec>]
// [if|switch ...]
// {{ [<lang> ...]
// ...
// }}
+ // ...
//
// enter: start is percent or openining multi-curly-brace
// leave: token past newline after last closing multi-curly-brace
@@ -1078,6 +1079,9 @@ namespace build2
recipes.push_back (nullptr); // For missing else/default (see below).
attributes as;
+ buildspec bs;
+ location bsloc;
+
struct data
{
small_vector<shared_ptr<adhoc_rule>, 1>& recipes;
@@ -1085,7 +1089,9 @@ namespace build2
bool& clean;
size_t i;
attributes& as;
- } d {recipes, first, clean, i, as};
+ buildspec& bs;
+ const location& bsloc;
+ } d {recipes, first, clean, i, as, bs, bsloc};
// Note that this function must be called at most once per iteration.
//
@@ -1197,8 +1203,74 @@ namespace build2
fail (d.as.loc) << "unknown recipe attribute " << a << endf;
}
- target_->adhoc_recipes.push_back (
- adhoc_recipe {perform_update_id, move (ar)});
+ auto& ars (target_->adhoc_recipes);
+ ars.push_back (adhoc_recipe {{}, move (ar)});
+
+ // Translate each buildspec entry into action and add it into the
+ // target's ad hoc recipes entry.
+ //
+ const location& l (d.bsloc);
+
+ for (metaopspec& m: d.bs)
+ {
+ meta_operation_id mi (ctx.meta_operation_table.find (m.name));
+
+ if (mi == 0)
+ fail (l) << "unknown meta-operation " << m.name;
+
+ const meta_operation_info* mf (
+ root_->root_extra->meta_operations[mi]);
+
+ if (mf == nullptr)
+ fail (l) << "target " << *target_ << " does not support meta-"
+ << "operation " << ctx.meta_operation_table[mi].name;
+
+ for (opspec& o: m)
+ {
+ operation_id oi;
+ if (o.name.empty ())
+ {
+ if (mf->operation_pre == nullptr)
+ oi = update_id;
+ else
+ // Calling operation_pre() to translate doesn't feel
+ // appropriate here.
+ //
+ fail (l) << "default operation in recipe action";
+ }
+ else
+ oi = ctx.operation_table.find (o.name);
+
+ if (oi == 0)
+ fail (l) << "unknown operation " << o.name;
+
+ const operation_info* of (root_->root_extra->operations[oi]);
+
+ if (of == nullptr)
+ fail (l) << "target " << *target_ << " does not support "
+ << "operation " << ctx.operation_table[oi];
+
+ // Note: for now always inner (see match_rule() for details).
+ //
+ action a (mi, oi);
+
+ // Check for duplicates.
+ //
+ if (find_if (
+ ars.begin (), ars.end (),
+ [a] (const adhoc_recipe& r)
+ {
+ auto& as (r.actions);
+ return find (as.begin (), as.end (), a) != as.end ();
+ }) != ars.end ())
+ {
+ fail (l) << "duplicate recipe for " << mf->name << '('
+ << of->name << ')';
+ }
+
+ ars.back ().actions.push_back (a);
+ }
+ }
}
next (t, tt);
@@ -1210,6 +1282,11 @@ namespace build2
if (tt == type::percent)
{
+ // Similar code to parse_buildspec() except here we recognize
+ // attributes and newlines.
+ //
+ mode (lexer_mode::buildspec, '@', 1 /* recognize newline */);
+
next_with_attributes (t, tt);
attributes_push (t, tt, true /* standalone */);
@@ -1221,7 +1298,36 @@ namespace build2
as = move (attributes_top ());
attributes_pop ();
- next_after_newline (t, tt, '%');
+ // Handle the buildspec.
+ //
+ // @@ TODO: diagnostics is a bit off ("operation or target").
+ //
+ if (tt != type::newline && tt != type::eos)
+ {
+ const location& l (bsloc = get_location (t));
+ bs = parse_buildspec_clause (t, tt);
+
+ // Verify we have no targets and assign default meta-operations.
+ //
+ // Note that here we don't bother with lifting operations to meta-
+ // operations like we do in the driver (this seems unlikely to be a
+ // pain point).
+ //
+ for (metaopspec& m: bs)
+ {
+ for (opspec& o: m)
+ {
+ if (!o.empty ())
+ fail (l) << "target in recipe action";
+ }
+
+ if (m.name.empty ())
+ m.name = "perform";
+ }
+ }
+
+ expire_mode ();
+ next_after_newline (t, tt, "recipe action");
// See if this is if-else or switch.
//
@@ -1259,6 +1365,14 @@ namespace build2
// Fall through.
}
+ // Default is perform(update).
+ //
+ if (bs.empty ())
+ {
+ bs.push_back (metaopspec ("perform"));
+ bs.back ().push_back (opspec ("update"));
+ }
+
parse_block (t, tt, false /* skip */, "" /* kind */);
}
@@ -6308,7 +6422,7 @@ namespace build2
next (t, tt);
buildspec r (tt != type::eos
- ? parse_buildspec_clause (t, tt, 0)
+ ? parse_buildspec_clause (t, tt)
: buildspec ());
if (tt != type::eos)
@@ -6437,8 +6551,8 @@ namespace build2
}
}
- // No nested meta-operations means we should have a single
- // metaopspec object with empty meta-operation name.
+ // No nested meta-operations means we should have a single metaopspec
+ // object with empty meta-operation name.
//
assert (nbs.size () == 1);
const metaopspec& nmo (nbs.back ());
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 88b4ad9..78c7d17 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -8,11 +8,11 @@
#include <libbuild2/forward.hxx>
#include <libbuild2/utility.hxx>
-#include <libbuild2/spec.hxx>
#include <libbuild2/file.hxx>
#include <libbuild2/lexer.hxx>
#include <libbuild2/token.hxx>
#include <libbuild2/variable.hxx>
+#include <libbuild2/buildspec.hxx>
#include <libbuild2/diagnostics.hxx>
#include <libbuild2/export.hxx>
@@ -496,7 +496,7 @@ namespace build2
// Buildspec.
//
buildspec
- parse_buildspec_clause (token&, token_type&, size_t);
+ parse_buildspec_clause (token&, token_type&, size_t = 0);
// Customization hooks.
//
diff --git a/libbuild2/recipe.hxx b/libbuild2/recipe.hxx
index efd184a..823f804 100644
--- a/libbuild2/recipe.hxx
+++ b/libbuild2/recipe.hxx
@@ -58,10 +58,8 @@ namespace build2
struct adhoc_recipe
{
- // @@ TODO: maybe we should have a small vector of actions (for dump).
- //
- build2::action action;
- shared_ptr<adhoc_rule> rule;
+ small_vector<action, 1> actions;
+ shared_ptr<adhoc_rule> rule;
};
}
diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx
index 7ea6e68..0b9f066 100644
--- a/libbuild2/rule.cxx
+++ b/libbuild2/rule.cxx
@@ -333,6 +333,11 @@ namespace build2
return true;
}
+ void adhoc_rule::
+ dump_attributes (ostream&) const
+ {
+ }
+
// Scope operation callback that cleans up recipe builds.
//
target_state adhoc_rule::
@@ -406,28 +411,23 @@ namespace build2
}
void adhoc_script_rule::
- dump (ostream& os, string& ind) const
+ dump_attributes (ostream& os) const
{
- // Do we need the header?
- //
- // @@ TODO: for now we dump it as an attribute whether it was specified or
- // derived from the script. Maybe that's ok?
+ // For now we dump it as an attribute whether it was specified or derived
+ // from the script. Maybe that's ok (we use this in tests)?
//
if (script.diag_name)
{
- os << ind << '%';
-
- if (script.diag_name)
- {
- os << " [";
- os << "diag=";
- to_stream (os, name (*script.diag_name), true /* quote */, '@');
- os << ']';
- }
-
- os << endl;
+ os << " [";
+ os << "diag=";
+ to_stream (os, name (*script.diag_name), true /* quote */, '@');
+ os << ']';
}
+ }
+ void adhoc_script_rule::
+ dump_text (ostream& os, string& ind) const
+ {
os << ind << string (braces, '{') << endl;
ind += " ";
script::dump (os, ind, script.lines);
@@ -807,7 +807,7 @@ namespace build2
}
void adhoc_cxx_rule::
- dump (ostream& os, string& ind) const
+ dump_text (ostream& os, string& ind) const
{
// @@ TODO: indentation is multi-line recipes is off (would need to insert
// indentation after every newline).
diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx
index a79eeed..c98c29e 100644
--- a/libbuild2/rule.hxx
+++ b/libbuild2/rule.hxx
@@ -153,8 +153,13 @@ namespace build2
virtual bool
match (action, target&, const string&) const override;
+ // Dump support.
+ //
+ virtual void
+ dump_attributes (ostream&) const;
+
virtual void
- dump (ostream&, string& indentation) const = 0;
+ dump_text (ostream&, string& indentation) const = 0;
// Implementation details.
//
@@ -188,14 +193,17 @@ namespace build2
target_state
default_action (action, const target&) const;
- virtual void
- dump (ostream&, string&) const override;
-
adhoc_script_rule (const location& l, size_t b): adhoc_rule (l, b) {}
virtual bool
recipe_text (context&, const target&, string&&, attributes&) override;
+ virtual void
+ dump_attributes (ostream&) const override;
+
+ virtual void
+ dump_text (ostream&, string&) const override;
+
public:
using script_type = build::script::script;
@@ -245,9 +253,6 @@ namespace build2
virtual recipe
apply (action, target&) const override;
- virtual void
- dump (ostream&, string&) const override;
-
adhoc_cxx_rule (const location&, size_t, uint64_t version);
virtual bool
@@ -256,6 +261,9 @@ namespace build2
virtual
~adhoc_cxx_rule () override;
+ virtual void
+ dump_text (ostream&, string&) const override;
+
public:
// Note that this recipe (rule instance) can be shared between multiple
// targets which could all be matched in parallel.
diff --git a/tests/dependency/recipe/testscript b/tests/dependency/recipe/testscript
index b39abde..64947dd 100644
--- a/tests/dependency/recipe/testscript
+++ b/tests/dependency/recipe/testscript
@@ -17,7 +17,7 @@ dump alias{x}
EOI
<stdin>:5:1: dump:
% .+/alias\{x\}: .+/:alias\{z\}%
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -34,7 +34,7 @@ dump alias{y}
EOI
<stdin>:5:1: dump:
% .+/alias\{y\}: .+/:alias\{z\}%
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -44,7 +44,7 @@ EOE
:
$* <<EOI 2>>/~%EOE%
alias{x}:
-%
+% update clean
{{
echo
}}
@@ -52,7 +52,7 @@ dump alias{x}
EOI
<stdin>:6:1: dump:
% .+/alias\{x\}:%
- % [diag=echo]
+ % [diag=echo] perform(update) perform(clean)
{{
echo
}}
@@ -62,7 +62,7 @@ EOE
:
$* <<EOI 2>>/~%EOE%
alias{x y}:
-%
+% perform(update clean)
{{
echo
}}
@@ -70,7 +70,7 @@ dump alias{y}
EOI
<stdin>:6:1: dump:
% .+/alias\{y\}:%
- % [diag=echo]
+ % [diag=echo] perform(update) perform(clean)
{{
echo
}}
@@ -87,6 +87,7 @@ dump alias{x}
EOI
<stdin>:5:1: dump:
% .+/alias\{x\}:%
+ % perform(update)
{{ c++ 1
void f ();
}}
@@ -109,7 +110,7 @@ EOI
{
var = x
}
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -132,7 +133,7 @@ EOI
{
var = x
}
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -145,7 +146,7 @@ alias{x}: alias{z}
{
var = x
}
-%
+% perform(update)
{{
echo
}}
@@ -156,7 +157,7 @@ EOI
{
var = x
}
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -169,7 +170,7 @@ alias{x y}:
{
var = x
}
-%
+% perform(update)
{{
echo
}}
@@ -180,7 +181,7 @@ EOI
{
var = x
}
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
@@ -193,18 +194,19 @@ alias{x}:
{{
echo
}}
+% clean
{{{
cat
}}}
dump alias{x}
EOI
-<stdin>:8:1: dump:
+<stdin>:9:1: dump:
% .+/alias\{x\}:%
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
- % [diag=cat]
+ % [diag=cat] perform(clean)
{{{
cat
}}}
@@ -217,18 +219,19 @@ alias{x y}: alias{z}
{{
echo
}}
+% clean
{{{
cat
}}}
dump alias{y}
EOI
-<stdin>:8:1: dump:
+<stdin>:9:1: dump:
% .+/alias\{y\}: .+/:alias\{z\}%
- % [diag=echo]
+ % [diag=echo] perform(update)
{{
echo
}}
- % [diag=cat]
+ % [diag=cat] perform(clean)
{{{
cat
}}}
@@ -238,12 +241,12 @@ EOE
:
$* <<EOI 2>>/~%EOE%
alias{x}: alias{z}
-
+% clean
{{
echo
}}
-%
+% update
{{{
cat
}}}
@@ -251,11 +254,11 @@ dump alias{x}
EOI
<stdin>:11:1: dump:
% .+/alias\{x\}: .+/:alias\{z\}%
- % [diag=echo]
+ % [diag=echo] perform(clean)
{{
echo
}}
- % [diag=cat]
+ % [diag=cat] perform(update)
{{{
cat
}}}
@@ -266,23 +269,24 @@ EOE
$* <<EOI 2>>/~%EOE%
alias{x y}:
+% clean
{{
echo
}}
-%
+% update
{{{
cat
}}}
dump alias{y}
EOI
-<stdin>:11:1: dump:
+<stdin>:12:1: dump:
% .+/alias\{y\}:%
- % [diag=echo]
+ % [diag=echo] perform(clean)
{{
echo
}}
- % [diag=cat]
+ % [diag=cat] perform(update)
{{{
cat
}}}
@@ -323,7 +327,7 @@ dump alias{x}
EOI
<stdin>:6:1: dump:
! .+/alias\{x\}:!
- % [diag=gen]
+ % [diag=gen] perform(update)
{{
echo
}}
@@ -341,7 +345,7 @@ dump alias{y}
EOI
<stdin>:6:1: dump:
! .+/alias\{y\}:!
- % [diag=gen]
+ % [diag=gen] perform(update)
{{
echo
}}
@@ -359,6 +363,33 @@ EOI
<stdin>:3:1: error: expected recipe block instead of '{'
EOE
+: duplicate-action-single
+:
+$* <<EOI 2>>EOE != 0
+alias{x}:
+% update perform(update)
+{{
+ echo
+}}
+EOI
+<stdin>:2:3: error: duplicate recipe for perform(update)
+EOE
+
+: duplicate-action-multiple
+:
+$* <<EOI 2>>EOE != 0
+alias{x}:
+{{
+ echo
+}}
+% perform(update)
+{{
+ echo
+}}
+EOI
+<stdin>:5:3: error: duplicate recipe for perform(update)
+EOE
+
: diag
:
{
@@ -391,7 +422,7 @@ EOE
dump alias{x}
EOI
%.{2}
- % [diag=rm]
+ % [diag=rm] perform(update)
%.{4}
EOE
@@ -406,7 +437,7 @@ EOE
dump alias{x}
EOI
%.{2}
- % [diag=echo]
+ % [diag=echo] perform(update)
%.{4}
EOE
@@ -455,7 +486,7 @@ EOE
dump alias{x}
EOI
%.{2}
- % [diag=c++]
+ % [diag=c++] perform(update)
%.{3}
EOE
}
@@ -477,7 +508,7 @@ EOE
<stdin>:4:11: info: use the '\?' escape sequence if this is a wildcard pattern
<stdin>:4:4: info: while deducing low-verbosity script diagnostics name
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
: empty
@@ -492,7 +523,7 @@ EOE
EOI
<stdin>:4:3: error: unable to deduce low-verbosity script diagnostics name
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
: process-path-typed
@@ -506,7 +537,7 @@ EOE
EOI
%<stdin>:3:4: error: unable to deduce low-verbosity script diagnostics name from process path .+%
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
: process-path-syntactic
@@ -521,7 +552,7 @@ EOE
EOI
%<stdin>:4:4: error: unable to deduce low-verbosity script diagnostics name from process path .+%
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
: target-no-name
@@ -541,7 +572,7 @@ EOE
EOI
%<stdin>:5:3: error: unable to deduce low-verbosity script diagnostics name from target .+/exe\{b\}%
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
}
@@ -557,7 +588,7 @@ EOE
EOI
<stdin>:4:3: error: unable to deduce low-verbosity script diagnostics name for program foo
info: consider specifying it explicitly with the 'diag' recipe attribute
- info: or provide custom low-verbosity diagnostics with the 'diag' builtin
+ info: or provide custom low-verbosity diagnostics with the 'diag' builtin
EOE
}
@@ -577,7 +608,7 @@ EOE
dump alias{x}
EOI
%.{2}
- % [diag=foo]
+ % [diag=foo] perform(update)
%.{5}
EOE
@@ -596,6 +627,7 @@ EOE
EOI
%.
% .+alias\{x\}:%
+ % perform(update)
{{
%.{4}
EOE