As far as I can tell people still prefer using python for scripting in their Delphi projects. This is probably because python scripting in Delphi has a long history and it is a proven method with easy integration. What if I would tell you that there is a free solution which enables you to write also your scripts in pascal? A few years ago I discovered an alternative that makes this possible. This highly influenced my vision about the importance of scripting. Since that I accompanied all my hobby projects with full scripting support.

The first question of the reader might be that why I would need a script language in my program? It is, however, very easy to answer this question. The presence of some sort of scripting support in a software product has many benefits both from developer and customer point of view:

  • Less wasted time on software building by customizing application without the need for recompilation.
  • Unusually flexible reflection capabilities by creating script code on-the-fly with string manipulation.
  • Very flexible debugging possibilities by modifying executed code during the debug session.
  • Easy separation of often changing high level logic and rarely changing internal framework.
  • Powerful tool for the user to customize application for own needs.

These are just a few examples what additions a scripting engine can give. Personally my favorite one is the second mentioned example in the list above. As a result that I’ve worked as a PHP developer for over a year I really got used to the ability to compose code on-the-fly by just putting some strings together. It is a built-in feature of PHP and most other interpreted languages, however it is fairly uncommon that such functionality exists in native programming languages. I knew that to emulate the presence of this facility I have to use some scripting language but I never thought it will be so easy to find one which suits my needs.

First, I was looking around to find out what other Delphi developers use in their projects. That’s how I first met with python. The language itself has a very powerful OOP tool-set but the syntax was too extraneous for me. After checking tons of other scripting languages out there which had mostly no easy integration possibilities with Delphi, finally I found RemObjects Pascal Script.

Pascal Script for Delphi

First, I just said “Wow! This is exactly what I was looking for”. It not just enables you to write your scripts using the language what you also use to develop the application itself but it also provides incredibly easy integration with Delphi. Just to mention a few features of Pascal Script:

  • Calling Pascal Script code from Delphi code or vice versa.
  • Using external DLLs from within the script without requiring any type of function header.
  • Sharing any kind of data between the script and the Delphi code in both direction.

For a full list of features please refer to the official site of RemObjects Pascal Script.

One thing that most Delphi developers got used to is that most of the third-party components and tools available for Delphi are with a commercial licensing. Well, this is not the case with Pascal Script. It is not just freely available but also comes with full source code. This further increases the potentials of it as you can add new features to it if you wish. However, it is already powerful enough for most use cases.

How it works?

In a nutshell, using Pascal Script is piece of cake. You just have to put together your source code string, compile it and then execute. Yes, Pascal Script needs a compilation phase which produces a byte code as an intermediate format. By telling this, you’ve probably already figured out that Pascal Script is not just very flexible but also provides adequate performance by not having to interpret directly the source code. Let’s start with a very simple script:

{ some very simple pascal script }
begin
  PrintString('Hello World!');
end.

This will call the procedure PrintString with the string parameter “Hello World!” . But where this procedure comes from? Well, actually you have to bind it using the run-time library that comes with Pascal Script. To execute this script having an actual Delphi procedure bound to the procedure name used in the script you’ll need some code similar to the following:

program HelloWorldScript; { host application that executes the script }

uses
  uPSCompiler, uPSRuntime;

procedure PrintString(message: String);
begin
  writeln('Message from script: ', message);
end;

function LoadScript: String;
begin
  { load the script from some file and return it }
end;

var
  Compiler: TPSPascalCompiler;
  Exec: TPSExec;
  ByteCode: tbtString;
begin
  Compiler := TPSPascalCompiler.Create;  // create an instance of the compiler
  // register user procedure to compiler
  Compiler.AddDelphiFunction('procedure PrintString(message: String)');
  if Compiler.Compile(LoadScript) then  // compile the script to byte code
  begin
    Compiler.GetOutput(ByteCode);
    Exec := TPSExec.Create;  // create an instance of the executer
    // register user procedure to executer
    Exec.RegisterDelphiFunction(@PrintString, 'PRINTSTRING', cdRegister);
    if Exec.LoadData(ByteCode) then  // load byte code to executer
      Exec.RunScript;  // run the script
  end;
  Compiler.Free;
  Exec.Free;
end.

If a newbie looks at this code, probably thinks that it’s overcomplicated. Well, actually this is true. Pascal Script needs some basic setup stuff but if you take the time to learn it, you will figure out that it does not involve too much code to use it. One thing that may still need some clarification is the registration of the user procedure provided to the script…

Connecting the script to the Delphi code

Pascal Script needs that all the procedures, functions, variables, types and classes that we would like to provide to the executing script needs to be registered both to the compiler and the executer. The compiler needs this information for syntax validation and to produce the byte code, that’s why it’s enough to provide the signature of the particular language element to it. The registration to the executer is which actually binds the concrete object to the script.

All these manual registrations looks like a pain in the a** at first sight, however, they are unavoidable. Fortunately, Pascal Script provides a very handy tool for us to automate this process, namely the UnitImporter. This tool can create an import unit based on an actual production code unit that will provide one parameterless procedure that registers all the classes, methods, etc. to the script compiler and run-time.

Beside this, Pascal Script provides ready baked units for the registration of the standard units of Delphi and a component set that integrates into the IDE, although I haven’t used them so far. Anyway, even if the framework seems to be a bit too complex and needs too much auxiliary code, in practice it is very easy to use it and most of the support code for scripting can be generated with the UnitImporter. If you don’t believe me, try using it for a while and you will see.

Portability and usage limitations

Maybe Pascal Script is not the Holy Grail of Delphi programmers but it is a very powerful scripting engine. The first question in those who are not developing on/for Windows platform can be that “Is it portable?”. This is another advantage of Pascal Script as it is as portable as Delphi can be. This means that it will work fine also with the Free Pascal compiler and it comes with the same component set for the Lazarus IDE as well.

So if not the portability and the ease of use then has it any disadvantages by the way? Unfortunately, yes. We’ve already seen that it has both-way interworking capability with Delphi, it has tools for automating the integration process and it can be used also for cross-platform projects, but it has small problem: it supports only a subset of the Delphi language so you cannot define classes in the scripts. You can still use classes and objects inside the script, but only those which were defined in the host Delphi application.

Anyway, this does not necessarily mean that Pascal Script is not flexible enough. I used it in my project mainly for the following purposes:

  • Using the services provided to the script (classes, objects, etc.) to manipulate application behavior at run-time.
  • Handling Delphi events with procedures/functions implemented in scripts.
  • Baking a console that makes debugging tasks much easier by correcting errors while the program is running.

Personally I don’t understand how Embarcadero Technologies (the current supplier of Delphi) haven’t integrated it into the core Delphi distribution as they did with many other popular frameworks like DUnit.

Conclusion

Pascal Script is probably not a script language that can have a future on it’s own but it is still a great addition to the feature set of Delphi as it provides a way to push the flexibility of the language above it’s limits with minimal effort. It is fast, robust and stable, and it offers most of the facilities that usual developers expect from a scripting language. Maybe I’m quite biased as I really enjoyed working with Pascal Script, but I think you Delphi programmers out there should definitely take a look at it and give it a try.