Table of Contents

Basic language reference

This chapter describes the Basic language of TMS Scripter, for the people who write scripts. The language is similar to Visual Basic and VBScript, with the differences described here. Each language of TMS Scripter has its own reference chapter with the same structure: see also the Pascal and JavaScript references.

The objects, functions and libraries available to a script depend on the application that runs it. This chapter describes the language and the routines that are always available; the documentation of your application tells which additional objects and libraries it provides.

A first example

Uses Classes

Dim Names, I

Function Greeting(Name)
  Greeting = "Hello, " & Name & "!"
End Function

Names = New TStringList
Try
  Names.Add("Anna")
  Names.Add("Bruno")
  For I = 0 To Names.Count - 1
    ShowMessage(Greeting(Names[I]))
  Next
Finally
  Names.Free
End Try

Script structure

A script is made of these parts, in this order, all of them optional:

  1. A Uses clause listing the libraries and other scripts the script uses (see Using libraries and other scripts).
  2. Global declarations: Dim, Public, Private and Const.
  3. Subs and functions.
  4. The main statements: the statements that run when the script is executed.
Sub SayHello
  ShowMessage("Hello")
End Sub

SayHello

Each statement is on its own line. Several statements can be written on the same line, separated by colons:

A = 1 : B = 2 : C = A + B

A script can also contain only subs and functions; then the application calls them directly, for example as event handlers.

Script result

The main statements work like a function named Main: assign a value to Main, or use Return with a value, to return it to the application. Applications use this to evaluate expressions and formulas. If no value is assigned, the script returns Null.

Main = (10 + 6) / 4

Lexical elements

Case sensitivity

Basic is not case-sensitive: If, if and IF are the same keyword, and MyVar, myvar and MYVAR are the same identifier. String values are case-sensitive.

Comments

An apostrophe or the word Rem starts a comment, which ends at the end of the line. Rem must be at the beginning of the line or after a space or colon.

' a comment line
Total = Price * Quantity   ' a comment after a statement
Rem another comment

A line starting with # is also a comment; the #FORM and #CLASS directives use this form (see Declaring forms in script). Separate a comment from the code before it with a space, and do not write a comment after Then at the end of a multi-line If: write it on the next line.

Identifiers and reserved words

Identifiers (names of variables, constants, subs, functions and parameters) start with a letter or an underscore, followed by letters, digits or underscores. Letters are the ASCII letters A to Z.

Total  _temp  Item2  first_name     ' valid
2Items  first-name  my name         ' invalid

These reserved words cannot be used as identifiers: And, As, Case, Catch, Const, Dim, Div, Do, Else, ElseIf, End, Except, Exit, Finally, For, Forward, Function, If, Imports, Loop, Mod, Next, Not, Or, Private, Public, Return, Select, Shl, Shr, Step, Sub, Then, To, Try, Until, Uses, While, With, Xor. They are allowed as member names after a dot (Obj.End). An identifier can start with a reserved word, like Format or Ending.

Numbers

42          ' integer
-7          ' negative integer
3.25        ' floating-point number
1.5e-2      ' floating-point number with exponent (0.015)
0xFF        ' hexadecimal integer (255)

A number without fraction and exponent is an integer; integers are 64-bit values. Hexadecimal numbers use the 0x prefix (&H is not supported).

Strings

Strings are enclosed in double quotes. Two consecutive double quotes inside a string represent one double quote. Single quotes are ordinary characters inside a string.

S = "Hello, world"
S = "Say ""hi"""          ' Say "hi"
S = "It's here"
S = ""                    ' empty string

To include special characters, use Chr with the character code: "First line" & Chr(13) & Chr(10) & "Second line".

Special values

Value Meaning
True, False Boolean values.
Nothing No object. Object variables that refer to no object are Nothing.
Null The null value. A variable that is never assigned is Null.
Empty The unassigned value (converted to an empty string or zero).

Variables

Declaring variables

Variables are declared with Dim. A type is optional (As Type): every variable can hold values of any type (see Values and types). A variable can be initialized in its declaration.

Dim Count
Dim Name As String
Dim A, B, C
Dim Total = 0
Dim Title As String = "Report"

A declared type documents the variable and, for object types, lets the script editor offer code completion for the members of the object. It does not restrict the values the variable can hold.

Variables must be declared before they are used. Some applications relax this rule: then assigning a value to an undeclared name creates the variable.

