Spotlight on TdwsSymbolDictionary

A useful, yet not very prominent class of DWScript is TdwsSymbolDictionary. It provides a reference of  all symbols mentioned in your script, where they are declared, where they are used, etc. It is optionally filled up when you compile a script with the coSymbolDictionary compile option, and can be accessed from a compiler program object or interface.

It can be used for multiple purposes, centered around IDE features and auditing. Here are a few usage scenarios.

In-place symbol help and navigation

The most basic use of TdwsSymbolDictionary is probably to figure out which symbol is under the cursor or the mouse in your code editor. You can then use the symbol to provide relevant contextual help (either from your help file, or auto-generated from the script, such as a list of parameters for a function, of fields for a class, etc.) or look up the dictionary once more, and provide information about where it’s declared, implemented, used or forwarded. That positional information can also be used to offer navigation shortcuts between declaration and implementation, or to any of the symbol’s occurrences in the source.

Auto-completion

The TSymbolDictionary can be used it to figure out what is currently being typed, by identifying the symbol at the cursor, or the last recognized symbol in the code being entered. From that point on, you can generate a list of contextual variables, methods, fields, etc. that can be used to fill up an auto-completion drop down.

Code Refactoring

Once you have a symbol pinpointed, either by name or through one of its occurrences in the source, you have access to all the places it’s occurring in the code. A trivial use of such a list is for a rename refactoring: as the list of symbol positions is already sorted by source file, line and column, you merely have to walk the list backwards and replace occurrences in your sources files.

You can also team up TdwsSymbolDictionary with  other information sources to implement more complex refactorings. For instance alongside TdwsSourceContextMap (which is also provided in a compiled program), you can implement “extract method” (or its variants, “pull up” & “push down”).

Code Auditing

The symbol dictionary can be a convenient starting place for symbol-related audits and diagnostics. All audits that relate to the amount of times a symbol is used (or not) being the most trivial.

Another straightforward usage is when you have naming conventions for fields, variables, classes etc. and/or to enforce case consistency. The later can be handled in your IDE in a similar fashion as a rename refactoring, except you only replace in suReference and suImplementation symbol positions, and it is harmless enough you can do it in a background task without requiring user interaction.

You can also use it to diagnose code issues, for instance such patterns:

someObject.someProperty[stuff].otherProperty.function.method(1);
someObject.someProperty[stuff].otherProperty.function.method(2);
someObject.someProperty[stuff].otherProperty.function.method(3);

can be heuristically detected (either as “too many member symbols on the same line” or “member symbol repeated too much in nearby lines”), and the attention brought to the hot-spots so the code can be simplified and cleaned up.

DWScript news: classes, exceptions, speedups

There have been quite a few changes, fixes and enhancements to DelphiWebScript, available in the SVN version:
  • class visibility is now enforced: private and protected are equivalent to Delphi’s strict private and strict protected. Other levels are public (members accessible to the whole script) and published (default visibility, to be used for external exposure, RPC, persistence, etc.)
  • added support for class abstract and class sealed: an abstract class has to be subclassed before it can be instantiated, a sealed class can’t be subclassed.
  • virtual methods are now based on a Virtual-Method Table, previously they were implemented in a way vaguely similar to Delphi’s “dynamic” methods. The new implementation is much faster, but at the cost of a (hopefully reasonable) memory overhead.  VMTs are shared, and thus only use memory for classes that actually introduce or override a virtual method.
  • fixes and improvements to the exception handling (ExceptObject now available).
  • fixes to the circular reference garbage collector.
  • fixes and improvements to the virtual class methods support, and properties based on class methods.
  • class-less procedures and functions calls are now faster.
  • partial inlining loop unrolling optimization for small statement blocks*.
  • other misc. optimizations, improvements and fixes.

There is also a new JSON support unit, which isn’t currently used by DWS, but has been introduced for testing and investigations. The strict JSON parser is AFAICT about twice faster than the current “fastest” Delphi JSON parser, with still some room for improvements.

*: the impact of those seem to be highly CPU-dependent, f.i. on the “Mandelbrot” demo, the speedup is a few percentage points on an AMD Phenom, but about 40% on my Intel Core i5.

edit: to be more accurate, it brings the Intel processor up to the level of the AMD cpu, the code must have been hitting a weakness in the Core i5 branch predictor.

SamplingProfiler 1.7.7 released

Version 1.7.7 of Sampling Profiler has been released, you can grab it here (642 kB), this version fixes the following issues:

  • Fixed gathering of samples in Monte-Carlo multi-threading mode.
  • Fixed crash when closing a results page with Ctrl+F4.
  • No longer restores to maximized or minimized state.