Using Macros
Macros are one-line definitions of substitutions that you can use within ObjectScript code. This page describes how to create and use them. Also see Preprocessor Directives Reference and System Macros.
Creating Custom Macros
Macros are one-line definitions of substitutions that can support many aspects of ObjectScript functionality. In their basic form, they are created with a #define directive. For instance, the following code creates a macro called StringMacro and makes it a substitution for the string "Hello, World!":
#define StringMacro "Hello, World!"
(You can use ##continue to continue a #define directive to the next line.)
ObjectScript allows you to invoke a macro using the $$$ syntax, such as:
WRITE $$$StringMacro
which, in this case, displays the string "Hello, World!". Here is the entire sample:
#define StringMacro "Hello, World!"
WRITE $$$StringMacro
Supported functionality includes:
-
String substitutions, as demonstrated above.
-
Numeric substitutions:
#define NumberMacro 22
#define 25M ##expression(25*1000*1000)
As is typical in ObjectScript, the definition of the numeric macro does not require quoting the number, while the string must be quoted in the string macro’s definition.
-
Variable substitutions:
#define VariableMacro Variable
Here, the macro name substitutes for the name of a variable that is already defined. If the variable is not defined, there is an <UNDEFINED> error.
-
Command and argument invocations:
#define CommandArgumentMacro(%Arg) WRITE %Arg,!
Macro argument names must start with the % character, such as the %Arg argument above. Here, the macro invokes the WRITE command, which uses the %Arg argument.
-
Use of functions, expressions, and operators:
#define FunctionExpressionOperatorMacro ($ZDate(+$Horolog))
Here, the macro as a whole is an expression whose value is the return value of the $ZDate function. $ZDate operates on the expression that results from the operation of the + operator on the system time, which the system variable $Horolog holds. As shown above, it is a good idea to enclose expressions in parentheses so that they minimize their interactions with the statements in which they are used.
-
References to other macros:
#define ReferenceOtherMacroMacro WRITE $$$ReferencedMacro
Here, the macro uses the expression value of another macro as an argument to the WRITE command.
Note:If one macro refers to another, the referenced macro must appear on a line of code that is compiled before the referencing macro.
Macro Naming Conventions
-
The first character must be an alphanumeric character or the percent character (%).
-
The second and subsequent characters must be alphanumeric characters. A macro name may not include spaces, underscores, hyphens, or other symbol characters.
-
Macro names are case-sensitive.
-
Macro names can be up to 500 characters in length.
-
Macro names can contain Japanese ZENKAKU characters and Japanese HANKAKU Kana characters. For further details, refer to the “Pattern Codes” table in the Pattern Matching.
-
Macro names should not begin with ISC, because ISCname.inc files are reserved for system use.
Macro Whitespace Conventions
-
By convention, a macro directive is not indented and appears in column 1. However, a macro directive may be indented.
-
One or more spaces may follow a macro directive. Within a macro, any number of spaces may appear between macro directive, macro name, and macro value.
-
A macro directive is a single-line statement. The directive, macro name, and macro value must all appear on the same line. You can use ##continue to continue a macro directive to the next line.
-
#if and #elseIf directives take a test expression. This test expression may not contain any spaces.
-
An #if expression, an #elseIf expression, the #else directive, and the #endif directive all appear on their own line. Anything following one of these directives on the same line is considered a comment and is not parsed.
Macro Comments and Studio Assist
Macros can include comments, which are passed through as part of their definition. Comments delimited with /* and */, //, #;, ;, and ;; all behave in their usual way. See Comments.
Comments that begin with the /// indicator have a special functionality. If you wish to use Studio Assist with a macro that is in an include file, then place a /// comment on the line that immediately precedes its definition; this causes its name to appear in the Studio Assist popup. (All macros in the current file appear in the Studio Assist popup.) For example, if the following code were referenced through an #include directive, then the first macro would appear in the Studio Assist popup and the second would not:
/// A macro that is visible with Studio Assist
#define MyAssistMacro 100
//
// ...
//
// A macro that is not visible with Studio Assist
#define MyOtherMacro -100
For information on making macros available through include files, see Referring to External Macros (Include Files).
Saving Custom Macros
Macros can either appear in the file where they are invoked or, as is more common, in a separate include file. For a macro to be available class-wide (that is, available for any member to invoke), place its definition in an include file and include it in the class.
Invoking Macros
You can invoke a macro either when its definition is part of the method or routine being defined or when that method or routine uses the #include directive to refer to a definition in an external source. For information on #include, see the section Referring to External Macros or the reference section on #include.
To invoke a macro from within ObjectScript code, refer to it by its name prefixed with $$$. Hence, if you have defined a macro called MyMacro, you can call it by referring to $$$MyMacro. Note that macro names are case-sensitive.
You can invoke a macro to substitute a value in contexts where you cannot supply a variable value. For example:
#define StringMacro "Hello",!,"World!"
WRITE $$$StringMacro
#define myclass "Sample.Person"
SET x=##class($$$myclass).%New()
Remember that macros are text substitutions. After a macro is substituted in, the syntax for the resulting statement is checked for correctness. Therefore, the macro defining an expression should be invoked in a context requiring an expression; the macro for a command and its argument can stand as an independent line of ObjectScript; and so on.
Referring to External Macros (Include Files)
When you have saved macros to a separate file, you can make them available with the #include directive, which is not case-sensitive.
When including macros within a class or at the beginning of a routine, the directives are of the form:
#include MacroIncFile
where MacroIncFile refers to an included file containing macros that is called MacroIncFile.inc. Note that the .inc suffix is not included in the name of the referenced file when it is an argument of #include.
For example, if you have one or more macros in the file MyMacros.inc, you can include them with the following call:
#include MyMacros
If there are other macros that are in the file YourMacros.inc, you can include all of them with the following calls:
#include MyMacros
#include YourMacros
When you use #include in a routine you must specify a separate #include statement on a separate line for each include file.
To include an include file at the beginning of a class definition, the syntax is of the form:
include MyMacros
To include multiple include files at the beginning of a class definition, the syntax is of the form:
include (MyMacros, YourMacros)
Note that this include syntax does not have a leading pound sign; this syntax cannot be used for #include. Also, compilation in Studio converts the form of the word so that its first letter is capitalized and subsequent letters are lower case.
The ObjectScript compiler provides a /defines qualifier that permits including external macros. For further details refer to the Compiler Qualifiers table in the $SYSTEM special variable reference page in the ObjectScript Reference.
See also the reference section on #include.
Where to See Expanded Macros
Preprocessor directives are included in the MAC version of code. When you compile MAC code, the ObjectScript compiler performs preprocessing and generates INT (intermediate, readable ObjectScript) code and OBJ (executable object) code.
The preprocessor expands macros before the ObjectScript parser handles any Embedded SQL. The preprocessor supports Embedded SQL in either embedded or deferred compilation mode; the preprocessor does not expand macros within Dynamic SQL.
The ObjectScript parser removes multiple line comments before parsing preprocessor directives. Therefore, any macro preprocessor directive specified within a /* . . . */ multiple line comment is not executed.
The following globals return MAC code information. Use ZWRITE to display these globals and their subscripts:
-
^rINDEX(routinename,"MAC") contains the timestamp when the MAC code was last saved after being modified, and the character count for this MAC code file. The character count including comments and blank lines. The timestamp when the MAC code was last saved, when it was compiled, and information about #include files used are recorded in the ^ROUTINE global for the .INT file. For further details about .INT code, refer to the ZLOAD command.
-
^rMAC(routinename) contains a subscript node for each line of code in the MAC routine, as well as ^rMAC(routinename,0,0) containing the line count, ^rMAC(routinename,0) containing the timestamp when it was last saved, and ^rMAC(routinename,0,"SIZE") containing the character count.
-
^rMACSAVE(routinename) contains the history of the MAC routine. It contains the same information as ^rMAC(routinename) for the past five saved versions of the MAC routine. It does not contain information about the current MAC version.