One of the key features of VB Migration Partner is migration pragmas, and possibly the most powerful pragma is PostProcess, which enables you to modify the VB.NET being generated. The PostProcess pragma is based on regular expressions and works much like the Regex.Replace method.

The PostProcess pragma can really do wonders in the hands of a developer who is familiar with regexes. As a matter of fact, we have already uploaded several KB articles that show how you can refactor your code using PostProcess pragmas:

[HOWTO] Modify project-level options in VB.NET programs
[HOWTO] Move the declaration of a variable into a For or For Each loop
[HOWTO] Transform “Not x Is y” expressions into “x IsNot y” expressions
[HOWTO] Replace App6 properties with native VB.NET members
[HOWTO] Get rid of warnings related to Screen.MousePointer property
[HOWTO] Convert While loops into Do loops
[HOWTO] Simplify code produced for UserControl classes
[HOWTO] Change the base class of a VB.NET class

[HOWTO] Avoid compilation errors caused by unsupported designers

In this post I am going to show you how you can use the PostProcess pragma in a creative way to optimize common Boolean expressions. The regex patterns I will show aren't exactly simple and I won't explain each in depth. But trust me, they work and they work great!

Important note #1: like all substitutions based on regular expressions, there is a small probability that the techniques discussed in this article might suffer from false matches and, therefore, might produce invalid VB.NET code. Ensure that you add these pragmas to your VB6 code only after you have checked that the conversion works well and be prepared to remove these pragmas if you notice that they produce invalid VB.NET code.

Important note #2: most regex patterns in this article are too long for the page width and will be split in two or more lines. If you are in trouble, at the bottom of this KB article you will find a link to a text file that gathers all of the PostProcess pragmas I am introducing here.

1. Comparisons with True and False

Some VB6 developers like to explicitly compare a Boolean variable with True or False, as in this example:
    Dim x As Integer, res As Boolean, res2 As Boolean
    ' ...
    If res = True And res2 = False Then x = 0


Explicit comparison of a Boolean variable with True or False adds a little overhead, which can be avoided by re-rewriting the expression as follows:
    If res And Not res2 Then x = 0

Here are the two PostProcess pragmas that do the trick, the former accounting for comparisons with True and the latter for comparisons with False:

'## PostProcess "(?<=\n[ \t]*)(?<key>If|ElseIf)\b(?<pre>.+)\b(?<cond>\S+)
    [ \t]*=[ \t]*\bTrue\b(?<post>.+)\bThen\b",
    "${key}${pre}${cond}${post}Then", True

'## PostProcess "(?<=\n[ \t]*)(?<key>If|ElseIf)\b(?<pre>.+)\b(?<cond>\S+)
    [ \t]*=[ \t]*\bFalse\b(?<post>.+)\bThen\b",
    "${key}${pre}Not ${cond}${post}Then", True


The condition can appear also inside Do, Loop, and While statements, thus we need two more PostProcess pragmas:

'## PostProcess "(?<=\n[ \t]*)(?<key>(Do|Loop)[ \t]+(While|Until)|While)\b
    (?<pre>.+)\b(?<cond>\S+)\s*=\s*\bTrue\b",
    "${key}${pre}${cond}", True

'## PostProcess "(?<=\n[ \t]*)(?<key>(Do|Loop)[ \t]+(While|Until)|While)\b
    (?<pre>.+)\b(?<cond>\S+)\s*=\s*\bFalse\b",
    "${key}${pre}Not ${cond}", True


2. Not keyword in Do While and Loop While statements

If a Do While or Loop While statement is followed by a condition that is prefixed by the Not keyword, you can drop the Not keyword and transform the statement into Do Until or Loop Until, respectively. For example, the following code
    Do While Not res
        ' ...
    Loop

can be transformed into:
    Do Until res
        ' ...
    Loop


This is the PostProcess pragma that can perform this substitution for you:

'## PostProcess "(?<=\n[ \t]*)(?!.*\b(And|Or|Xor)\b)(?<key>Do|Loop)
    [ \t]+While[ \t]+Not[ \t]+(?<cond>.+)", "${key} Until ${cond}", True


Notice that the regex pattern fails if the condition contains an And, Or, or Xor operator. This check is necessary to avoid to mistakenly match an expression such as this:
    Do While Not res And x = 10

3. Not keyword in Do Until and Loop Until statements

