mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 12:20:26 +02:00
303 lines
11 KiB
Text
303 lines
11 KiB
Text
-*- outline -*-
|
|
|
|
This directory holds the Scheme side of a translator for Emacs Lisp.
|
|
|
|
* Usage
|
|
|
|
To load up the base Elisp environment:
|
|
|
|
(use-modules (lang elisp base))
|
|
|
|
Then you can switch into this module
|
|
|
|
(define-module (lang elisp base))
|
|
|
|
and start typing away in Elisp, or evaluate an individual Elisp
|
|
expression from Scheme:
|
|
|
|
(eval EXP (resolve-module '(lang elisp base)))
|
|
|
|
A more convenient, higher-level interface is provided by (lang elisp
|
|
interface):
|
|
|
|
(use-modules (lang elisp interface))
|
|
|
|
With this interface, you can evaluate an Elisp expression
|
|
|
|
(eval-elisp EXP)
|
|
|
|
load an Elisp file with no effect on the Scheme world
|
|
|
|
(load-elisp-file "/home/neil/Guile/cvs/guile-core/lang/elisp/example.el")
|
|
|
|
load an Elisp file, automatically importing top level definitions into
|
|
Scheme
|
|
|
|
(use-elisp-file "/home/neil/Guile/cvs/guile-core/lang/elisp/example.el")
|
|
|
|
export Scheme objects to Elisp
|
|
|
|
(export-to-elisp + - * my-func 'my-var)
|
|
|
|
and try to bootstrap a complete Emacs environment:
|
|
|
|
(load-emacs)
|
|
|
|
* Status
|
|
|
|
Please see the STATUS file for the full position.
|
|
|
|
** Trying to load a complete Emacs environment.
|
|
|
|
To try this, type `(use-modules (lang elisp interface))' and then
|
|
`(load-emacs)'. The following output shows how far I get when I try
|
|
this.
|
|
|
|
guile> (use-modules (lang elisp interface))
|
|
guile> (load-emacs)
|
|
Calling loadup.el to clothe the bare Emacs...
|
|
Loading /usr/share/emacs/20.7/lisp/loadup.el...
|
|
Using load-path ("/usr/share/emacs/20.7/lisp/" "/usr/share/emacs/20.7/lisp/emacs-lisp/")
|
|
Loading /usr/share/emacs/20.7/lisp/byte-run.el...
|
|
Loading /usr/share/emacs/20.7/lisp/byte-run.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/subr.el...
|
|
Loading /usr/share/emacs/20.7/lisp/subr.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/version.el...
|
|
Loading /usr/share/emacs/20.7/lisp/version.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/map-ynp.el...
|
|
Loading /usr/share/emacs/20.7/lisp/map-ynp.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/widget.el...
|
|
Loading /usr/share/emacs/20.7/lisp/emacs-lisp/cl.el...
|
|
Loading /usr/share/emacs/20.7/lisp/emacs-lisp/cl.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/widget.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/custom.el...
|
|
Loading /usr/share/emacs/20.7/lisp/custom.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/cus-start.el...
|
|
Note, built-in variable `abbrev-all-caps' not bound
|
|
... [many other variable not bound messages] ...
|
|
Loading /usr/share/emacs/20.7/lisp/cus-start.el...done
|
|
Loading /usr/share/emacs/20.7/lisp/international/mule.el...
|
|
<unnamed port>: In procedure make-char-table in expression (@fop make-char-table (# #)):
|
|
<unnamed port>: Symbol's function definition is void
|
|
ABORT: (misc-error)
|
|
|
|
Type "(backtrace)" to get more information or "(debug)" to enter the debugger.
|
|
guile>
|
|
|
|
That's 3279 lines ("wc -l") of Elisp code already, which isn't bad!
|
|
|
|
I think that progress beyond this point basically means implementing
|
|
multilingual and multibyte strings properly for Guile. Which is a
|
|
_lot_ of work and requires IMO a very clear plan for Guile's role with
|
|
respect to Emacs.
|
|
|
|
* Design
|
|
|
|
When thinking about how to implement an Elisp translator for Guile, it
|
|
is important to realize that the great power of Emacs does not arise
|
|
from Elisp (seen as a language in syntactic terms) alone, but from the
|
|
combination of this language with the collection of primitives
|
|
provided by the Emacs C source code. Therefore, to be of practical
|
|
use, an Elisp translator needs to be more than just a transformer that
|
|
translates sexps to Scheme expressions.
|
|
|
|
The finished translator should consist of several parts...
|
|
|
|
** Syntax transformation
|
|
|
|
Although syntax transformation isn't all we need, we do still need it!
|
|
|
|
This part is implemented by the (lang elisp transform) module; it is
|
|
close to complete and seems to work pretty reliably.
|
|
|
|
Note that transformed expressions use the `@fop' and `@bind' macros
|
|
provided by...
|
|
|
|
** C support for transformed expressions
|
|
|
|
For performance and historical reasons (and perhaps necessity - I
|
|
haven't thought about it enough yet), some of the transformation
|
|
support is written in C.
|
|
|
|
*** @fop
|
|
|
|
The `@fop' macro is used to dispatch Elisp applications. Its first
|
|
argument is a symbol, and this symbol's function slot is examined to
|
|
find a procedure or macro to apply to the remaining arguments. `@fop'
|
|
also handles aliasing (`defalias'): in this case the function slot
|
|
contains another symbol.
|
|
|
|
Once `@fop' has found the appropriate procedure or macro to apply, it
|
|
returns an application expression in which that procedure or macro
|
|
replaces the `@fop' and the original symbol. Hence no Elisp-specific
|
|
evaluator support is required to perform the application.
|
|
|
|
*** @bind
|
|
|
|
Currently, Elisp variables are the same as Scheme variables, so
|
|
variable references are effectively untransformed.
|
|
|
|
The `@bind' macro does Elisp-style dynamic variable binding.
|
|
Basically, it locates the named top level variables, `set!'s them to
|
|
new values, evaluates its body, and then uses `set!' again to restore
|
|
the original values.
|
|
|
|
Because of the body evaluation, `@bind' requires evaluator support.
|
|
In fact, the `@bind' macro code does little more than replace itself
|
|
with the memoized SCM_IM_BIND. Most of the work is done by the
|
|
evaluator when it hits SCM_IM_BIND.
|
|
|
|
One theoretical problem with `@bind' is that any local Scheme variable
|
|
in the same scope and with the same name as an Elisp variable will
|
|
shadow the Elisp variable. But in practice it's difficult to set up
|
|
such a situation; an exception is the translator code itself, so there
|
|
we mangle the relevant Scheme variable names a bit to avoid the
|
|
problem.
|
|
|
|
Other possible problems with this approach are that it might not be
|
|
possible to implement buffer local variables properly, and that
|
|
`@bind' might become too inefficient when we implement full support
|
|
for undefining Scheme variables. So we might in future have to
|
|
transform Elisp variable references after all.
|
|
|
|
*** Truth value stuff
|
|
|
|
Following extensive discussions on the Guile mailing list between
|
|
September 2001 and January 2002, we decided to go with Jim Blandy's
|
|
proposal. See devel/translation/lisp-and-scheme.text for details.
|
|
|
|
- The Elisp nil value is a new immediate SCM_MAKIFLAG, eq?-distinct
|
|
from both #f and '() (and of course any other Scheme value). It can
|
|
be accessed via the (guile) binding `%nil', and prints as `#nil'.
|
|
|
|
- All Elisp primitives treat #nil, #f and '() as identical.
|
|
|
|
- Scheme truth-testing primitives have been modified so that they
|
|
treat #nil the same as #f.
|
|
|
|
- Scheme list-manipulating primitives have been modified so that they
|
|
treat #nil the same as '().
|
|
|
|
- The Elisp t value is the same as #t.
|
|
|
|
** Emacs editing primitives
|
|
|
|
Buffers, keymaps, text properties, windows, frames etc. etc.
|
|
|
|
Basically, everything that is implemented as a primitive in the Emacs
|
|
C code needs to be implemented either in Scheme or in C for Guile.
|
|
|
|
The Scheme files in the primitives subdirectory implement some of
|
|
these primitives in Scheme. Not because that is the right decision,
|
|
but because this is a proof of concept and it's quicker to write badly
|
|
performing code in Scheme.
|
|
|
|
Ultimately, most of these primitive definitions should really come
|
|
from the Emacs C code itself, translated or preprocessed in a way that
|
|
makes it compile with Guile. I think this is pretty close to the work
|
|
that Ken Raeburn has been doing on the Emacs codebase.
|
|
|
|
** Reading and printing support
|
|
|
|
Elisp is close enough to Scheme that it's convenient to coopt the
|
|
existing Guile reader rather than to write a new one from scratch, but
|
|
there are a few syntactic differences that will require changes in
|
|
reading and printing. None of the following changes has yet been
|
|
implemented.
|
|
|
|
- Character syntax is `?a' rather than `#\a'. (Not done. More
|
|
precisely, `?a' in Elisp isn't character syntax but an alternative
|
|
integer syntax. Note that we could support most of the `?a' syntax
|
|
simply by doing
|
|
|
|
(define ?a (char->integer #\a)
|
|
(define ?b (char->integer #\b)
|
|
|
|
and so on.)
|
|
|
|
- Vector syntax is `[1 2 3]' rather than `#(1 2 3)'.
|
|
|
|
- When in an Elisp environment, #nil and #t should print as `nil' and
|
|
`t'.
|
|
|
|
** The Elisp evaluation module (lang elisp base)
|
|
|
|
Fundamentally, Guile's module system can't be used to package Elisp
|
|
code in the same way it is used for Scheme code, because Elisp
|
|
function definitions are stored as symbol properties (in the symbol's
|
|
"function slot") and so are global. On the other hand, it is useful
|
|
(necessary?) to associate some particular module with Elisp evaluation
|
|
because
|
|
|
|
- Elisp variables are currently implemented as Scheme variables and so
|
|
need to live in some module
|
|
|
|
- a syntax transformer is a property of a module.
|
|
|
|
Therefore we have the (lang elisp base) module, which acts as the
|
|
repository for all Elisp variables and the site of all Elisp
|
|
evaluation.
|
|
|
|
The initial environment provided by this module is intended to be a
|
|
non-Emacs-dependent subset of Elisp. To get the idea, imagine someone
|
|
who wants to write an extension function for, say Gnucash, and simply
|
|
prefers to write in Elisp rather than in Scheme. He/she therefore
|
|
doesn't buffers, keymaps and so on, just the basic language syntax and
|
|
core data functions like +, *, concat, length etc., plus specific
|
|
functions made available by Gnucash.
|
|
|
|
(lang elisp base) achieves this by
|
|
|
|
- importing Scheme definitions for some Emacs primitives from the
|
|
files in the primitives subdirectory
|
|
|
|
- then switching into Elisp syntax.
|
|
|
|
After this point, `(eval XXX (resolve-module '(lang elisp base)))'
|
|
will evaluate XXX as an Elisp expression in the (lang elisp base)
|
|
module. (`eval-elisp' in (lang elisp interface) is a more convenient
|
|
wrapper for this.)
|
|
|
|
** Full Emacs environment
|
|
|
|
The difference between the initial (lang elisp base) environment and a
|
|
fully loaded Emacs equivalent is
|
|
|
|
- more primitives: buffers, char-tables and many others
|
|
|
|
- the bootstrap Elisp code that an undumped Emacs loads during
|
|
installation by calling `(load "loadup.el")'.
|
|
|
|
We don't have all the missing primitives, but we can already get
|
|
through some of loadup.el. The Elisp function `load-emacs' (defined
|
|
in (lang elisp base) initiates the loading of loadup.el; (lang elisp
|
|
interface) exports `load-emacs' to Scheme.
|
|
|
|
`load-emacs' loads so much Elisp code that it's an excellent way to
|
|
test the translator. In current practice, it runs for a while and
|
|
then fails when it gets to an undefined primitive or a bug in the
|
|
translator. Eventually, it should go all the way. (And then we can
|
|
worry about adding unexec support to Guile!) For the output that
|
|
currently results from calling `(load-emacs)', see above in the Status
|
|
section.
|
|
|
|
* Resources
|
|
|
|
** Ken Raeburn's Guile Emacs page
|
|
|
|
http://www.mit.edu/~raeburn/guilemacs/
|
|
|
|
** Keisuke Nishida's Gemacs project
|
|
|
|
http://gemacs.sourceforge.net
|
|
|
|
** Jim Blandy's nil/#f/() notes
|
|
|
|
http://sanpietro.red-bean.com/guile/guile/old/3114.html
|
|
|
|
Also now stored as guile-core/devel/translation/lisp-and-scheme.text
|
|
in Guile CVS.
|
|
|
|
** Mikael Djurfeldt's notes on translation
|
|
|
|
See file guile-core/devel/translation/langtools.text in Guile CVS.
|