to
etc. ¶When you define a word x, you can set its execution semantics
with set-does>
(see User-defined defining words using create) or set-execute
(see Header methods). But you can
also change the semantics of
to x \ aka ->x +to x \ aka +>x addr x action-of x \ aka `x defer@ is x \ aka `x defer!
This is all achieved through a common mechanism described in this
section. As an example, let’s define dvalue
(it behaves in
Gforth exactly like 2value
, see Values). First, we need a
table of the various to
-like actions:
: d+! ( d addr -- ) dup >r 2@ d+ r> 2! ; \ to +to action-of is addr to-table: d!-table 2! d+! n/a n/a [noop]
This defines a table d!-table
with a to
and a +to
action, no action for action-of
and is
, and an
addr
action. I.e., for our x defined with
dvalue
, if you is x
, you will get an error
message. Note that a word using this table must still be declared
addressable:
in order to legitimately use the addr
action.
At the end of the line you can leave trailing [noop]
for the
addr
entry and any trailing n/a
s for the other entries away,
but in the above we show them for completeness. I.e., the table could
also have been defined as
\ to +to action-of is addr to-table: d!-table 2! d+!
The entries in the table are words that get an address on the
top-of-stack. They possibly also expect some additional data deeper
in the stack, but that is data that is provided in the usual use of
the word. E.g., in the case of dvalue
, the expectation is that
you put a double-cell d on the stack before you do a to
x
, and that d and the address
where it should be stored is eventually passed to 2!
.
In the case of dvalue
, the address is computed from the xt of
x with >body
. In order to let that be known to the
system, you write
`>body d!-table to-class: dvalue-to
This defines the method implementations of the methods behind to
,
+to
, addr
, action-of
, and is
, and
corresponding the methods for value!
, value+!
, >addr
,
defer@
, and defer!
. The reason for defining the methods
in two steps (by first defining the table) is that the same table can be
used for several to-classes; e.g., !-table
is used for defining
value-to
(used for value
), but also for uvalue-to
used for defining uvalue
(see Task-local data) and
to-w:
(used for the default (w:
) locals).
>body
is appropriate for words with storage in the dictionary,
such as value
. But, e.g., for storage in user (task-local)
storage (e.g., uvalue
), you use >uvalue
instead. The
general case is that the system pushes the xt of x, and then
executes the xt that has been passed to to-class:
. This xt may
also consume one or more additional values passed on the stack (e.g.,
for value-flavoured struct fields, xt consumes the address of the
struct right below the xt); its overall stack effect is ( ... xt
-- addr )
.
Now you can define
: dvalue ( d "name" -- ) create 2, `2@ set-does> `dvalue-to set-to ;
Here the set-to
changes the created word name to use the
methods from dvalue-to
for implementing to
, +to
and addr
(and the others, but they are defined to deliver
errors).
Now you can define words with dvalue
and use them:
#5. dvalue x #2. +to x x d. \ prints "7 "
The +to x
first pushes the xt of x
, then performs
>body
(provided in the definition of dvalue-to
), and
finally performs the d+!
provided in the d!-table
.
In order to use addr x
, you should have defined x
with
#5. addressable: dvalue x
These are the words mentioned above:
to-table:
( "name" "to-word" "+to-word" "addr-word" "action-of-word" "is-word" – ) gforth-experimental “to-table-colon”
Create a table name with entries for TO
, +TO
,
ACTION-OF
, IS
, and ADDR
. The words for
these entries are called with xt on the stack, where xt
belongs to the word behind to
(or +to
etc.). Use
n/a
to mark unsupported operations. Default entries
operations can be left away at the end of the line; the default
is for the addr
entry is [noop]
while the default
for the other entries is n/a
.
n/a
( – ) gforth-experimental “not-available”
This word can be ticked, but throws an “Operation not supported” exception on interpretation and compilation. Use this for methods etc. that aren’t supported.
[noop]
( – ) gforth-experimental “bracket-noop”
Does nothing, both when executed and when compiled.
to-class:
( xt table "name" – ) gforth-experimental “to-class-colon”
Create a to-class implementation name, where xt
( ... xt -- addr )
computes the address to access the
data, and table (created with to-table:
) contains
the words for accessing it.
>uvalue
( xt – addr ) gforth-internal “to-uvalue”
Xt is the xt of a word x defined with uvalue
;
addr is the address of the data of x in the current
task. This word is useful for building, e.g., uvalue
.
Do not use it to circumvent that you cannot get the address of
a uvalue with addr
; in the future Gforth may perform
optimizations that assume that uvalues can only be accessed
through their name.
set-to
( to-xt – ) gforth-1.0 “set-to”
Changes the implementations of the to-class methods of the most recently defined word to come from the to-class that has the xt to-xt.