gmPL Refactoring Statements
Within
gmBasic many of the changes made to the code as it moves from its VB6/ASP source code form into its ultimate .NET target code form can most easily be formulated as refactoring operations. These include:
- Renaming symbols either to avoid clashes or to make them easier to maintain.
- Reauthoring a subprogram because its original approach is inappropriate or unworkable in the .NET environment
- Changing the type of a symbol which was either undefined or too weakly specified.
- Changing the status of a symbol to change its scope or behavior
- Changing the structure of a symbol to clarify its size and dimensionality.
- Removing a symbol because it is not needed or wanted.
- Changing logic flow and/or program operations to conform to new requirements.
- Replacing references to external libraries with references to native libraries
All of these operations involve manipulations of the symbol table and of the intermediate code produced. They do not directly reference the source or target code. The refactoring statements themselves are:
Statement | Description of use |
---|
Refactor | Introduces a set of refactoring statements |
CallByName | Changes symbol-related code events that yield CallByName late binding calls into direct boxed calls. |
Extend | Extends the content of a class by adding new components. |
FixType | Changes the binary type of a component or group of components |
Generic | Specifies that individual subprogram parameters be implemented as being generic to accept a list of different types. |
Implements | Specifies that a VB6 class implements another class or interface. |
MigClass | Introduces a new class that contains related refactoring information used for complex migration operations, especially as related to designer code. |
Migrate | Specifies migration of a specific symbol introduced via an external library description. |
OverGeneric | Specifies that individual subprogram parameters be implemented as being generic in an overloaded method to accept a list of different types. |
Overload | Specifies that individual subprogram arguments be overloaded to accept a list of different types. |
Reauthor | Replaces the content of a subprogram with a completely rewritten block of code |
Remove | Prevents a component from being authored |
Rename | Changes the authored name of components |
Replace | Replaces either the members of an external class or the patterns of opcodes via replacement declarations. |
Within
gmBasic the portation process proceeds in 8 steps:
- Loading the VB6/ASP source code.
- Fixing the VB6/ASP source code.
- Building the symbol table from the source code
- Compiling the source code into intermediate code
- Analysing the symbol table and intermediate code
- Authoring the target code from the intermediate code and symbol table
- Fixing the target code
- Deploying the target code
During this process there are 3 points at which refactoring operations can be made. First after step 3, which builds the symbol table. This is a very effective place to strengthen the specifications of the symbols so that the compiler can take advantage of this additional information while generating the intermediate code. Second after step 4 when the compiler has completed, but the code analyser has not yet run. This is an excellent time to introduce .NET types explicitly and to do any removals. Third after step 5, when the analyser has run, but before the author has executed. This is the best time to do symbol renaming and code reauthoring.
Refactoring tends to effect the entire code base. It is not intended to make individual changes in actual code. The source code fixing operations are intended for this. The rule of thumb for using a refactoring operation as opposed to a fix editing operation is that the specification for the final recipient of the change is a symbol as opposed to a line/block of code. In general, portation is an art and the selection of which approach to use will clearly vary by individual and application.
Whenever possible, refactoring should be done via "shallow" changes -- changes which are applied to the actual surface or source form of the code using the
Fix statement. These shallow changes can be applied to both the source code before it is translated and to the target code after it is produced, but before it is published. Such changes are easy to visualize and to specify. Unfortunately many of the changes needed cannot be specified in this way -- refactoring is required.
Refactoring Property Specifications
Many of the refactoring statements are used to deal with the transformation of the VB6 property specifications into .NET designer code. Much of the code within VB6 forms deals with controls. These controls all have complex sets of properties that must be initialized within the VB6 code. This initialization code contains nested sets of "name=value" pairs organized into nested blocks started off by
BEGIN or
BEGINPROPERTY statements and ending with
END or
ENDPROPERTY statements. Here is a simple example of such a specification.
Begin VB.Form VB0001Form
Caption = "VB0001"
ClientHeight = 5115
ClientLeft = 60
ClientTop = 345
ClientWidth = 5280
LinkTopic = "Form1"
ScaleHeight = 5115
ScaleWidth = 5280
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command1
Caption = "Run VB0001 Test"
Height = 375
Left = 1440
TabIndex = 0
Top = 1320
Width = 1935
End
End
In the above, the
Begin has the syntax "Begin controltype identifier" where
controltype is a defined control type and
identifier is the identifier of the control object in the user code that is being defined. In the
name=value pairs the
name is the name of a property defined for the control type class and the
value is the value to be assigned to that property for the identified instance of the control type.
There are of course properties of controls that are themselves object types rather than simple value types. The most common of these is the
Font property. Here is an example of a specification of this type.
Begin VB.Label lblFirst
Alignment = 2 'Center
BorderStyle = 1 'Fixed Single
Caption = "VB is fun"
BeginProperty Font
Name = "MS Sans Serif"
Size = 24
Charset = 0
Weight = 700
Underline = 0 'False
Italic = 0 'False
Strikethrough = 0 'False
EndProperty
Height = 615
Left = 2040
TabIndex = 0
Top = 480
Width = 2655
End
In the above the
BeginProperty statement has the syntax "BeginProperty property" where
property is the identifier of a property in the containing control type that has an object type. There is no additional identifier here because the values are part of the higher instance.
BeginProperty is semantically equivalent to a simple
name=value pair except that multiple values are being supplied.
All of the above is an oversimplification in every possible way. Even in the above "simplest of all examples", for example, the
VB.Label control type does not have a property called
Font; rather it has properties like
FontName,
FontSize etc. When the above syntax is extended to
COM CONTROLS all formal relationships are ignored in every possible way. The specifications look like the above, but there truly are no real rules. Each
COM property specification has to be examined carefully and converted into a specification that associates values with a set of user-defined controls in a consistent manner.
Converting the input property specifications into a consistent form is a difficult, but trivial problem when compared to the problem of reauthoring those specifications in .NET. The two primary problems are that in .NET controls are not nested, they have a linear structure and then there are later instructions that add children into the scope of the parents. How and when and with what adornments are needed to make these scope specifications vary widely. In addition in .NET some values are assigned to properties directly in the code and others are assigned via external resource files.
An important point to be remembered about the property specification code is that though it uses opcodes, though opcodes are not authored via a string-machine. It has code fragments in it that can be evaluated and viewed in the same way as procedural code, but it is used simply as a data-store for the information initially obtained from the VB6 specifications and then as changed to supply information to the .NET control author. New properties must be added, old properties must be removed or restructured or radically migrated. There are no
dependable simplistic correspondences between properties defined for the classes and references to those properties. The goal is that the eventual authored .NET property specifications will accurately reflect the original intent of the VB6 source; however, that goal is achieved via the interaction of diverse components and not directly in the property code blocks.