Working with scripter
This chapter explains how to use the scripter component in your application: how to run scripts, call subroutines, pass parameters back and forth, configure where script libraries are loaded from, and debug a running script.
To make your own Delphi classes, objects, functions, variables and libraries available to scripts, see Extending Scripter. For the script language itself — syntax, forms and classes declared in script — see Writing Scripts.
Getting started
To start using scripter, you just need to know one property (TatCustomScripter.SourceCode) and one method (TatCustomScripter.Execute). To execute a simple script, drop a scripter component on a form and use the following code (in a button click event, for example):
Scripter.SourceCode.Text := 'ShowMessage(''Hello world!'');';
Scripter.Execute;
You will get a "Hello world!" message after calling the Execute method. That's it — from
now on you can execute scripts. To make it more interesting, drop a TAdvMemo component on
the form and change the code to:
Scripter.SourceCode := AdvMemo1.Lines;
Scripter.Execute;
Now you can type scripts at runtime and execute them.
From this point on, any reference to the scripter object (its methods, properties and events) refers to TatScripter. The script examples are given in Pascal syntax.
Cross-language feature: TatScripter and TIDEScripter
TatScripter is a single scripter component that supports cross-language and cross-platform scripting: a script written in Basic can call a procedure written in Pascal and vice-versa, transparently, within the same scripter.
The language of each script in the TatScripter component is controlled by two members:
TatBaseScripter.DefaultLanguage is the language used for scripts created
the usual way (Scripter.Scripts.Add). Its type is TScriptLanguage (slPascal or
slBasic) and it defaults to slPascal. Set it to slBasic to make new scripts use Basic
by default.
TScriptLanguage = (slPascal, slBasic);
property DefaultLanguage: TScriptLanguage;
TatBaseScripter.AddScript creates a new script with an explicit language,
regardless of DefaultLanguage. For example, to create one Pascal and one Basic script in
the same component:
MyPascalScript := atScripter1.AddScript(slPascal);
MyBasicScript := atScripter1.AddScript(slBasic);
Two compilation options affect how scripts are interpreted, both True by default:
- TatCustomScripter.OptionExplicit requires all variables to be declared
in script. Set it to
Falseto allow undeclared variables. - TatCustomScripter.ShortBooleanEval enables short-circuit evaluation of
boolean expressions. Set it to
Falseto evaluate all operands.
Note
TIDEScripter is a TatScripter descendant with the same
scripting capabilities plus the ability to integrate with the Scripter Studio
IDE. Use it instead of TatScripter when you embed the IDE; it adds no overhead
otherwise. The legacy single-language components TatPascalScripter and TatBasicScripter
remain available for backward compatibility.
Common tasks
Calling a subroutine in script
If the script declares one or more functions or procedures, you can call them directly with TatCustomScripter.ExecuteSubroutine:
Pascal script:
procedure DisplayHelloWorld;
begin
ShowMessage('Hello world!');
end;
procedure DisplayByeWorld;
begin
ShowMessage('Bye world!');
end;
Basic script:
sub DisplayHelloWorld
ShowMessage("Hello world!")
end sub
sub DisplayByeWorld
ShowMessage("Bye world!")
end sub
CODE:
Scripter.ExecuteSubroutine('DisplayHelloWorld');
Scripter.ExecuteSubroutine('DisplayByeWorld');
This displays the "Hello world!" and "Bye world!" message dialogs.
Returning a value from script
TatCustomScripter.Execute is a function whose result is a Variant. If the
script returns a value, it can be read from Delphi code. For example, calling a script
function Calculate:
Pascal script:
function Calculate;
begin
result := (10+6)/4;
end;
Basic script:
function Calculate
Calculate = (10+6)/4
end function
CODE:
FunctionValue := Scripter.ExecuteSubroutine('Calculate');
FunctionValue receives 4. You don't need to declare a function to return a value; the
script main block can return a value directly:
Pascal script:
result := (10+6)/4;
CODE:
FunctionValue := Scripter.Execute;
Tip
In Basic syntax, to return a function value use the FunctionName = Value syntax. You can
also return a value without declaring a function by using the reserved word MAIN:
MAIN = (10+6)/4.
Passing parameters to script
To pass values to a script, use the same TatCustomScripter.Execute and TatCustomScripter.ExecuteSubroutine methods with their overloaded forms. Parameters are Variant types:
Pascal script:
function Double(Num);
begin
result := Num*2;
end;
Basic script:
function Double(Num)
Double = Num*2
End function
CODE:
FunctionValue := Scripter.ExecuteSubroutine('Double', 5);
FunctionValue receives 10. To pass more than one parameter, use a Variant array or an
array of const:
Pascal script:
function MaxValue(A,B);
begin
if A > B then
result := A
else
result := B;
end;
procedure Increase(var C; AInc);
begin
C := C + AInc;
end;
CODE:
var
MyVar: Variant;
begin
FunctionValue := Scripter.ExecuteSubroutine('MaxValue', VarArrayOf([5,8]));
Scripter.ExecuteSubroutine('Increase', [MyVar, 3]);
end;
Note
To pass a parameter by reference when calling a script subroutine, the Delphi variable must
be declared as a Variant. In the example above, MyVar must be of Variant type, otherwise
the script will not update its value.
Note
Script parameters don't need types; you just declare their names.
Loading script libraries from files
A script can use other scripts as libraries with a uses clause (see
Using other scripts for the script-author side). When
the compiler reaches a name in a uses clause, it tries to resolve it in this order:
- A registered Delphi-based library with that name — any library registered with
RegisterScripterLibrary (for example the imported VCL units such as
ClassesandForms). See Using libraries. - A script in the
Scriptscollection whoseUnitNamematches the name. Each TatScript object has aUnitNameproperty you can set so the script is treated as a library. - A file whose name matches the library name, when TatCustomScripter.LibOptions enables file loading.
The TatCustomScripter.LibOptions property controls the file search:
SearchPath— aTStringsof paths where scripter looks for the file. It accepts the constants$(CURDIR)(the current directory) and$(APPDIR)(the application path).SourceFileExt— the default extension for source files (for example.psc, souses Script2looks forScript2.psc).CompileFileExt— the default extension for compiled files (for example.pcu). Scripter looks for compiled files first, then source files.UseScriptFiles— turns file-based library loading on or off. WhenFalse, scripter does not look for files at all.
Debugging scripts
TMS Scripter provides two ways to debug scripts at run time: using the scripter component's own properties and methods, which lets you build your own debug environment; or using the ready-made debug component, which requires only dropping a component and calling a method.
Using methods and properties for debugging
The scripter component exposes the following members for driving execution from Delphi code:
- TatCustomScripter.Running — read/write;
Truewhile the script is executing (it may be paused but still running). Setting it toTrueis equivalent to calling TatCustomScripter.Execute. - TatCustomScripter.Paused — read/write; pause execution or resume it.
- TatCustomScripter.DebugTraceIntoLine — executes the current line, stepping into a subroutine if the line calls one (Trace Into).
- TatCustomScripter.DebugStepOverLine — executes the current line, running any called subroutine to completion (Step Over).
- TatCustomScripter.DebugRunUntilReturn — runs until the current subroutine finishes, stopping one line after the call site.
- TatCustomScripter.DebugRunToLine — runs until the given line (Run to Cursor).
- TatCustomScripter.DebugToggleBreakLine — enables/disables a breakpoint at a line.
- TatCustomScripter.DebugExecutionLine — returns the line that will be executed next.
- TatCustomScripter.Halt — stops execution regardless of the current
position; TatCustomScripter.Halted is briefly
Truebetween the call and the actual termination. - TatCustomScripter.BreakPoints — the list of breakpoints. Each breakpoint
(accessed by
Items[Index]orBreakPointByLine) hasEnabledandPassCountproperties. - TatCustomScripter.OnDebugHook — fires for every step during debugging.
- TatCustomScripter.OnPauseChanged and
TatCustomScripter.OnRunningChanged — fire when
PausedorRunningchange.
Using the debug component
For VCL applications, the TatScriptDebugDlg component provides high-level debugging. Drop
it on a form, assign its Scripter property to an existing scripter component, and call its
Execute method: a debug dialog appears showing the script source with a toolbar. The
shortcut keys match Delphi's:
- F4: Run to cursor
- F5: Toggle breakpoint
- F7: Step into
- F8: Step over
- F9: Run
- Shift+F9: Pause
- Ctrl+F2: Reset
- Shift+F11: Run until return
Form-aware scripters (legacy)
Note
TatPascalFormScripter and TatBasicFormScripter are legacy single-language scripters,
kept for backward compatibility, that descend from TatPascalScripter and
TatBasicScripter. They automatically register the components owned by the form the scripter
belongs to, so a script can access those components without registering them first. New
applications should use TatScripter and register the objects they need with
TatCustomScripter.AddComponent.