Scope

Variables declared outside subs and functions are global: they are visible in the main statements and in every sub and function. Global variables can be declared with Public or Private instead of Dim: Private variables are not visible to other scripts that use this script; Dim and Public variables are.

Variables declared inside a sub or function are local to it, and a local variable hides a global variable with the same name.

Dim Counter            ' global

Sub Increment
  Dim Stp              ' local
  Stp = 1
  Counter = Counter + Stp
End Sub

Counter = 0
Increment
Increment
ShowMessage(Counter)   ' 2

Constants

Constants are declared with Const, globally or inside a sub or function, one per statement. Their value can be an expression. A constant cannot be changed.

Const MaxItems = 100
Const Title = "Report"
Const HalfMax = MaxItems Div 2

Values and types

Variables, parameters and function results hold values of any type, and the type of the value can change when a new value is assigned. Scripts work with these kinds of values:

  • integers (64-bit) and floating-point numbers;
  • strings;
  • Boolean values (True, False);
  • dates and times (floating-point numbers: the integer part is the date, the fraction is the time of day);
  • objects (or Nothing);
  • arrays;
  • Null and Empty.

Values are converted automatically when an operation needs another type, following the rules of the Delphi Variant type:

  • & converts its operands to strings and concatenates them: "Total: " & 5 is "Total: 5".
  • + between two strings concatenates them. A string that contains a number is converted to a number when added to a number: "1" + 2 is 3. A string that does not contain a number cannot be added to a number: "Total: " + 5 is an error. Use & to concatenate.
  • Comparisons between strings and numbers compare the numbers: "10" = 10 is True.
  • Arithmetic with Null gives Null.

Use the conversion routines (IntToStr, StrToInt, FloatToStr, VarToStr and others, see Built-in routines) to convert values explicitly.

Expressions and operators

Arithmetic operators

Operator Operation Example Result
+ Addition (or string concatenation) 7 + 2 9
- Subtraction 7 - 2 5
* Multiplication 7 * 2 14
/ Division, always a floating-point result 7 / 2 3.5
Div Integer division, truncated toward zero 7 Div 2 3
Mod Remainder of the integer division 7 Mod 2 1
^ Power, always a floating-point result 2 ^ 3 8.0
- (unary) Negation -X

Division by zero with Div or Mod is an error. \ (integer division in VB) is not supported: use Div.

Comparison operators

Operator Meaning
= Equal
<> Not equal
<, > Less than, greater than
<=, >= Less than or equal, greater than or equal

In an expression, = is a comparison: A = B = 2 assigns to A the result of B = 2. String comparisons are case-sensitive: "abc" = "ABC" is False. Use CompareText or UpperCase to compare strings without case sensitivity.

Logical and bitwise operators

Operator Operation
Not Logical negation
And Logical and; bitwise and on integers
Or Logical or; bitwise or on integers
Xor Logical exclusive or; bitwise exclusive or on integers
Shl, Shr Bitwise shift left and right

And and Or are short-circuit operators: when the left operand decides the result, the right operand is not evaluated. This makes expressions like the following safe:

If (Count > 0) And (Total Div Count > 10) Then ShowMessage("Average above 10")
Warning

Unlike Visual Basic, And and Or have a higher precedence than the comparison operators (see Operator precedence). Always put comparisons in parentheses when combining them: write (A > 0) And (B > 0), not A > 0 And B > 0.

Note

And, Or and Xor work as integer operations: with Boolean operands, the result may be the integer -1 (true) or 0 (false) instead of True or False. Both work in any condition. Not is always a logical operation: Not X is True when X is False or zero.

String operators

& concatenates two values as strings, converting numbers and other values to text. + also concatenates two strings.

Msg = "You have " & Count & " new messages"

& has the same precedence as +: put arithmetic in parentheses when mixing them, as in "Total: " & (A + B).

Object operators

Is tests if an object is an instance of a class, or of a descendant class: Sender Is TButton.

Operator precedence

Operators with higher precedence are evaluated first. Operators with the same precedence are evaluated from left to right. Use parentheses to change the order.

Precedence Operators
1 (highest) Not, unary - and +
2 ^, Is
3 *, /, Div, Mod, And, Shl, Shr
4 +, -, &, Or, Xor
5 (lowest) =, <>, <, >, <=, >=

