[−][src]Module c2rust_refactor::rewrite
Module for rewriting source text to reflect changes in the AST.
Rewriting takes as input an old AST, a new AST, and source text that parses to the old AST, and transforms that source text into text that parses to the new AST. Rewriting is designed to preserve comments and whitespace whenever possible.
At a high level, rewriting is a recursive traversal on the old and new ASTs. Everywhere the two are equal, there is no work to do. But where they differ, it applies a number of "rewrite strategies" that attempt to turn the old text into new text. In cases where no strategy can perform the rewrite, it propagates the error upward, trying the available strategies to rewrite enclosing nodes of the ASTs.
The core of the actual implementation is the Rewrite::rewrite(old, new, rcx) -> bool
method,
which attempts to rewrite the old
AST into the new
AST. The implementation of this method
for each node type simply tries each applicable strategy for the node type until either one of
the strategies succeeds or it runs out of strategies to try. Rewrite::rewrite
is not
(directly) recursive - the recursive traversal is handled by the recursive
strategy.
There are three core rewrite strategies:
-
equal
: If the two nodes are equal, rewriting succeeds. If they aren't, it fails. In either case, this strategy performs no actual rewrites.For leaf nodes, this strategy is tried first.
-
recursive
: If every child of the first can be rewritten to the corresponding child of the second, then rewriting succeeds. For nodes of enum type, the two nodes must be instances of the same variant (otherwise there would be no correspondence between the old and new nodes' children). If the variants are unequal or rewriting of any child fails, then the overall rewrite fails. This strategy performs no rewrites beyond those performed by its recursive calls.This is where the recursion happens in the actual implementation. Since it implements a superset of
equal
's functionality, it replacesequal
as the first strategy to try for all non-leaf node types. -
print
: Pretty-prints the new node, and performs a rewrite to replace the old source with this new source text. This strategy always succeeds, but is only implemented for a few node types (mostly major ones such asItem
,Expr
, etc).Since pretty-printer's output is cosmetically quite bad (it includes no comments, prints macros in expanded form, and sometimes makes questionable decisions regarding whitespace), the
print
strategy tries to replace pretty-printer output with original (user-written) source text whenever possible. See therewrite::strategy::print
module docs for details.Since this strategy always succeeds, but often produces bad results, it is tried last for any node types that support it.
Since print
and the more specialized (non-core) strategies only work for a small set of node
types, for most nodes Rewrite::rewrite
simply tries equal
(leaf nodes) or recursive
(non-leaf nodes), and fails if the strategy fails. This failure will cause a failure in the
enclosing recursive
, and will propagate upward until it reaches a node type that actually
does support another strategy, such as Item
. This is the point where rewriting actually
happens: when recursive
fails, Rewrite::rewrite
will try the next strategy (such as
print
), which can perform rewrites to correct the error at this higher level.
Modules
files | Code for applying |
json |
Structs
RewriteCtxt | |
RewriteCtxtRef | |
TextRewrite |
Enums
ExprPrec | Precedence information about the context surrounding an expression. Used to determine whether an expr needs to be parenthesized. |
SeqItemId | Common ID type for nodes and |
TextAdjust |
Traits
Rewrite |
Functions
rewrite |