Let us say you have a number of Scheme files in
a directory that you intend to package as a
distribution. For specificity let’s say the name of the
directory is pkgdir
and you have three Scheme files in it,
viz, apple
, orange.scm
, and banana.rkt
.
There is no restriction on the names of these Scheme
files: They may have any or no extension. An end-user
of your distribution will unpack it to produce a
pkgdir
of their own with the three Scheme files in
it.
Let us now say that you wrote the Scheme files in the
Racket dialect of Scheme, but that the end-user
uses the Guile dialect of Scheme. In order for them to
be able to create Guile versions of your files, you
need to provide in pkgdir
some configuration
information. This can be done as follows:
Create a subdirectory called dialects
in
pkgdir
. In the dialects
subdirectory,
create a file called files‑to‑be‑ported.scm
containing the names of the Scheme files to be
translated, viz.,
"apple" "orange.scm" "banana.rkt"
and a file called dialects‑supported.scm
containing
the line
guile
The symbol guile
of course stands for the Scheme
dialect Guile.
The Guile-using user can now start Guile in pkgdir
,
and load scmxlate.scm
(using the appropriate
pathname for scmxlate.scm
on their system, as
described in Section 1). Scmxlate will learn
from dialects/files‑to‑be‑ported.scm
that the files
apple
, orange.scm
, and banana.rkt
need to be
translated. It will ask the user what the dialect is,
offering as choices the dialects listed in
dialects/dialects‑supported.scm
, plus a catch-all
dialect called Other:1
What is your Scheme dialect? (guile other)
The user types guile
in response. Scmxlate now
understands that it is to create Guile translations of
the three files, and proceeds to do so. By default,
the translation-result files are created in the
pkgdir
directory and have the same names as the
original but with the prefix my‑
attached. Thus,
in this case, their names are my‑apple
,
my‑orange.scm
, and my‑banana.rkt
.
In the following, we will for convenience use the following terms:
(i) input file: a file to be translated;
(ii) output file: a file that is the result of a translation;
(iii) target dialect: the dialect translated to.
In our example above, apple
is an input
file, my‑apple
is its corresponding output file,
and Guile is the target dialect.
The output file my‑apple
above uses Scmxlate’s
default rules for an Racket-to-Guile translation.
These rules are general and cannot be expected to cover
any peculiar translational information that may be
relevant to the code in apple
. You can supply such
additional information to Scmxlate via a
dialect-configuration file called guile‑apple
in
the dialects
subdirectory. I.e., the name of
the dialect-configuration file for a given input file
and a given dialect is formed from the Scmxlate symbol
for the dialect, followed by a hyphen, followed by the
name of the input file.
Scmxlate typically takes code from a dialect-configuration file and sticks it ahead of the translated code in the output file. This code can be any Scheme code in the target dialect, and in particular, it can include definitions. The order of the code in the dialect-configuration file is preserved in the output file.
For instance, if the Racket code in apple
made
use of a nonstandard (Racket-only) primitive such as
file‑or‑directory‑modify‑seconds
, we could supply
the following Guile definition in the
dialect-configuration file,
dialects/guile‑apple
:
(define file-or-directory-modify-seconds (lambda (f) (vector-ref (stat f) 9)))
If the dialect-configuration file supplies a definition for
a name that is also defined in the input file,
then the output file will contain the definition from
the dialect-configuration file, not the input file.
For example, if apple
contained
the definition
(define file-newer? (lambda (f1 f2) ;checks if f1 is newer than f2 (> (file-or-directory-modify-seconds f1) (file-or-directory-modify-seconds f2))))
we could put a competing Guile-specific definition
in dialects/guile‑apple
:
(define file-newer? (lambda (f1 f2) (> (vector-ref (stat f1) 9) (vector-ref (stat f2) 9))))
When Scmxlate translates apple
, it will directly
incorporate this Guile definition into the output file
my‑apple
and won’t even attempt to translate
the Racket definition of the same name in the
input file.
In the above, we used the symbol guile
in the
dialects/dialects‑supported.scm
file to signal to
Scmxlate that Guile is one of the dialects into which
the package can be translated. The list of dialect symbols
recognized by Scmxlate is: bigloo
, chez
,
chibi
, chicken
, cl
,
gambit
, gauche
, guile
, ikarus
, kawa
, mitscheme
,
mzscheme
, other
, petite
, plt
, pscheme
,
racket
, scheme48
,
scm
, scsh
, stk
, stklos
, sxm
,
umbscheme
, ypsilon
.
The symbol cl
stands for
Common Lisp.2
The symbol other
can be used by the package author
to provide a default configuration for an unforeseen
dialect. Since the dialect is unknown, there isn’t
much information to exploit, but it may be
possible to provide some bare-minimum functionality
(or at least display some advice).
The package author can make use of other symbols to denote other Scheme dialects. However, as Scmxlate cannot do any special translation for such dialects, it is the responsibility of the package author to provide additional configuration information for them by writing dialect-configuration files.
Some packages need some configuration information that the package author cannot predict and that therefore can come only come from the user. The information typically contains user preferences for global variables in the program. It should not be dialect-specific.
Such user information can be placed in
user-configuration files in the package directory.
Each input file can have its own
user-configuration file, and the latter’s name
consists of the prefix scmxlate‑
followed by the
name of the input file. Thus the user configuration
file for orange.scm
is scmxlate‑orange.scm
.
While the package author may not be able to predict the values of the globals preferred by their various users, they can include in the package sample user-configuration files that mention the globals requiring the user’s intervention, with comments instructing how the user is to customize them.
Note that user-configuration code comes ahead of the dialect-configuration code in the output file. Definitions in the user-configuration code override definitions in the dialect-configuration code, just as the latter themselves override definitions in the input file.
1 The astute reader may wonder why Scmxlate needs to explicitly ask the user what the target dialect is, when it is already running on it! Unfortunately, since the Scxmlate code is necessarily written in a style that must load in all Schemes, it cannot portably determine the identity of the particular Scheme dialect it is currently running on.
2 Note that Scmxlate can readily determine if it’s running on Common Lisp (as opposed to Scheme), so it will not query the user for further “dialect” information.