If a Do Until or Loop Until statement is followed by a condition that is prefixed by the Not keyword, you can drop the Not keyword and transform the statement into Do While or Loop While, respectively. For example, the following code
    Do Until Not res
        ' ...
    Loop

can be transformed into:
    Do While res
        ' ...
    Loop


The PostProcess pragma that can perform this substitution is as follows:

'## PostProcess "(?<=\n[ \t]*)(?!.*\b(And|Or|Xor)\b)(?<key>Do|Loop)
    [ \t]+Until[ \t]+Not[ \t]+(?<cond>.+)", "${key} While ${cond}", True


4. Assigning True/False to a variable in a If...Then...Else block

A common (yet inefficient) coding pattern among developers is to use an If…Then…Else block to assign True or False to a Boolean variable. For example, consider the following VB6 code:
    Dim x As Integer, res As Boolean, res2 As Boolean
    ' ...
    If x <> 0 Then
        res = True
    Else
        res = False
    End If            

    If x > 10 And x < 20 Then
        res2 = False
    Else
        res2 = True
    End If


It is evident that it can be simplified (and optimized) as follows:

    res = (x <> 0)
    res2 = Not (x > 10 And x < 20)


Creating a regular expression pattern that allows you capture and transform the If…Then…Else block isn’t a trivial task, also because we need a different PostProcess pragma to account for single-line If statements:

'## PostProcess "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n[ \t]
    *\b(?<var>(Return\b|\S+[ \t]*=))[ \t]*True[ \t]*\r?\n[ \t]*Else
    [ \t]*\r?\n[ \t]*\k<var>[ \t]*False[ \t]*\r?\n[ \t]*End[ \t]+If
    [ \t]*\r?\n", "${var} (${cond})\r\n", True

'## PostProcess "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
    (?<var>(Return\b|\S+[ \t]*=))[ \t]*True[ \t]+Else[ \t]+\k<var>
    [ \t]*False[ \t]*\r?\n", "${var} (${cond})\r\n", True


The next two PostProcess pragmas account for the cases when the variable is assigned False when the condition is true. Again, we need a second pragma to account for single-line IF statements.

'## PostProcess "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n[ \t]
    *\b(?<var>(Return\b|\S+[ \t]*=))[ \t]*False[ \t]*\r?\n[ \t]*Else
    [ \t]*\r?\n[ \t]*\k<var>[ \t]*True[ \t]*\r?\n[ \t]*End[ \t]+If
    [ \t]*\r?\n", "${var} Not (${cond})\r\n", True

'## PostProcess "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
    (?<var>(Return\b|\S+[ \t]*=))[ \t]*False[ \t]+Else[ \t]+\k<var>
    [ \t]*True[ \t]*\r?\n", "${var} Not (${cond})\r\n", True


Notice that the patterns that follow account both for variable assignements and for the Return keyword used to return a value from a function (such Return keyword is used by VB Migration Partner if possible).

5. Assigning different values to a variable inside an If...Then...Else block

Another common coding pattern - which is actually a variant of the previous one - is to use an If…Then…Else block to assign one of two possible values to the same variable, as in these examples:
    If x <> 0 Then
        y = x + 10
    Else
        y = 20
    End If

    ' single-line variant
    If x <> 0 Then y = x + 10 Else y = 20


There is a more concise – though not necessarily more efficient – way to perform the same assignment:
    y = IIf(x <> 0, x + 10, 20)

If you are interested in performing this substitution automatically, you can use the following two pragmas, where the latter works for single-line IF statements:

'## PostProcess "(?<!\bEnd[ \t]+)\bIf[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n
    [ \t]*\b(?<var>(Return\b|\S+[ \t]*=))[ \t]*(?<v1>[^\r\n]+)\r?\n
    [ \t]*Else[ \t]*\r?\n[ \t]*\k<var>[ \t]*(?<v2>[^\r\n]+)[ \t]*\r?\n
    [ \t]*End[ \t]+If[ \t]*\r?\n",
    "${var} IIf(${cond}, ${v1}, ${v2})\r\n", True

'## PostProcess "(?<!\bEnd[ \t]+)\bIf[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
    (?<var>(Return\b|\S+[ \t]*=))[ \t]*(?<v1>[^\r\n]+)\bElse[ \t]+\k<var>
    [ \t]*(?<v2>[^\r\n]+)\r?\n",
    "${var} IIf(${cond}, ${v1}, ${v2})\r\n", True


---------------------------

That's it, folk! If you ever wondered why you should care about regular expressions, I hope I gave you something to think about Wink