* bin/check.hb
* config/*/*.mk
* contrib/gtwvg/wvgwing.c
* contrib/hbcomm/comm.prg
* contrib/hbfbird/tfirebrd.prg
* contrib/hbfimage/fi_wrp.c
* contrib/hbformat/hbfmtcls.prg
* contrib/hbformat/utils/hbformat.prg
* contrib/hbhttpd/core.prg
* contrib/hbnetio/utils/hbnetio/hbnetio.prg
* contrib/hbnetio/utils/hbnetio/netiomgm.hb
* contrib/hbsqlit3/hdbc.prg
* contrib/hbwin/win_bmp.c
* contrib/xhb/htmutil.prg
* contrib/xhb/thtm.prg
* contrib/xhb/xhbarr.c
* contrib/xhb/xhbtedit.prg
* ChangeLog.txt
* debian/control
* debian/copyright
* doc/*.txt
* LICENSE.txt
* package/harbour.spec
* README.md
* src/compiler/hbusage.c
* src/pp/hbpp.c
* src/rtl/memoedit.prg
* src/rtl/teditor.prg
* src/rtl/tget.prg
* src/rtl/version.c
* utils/hbi18n/hbi18n.prg
* utils/hbmk2/hbmk2.prg
* utils/hbmk2/po/hbmk2.hu.po
* utils/hbtest/hbtest.prg
* sync with 3.4 fork (no change in functionality)
CC3 -> CC4 license, copyright banners, some strings, minor
code changes, doc folder, TOFIX -> FIXME
166 lines
5.1 KiB
Plaintext
166 lines
5.1 KiB
Plaintext
This document attempts to describe the features separating Harbour from
|
|
CA-Cl*pper.
|
|
|
|
/* 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 CA-Cl*pper.
|
|
|
|
hb_SetMacro( HB_SM_HARBOUR, .T. ) will enable macro compilation and
|
|
evaluation of complex expressions not supported by CA-Cl*pper like:
|
|
|
|
- exp++, exp--, var += exp, (exp), etc..
|
|
- Nested codeblocks.
|
|
- Expressions longer then 254 characters.
|
|
|
|
hb_SetMacro( HB_SM_XBASE, .T. ) will enable macro compilation and
|
|
evaluation of comma separated lists in all contexts where lists are
|
|
acceptable by CA-Cl*pper*, including:
|
|
|
|
- { &cMacro } // Literal array elements list.
|
|
- SomeArray[ &cMacro ] // Array index list.
|
|
- SomeFun( &cMacro ) // Arguments list.
|
|
- ( &cMacro ) // parenthesized list expression.
|
|
|
|
*CA-Cl*pper only supports list macros within codeblocks context.
|
|
|
|
Both these extra layers are activated by default.
|
|
|
|
* See also -k Compiler switch.
|
|
|
|
INIT/EXIT and startup procedures
|
|
--------------------------------
|
|
|
|
In CA-Cl*pper 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, an array, an hash array or an object with
|
|
custom FOR EACH action
|
|
- enumerator variable 'var<n>' stores a reference to the element of
|
|
an hash, array or a string specified by 'expr<n>' thus assignments
|
|
to the enumerator changes the value of given element of iterated
|
|
item. If FOR EACH is used to iterate string items them assignment
|
|
to enumerator item changes the original string only if it was passed
|
|
to FOR EACH statement by reference, i.e.:
|
|
FOR EACH c IN @string
|
|
IF IsAlpha( c )
|
|
c := Upper( c )
|
|
ELSE
|
|
c := "*"
|
|
ENDIF
|
|
NEXT
|
|
- after the loop the controlling variable(s) restore the value which
|
|
they had before entering the loop
|
|
- the enumerator variable supports the following properties
|
|
:__enumIndex() - the loop counter for variable
|
|
:__enumKey() - the hash key value of traversed hash item pair
|
|
:__enumBase() - the value that is being traversed
|
|
:__enumValue() - the value of variable
|
|
:__enumIsFirst() - is it the first enumerated item?
|
|
:__enumIsLast() - is it the last enumerated item?
|
|
- defining new class or overloading existing one user can define
|
|
his own behavior of FOR EACH iterating overloading chosen of above
|
|
methods and/or the following ones:
|
|
:__enumStart()
|
|
:__enumSkip()
|
|
:__enumStop()
|
|
By default FOR EACH iterate all object instance variables
|
|
|
|
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 }
|
|
// however `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
|
|
...
|
|
ENDWITH
|
|
|
|
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
|
|
ENDWITH
|
|
|
|
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:
|
|
CREATE CLASS foo
|
|
VAR name INIT "FOO"
|
|
ENDCLASS
|
|
|
|
CREATE CLASS bar
|
|
VAR name INIT "BAR"
|
|
ENDCLASS
|
|
|
|
WITH OBJECT foo():new()
|
|
? :name // prints `FOO`
|
|
? :__withObject():name // also prints `FOO`
|
|
? :__withObject := bar():new()
|
|
? :name // prints `BAR`
|
|
ENDWITH
|