Write a unary minus or plus right before its operand, without a space: -X, -(A + B).

Statements

Assignment

The assignment operator is =. The target can be a variable, an object property, an array item or a string character. The Set keyword is optional.

Total = Price * Quantity
Button1.Caption = "OK"
Items[2] = "third"
Set List = New TStringList

If statement

If has a single-line form and a multi-line form.

In the single-line form, the statements follow Then on the same line; several statements are separated by colons, and an Else part can follow on the same line. End If is optional.

If Total > 100 Then Discount = 10
If Total > 100 Then Discount = 10 Else Discount = 0
If Found Then Count = Count + 1 : ShowMessage("Found")

In the multi-line form, Then ends the line, the statements follow on the next lines, and End If ends the statement. ElseIf and Else parts are optional.

If Score >= 90 Then
  Grade = "A"
ElseIf Score >= 80 Then
  Grade = "B"
Else
  Grade = "C"
End If

The condition can be a Boolean value or a number (zero is false). Write a space after If when the condition starts with a parenthesis: If (A > 0) Then.

Select Case statement

Select Case runs the statements of the Case whose value matches the selector. The selector and the values can be of any type, including strings, and the values can be expressions. Several values can share a Case, separated by commas. The optional Case Else part runs when no value matches.

Select Case UpperCase(Fruit)
  Case "LIME", "KIWI"
    Color = "green"
  Case "LEMON"
    Color = "yellow"
  Case "APPLE"
    Color = "red"
    Found = True
  Case Else
    Color = "unknown"
End Select

Only the first matching Case runs, and the selector is evaluated once. Ranges (Case 1 To 5) and comparisons (Case Is > 5) are not supported: list the values.

For statement

For I = 1 To 10
  Sum = Sum + I
Next

For I = 10 To 0 Step -2
  ShowMessage(I)
Next
  • Step sets the increment, which is 1 when omitted. It must be a number (negative or floating-point numbers are allowed); a negative step counts down.
  • The initial and final values are evaluated once, before the loop starts.
  • If the range is empty (For I = 5 To 1), the loop body does not run.
  • After the loop, the counter variable holds the final value plus one step.
  • Next is written without the counter name.

Do Loop statement

Do..Loop repeats statements while (While) or until (Until) a condition is true. With the condition after Do, it is tested before each iteration, so the statements may not run at all. With the condition after Loop, it is tested after each iteration, so the statements run at least once.

Do While I < Count
  Process(I)
  I = I + 1
Loop

Do Until I >= Count
  I = I + 1
Loop

Do
  K = I Mod J
  I = J
  J = K
Loop Until J = 0

Do
  Line = ReadLn(F)
Loop While Line <> ""

While statement

While..End While repeats statements while a condition is true, tested before each iteration:

While I < Count
  Process(I)
  I = I + 1
End While

Exit statements

Statement Effect
Exit For Leaves the innermost For loop.
Exit Do Leaves the innermost Do or While loop.
Exit Sub Leaves the current sub.
Exit Function Leaves the current function, which returns the value already assigned.
For I = 0 To List.Count - 1
  If List[I] = "END" Then Exit For
  Process(List[I])
Next

Exit For must be used directly in a For loop (not in a Do loop inside it), and Exit Do directly in a Do or While loop. There is no Continue statement: use an If around the rest of the loop body.

Return statement

Return leaves the current sub or function. In a function, Return followed by a value on the same line sets the result of the function. In the main statements, Return ends the script.

Function Max(A, B)
  If A > B Then Return A
  Return B
End Function

With statement

With gives direct access to the members of an object, without repeating its name:

With Button1
  Caption = "OK"
  Width = 100
End With

The class of the object must be known when the script is compiled: an object provided by the application, or a variable declared with a class type (Dim B As TButton).

Subs and functions

Declaring subs and functions

A sub performs an action; a function also returns a value. Declare them before the main statements. Parameter and result types are optional (As Type).

Sub ShowTotal(Value)
  ShowMessage("Total: " & Value)
End Sub

Function Max(A, B)
  If A > B Then
    Max = A
  Else
    Max = B
  End If
End Function

Function Average(Total As Double, Count As Integer) As Double
  Average = Total / Count
End Function

A routine without parameters is declared without parentheses: Sub Refresh. A routine can declare its own variables with Dim and constants with Const.

