aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/build/script/parser.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/build/script/parser.hxx')
-rw-r--r--libbuild2/build/script/parser.hxx255
1 files changed, 213 insertions, 42 deletions
diff --git a/libbuild2/build/script/parser.hxx b/libbuild2/build/script/parser.hxx
index 948c381..8f86b24 100644
--- a/libbuild2/build/script/parser.hxx
+++ b/libbuild2/build/script/parser.hxx
@@ -8,7 +8,6 @@
#include <libbuild2/forward.hxx>
#include <libbuild2/utility.hxx>
-#include <libbuild2/depdb.hxx>
#include <libbuild2/diagnostics.hxx>
#include <libbuild2/script/parser.hxx>
@@ -46,7 +45,9 @@ namespace build2
// we will end up with mismatching diagnostics.
//
script
- pre_parse (const scope&, const small_vector<action, 1>&,
+ pre_parse (const scope&,
+ const target_type&,
+ const small_vector<action, 1>&,
istream&, const path_name&, uint64_t line,
optional<string> diag_name, const location& diag_loc);
@@ -64,11 +65,18 @@ namespace build2
pre_parse_script ();
void
- pre_parse_line (token&, token_type&, bool if_line = false);
+ pre_parse_line (token&, token_type&,
+ optional<line_type> flow_control_type = nullopt);
+
+ void
+ pre_parse_block_line (token&, token_type&, line_type block_type);
void
pre_parse_if_else (token&, token_type&);
+ void
+ pre_parse_loop (token&, token_type&, line_type);
+
command_expr
parse_command_line (token&, token_type&);
@@ -80,31 +88,122 @@ namespace build2
// initialize/clean up the environment before/after the script
// execution.
//
+ // Note: having both root and base scopes for testing (where we pass
+ // global scope for both).
+ //
void
execute_body (const scope& root, const scope& base,
environment&, const script&, runner&,
bool enter = true, bool leave = true);
-
+ // Execute the first or the second (dyndep) half of the depdb
+ // preamble.
+ //
// Note that it's the caller's responsibility to make sure that the
// runner's enter() function is called before the first preamble/body
// command execution and leave() -- after the last command.
//
+ // Note: target must be file or group.
+ //
void
- execute_depdb_preamble (const scope& root, const scope& base,
- environment&, const script&, runner&,
- depdb&);
+ execute_depdb_preamble (action a, const scope& base, const target& t,
+ environment& e, const script& s, runner& r,
+ depdb& dd)
+ {
+ auto b (s.depdb_preamble.begin ());
+ exec_depdb_preamble (
+ a, base, t,
+ e, s, r,
+ b,
+ (s.depdb_dyndep
+ ? b + *s.depdb_dyndep
+ : s.depdb_preamble.end ()),
+ dd);
+ }
+
+ struct dynamic_target
+ {
+ string type; // Target type name (absent if static member).
+ build2::path path;
+ };
+
+ using dynamic_targets = vector<dynamic_target>;
-
- // Parse a special builtin line into names, performing the variable
- // and pattern expansions. If omit_builtin is true, then omit the
- // builtin name from the result.
+ void
+ execute_depdb_preamble_dyndep (
+ action a, const scope& base, target& t,
+ environment& e, const script& s, runner& r,
+ depdb& dd,
+ dynamic_targets& dyn_targets,
+ bool& update, timestamp mt, bool& deferred_failure)
+ {
+ exec_depdb_preamble (
+ a, base, t,
+ e, s, r,
+ s.depdb_preamble.begin () + *s.depdb_dyndep,
+ s.depdb_preamble.end (),
+ dd, &dyn_targets, &update, mt, &deferred_failure);
+ }
+
+ // This version doesn't actually execute the depdb-dyndep builtin (but
+ // may execute some variable assignments) instead returning all the
+ // information (extracted from options) necessary to implement the
+ // depdb-dyndep --byproduct logic (which fits better into the rule
+ // implementation).
+ //
+ enum class dyndep_format {make, lines};
+
+ struct dyndep_byproduct
+ {
+ location_value location;
+ dyndep_format format;
+ optional<dir_path> cwd;
+ path file;
+ string what;
+ const target_type* default_type;
+ bool drop_cycles;
+ };
+
+ dyndep_byproduct
+ execute_depdb_preamble_dyndep_byproduct (
+ action a, const scope& base, const target& t,
+ environment& e, const script& s, runner& r,
+ depdb& dd, bool& update, timestamp mt)
+ {
+ // Dummies.
+ //
+ // This is getting a bit ugly (we also don't really need to pass
+ // depdb here). One day we will find a better way...
+ //
+ dynamic_targets dyn_targets;
+ bool deferred_failure;
+
+ dyndep_byproduct v;
+ exec_depdb_preamble (
+ a, base, t,
+ e, s, r,
+ s.depdb_preamble.begin () + *s.depdb_dyndep,
+ s.depdb_preamble.end (),
+ dd, &dyn_targets, &update, mt, &deferred_failure, &v);
+ return v;
+ }
+
+ // If the diag argument is true, then execute the preamble including
+ // the (trailing) diagnostics line and return the resulting names and
+ // its location (see exec_special() for the diagnostics line execution
+ // semantics). Otherwise, execute the preamble excluding the
+ // diagnostics line and return an empty names list and location. If
+ // requested, call the runner's enter() and leave() functions that
+ // initialize/clean up the environment before/after the preamble
+ // execution.
//
- names
- execute_special (const scope& root, const scope& base,
- environment&,
- const line&,
- bool omit_builtin = true);
+ // Note: having both root and base scopes for testing (where we pass
+ // global scope for both).
+ //
+ pair<names, location>
+ execute_diag_preamble (const scope& root, const scope& base,
+ environment&, const script&, runner&,
+ bool diag, bool enter, bool leave);
protected:
// Setup the parser for subsequent exec_*() function calls.
@@ -113,12 +212,50 @@ namespace build2
pre_exec (const scope& root, const scope& base,
environment&, const script*, runner*);
+ using lines_iterator = lines::const_iterator;
+
void
- exec_lines (const lines&, const function<exec_cmd_function>&);
+ exec_lines (lines_iterator, lines_iterator,
+ const function<exec_cmd_function>&);
+ void
+ exec_lines (const lines& l, const function<exec_cmd_function>& c)
+ {
+ exec_lines (l.begin (), l.end (), c);
+ }
+
+ // Parse a special builtin line into names, performing the variable
+ // and pattern expansions. Optionally, skip the first token (builtin
+ // name, etc).
+ //
names
- exec_special (token& t, build2::script::token_type& tt,
- bool omit_builtin = true);
+ exec_special (token&, build2::script::token_type&, bool skip_first);
+
+ // Note: target must be file or group.
+ //
+ void
+ exec_depdb_preamble (action, const scope& base, const target&,
+ environment&, const script&, runner&,
+ lines_iterator begin, lines_iterator end,
+ depdb&,
+ dynamic_targets* dyn_targets = nullptr,
+ bool* update = nullptr,
+ optional<timestamp> mt = nullopt,
+ bool* deferred_failure = nullptr,
+ dyndep_byproduct* = nullptr);
+
+ // Note: target must be file or group.
+ //
+ void
+ exec_depdb_dyndep (token&, build2::script::token_type&,
+ size_t line_index, const location&,
+ action, const scope& base, target&,
+ depdb&,
+ dynamic_targets& dyn_targets,
+ bool& update,
+ timestamp,
+ bool& deferred_failure,
+ dyndep_byproduct*);
// Helpers.
//
@@ -130,7 +267,7 @@ namespace build2
//
protected:
virtual lookup
- lookup_variable (name&&, string&&, const location&) override;
+ lookup_variable (names&&, string&&, const location&) override;
virtual void
lookup_function (string&&, const location&) override;
@@ -148,17 +285,18 @@ namespace build2
//
virtual optional<process_path>
parse_program (token&, build2::script::token_type&,
- bool first,
- bool env,
- names&) override;
+ bool first, bool env,
+ names&, parse_names_result&) override;
protected:
script* script_;
const small_vector<action, 1>* actions_; // Non-NULL during pre-parse.
- // True if performing update is one of the actions. Only set for the
- // pre-parse mode.
+ // True if this script is for file- or file group-based targets and
+ // performing update is one of the actions, respectively. Only set for
+ // the pre-parse mode.
//
+ bool file_based_;
bool perform_update_;
// Current low-verbosity script diagnostics and its weight.
@@ -186,18 +324,24 @@ namespace build2
//
// If the diag builtin is encountered, then its whole line is saved
// (including the leading 'diag' word) for later execution and the
- // diagnostics weight is set to 4.
+ // diagnostics weight is set to 4. The preceding lines, which can only
+ // contain variable assignments (including via the set builtin,
+ // potentially inside the flow control constructs), are also saved.
//
// Any attempt to manually set the custom diagnostics twice (the diag
// builtin after the script name or after another diag builtin) is
// reported as ambiguity.
//
- // At the end of pre-parsing either diag_name_ or diag_line_ (but not
- // both) are present.
+ // If no script name is deduced by the end of pre-parsing and the
+ // script is used for a single operation, then use this operation's
+ // name as a script name.
+ //
+ // At the end of pre-parsing either diag_name_ is present or
+ // diag_preamble_ is not empty (but not both).
//
optional<pair<string, location>> diag_name_;
optional<pair<string, location>> diag_name2_; // Ambiguous script name.
- optional<pair<line, location>> diag_line_;
+ lines diag_preamble_;
uint8_t diag_weight_ = 0;
// Custom dependency change tracking.
@@ -216,11 +360,27 @@ namespace build2
// depdb env <var-names> - Track the environment variables change as a
// hash.
//
- optional<location> depdb_clear_; // 'depdb clear' location if any.
- lines depdb_preamble_; // Note: excludes 'depdb clear'.
+ // depdb dyndep ... - Extract dynamic dependency information. Can
+ // only be the last depdb builtin call in the
+ // preamble. Note that such dependencies don't
+ // end up in $<. We also don't cause clean of
+ // such dependencies (since there may be no .d
+ // file) -- they should also be listed as
+ // static prerequisites of some other target
+ // (e.g., lib{} for headers) or a custom clean
+ // recipe should be provided.
+ //
+ //
+ optional<location> depdb_clear_; // depdb-clear location.
+ bool depdb_value_ = false; // depdb-{string,hash}
+ optional<pair<location, size_t>>
+ depdb_dyndep_; // depdb-dyndep location/position.
+ bool depdb_dyndep_byproduct_ = false; // --byproduct
+ bool depdb_dyndep_dyn_target_ = false; // --dyn-target
+ lines depdb_preamble_; // Note: excluding depdb-clear.
// If present, the first impure function called in the body of the
- // script that performs update.
+ // script that performs update of a file-based target.
//
// Note that during the line pre-parsing we cannot tell if this is a
// body or depdb preamble line. Thus, if we encounter an impure
@@ -230,7 +390,18 @@ namespace build2
//
optional<pair<string, location>> impure_func_;
- // True during pre-parsing when the pre-parse mode is temporarily
+ // Similar to the impure function above but for a computed (e.g.,
+ // target-qualified) variable expansion. In this case we don't have a
+ // name (it's computed).
+ //
+ optional<location> computed_var_;
+
+ // True if we (rather than the base parser) turned on the pre-parse
+ // mode.
+ //
+ bool top_pre_parse_;
+
+ // True during top-pre-parsing when the pre-parse mode is temporarily
// suspended to perform expansion.
//
bool pre_parse_suspended_ = false;
@@ -240,19 +411,19 @@ namespace build2
// Before the script line gets parsed, it is set to a temporary value
// that will by default be appended to the script. However,
// parse_program() can point it to a different location where the line
- // should be saved instead (e.g., diag_line_, etc) or set it to NULL
- // if the line is handled in an ad-hoc way and should be dropped
- // (e.g., depdb_clear_, etc).
+ // should be saved instead (e.g., diag_preamble_ back, etc) or set it
+ // to NULL if the line is handled in an ad-hoc way and should be
+ // dropped (e.g., depdb_clear_, etc).
//
line* save_line_;
- // The if-else nesting level (and in the future for other flow
- // control constructs).
+ // The flow control constructs nesting level.
//
- // Maintained during pre-parsing and is incremented when the cmd_if or
- // cmd_ifn lines are encountered, which in particular means that it is
- // already incremented by the time the if-condition expression is
- // pre-parsed. Decremented when the cmd_end line is encountered.
+ // Maintained during pre-parsing and is incremented when flow control
+ // construct condition lines are encountered, which in particular
+ // means that it is already incremented by the time the condition
+ // expression is pre-parsed. Decremented when the cmd_end line is
+ // encountered.
//
size_t level_ = 0;