Monday, September 27, 2010

Delphi Converter improves

Converter has taken a big step forward during the past few months. The main features I had in mind are now implemented. Most details are configurable in Settings dialog. All settings are saved in file delphiconverter.xml in local Lazarus configuration directory and thus are persistent.

This is the settings dialog:

There is a wiki page with detailed explanation of conversions: Delphi_Converter_in_Lazarus

Here is a brief list of them.

Conversions for Unit file

* All unit source files get a {$mode delphi} directive. It makes the compiler support language syntax exactly like Delphi has it.

* {$R *.DFM} is replaced with {$R *.lfm} if the form file is renamed and converted. Conditional compilation is used if the target is "Lazarus and Delphi".

* Unit names in Uses section and include file names are fixed to match the real case sensitive name found in the file system. This is needed for case sensitive file systems.

* Some unit names in Uses section are either replaced or removed.

* Some Delphi types are replaced with "fall-back" LCL types (same as in form files).

* Some function names called in the code are replaced.

Conversions for Form file

* Older Delphi versions used a binary format for .dfm form files. The converter always converts them to ascii text format.

* .dfm form file is renamed or copied to .lfm and converted as needed. There is also an option to use the same Delphi form file directly. See section Target below.

* Unknown properties are removed.

* Some Delphi types are replaced with "fall-back" LCL types (same as in unit files).

* Top and Left coordinate offset adjustment for controls inside visual containers.

Implementation details

Codetools are used a lot when changing the source code and .lfm form file.

One challenge was to replace function calls inside the source code, using parameters from the original call as defined in configuration. Codetools create a parse tree of the code but it includes only definitions, not function calls or other code constructs.
It means that the source code must be parsed char by char when looking for function calls to replace. Fortunately there was TFindDeclarationTool.FindReferences which I could use as the base for my TConvDelphiCodeTool.ReplaceFuncCalls. I copied the code, studied and debugged it for some time, then stripped useless parts out and added more code for replacing the function calls.

Another challenge was adjusting Top and Left coordinates of controls inside visual containers.
I based my TConvDelphiCodeTool.CheckTopOffsets on TStandardCodeTool.CheckLFM.
Again, I copied, studied, stripped, modified and added code.

The huge code-base of codetools looks first almost incomprehensible. The code browsing features of Lazarus are a big help here. They let you jump around code with no delays. After jumping and debugging for some time the code starts to make sense, piece by piece.

It is funny. When you first look at complicated code in a big project, you think: "oh, who is able create such code?". Then you make some code yourself and then have a month or 2 pause, and then look at the code and think: "oh, who has made this? Must be a clever person! ... oops, it is my own code...".
I guess other coders have similar feelings. Nobody can handle big amounts of code at one time. Sometimes you concentrate on the big picture and forget the details, sometimes you fiddle with the details and forget everything else.
In the end, for an outsider, the code may look like some intelligent person had made it. :-)

Juha Manninen