* include/hbcomp.h
* include/hberrors.h
* include/hbexpra.c
* include/hbexprb.c
* include/hbexprc.c
* include/hbmacro.h
* include/hbpcode.h
* include/hbpp.h
* include/hbxvm.h
* source/common/expropt1.c
* source/compiler/cmdcheck.c
* source/compiler/expropta.c
* source/compiler/exproptb.c
* source/compiler/exproptc.c
* source/compiler/genc.c
* source/compiler/gencc.c
* source/compiler/gencli.c
* source/compiler/genhrb.c
* source/compiler/genjava.c
* source/compiler/genobj32.c
* source/compiler/harbour.c
* source/compiler/harbour.l
* source/compiler/harbour.y
* source/compiler/hbdead.c
* source/compiler/hbfix.c
* source/compiler/hbfunchk.c
* source/compiler/hbgenerr.c
* source/compiler/hblbl.c
* source/compiler/hbpcode.c
* source/compiler/hbstripl.c
* source/macro/macroa.c
* source/macro/macrob.c
* source/macro/macroc.c
* source/vm/hvm.c
* source/vm/macro.c
* fixed compilation of code that uses '@' pass by
reference. The following syntax is no longer supported:
var := IIF( .T., @var, var )
however you can still use the following:
funcall( IIF( bPassbyRef, @someVar, someVar ) )
+added support for the following statement:
WITH OBJECT <objexpression>
...
END
inside this statement you can use simplified form of sending
messages to the object specified by <objexpression>
:message( ) instead objexpression:message()
:property instead objexpression:property
The runtime error will be generated at the time of message
sending (or property access/assign) if <objexpression>
is not a value of type object.
You can use the reserved property:
:__withobject
to access/assign the controlling object.
*fixed support for command line response file (@file.clp)
to be compatible with Clipper (Clipper genertes a single
obj file)
*fixed memory leaks when there is a fatal error in autoopened
module (using DO ... statement)
*implicit startup functions are removed from the list of
functions before generation of output code
* source/pp/ppcomp.c
* source/pp/pplib.c
* source/pp/ppcore.c
* redefinition of #define no longer causes a memory leak
* fixed repeatable optional clauses
#xcommand SET <var1> [, <varN>] WITH <val> =>
<var1>:=<val>[; <varN>:=<val>]
* fixed compilation of optional clauses (when used in different
order then declared) -this fixes the following long
waiting bug:
#command MYCOMMAND [<mylist,...>] [MYCLAUSE <myval>] => ;
MyFunction( {<mylist>} [, <myval>] )
MYCOMMAND MYCLAUSE 321 "HELLO"
* fixed restricted macro match marker <x:&>
* tests/Makefile
- tests/pretest.prg
+ utils/hbpptest
+ utils/hbpptest/Makefile
+ utils/hbpptest/pretest.prg
* moved file 'pretest.prg' from tests to separate directory
to make easier validation of the preprocessor
* TODO
* added note to fix hb_objGetMethod() so it will not generate
error if there is no method
* doc/en/clipper.txt
* added documentation for WITH OBJECT usage
165 lines
4.7 KiB
Plaintext
165 lines
4.7 KiB
Plaintext
$Id$
|
|
|
|
This document attempts to describe the features separating Harbour from
|
|
Clipper.
|
|
|
|
/* TODO: @FunPointer(), and all other Harbour extensions. */
|
|
|
|
Harbour Macro Compiler
|
|
----------------------
|
|
The Harbour Macro Compiler offers 2 additional layers of functionality
|
|
controlled by means of HB_SETMACRO()* function, not available in Clipper.
|
|
|
|
HB_SETMACRO( HB_SM_HARBOUR, TRUE ) will enable macro compilation and
|
|
evaluation of complex expressions not supported by Clipper like:
|
|
|
|
- exp++, exp--, var += exp, (exp), etc..
|
|
- Nested codeblocks.
|
|
- Expressions longer then 254 characters.
|
|
|
|
HB_SETMACRO( HB_SM_XBASE, TRUE ) will enable macro compilation and
|
|
evaluation of comma separated lists in all contexts where lists are
|
|
acceptable by Clipper*, including:
|
|
|
|
- { &cMacro } // Literal array elements list.
|
|
- SomeArray[ &cMacro ] // Array index list.
|
|
- SomeFun( &cMacro ) // Arguments list.
|
|
- ( &cMacro ) // parenthesized list expression.
|
|
|
|
*Clipper only supports list macros within codeblocks context.
|
|
|
|
Both these extra layers are activated by default.
|
|
|
|
* See also -k Compiler switch.
|
|
|
|
LIST Command
|
|
------------
|
|
|
|
LIST &cMacro
|
|
|
|
LIST in clipper [superficially] supports macros of lists expressions.
|
|
No error will be produced, and all expressions in the list will be
|
|
evaluated, but *only* the *last* expression will be displayed. This is
|
|
not documented in either the LIST Command or the Macro Operator
|
|
descriptions, but is the de-facto behavior in all Clipper 5.x versions.
|
|
|
|
Harbour instead will not only evaluate all of the expressions in
|
|
such list macro, but will also display all such values. This default
|
|
behavior may be disabled with HB_SETMACRO( HB_SM_XBASE, .F. )*
|
|
|
|
* See also -k Compiler switch.
|
|
|
|
INIT/EXIT and startup procedures
|
|
--------------------------------
|
|
|
|
In Clipper the startup procedure is always the first procedure/function
|
|
of the main module, even if such symbol is an INIT or EXIT symbol. In
|
|
such case the program will never execute the "main" symbol. In Harbour
|
|
the first *non* INIT/EXIT symbol, will be executed as the main symbol
|
|
after all INIT procedures have been executed.
|
|
|
|
FOR EACH statement
|
|
------------------
|
|
Harbour has support enumeration loop with the following syntax:
|
|
|
|
FOR EACH var1 [,var255] IN expr1 [,expr255] [DESCEND]
|
|
[EXIT]
|
|
[LOOP]
|
|
...
|
|
NEXT
|
|
|
|
Note:
|
|
-expr can be a string or an array
|
|
-enumerator variable 'var<n>' stores a reference to the element of
|
|
an array or a string specified by 'expr<n>' thus assigments to the
|
|
enumerator changes the value of given array element
|
|
-after the loop the controlling variable(s) store the value which
|
|
they had before entering the loop
|
|
-the enumeraqtor variable supports the following properties
|
|
:__enumindex - the loop counter for variable
|
|
:__enumbase - the value that is being traversed
|
|
:__enumvalue - the value of variable
|
|
|
|
|
|
for example:
|
|
a = 'A'
|
|
b = 'B'
|
|
FOR EACH a,b IN { 1, 2, 3, 4 }, "abcd"
|
|
? a, b //prints: 1 a
|
|
// 2 b
|
|
// 3 c
|
|
// 4 d
|
|
NEXT
|
|
? a, b //prints: A B
|
|
|
|
// you can use EXIT statement inside the loop
|
|
FOR EACH a IN { 1, 2, 3, 4 }
|
|
IF( a:__enumindex == 3 )
|
|
? a
|
|
EXIT
|
|
ENDIF
|
|
NEXT
|
|
|
|
arr := { 1, 2, 3 }
|
|
str := "abc"
|
|
FOR EACH a, b IN arr, str
|
|
a *= 2
|
|
str := UPPER( str )
|
|
NEXT
|
|
//now 'arr' stores { 2, 4, 6 }
|
|
//howerer 'str' still stores "abc"
|
|
|
|
Notice the difference:
|
|
FOR EACH a IN someValue
|
|
? a:__enumindex //prints current value of the index
|
|
? (a):__enumindex //sends '__enumindex' message to the current value
|
|
NEXT
|
|
|
|
|
|
WITH OBJECT
|
|
-----------
|
|
Harbour supports the following statement:
|
|
|
|
WITH OBJECT expression
|
|
...
|
|
END
|
|
|
|
Inside this WITH OBJECT/END enclosure you can use the simplified
|
|
form of sending messages to the object. You can use the syntax
|
|
:message( [params] )
|
|
:property
|
|
to send messages to the object specified by 'expression'
|
|
|
|
for example:
|
|
WITH OBJECT myobj:a[1]:myitem
|
|
:message( 1 )
|
|
:value := 9
|
|
END
|
|
|
|
The above code is equivalent to:
|
|
myobj:a[1]:myitem:message( 1 )
|
|
myobj:a[1]:myitem:value := 9
|
|
|
|
Inside WITH OBJECT/END you can access (or even assign a new object)
|
|
using a special reserved property :__withobject
|
|
|
|
The runtime error will be generated at the time of message
|
|
sending (or property access/assign) if <objexpression>
|
|
is not a value of type object.
|
|
|
|
for example:
|
|
CLASS foo
|
|
DATA name INIT 'FOO'
|
|
ENDCLASS
|
|
|
|
CLASS bar
|
|
DATA name INIT 'BAR'
|
|
ENDCLASS
|
|
|
|
WITH OBJECT foo():new()
|
|
? :name //prints 'FOO'
|
|
? :__withobject:name //also prints 'FOO'
|
|
? :__withobject := bar():new()
|
|
? :name //prints 'BAR'
|
|
END
|
|
|