Expression pattern matching
To find and replace an expression pattern, create a struct that inherits
publicly from bronto::rewrite_expr
(either directly or indirectly) and use the BRONTO_BEFORE()
and BRONTO_AFTER()
annotations to identify expressions and define their replacements.
struct OperatorPlusToStrCat : bronto::rewrite_expr {
BRONTO_BEFORE()
auto operator_plus(std::string lhs, std::string rhs) {
return lhs + rhs;
}
BRONTO_AFTER()
auto use_strcat(std::string lhs, std::string rhs) {
return absl::StrCat(lhs, rhs);
}
};
BRONTO_BEFORE
Requirements
Each struct inheriting from bronto::rewrite_expr
must have one member function or template member function marked BRONTO_BEFORE()
. This function must have a single return statement (and no other statements).
Semantics
The returned expression from a function annotated with BRONTO_BEFORE()
defines the pattern to be matched. The pattern is syntactic in the
sense that any implicit casts/conversions are ignored. However there are some
syntactic constructs that are also ignored. In particular, parentheses that do
not change the meaning of an expression are ignored in the pattern. For example,
a pattern such as (a + b) + c
will match 1 + 2 + 3
, even though it does not
have parentheses.
Parameters
Each function parameter represents a "hole" that can bind to any expression of the appropriate type ignoring qualifiers. If the parameter's type is dependent on a template parameter, the parameter represents any expression whose type can be represented by appropriate choices for the template parameters. In other words,
template <typename T>
BRONTO_BEFORE()
auto f(T *ptr) {
return ptr->something();
}
will match calls to something
through operator->
on a pointer type but will
not match calls to something
on a std::unique_ptr
. Even though
operator->
is defined, std::unique_ptr<U>
will not bind to a function
template parameter T*
.
For each matched pattern, the expressions and types that correspond to a
parameter and template parameter "holes" are said to be captured (the same
terminology as regular expression captures). These expressions and types can be
used in the replacement pattern annotated with BRONTO_AFTER
.
BRONTO_AFTER
Requirements
Each struct inheriting from bronto::rewrite_expr
must have one member function or template member function marked BRONTO_AFTER()
. The function must have a single return statement and must be able to accept any function parameters or template
parameters from any function marked BRONTO_BEFORE()
in the struct.
Semantics
The returned expression represents the pattern to replace things found by BRONTO_BEFORE
with. Each captured expression or type is used in
place of the parameter or template parameter of the same name.
struct StrCatPerformanceExample : bronto::rewrite_expr {
BRONTO_BEFORE()
auto find(auto x, auto y) {
return absl::StrCat(x, std::to_string(y));
}
// NOTE: Even though the parameters are in reverse order (`y`
// before `x`), they still bind to the variables of the same name
// in `find`. Their positioning here is not relevant.
BRONTO_BEFORE()
auto replace(auto y, auto x) {
return absl::StrCat(x, y);
}
};