Subs and functions are public: other scripts that use this script can call them. Declare them with Private to make them visible only in this script: Private Function Helper(X).

Returning a value

A function returns the value assigned to the function name, or the value of a Return statement. The function name can be assigned and read any number of times; if no value is assigned, the function returns Null.

Function Factorial(N)
  Factorial = 1
  Do While N > 1
    Factorial = Factorial * N
    N = N - 1
  Loop
End Function

Parameters by value and by reference

Parameters are passed by value (ByVal, the default): the routine receives a copy, and changing the parameter does not change the variable passed by the caller. Declare a parameter with ByRef to pass it by reference: then the routine changes the variable of the caller. Only a variable can be passed to a ByRef parameter (not an expression, an array item or a property).

Sub Swap(ByRef A, ByRef B)
  Dim Temp
  Temp = A
  A = B
  B = Temp
End Sub

Dim X, Y
X = 1
Y = 2
Swap(X, Y)    ' now X is 2 and Y is 1

Calling subs and functions

Arguments are always given in parentheses, also when calling a sub: ShowTotal(10). A routine without parameters is called with or without empty parentheses (Refresh or Refresh()). The number of arguments must match the declaration.

A routine must be declared before the code that calls it. To call a routine that is declared later, for example in two routines that call each other, declare it first with Forward:

Function IsOdd(N) Forward

Function IsEven(N)
  If N = 0 Then
    IsEven = True
  Else
    IsEven = IsOdd(N - 1)
  End If
End Function

Function IsOdd(N)
  If N = 0 Then
    IsOdd = False
  Else
    IsOdd = IsEven(N - 1)
  End If
End Function

Routines can call themselves (recursion).

Error handling

Try..Catch

The statements between Try and Catch run; if an error occurs, execution continues in the Catch part. Errors raised by the script, by the routines it calls and by the application are all handled. Except can be used instead of Catch, and End instead of End Try.

Try
  Value = StrToInt(Text)
Catch
  ShowMessage("Invalid number: " & LastExceptionMessage)
  Value = 0
End Try

Try..Finally

The statements of the Finally part always run, whether an error occurred or not; the error, if any, continues after the Finally part. Use it to release resources:

List = New TStringList
Try
  List.LoadFromFile(FileName)
  Process(List)
Finally
  List.Free
End Try

A Try block has either a Catch part or a Finally part. Nest two Try blocks to combine both behaviors.

Raising errors

Raise raises an error with a message. The script stops at that point, unless the error is handled by a Try..Catch block.

If Quantity <= 0 Then Raise("Quantity must be positive")

Information about the last error

Inside a Catch block, these values describe the error being handled:

Name Description
LastExceptionMessage The error message.
LastExceptionClassName The class name of the error (exception class).
LastExceptionLine, LastExceptionCol The script position where the error occurred.
LastExceptionHelpContext The help context number of the error.

An error that is not handled stops the script, and the application receives it with its message and position.

Arrays

Square brackets create an array from a list of values. Arrays are zero-based, and items can be of any type. Nested arrays give multi-dimensional arrays. Items are accessed with square brackets too (not parentheses).

Dim Primes, Matrix, Item

Primes = [2, 3, 5, 7]
Item = Primes[1]                  ' 3
Primes[0] = 1

Matrix = [["a", "b"], ["c", "d"]]
Item = Matrix[1, 0]               ' "c"
Item = Matrix[1][0]               ' also "c"
  • Length(A) is the number of items; Low(A) and High(A) are the first and last indexes.
  • VarArrayCreate([0, 9], 12) creates an array of 10 empty items.
  • Accessing an index out of the bounds is an error.

Strings

Besides the operators and the string routines (see Built-in routines), strings can be indexed with square brackets to read or change a single character. The first character has index 1:

S = "Hello"
C = S[1]        ' "H"
S[1] = "J"      ' S is "Jello"

Working with objects

The application makes objects available to scripts: the controls of a form, data objects, or any other object of the application. Scripts can also create objects of the classes the application provides, like TStringList.

Properties and methods

Use a dot to access properties and methods. Methods without parameters can be called with or without parentheses.

Edit1.Text = "Hello"
Width = Panel1.Width - 10
Memo1.Lines.Add("New line")
Memo1.Lines.Clear

Creating and destroying objects

