gimp/plug-ins/script-fu/docs/using-v3-binding.md

283 lines
8.2 KiB
Markdown
Raw Normal View History

# The version 3 dialect of the ScriptFu language
## About
This describes a new dialect of ScriptFu,
used when a script calls: (script-fu-use-v3).
The new dialect is more like Scheme and makes scripts shorter.
The dialect only affects calls to the PDB.
The audience is script authors and other developers.
This describes the new dialect and how to port old scripts to the new dialect.
## Quick Start
A script that calls:
```
(script-fu-use-v3)
```
binds to certain PDB calls differently:
1. PDB procedures that return single values return just that single value,
*not wrapped in a list.*
Formerly, every PDB call returned a list (possibly nesting more lists.)
2. You can use #t and #f as arguments to PDB calls taking a boolean.
3. PDB calls returning a boolean return #t or #f, not TRUE or FALSE (1 or 0.)
## Script-Fu Console
The Script-Fu Console always starts in the v2 dialect.
You can call *script-fu-use-v3* in the console.
Then, the console interprets the v3 dialect.
It continues to interpret the v3 dialect in that session,
until you call *script-fu-use-v2.*
## Where to call *script-fu-use-v3* in scripts
Call *script-fu-use-v3* early.
This sets the dialect version for the remaining interpretation of the script.
Call *script-fu-use-v3* at the beginning of the run function.
!!! Do not call *script-fu-use-v3* at the top level of a script.
This has no effect, since it is only executed in the query phase.
The interpreter starts at the run function during the run phase.
*The interpreter always starts interpreting each script in the v2 dialect.
This is true even for extension-script-fu, the long-running interpreter.*
There is no need to call *script-fu-use-v2* before returning from a script,
to ensure that the next script is interpreted in v2 dialect.
Example:
```
(define (script-fu-testv3 img drawables )
(script-fu-use-v3) ; <<<
(let* (
...
```
### Technically speaking
The dialect version has "execution scope" versus "lexical scope."
Setting the dialect version is effective even for
other functions defined in the same script but lexically
outside the function where the dialect is set.
## Don't call v2 scripts from v3 scripts
When using the v3 dialect,
you can't call plugin scripts or other library scripts that depend on the v2 dialect.
And vice versa.
(When a script calls a PDB procedure that is a script,
a new interpreter process is *NOT* started.)
For example, a new plugin script should not call the PDB procedure
script-fu-add-bevel because it is implemented in ScriptFu Scheme
and for example has:
```
(width (car (gimp-drawable-get-width pic-layer)))
```
which is v2 dialect and would throw an error such as:
```
Error: car requires a pair.
```
*It is rare that a script calls another plugin script.*
A script usually calls the PDB,
but rarely calls a plugin script of the PDB.
There are very few, obscure library scripts that call the PDB using v2 dialect.
These are in scripts/script-fu-util.scm.
## Pure Scheme is unaffected
The dialect only affects calls the to PDB.
This means you can usually call most library scripts when using v3,
since most library scripts are pure Scheme,
that is, with no calls to the GIMP PDB.
## TRUE and FALSE
TRUE and FALSE are still in v3 dialect and are still numbers 1 and 0.
But we recommend not using them.
You can still pass them as arguments to PDB calls taking a boolean,
and they are still converted to the C notion of boolean truth.
FALSE which is 0 is truthy in Scheme!!!
It converts to the C notion of false only in a call the the PDB.
In the ScriptFu Console:
```
>(equal? FALSE #t)
#t
```
TRUE and FALSE symbols may become obsolete in the future.
## Plans for the future
This dialect is shorter and more natural for Scheme programmers.
The long-term goal is for the v3 dialect to be the only dialect of ScriptFu.
For the short term, for backward compatibility,
the default dialect of ScriptFu is the v2 dialect.
You should write any new scripts in the v3 dialect,
and call *script-fu-use-v3*.
You should plan on porting existing scripts to the v3 dialect,
since eventually ScriptFu might not support v2 dialect.
## Example conversions from v2 to v3
### A call to a PDB procedure returning a single value
```
(set! (width (car (gimp-drawable-get-width pic-layer))))
```
*must* become
```
(set! (width (gimp-drawable-get-width pic-layer)))
```
The PDB call returns a single integer,
so no *car* is needed.
### A call to a PDB procedure returning boolean
```
(if (= (gimp-image-is-rgb image) TRUE) ...
```
*must* become:
```
(if (gimp-image-is-rgb image) ...
```
The PDB procedure returns a boolean,
which is bound to #t or #f,
the usual symbols for Scheme truth.
### A call to a PDB procedure taking a boolean
```
(gimp-context-set-antialias TRUE)
```
*should* become
```
(gimp-context-set-antialias #t)
```
This doesn't *require* conversion because TRUE is 1 and is truthy in Scheme.
!!! But FALSE is 0 and 0 is truthy in Scheme
```
(gimp-context-set-antialias FALSE)
```
This *should* be converted, for clarity, but doesn't *require* conversion.
For now, ScriptFu still binds Scheme 0 to C 0.
So it still does what the script intends.
### A call to a PDB procedure returning a list
```
(set! brushes (car (gimp-brushes-get-list)))
```
*must* become:
```
(set! brushes (gimp-brushes-get-list))
```
Formerly, the PDB procedure returned a list wrapped in a list,
i.e. ((...))
In the v3 dialect, it returns just a list, i.e. (...)
which is a single value, a single container.
### A call to a PDB procedure returning a list, getting the first element
```
(set! first-brush (caar (gimp-brushes-get-list)))
```
Gets the first brush in GIMP.
This *must* become:
```
(set! first-brush (car (gimp-brushes-get-list)))
```
The call to *caar* is consecutive calls to *car*,
and you must eliminate the first call to *car*.
## Knowing what constructs need conversion
You *should* (but are not required to)
eliminate all uses of symbols TRUE and FALSE from a script
using v3 dialect.
You should eliminate many, *but not all*, uses of the *car* function wrapping a call to the PDB,
where the PDB procedure returns a single value.
There are several hundred such PDB procedures in the PDB.
Examine the signature of a PDB procedure using the PDB Browser.
For example, gimp-brush-get-angle:
```
Return Values
angle gdouble ....
Additional Information
```
This returns a single value so no need to use car.
For example, gimp-brushes-get-list:
```
Return Values
brush-list GStrv
Additional Information
```
This also returns a single value.
The single value is a list i.e. container.
In the v2 dialect, this returned a list wrapped in a list,
for example (("foo" "bar")).
See "Example conversions from v2 to v3"
### Does not require changes to calls to PDB procedures returning void
You should not need to change scripts on calls to PDB procedures returning C void because a script should not be examining the result.
Some scripts might examine the result of a call to a void PDB procedure, thinking that (#t) is the success of the call,
but that is a misconception and should be fixed.
Calls to PDB procedures that return C void return (#t) in v2 and the empty list (), sometimes called nil, in v3 dialect.
## Details of the implementation
There are new functions in the dialect:
```
script-fu-use-v3
script-fu-use-v2
```
These functions have side-effects on the state of the interpreter.
They always return the empty list ().
The effect is immediate.
The interpreter interprets a dialect from then on,
until the script returns,
or until the script changes the dialect again.
A call to *script-fu-use-v3* sets a flag in the state of the interpreter.
When the flag is set, the interpreter binds arguments to PDB calls slightly differently, as described.
Binding of args to PDB calls is done at run time.
Similarly, a call to *script-fu-use-v2* clears the flag
and restores the interpreter state to binding using the v2 dialect.
When in the v3 state,
any PDB call constructs using v2 binding will yield errors,
and vice versa.
Note that the difference in interpretation is only in binding, but both to and from the PDB:
1. Single return values *from* the PDB are not wrapped in lists.
2. Boolean return values *from* the PDB are bound to #t and #f.
3. Boolean values *to* the PDB can be #t and #f.