Jim noticed that the regex command is unintentionally recursive:
Let's use the following command regex as an example:
(lldb) com regex humm 's/([^ ]+) ([^ ]+)/p %1 %2 %1 %2/'
If we call it with arguments foo bar, thing behave as expected:
(lldb) humm foo bar (...) foo bar foo bar
However, if we include %2 in the arguments, things break down:
(lldb) humm fo%2o bar (...) fobaro bar fobaro bar
The problem is that the implementation of the substitution is too naive. It substitutes the %1 token into the target template in place, then does the %2 substitution starting with the resultant string. So if the previous substitution introduced a %2 token, it would get processed in the second sweep, etc.
This patch addresses the issue by walking the command once and substituting the % variables in place. I didn't really trust myself so I also wrote a few unit tests to make sure I didn't miss any edge cases.
(lldb) humm fo%2o bar (...) fo%2o bar fo%2o bar
rdar://81236994
Do we want a "Expected<std::string>" as the result? If any index that follows a '%' 'that is 1 or higher could require the index be valid within "replacements" or we would return an error like "%4 is out of range, not enough arguments specified". Seems weird to just leave it in the resulting string as that is most certainly not what the user would expect? I might be what we used to do, but since we are improving things here, is seems like this would be easy to do