New creates an object: it calls the Create method of the class, with the arguments given in parentheses. Calling Create directly also works. Free destroys the object. To check if a variable refers to an object, use Assigned(Obj): comparing with Nothing works only for variables that were set to Nothing or to an object, not for variables never assigned.

Dim List, Lbl

List = New TStringList
Lbl = New TLabel(Form1)
List.Add("one")
List.Free

Default and indexed properties

Indexed properties take the index in square brackets. When a class has a default indexed property, the property name can be omitted:

S = Memo1.Lines.Strings[0]
S = Memo1.Lines[0]            ' the same: Strings is the default property

Enumerations and sets

Enumeration values are used by name, like constants. To set a set property, assign an array of values. Where a routine expects a set, convert the array with SetOf:

Panel1.Align = alClient
Label1.Font.Style = [fsBold, fsItalic]
Answer = MessageDlg("Save changes?", mtConfirmation, SetOf([mbYes, mbNo]), 0)

Events

To handle an event of an object, write a sub with the parameters of the event, and assign the sub name, as a string, to the event property:

Sub Button1Click(Sender)
  ShowMessage("Clicked")
End Sub

Sub FormCloseQuery(Sender, ByRef CanClose)
  CanClose = Memo1.Lines.Count > 0
End Sub

Button1.OnClick = "Button1Click"
Form1.OnCloseQuery = "FormCloseQuery"

Declare as ByRef the event parameters that the handler changes, like CanClose above.

Using libraries and other scripts

The Uses clause, at the beginning of the script, gives access to libraries: units of the application (for example Classes, SysUtils, Dialogs or Forms, when the application provides them) and other scripts.

Uses Classes, Dialogs, MyLibrary

The names of a library can be used directly, or qualified with the library name: MyLibrary.Calculate(10). Imports loads a library without making its names directly visible: they must be qualified.

When a script uses another script, the public global variables, constants, subs and functions of the other script are available to it:

' Script "MathLib"
Dim Precision

Function RoundTo2(Value)
  RoundTo2 = Round(Value * 100) / 100
End Function
' Main script
Uses MathLib

Precision = 2
ShowMessage(RoundTo2(3.14159))

The main statements of a used script do not run when another script uses it, so its global variables start without a value. Initialize them in a routine of the library that the other scripts call.

The application defines where used scripts are found (another script it manages, or a file). A script used as a library can be written in any of the TMS Scripter languages.

Declaring forms in script

A script can declare a form, designed in a form file (.dfm, or .sfm in the TMS Scripter IDE), and be used as a class to create and show instances of that form. The #FORM directive at the beginning of the script gives the form class name and the form file:

#FORM TCustomerForm, customerform.dfm

Dim CustomerId      ' a property of each form instance

Sub btSaveClick(Sender)
  ShowMessage("Saving customer " & CustomerId & ": " & edName.Text)
  Close
End Sub

Sub Init(AId)
  CustomerId = AId
  btSave.OnClick = "btSaveClick"
End Sub
  • The components of the form file are available by name (edName, btSave), and so are the properties and methods of the form itself (Caption, Close).
  • The global variables of the form script are properties of the form, and its subs and functions are methods. Each instance of the form has its own variable values.
  • The form file must not contain event handlers: assign the events in script, as above.

Another script uses the form script and creates instances of the form class:

Uses Forms, CustomerFormScript

Dim F
F = New TCustomerForm(Application)
F.Init(42)
F.edName.Text = "John"
F.ShowModal
F.Free

Declaring classes in script

A script can declare a class with the #CLASS directive. The global variables of the script are the properties of the class, its subs and functions are the methods, and its main statements run when an instance is created (use them to initialize the properties).

#CLASS TCounter

Dim Count, Stp

Sub Increment
  Count = Count + Stp
End Sub

Count = 0
Stp = 1
Uses CounterScript

Dim C
C = New TCounter
C.Stp = 5
C.Increment
ShowMessage(C.Count)   ' 5
C.Free

Script classes cannot inherit from other classes. Calling Free is optional: objects of script classes that are not freed are destroyed automatically later.

Calling DLL functions

Scripts can declare and call functions of DLLs (Windows only, when the application allows it). See Calling DLL functions.

Built-in routines

The routines available to every script (strings, conversions, math, date and time, dialogs, files) are listed in Built-in routines. Applications can also provide the VBScript library, with functions like MsgBox, InStr and UCase.