xHarbour Reference Documentation > Operator Reference |
![xHarbour Developers Network](../../img/xh_icon.gif) |
|
& (macro operator)
Macro operator (unary): compiles a character string at runtime.
Syntax
a) &<cVarName>
b) "Text &<cVarName>. substitution"
c) &<cExpression>
d) <objVar>:&<cIVarName> [:= <xValue>]
<objVar>:&<cMethodName>([<params,...>])
e) &<cFunctionName>([<params,...>])
Arguments
- <cVarName>
- This is a character string indicating the name of a variable whose symbolic
name is known at runtime. This applies to variables of type PRIVATE, PUBLIC
or FIELD.
- <cExpression>
- A character string holding a valid xHarbour expression to compile at runtime.
- <objVar>
- This is a variable holding a reference to an object value (Valtype() == "O")
to which a message is sent.
- <cIVarName>
- A character string indicating the name of an instance variable of the object.
If no assignment operator is used in the expression, the value of the instance
variable is retrieved by the macro operator. Otherwise, the value <xValue> is
assigned to the instance variable.
- <cMethodName>
- A character string indicating the name of a method of the object to execute.
Calling a method with the macro operator requires the parentheses () be added
to the expression. Optionally, a list of parameters can be specified within
the parentheses. The list of <params,...> is passed to the method.
- <cFunctionName>
- A character string indicating the name of a function or procedure to execute.
Calling a function with the macro operator requires the parentheses () be
added to the expression. Optionally, a list of parameters can be specified
within the parentheses. The list of <params,...> is passed to the function or
procedure.
Description
One extremely powerful feature of xHarbour is the Macro operator (&). It
allows for compiling and executing program code at runtime of an application.
The program code is supplied in form of a character string and can be as
simple as a variable name or may include very complex expressions. Despite its
power, there are some limitations a programmer must be aware of when using the
Macro operator.
As a first rule, no white space characters may follow the macro operator.
This is required to distinguish the & sign from the bitwise AND operator.
The macro expression must follow the & operator immediately.
All entities that do not have a symbolic name at runtime of an application
cannot be accessed by the Macro operator. This applies to memory variables
of type GLOBAL, LOCAL and STATIC, to STATIC declared functions and procedures,
as well as commands and statements. Also, the Macro operator cannot resolve
multiple line expressions, it can only compile expressions programmed within
one line of code.
As indicated in the syntax description, there are some typical scenarios
where the Macro operator is used. Examples for these scenarios follow:
a) |
Acessing and creating variables
|
|
The values of PRIVATE, PUBLIC and FIELD variables can be retrieved by using
a character string indicating the symbolic name of a variable.
|
LOCAL cPrivate := "myPrivate"
LOCAL cPublic := "myPublic"
LOCAL cField := "LastName"
LOCAL x, y, z
PUBLIC myPublic := "A public variable"
PRIVATE myPrivate := 10
USE Customer
x := &cPrivate
y := &cPublic
z := &cField
? x, y, z
// result: 10 A public variable Miller
|
The macro operator is used in this example as the right-hand-side
expression of the assignments. As a result, the values of the variables
whose names are stored in LOCAL variables are retrieved and assigned
to the LOCAL variables x, y and z.
|
|
When the macro operator is used on the left-hand-side of an assignment,
a value is assigned to the corresponding variable. If the variable does
not exist prior to the assignment, it is created as a PRIVATE variable:
|
LOCAL cPrivate := "myPrivate"
LOCAL cPublic := "myPublic"
LOCAL cField := "LastName"
PUBLIC myPublic := "A public variable"
USE Customer
&cPrivate := 10 // creates a PRIVATE variable
// named myPrivate
&cPublic := "New text"
FIELD->&cField := "McBride"
? &cPrivate, &cPublic, &cField
// result: 10 New text McBride
|
Note that PUBLIC variables cannot be created using this technique while
field variables must be aliased to assign a value.
|
|
Text substitution is a special situation where the macro operator appears
within a character string.
|
LOCAL cText
PRIVATE cMacro := "xHarbour"
cText := "This is a &cMacro. test."
? cText
// result: This is a xHarbour test."
cMacro := CDoW(Date())
cText := "Today is &cMacro.!"
? cText
// result: Today is Tuesday!"
|
When a character string contains a macro variable, the macro is substituted
with the contents of the macro variable. Note that the end of the macro
variable within the text string is indicated with a period. This period
does not appear in the result string but serves as "end-of-macro" marker.
|
|
The most common situation for using the Macro operator is the compilation
of expressions at runtime. Expressions must be syntactically correct and
may only refer to entities whose symbolic names are known at runtime.
If, for example, a function is called only within a Macro expression and
nowhere else in the program code, the function symbol must be declared with
the REQUEST statement so that it is linked to the executable file.
|
PROCEDURE Main
REQUEST CDoW, Date
LOCAL cExpr := "CDoW(Date())"
? &cExpr
// result: Tuesday
RETURN
|
The creation of code blocks as complex data types is also a very common
usage scenario for the Macro operator.
|
PROCEDURE Main
LOCAL i, cExpr, cFPos
REQUEST FieldGet, FieldPut
USE Customer
aBlocks := Array( FCount() )
FOR i:=1 TO FCount()
cFPos := LTrim( Str(i) )
cExpr := "{|x| IIf(x==NIL,FieldGet(" + cFPos + ")," + ;
"FieldPut(" + cFPos + ",x)) }"
aBlocks[i] := &cExpr
NEXT
AEval( aBlocks, {|b| QOut(Eval(b)) } )
USE
RETURN
|
Within the FOR..NEXT loop, the syntax for code blocks accessing different
field variables is created as character strings. Each string differs by the
value of the loop counter variable which identifies individual field
variables by their ordinal position. The character strings are compiled
to code blocks and stored in an array.
|
d) |
Sending messages to objects
|
|
The possibility of sending messages to objects is another field of
Macro operator usage that allows for highly dynamic application
development. Messages are encoded as character strings:
|
#include "hbclass.ch"
PROCEDURE Main
LOCAL obj := TestClass():new( "Text to display" )
LOCAL cMsg := "display"
obj:&cMsg() // displays: Text to display
cMsg := "cValue"
obj:&cMsg := "New text"
obj:display() // displays: New text
RETURN
CLASS TestClass
EXPORTED:
DATA cValue
METHOD new( cString ) CONSTRUCTOR
METHOD display
ENDCLASS
METHOD new( cString ) CLASS TestClass
::cValue := cString
RETURN self
METHOD display() CLASS TestClass
? ::cValue
RETURN self
|
When the send operator (:) is followed by the Macro operator, the contents
of the variable following the Macro operator is interpreted as message to
send to the object. Note that calling an object's method requires the
parentheses be added to the expression.
|
|
There are two possibilities for calling functions using the macro operator:
one is to encode a complete function call as a macro expression, the other
is to use only the function name. The difference between both possibilities
lies in the type of variables that can be passed to a Macro operator called
function.
|
PROCEDURE Main
LOCAL cMacro
LOCAL nValue := 2
PRIVATE nNumber := 3
cMacro := "TestFunc( nNumber )" // result: 30
? &cMacro
cMacro := "TestFunc"
? &cMacro( nValue ) // result: 20
RETURN
FUNCTION TestFunc( n )
RETURN 10 * n
|
When the macro expression includes parentheses for the function call, only
PRIVATE, PUBLIC or FIELD variables can be passed as parameters, since the
variable names appear in the macro string. LOCAL variables, in contrast,
can be passed when the parentheses are "hard coded", i.e. the macro string
contains only the name of the function to call.
|
Info
Copyright © 2006-2007 xHarbour.com Inc. All rights reserved.
http://www.xHarbour.com
Created by docmaker.exe