123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- -*- 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.
|