Compiler Options |
Since there are currently no in-depth information available this post tries to clarify the topic a bit. Let's first start with the basic compiler options as can be seen in the screenshot below:.
In the above example, we might well use the If statement to check for the Enter key.
Under 'Compiler Options' the user can adjust the internal DWScript compiler, which is responsible for compiling the Object Pascal source code into an internal representation. While the DWScript compiler offers a few more options, these are the only ones the user can play with.
If ‘Assertions’ is checked statements like Assert(BoolExpression) will be compiled. If you’re not familiar with asserts, just think of them as additional stability checks you can add every here and there. They are translated to something like:
if not BoolExpression then
raise EAssertionFailed.Create('Assertion failed');
where the Boolean experession can be something like “SomeValue < AnotherValue” or a function call like "IsValueValid(SomeValue)".As soon as any assertion appears in your source code the following lines will be added to your JavaScript source code:
var EAssertionFailed={
$ClassName: "EAssertionFailed",
$Parent: Exception,
$Init: Exception.$Init
}
function $Assert(b,m,z) { if (!b) throw Exception.Create($New(EAssertionFailed),
"Assertion failed"+z+((m=="")?"":" : ")+m); }
If you uncheck this option, the entire statement will be replaced by /* null */ in the JavaScript source code. If you call a function in that expression, it won’t be called at all. So be careful to only put checks in an assertion.
If ‘Optimization’ is checked the internal coOptimize is passed to the DWScript. This triggers several countless optimizations in the DWScript compiler. A detailed list of what this influences is yet missing, but in general it tries to omit empty statements or eliminate dead code. Here’s a brief list of what is done
It adds another pass to the compilation, which results in longer compilation times.
NOTE: At the time of writing it seems as if this option is not taken into account (even if enabled) in Smart Mobile Studio due to an improper setup. It will be fixed as soon as possible.
Hints With ‘Hints’ several options about the hinting level of the compiler are available. If set to ‘Disabled’ no hints will be shown in the compiler message list. If set to ‘Normal’ the usual hints are emitted. Even more hints are emited with ‘Strict’ and in ‘Pedantic’ it will even complain differences in case sensitivity. The latter can be in particular useful if interfacing the case sensitive JavaScript language.
The predefined conditions are nothing more than a convenient way to specify some compiler definitions. These correspond to:
and will be set at a compiler level (for all units).
In addition the linker will output a file called ‘timestamp.txt’ if the ‘Automatically refresh in the browser’ is checked. This will be used to identify if the file has been changed.
You can set up your smart mobile program to be automatically reloaded when it is recompiled. That is, whenever you change the smart program and recompile it, the index.html will automatically be reloaded in the browser, it is not necessary, for instance, refresh the browser manually - but it's necessary a local web server running, because this autorefresh option will use ajax to ping to project generated files. If you wouldn't like to use this trick, just uncheck this option: just go to the "Project Options" --> Compiler --> uncheck "Automatically refresh in browser". If you check this option, make sure a local web server should is running up, your project uses a directive such as (DEFINES SMART_INTERNAL_AUTOREFRESH internally so that the program unit can make use of it)
In addition to the predefined conditions you can specify custom conditional defines. These will add to the compiler and similar to the predefined conditions set at the compiler level (i.E. set in all units).
Previously the DWScript compiler options were described. This section now covers the code generation options. These correspond to the DWScript JSCodeGen, which was to some point available as open source. As it hasn’t evolved much in regards of the basic options, you can still find it around if you need more details.
The ‘Code Generation’ section is combined with the ‘Runtime Checks’ section. The latter sits in between the compiler and the code generation as it adds runtime checks at compile time, which are then transpiled to JavaScript.
With inline magic the compiler will inline the DWScript’s mini RTL functions: AnsiLowerCase, AnsiUpperCase, ArcCos, ArcSin, ArcTan, ArcTan2, Ceil, Cos, Copy, MidStr, Exp, FloatToStr, Floor, Format, HexToInt, Infinity, IntPower, IntToHex, IntToStr, IsFinite, IsNaN, LeftStr, Ln, LowerCase, Max, Min, MaxInt, MinInt, NaN, Pi, Pos, PosEx, Power, Round, Sign, Sin, Sqr, Sqrt, StrBeginsWith, StrDeleteLeft, StrContains, StrFind, StrJoin, StrMatches, StrSplit, StrToFloat, StrToInt, SubStr, SubString, Tan, TypeOf, Unsigned32, UpperCase, VarIsNull, VarIsClear and VarIsArray with direct JS code instead of call them as functions.
This typically speeds up the application as typically less code is generated.
With ‘Emit RTTI information’ the compiler will output RTTI information. It can be left unchecked if no RTTI is needed.
No information available so far.
Often methods are declared as virtual, but there is no override used in the source code. In this case it might make sense to unmark it as virtual to improve its performance upon calls. Since it is cumbersome to maintain by hand (especially if overrides are planned to be implemented in the future) and sometimes difficult (if an overrided function doesn’t call the inherited function) to find, this feature de-virtualizes your code.
The feature takes time to perform, but might result in a major boost if enough de-virtualize opportunities exist (ie. if virtual methods are not called directly or indirectly in initialization sections or constructors)
This controls whether source locations are emitted or not. This feature links to the verbosity options.
Checks if the function is used at all. If not, it is not generated at all.
As a dedicated stage in the code generation process this takes time, but it might be well worth it. In order to work decently, the units shouldn’t have much cross-dependencies.
NOTE: This feature still contains a bug for functions that are only called from within a lambda statement.
If enabled the code will be packed by stripping empty lines. It is marked as recommended, especially for a release.
If enabled the code will be obfuscated by replacing the function names with strings from a random generator. This will make deciphering of the JS source code much harder.
It is marked as recommended, especially for a release, when it is important to protect your source. If you want others to read your code, you should of course uncheck this option.
NOTE: Class names will not be obfuscated as RTTI or other functions such as comparing the ClassName won’t work. This is important to know as this can be the reason why tools like Google’s closure compiler might not work as expected although it does similar techniques like obfuscation.
If ‘Use main body’ is checked the entire code is wrapped into a main function by the compiler. This might or might not necessary depending on the context where you want to use the script. For example the default HTML template already adds another main body, so it might not be needed. 'main body' in this context means:
var $Application = function() {
// your code will appear here
}
$Application();
Especially for environments where less is more (e.g. microcontroller programming), this just adds an unnecessary overhead.
With ‘Verbosity’ the verbosity of the generated JavaScript code can be controlled. If set to ‘None’, the JavaScript output will not contain any comments that link to the original Object Pascal source. With ‘Normal’ it will contain comments with the function names and position in the original source code. And with ‘Verbose’ it will contain even more comments (about the classes etc.).
If checked the code generation will add several runtime checks. JavaScript itself is not very critical so eventually an access beyond the bounds might just create a new field you are not aware of.
For example the code below will compile and run without complains.
var MyArray: array [0 .. 1] of Integer;
for var Index := 0 to 9 do
MyArray[Index] := Index;
As can be seen easily the code is not doing right as the array index clearly exceeds the range of elements. This would result in a hidden issue that can be very hard to locate. With ‘range checking’ enabled, an exception is raised, which points you to the location in the source code where the range is exceeded.
NOTE: Due to a bug in the, range checking does not work with the code below when the array is allocated dynamically:
var MyArray: array of Integer;
MyArray.SetLength(2);
for var Index := 0 to 9 do
MyArray[Index] := Index;
This bug will hopefully be fixed in one of the next version 2.2.1
Other runtime checks include
At the time of writing several issues in the IDE could be revealed. These will (hopefully) be fixed and the article will be revised in the future.
This also includes items that are not yet described perfectly clear in this article.