mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-24 04:15:36 +02:00
* Add non-libguile Elisp support files to CVS trunk. (NB work in progress.)
This commit is contained in:
parent
c96d76b88d
commit
3d1a89b9ee
46 changed files with 2139 additions and 1 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2002-01-13 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* Makefile.am (SUBDIRS): Added lang.
|
||||||
|
|
||||||
|
* configure.in (AC_CONFIG_FILES): Added Makefiles in lang,
|
||||||
|
lang/elisp, lang/elisp/internals and lang/elisp/primitives.
|
||||||
|
|
||||||
|
2002-01-11 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* acconfig.h (SCM_ENABLE_ELISP): New conditional.
|
||||||
|
|
||||||
|
* configure.in (SCM_ENABLE_ELISP): Define this conditional (or
|
||||||
|
not) according to absence (or presence) of `--disable-elisp'
|
||||||
|
in the configure args.
|
||||||
|
|
||||||
2001-12-31 Dirk Herrmann <D.Herrmann@tu-bs.de>
|
2001-12-31 Dirk Herrmann <D.Herrmann@tu-bs.de>
|
||||||
|
|
||||||
* TODO: Added two items.
|
* TODO: Added two items.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS = oop qt libltdl libguile ice-9 guile-config guile-readline \
|
SUBDIRS = oop qt libltdl libguile ice-9 guile-config guile-readline \
|
||||||
scripts srfi doc examples test-suite
|
scripts srfi doc examples test-suite lang
|
||||||
|
|
||||||
bin_SCRIPTS = guile-tools
|
bin_SCRIPTS = guile-tools
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,9 @@
|
||||||
/* Define this if you want support for arrays and uniform arrays. */
|
/* Define this if you want support for arrays and uniform arrays. */
|
||||||
#undef HAVE_ARRAYS
|
#undef HAVE_ARRAYS
|
||||||
|
|
||||||
|
/* Define this if you want Elisp support (in addition to Scheme). */
|
||||||
|
#undef SCM_ENABLE_ELISP
|
||||||
|
|
||||||
/* Define this if your IPv6 has sin6_scope_id in sockaddr_in6 struct. */
|
/* Define this if your IPv6 has sin6_scope_id in sockaddr_in6 struct. */
|
||||||
#undef HAVE_SIN6_SCOPE_ID
|
#undef HAVE_SIN6_SCOPE_ID
|
||||||
|
|
||||||
|
|
12
configure.in
12
configure.in
|
@ -129,6 +129,10 @@ dnl a required part of the distribution.
|
||||||
AC_DEFINE(DEBUG_EXTENSIONS)
|
AC_DEFINE(DEBUG_EXTENSIONS)
|
||||||
AC_DEFINE(READER_EXTENSIONS)
|
AC_DEFINE(READER_EXTENSIONS)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(elisp,
|
||||||
|
[ --disable-elisp omit Emacs Lisp support],,
|
||||||
|
enable_elisp=yes)
|
||||||
|
|
||||||
dnl files which are destined for separate modules.
|
dnl files which are destined for separate modules.
|
||||||
|
|
||||||
if test "$enable_arrays" = yes; then
|
if test "$enable_arrays" = yes; then
|
||||||
|
@ -150,6 +154,10 @@ if test "$enable_debug_malloc" = yes; then
|
||||||
LIBOBJS="$LIBOBJS debug-malloc.o"
|
LIBOBJS="$LIBOBJS debug-malloc.o"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$enable_elisp" = yes; then
|
||||||
|
AC_DEFINE(SCM_ENABLE_ELISP)
|
||||||
|
fi
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
#--------------------------------------------------------------------
|
||||||
|
|
||||||
dnl Some more checks for Win32
|
dnl Some more checks for Win32
|
||||||
|
@ -660,6 +668,10 @@ AC_CONFIG_FILES([
|
||||||
libguile/guile-snarf-docs-texi
|
libguile/guile-snarf-docs-texi
|
||||||
libguile/version.h
|
libguile/version.h
|
||||||
ice-9/Makefile
|
ice-9/Makefile
|
||||||
|
lang/Makefile
|
||||||
|
lang/elisp/Makefile
|
||||||
|
lang/elisp/internals/Makefile
|
||||||
|
lang/elisp/primitives/Makefile
|
||||||
oop/Makefile
|
oop/Makefile
|
||||||
oop/goops/Makefile
|
oop/goops/Makefile
|
||||||
scripts/Makefile
|
scripts/Makefile
|
||||||
|
|
2
lang/.cvsignore
Normal file
2
lang/.cvsignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
24
lang/Makefile.am
Normal file
24
lang/Makefile.am
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2000 Free Software Foundation, Inc.
|
||||||
|
##
|
||||||
|
## This file is part of GUILE.
|
||||||
|
##
|
||||||
|
## GUILE is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as
|
||||||
|
## published by the Free Software Foundation; either version 2, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## GUILE is distributed in the hope that it will be useful, but
|
||||||
|
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with GUILE; see the file COPYING. If not, write
|
||||||
|
## to the Free Software Foundation, Inc., 59 Temple Place, Suite
|
||||||
|
## 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
|
SUBDIRS = elisp
|
2
lang/elisp/.cvsignore
Normal file
2
lang/elisp/.cvsignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
194
lang/elisp/ChangeLog
Normal file
194
lang/elisp/ChangeLog
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
2001-11-03 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* README (Resources): Fill in missing URLs.
|
||||||
|
|
||||||
|
2001-11-02 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* Makefile.am (elisp_sources): Added base.scm, example.el,
|
||||||
|
interface.scm; removed emacs.scm.
|
||||||
|
|
||||||
|
* README: Updated accordingly.
|
||||||
|
|
||||||
|
* internals/load.scm (load): Avoid using `load-path' if the
|
||||||
|
supplied file name begins with a slash.
|
||||||
|
|
||||||
|
* internals/fset.scm: Support export of defuns, defmacros and
|
||||||
|
defvars to a module specified by the fluid `elisp-export-module'.
|
||||||
|
This allows us to automate the importing of Elisp definitions into
|
||||||
|
Scheme.
|
||||||
|
|
||||||
|
* example.el: New file: example code for `load-elisp-file'.
|
||||||
|
|
||||||
|
* interface.scm: New file - mechanisms to exchange definitions
|
||||||
|
between Scheme and Elisp.
|
||||||
|
|
||||||
|
Following changes try to make the Elisp evaluation module less
|
||||||
|
Emacs-dependent; in other words, so that it isn't necessary to try
|
||||||
|
to load the whole Emacs environment before evaluating basic
|
||||||
|
non-Emacs-specific Elisp code.
|
||||||
|
|
||||||
|
* variables.scm, internals/evaluation.scm: Changed (lang elisp
|
||||||
|
emacs) to (lang elisp base).
|
||||||
|
|
||||||
|
* emacs.scm (lang): Removed.
|
||||||
|
|
||||||
|
* base.scm (lang): New file (non-emacs-specific replacement for
|
||||||
|
emacs.scm).
|
||||||
|
|
||||||
|
2001-10-28 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* primitives/symprop.scm (symbol-name): New primitive.
|
||||||
|
|
||||||
|
* primitives/strings.scm (stringp): New primitive.
|
||||||
|
|
||||||
|
* primitives/pure.scm (purify-flag): New variable.
|
||||||
|
|
||||||
|
* primitives/numbers.scm (numberp): New primitive.
|
||||||
|
|
||||||
|
* internals/fset.scm (fset): Set procedure and macro name
|
||||||
|
properties usefully to match Elisp symbol names. Also bind Elisp
|
||||||
|
function definition variables to similarly named symbols in the
|
||||||
|
(lang elisp variables) module.
|
||||||
|
|
||||||
|
* transform.scm (transformer, m-unwind-protect): Added support for
|
||||||
|
`unwind-protect'.
|
||||||
|
(m-quasiquote): Use 'quasiquote rather than 'quote.
|
||||||
|
(transform-lambda, m-defmacro): When no rest arguments, set the
|
||||||
|
rest parameter to '() rather than #f. It shouldn't make any
|
||||||
|
difference, but it feels more right.
|
||||||
|
|
||||||
|
* README: Enlarged description of current status.
|
||||||
|
|
||||||
|
* Makefile.am (elisp_sources): Added variables.scm.
|
||||||
|
|
||||||
|
* variables.scm: New file.
|
||||||
|
|
||||||
|
2001-10-26 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* buffers.scm, calling.scm: Removed. These should have
|
||||||
|
disappeared during the reorganization described below, but I
|
||||||
|
missed them by mistake.
|
||||||
|
|
||||||
|
* primitives/symprop.scm (set, boundp, symbol-value): Changed to
|
||||||
|
use (module-xx the-elisp-module ...) rather than (local-xx ...).
|
||||||
|
(symbolp): Accept either symbols or keywords.
|
||||||
|
(set-default, default-boundp, default-value,
|
||||||
|
local-variable-if-set-p): New.
|
||||||
|
|
||||||
|
* primitives/match.scm (string-match, match-data): Store last
|
||||||
|
match data in Emacs rather than Guile form, to simplify
|
||||||
|
implementation of ...
|
||||||
|
(set-match-data, store-match-data): New.
|
||||||
|
|
||||||
|
* primitives/load.scm (autoload, current-load-list): New. (But
|
||||||
|
autoload is just stubbed, not properly implemented.)
|
||||||
|
|
||||||
|
* primitives/lists.scm (nth, listp, consp, nconc): New.
|
||||||
|
|
||||||
|
* primitives/fns.scm (byte-code-function-p, run-hooks): New.
|
||||||
|
|
||||||
|
* transform.scm (transform-application, transformer-macro): New
|
||||||
|
scheme for transforming procedure arguments while leaving macro
|
||||||
|
args untransformed. (See also associated change in libguile.)
|
||||||
|
(m-defconst): Simplified, now uses m-setq.
|
||||||
|
|
||||||
|
* Makefile.am: Changed so that it only deals with files directly
|
||||||
|
in this directory; otherwise files don't install cleanly.
|
||||||
|
|
||||||
|
* internals/Makefile.am, primitives/Makefile.am,
|
||||||
|
internals/.cvsignore, primitives/.cvsignore: New files.
|
||||||
|
|
||||||
|
2001-10-26 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* transform.scm (transformer): New handling for (1) quasiquoting
|
||||||
|
syntax like "(` ...)" as well as the more normal "` ..."; (2)
|
||||||
|
`function'; (3) interactive specification in lambda body.
|
||||||
|
Simplied handling for `setq'.
|
||||||
|
(transform-inside-qq): Fixed to handle improper as well as proper
|
||||||
|
lists.
|
||||||
|
(transform-lambda/interactive): New; wraps transform-lambda to
|
||||||
|
handle setting of various procedure properties.
|
||||||
|
(transform-lambda, m-defmacro): Changed `args' and `num-args' to
|
||||||
|
`%--args' and `%--num-args' in the hope of avoiding lexical
|
||||||
|
vs. dynamic name clashes.
|
||||||
|
(m-and): Use #f instead of '() where a condition fails.
|
||||||
|
|
||||||
|
Plus big hierarchy reorganization, in which most of the previous
|
||||||
|
occupants of lang/elisp moved to lang/elisp/primitives, with some
|
||||||
|
internal processing being split out into lang/elisp/internals.
|
||||||
|
The upshot looks like this:
|
||||||
|
|
||||||
|
* internals/trace.scm, internals/set.scm, internals/load.scm,
|
||||||
|
internals/fset.scm, internals/signal.scm, internals/time.scm,
|
||||||
|
internals/format.scm, internals/null.scm,
|
||||||
|
internals/evaluation.scm, primitives/buffers.scm,
|
||||||
|
primitives/features.scm, primitives/format.scm,
|
||||||
|
primitives/time.scm, primitives/guile.scm, primitives/keymaps.scm,
|
||||||
|
primitives/lists.scm, primitives/load.scm, primitives/match.scm,
|
||||||
|
primitives/numbers.scm, primitives/pure.scm, primitives/read.scm,
|
||||||
|
primitives/signal.scm, primitives/strings.scm,
|
||||||
|
primitives/symprop.scm, primitives/system.scm, primitives/fns.scm:
|
||||||
|
New files.
|
||||||
|
|
||||||
|
* features.scm, format.scm, fset.scm, guile.scm, keymaps.scm,
|
||||||
|
lists.scm, load.scm, match.scm, numbers.scm, pure.scm, read.scm,
|
||||||
|
signal.scm, strings.scm, symprop.scm, system.scm, time.scm,
|
||||||
|
trace.scm: Removed files.
|
||||||
|
|
||||||
|
2001-10-23 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* match.scm (string-match): New implementation using new
|
||||||
|
`make-emacs-regexp' primitive; old workaround implementation
|
||||||
|
renamed to `string-match-workaround'.
|
||||||
|
|
||||||
|
2001-10-21 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* transform.scm (m-defun, m-defmacro, m-let, m-defvar,
|
||||||
|
m-defconst): Use more selective tracing mechanism (provided by new
|
||||||
|
file trace.scm).
|
||||||
|
|
||||||
|
* symprop.scm (get, boundp), transform.scm (transform-lambda,
|
||||||
|
m-defmacro): Remove unnecessary uses of nil-ify and t-ify.
|
||||||
|
|
||||||
|
* match.scm (string-match): Workaround Guile/libc regex
|
||||||
|
parenthesis bug.
|
||||||
|
|
||||||
|
* emacs.scm: Move elisp primitive definitions into more specific
|
||||||
|
files, so that emacs.scm contains only overall code.
|
||||||
|
|
||||||
|
* Makefile.am: Added new files.
|
||||||
|
|
||||||
|
* numbers.scm, trace.scm, time.scm, pure.scm, system.scm,
|
||||||
|
read.scm, calling.scm, guile.scm: New files.
|
||||||
|
|
||||||
|
2001-10-20 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* Makefile.am (elisp_sources): Added match.scm and strings.scm.
|
||||||
|
|
||||||
|
* match.scm, strings.scm: New files.
|
||||||
|
|
||||||
|
2001-10-19 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
* transform.scm: Replace uses of `nil' by `#f' or `'()'.
|
||||||
|
|
||||||
|
* Makefile.am (elisp_sources): Added lists.scm.
|
||||||
|
|
||||||
|
* load.scm (the-elisp-module): Corrected (lang elisp emacs) module
|
||||||
|
name.
|
||||||
|
|
||||||
|
* lists.scm (lang): New file containing list-related primitives.
|
||||||
|
|
||||||
|
* emacs.scm: Corrected module name.
|
||||||
|
|
||||||
|
2001-10-19 Neil Jerram <neil@ossau.uklinux.net>
|
||||||
|
|
||||||
|
Initial implementation of an Emacs Lisp translator, based on
|
||||||
|
transformer code originally written by Mikael Djurfeldt.
|
||||||
|
|
||||||
|
* Makefile.am, .cvsignore: New.
|
||||||
|
|
||||||
|
* ChangeLog, README, buffers.scm, emacs.scm, features.scm,
|
||||||
|
format.scm, fset.scm, keymaps.scm, load.scm, signal.scm,
|
||||||
|
symprop.scm, transform.scm: New files.
|
||||||
|
|
||||||
|
|
39
lang/elisp/Makefile.am
Normal file
39
lang/elisp/Makefile.am
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
##
|
||||||
|
## Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||||
|
##
|
||||||
|
## This file is part of GUILE.
|
||||||
|
##
|
||||||
|
## GUILE is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as
|
||||||
|
## published by the Free Software Foundation; either version 2, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## GUILE is distributed in the hope that it will be useful, but
|
||||||
|
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with GUILE; see the file COPYING. If not, write
|
||||||
|
## to the Free Software Foundation, Inc., 59 Temple Place, Suite
|
||||||
|
## 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
|
SUBDIRS = internals primitives
|
||||||
|
|
||||||
|
# These should be installed and distributed.
|
||||||
|
|
||||||
|
elisp_sources = \
|
||||||
|
base.scm \
|
||||||
|
example.el \
|
||||||
|
interface.scm \
|
||||||
|
transform.scm \
|
||||||
|
variables.scm
|
||||||
|
|
||||||
|
subpkgdatadir = $(pkgdatadir)/$(VERSION)/lang/elisp
|
||||||
|
subpkgdata_DATA = $(elisp_sources)
|
||||||
|
ETAGS_ARGS = $(subpkgdata_DATA)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(elisp_sources)
|
321
lang/elisp/README
Normal file
321
lang/elisp/README
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
-*- 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 note that this is work in progress; the translator is
|
||||||
|
incomplete and not yet widely tested.
|
||||||
|
|
||||||
|
** 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
|
||||||
|
|
||||||
|
Lots of stuff to do with providing the special self-evaluating `nil'
|
||||||
|
and `t' symbols, and macros that convert between Scheme and Elisp
|
||||||
|
truth values, and so on.
|
||||||
|
|
||||||
|
I'm hoping that most of this will go away, but I need to show that
|
||||||
|
it's feasible first.
|
||||||
|
|
||||||
|
** 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 adding Elisp
|
||||||
|
support to the reader.
|
||||||
|
|
||||||
|
- 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.)
|
||||||
|
|
||||||
|
- `nil' and `t' should be read (I think) as #f and #t. (Done.)
|
||||||
|
|
||||||
|
- Vector syntax is `[1 2 3]' rather than `#(1 2 3)'. (Not done.)
|
||||||
|
|
||||||
|
Correspondingly, when printing, #f and '() should be written as
|
||||||
|
`nil'. (Not done.)
|
||||||
|
|
||||||
|
** 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.
|
||||||
|
|
||||||
|
* nil, #f and '()
|
||||||
|
|
||||||
|
For Jim Blandy's notes on this, see the reference at the bottom of
|
||||||
|
this file. Currently I'm investigating a different approach, which is
|
||||||
|
better IMO than Jim's proposal because it avoids requiring multiple
|
||||||
|
false values in the Scheme world.
|
||||||
|
|
||||||
|
According to my approach...
|
||||||
|
|
||||||
|
- `nil' and `t' are read (when in Elisp mode) as #f and #t.
|
||||||
|
|
||||||
|
- `(if x ...)', `(while x ...)' etc. are translated to something
|
||||||
|
like `(if (and x (not (null? x))) ...)'.
|
||||||
|
|
||||||
|
- Functions which interpret an argument as a list --
|
||||||
|
`cons', `setcdr', `memq', etc. -- either convert #f to '(), or
|
||||||
|
handle the #f case specially.
|
||||||
|
|
||||||
|
- `eq' treats #f and '() as the same.
|
||||||
|
|
||||||
|
- Optionally, functions which produce '() values -- i.e. the reader
|
||||||
|
and `cdr' -- could convert those immediately to #f. This shouldn't
|
||||||
|
affect the validity of any Elisp code, but it alters the balance of
|
||||||
|
#f and '() values swimming around in that code and so affects what
|
||||||
|
happens if two such values are returned to the Scheme world and then
|
||||||
|
compared. However, since you can never completely solve this
|
||||||
|
problem (unless you are prepared to convert arbitrarily deep
|
||||||
|
structures on entry to the Elisp world, which would kill performance),
|
||||||
|
I'm inclined not to try to solve it at all.
|
||||||
|
|
||||||
|
* 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
|
||||||
|
|
||||||
|
** Mikael Djurfeldt's notes on translation
|
||||||
|
|
||||||
|
See file guile-cvs/devel/translation/langtools.text in Guile CVS.
|
38
lang/elisp/base.scm
Normal file
38
lang/elisp/base.scm
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
(define-module (lang elisp base))
|
||||||
|
|
||||||
|
;;; {Elisp Primitives}
|
||||||
|
;;;
|
||||||
|
;;; In other words, Scheme definitions of elisp primitives. This
|
||||||
|
;;; should (ultimately) include everything that Emacs defines in C.
|
||||||
|
|
||||||
|
(use-modules (lang elisp primitives buffers)
|
||||||
|
(lang elisp primitives features)
|
||||||
|
(lang elisp primitives format)
|
||||||
|
(lang elisp primitives fns)
|
||||||
|
(lang elisp primitives guile)
|
||||||
|
(lang elisp primitives keymaps)
|
||||||
|
(lang elisp primitives lists)
|
||||||
|
(lang elisp primitives load)
|
||||||
|
(lang elisp primitives match)
|
||||||
|
(lang elisp primitives numbers)
|
||||||
|
(lang elisp primitives pure)
|
||||||
|
(lang elisp primitives read)
|
||||||
|
(lang elisp primitives signal)
|
||||||
|
(lang elisp primitives strings)
|
||||||
|
(lang elisp primitives symprop)
|
||||||
|
(lang elisp primitives system)
|
||||||
|
(lang elisp primitives time))
|
||||||
|
|
||||||
|
;;; Now switch into Emacs Lisp syntax.
|
||||||
|
|
||||||
|
(use-modules (lang elisp transform))
|
||||||
|
(read-set! keywords 'prefix)
|
||||||
|
(read-set! language 'elisp)
|
||||||
|
(set-module-transformer! (current-module) transformer)
|
||||||
|
|
||||||
|
;;; Everything below here is written in Elisp.
|
||||||
|
|
||||||
|
(defun load-emacs ()
|
||||||
|
(message "Calling loadup.el to clothe the bare Emacs...")
|
||||||
|
(load "loadup.el")
|
||||||
|
(message "Guile Emacs now fully clothed"))
|
10
lang/elisp/example.el
Normal file
10
lang/elisp/example.el
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
(defun html-page (title &rest contents)
|
||||||
|
(concat "<HTML>\n"
|
||||||
|
"<HEAD>\n"
|
||||||
|
"<TITLE>" title "</TITLE>\n"
|
||||||
|
"</HEAD>\n"
|
||||||
|
"<BODY>\n"
|
||||||
|
(apply 'concat contents)
|
||||||
|
"</BODY>\n"
|
||||||
|
"</HTML>\n"))
|
122
lang/elisp/interface.scm
Normal file
122
lang/elisp/interface.scm
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
(define-module (lang elisp interface)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module ((lang elisp internals load) #:select ((load . elisp:load)))
|
||||||
|
#:export (eval-elisp
|
||||||
|
elisp-function
|
||||||
|
elisp-variable
|
||||||
|
load-elisp-file
|
||||||
|
load-elisp-library
|
||||||
|
use-elisp-file
|
||||||
|
use-elisp-library
|
||||||
|
export-to-elisp
|
||||||
|
load-emacs))
|
||||||
|
|
||||||
|
;;; This file holds my ideas for the mechanisms that would be useful
|
||||||
|
;;; to exchange definitions between Scheme and Elisp.
|
||||||
|
|
||||||
|
(define (eval-elisp x)
|
||||||
|
"Evaluate the Elisp expression @var{x}."
|
||||||
|
(eval x the-elisp-module))
|
||||||
|
|
||||||
|
(define (elisp-function sym)
|
||||||
|
"Return the procedure or macro that implements @var{sym} in Elisp.
|
||||||
|
If @var{sym} has no Elisp function definition, return @code{#f}."
|
||||||
|
(fref sym))
|
||||||
|
|
||||||
|
(define (elisp-variable sym)
|
||||||
|
"Return the variable that implements @var{sym} in Elisp.
|
||||||
|
If @var{sym} has no Elisp variable definition, return @code{#f}."
|
||||||
|
(module-variable the-elisp-module sym))
|
||||||
|
|
||||||
|
(define (load-elisp-file file-name)
|
||||||
|
"Load @var{file-name} into the Elisp environment.
|
||||||
|
@var{file-name} is assumed to name a file containing Elisp code."
|
||||||
|
;; This is the same as Elisp's `load-file', so use that if it is
|
||||||
|
;; available, otherwise duplicate the definition of `load-file' from
|
||||||
|
;; files.el.
|
||||||
|
(let ((load-file (elisp-function 'load-file)))
|
||||||
|
(if load-file
|
||||||
|
(load-file file-name)
|
||||||
|
(elisp:load file-name #f #f #t))))
|
||||||
|
|
||||||
|
(define (load-elisp-library library)
|
||||||
|
"Load library @var{library} into the Elisp environment.
|
||||||
|
@var{library} should name an Elisp code library that can be found in
|
||||||
|
one of the directories of @code{load-path}."
|
||||||
|
;; This is the same as Elisp's `load-file', so use that if it is
|
||||||
|
;; available, otherwise duplicate the definition of `load-file' from
|
||||||
|
;; files.el.
|
||||||
|
(let ((load-library (elisp-function 'load-library)))
|
||||||
|
(if load-library
|
||||||
|
(load-library library)
|
||||||
|
(elisp:load library))))
|
||||||
|
|
||||||
|
(define export-module-name
|
||||||
|
(let ((counter 0))
|
||||||
|
(lambda ()
|
||||||
|
(set! counter (+ counter 1))
|
||||||
|
(list 'lang 'elisp
|
||||||
|
(string->symbol (string-append "imports:"
|
||||||
|
(number->string counter)))))))
|
||||||
|
|
||||||
|
(define-macro (use-elisp-file file-name . imports)
|
||||||
|
"Load Elisp code file @var{file-name} and import its definitions
|
||||||
|
into the current Scheme module. If any @var{imports} are specified,
|
||||||
|
they are interpreted as selection and renaming specifiers as per
|
||||||
|
@code{use-modules}."
|
||||||
|
(let ((export-module-name (export-module-name)))
|
||||||
|
`(begin
|
||||||
|
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name))
|
||||||
|
(beautify-user-module! (resolve-module ',export-module-name))
|
||||||
|
(load-elisp-file ,file-name)
|
||||||
|
(use-modules (,export-module-name ,@imports))
|
||||||
|
(fluid-set! ,elisp-export-module #f))))
|
||||||
|
|
||||||
|
(define-macro (use-elisp-library library . imports)
|
||||||
|
"Load Elisp library @var{library} and import its definitions into
|
||||||
|
the current Scheme module. If any @var{imports} are specified, they
|
||||||
|
are interpreted as selection and renaming specifiers as per
|
||||||
|
@code{use-modules}."
|
||||||
|
(let ((export-module-name (export-module-name)))
|
||||||
|
`(begin
|
||||||
|
(fluid-set! ,elisp-export-module (resolve-module ',export-module-name))
|
||||||
|
(beautify-user-module! (resolve-module ',export-module-name))
|
||||||
|
(load-elisp-library ,library)
|
||||||
|
(use-modules (,export-module-name ,@imports))
|
||||||
|
(fluid-set! ,elisp-export-module #f))))
|
||||||
|
|
||||||
|
(define (export-to-elisp . defs)
|
||||||
|
"Export procedures and variables specified by @var{defs} to Elisp.
|
||||||
|
Each @var{def} is either an object, in which case that object must be
|
||||||
|
a named procedure or macro and is exported to Elisp under its Scheme
|
||||||
|
name; or a symbol, in which case the variable named by that symbol is
|
||||||
|
exported under its Scheme name; or a pair @var{(obj . name)}, in which
|
||||||
|
case @var{obj} must be a procedure, macro or symbol as already
|
||||||
|
described and @var{name} specifies the name under which that object is
|
||||||
|
exported to Elisp."
|
||||||
|
(for-each (lambda (def)
|
||||||
|
(let ((obj (if (pair? def) (car def) def))
|
||||||
|
(name (if (pair? def) (cdr def) #f)))
|
||||||
|
(cond ((procedure? obj)
|
||||||
|
(or name
|
||||||
|
(set! name (procedure-name obj)))
|
||||||
|
(if name
|
||||||
|
(fset name obj)
|
||||||
|
(error "No procedure name specified or deducible:" obj)))
|
||||||
|
((macro? obj)
|
||||||
|
(or name
|
||||||
|
(set! name (macro-name obj)))
|
||||||
|
(if name
|
||||||
|
(fset name obj)
|
||||||
|
(error "No macro name specified or deducible:" obj)))
|
||||||
|
((symbol? obj)
|
||||||
|
(or name
|
||||||
|
(set! name symbol))
|
||||||
|
(module-add! the-elisp-module name
|
||||||
|
(module-ref (current-module) obj)))
|
||||||
|
(else
|
||||||
|
(error "Can't export this kind of object to Elisp:" obj)))))
|
||||||
|
defs))
|
||||||
|
|
||||||
|
(define load-emacs (elisp-function 'load-emacs))
|
2
lang/elisp/internals/.cvsignore
Normal file
2
lang/elisp/internals/.cvsignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
41
lang/elisp/internals/Makefile.am
Normal file
41
lang/elisp/internals/Makefile.am
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
##
|
||||||
|
## Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||||
|
##
|
||||||
|
## This file is part of GUILE.
|
||||||
|
##
|
||||||
|
## GUILE is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as
|
||||||
|
## published by the Free Software Foundation; either version 2, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## GUILE is distributed in the hope that it will be useful, but
|
||||||
|
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with GUILE; see the file COPYING. If not, write
|
||||||
|
## to the Free Software Foundation, Inc., 59 Temple Place, Suite
|
||||||
|
## 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
|
# These should be installed and distributed.
|
||||||
|
|
||||||
|
elisp_sources = \
|
||||||
|
evaluation.scm \
|
||||||
|
format.scm \
|
||||||
|
fset.scm \
|
||||||
|
load.scm \
|
||||||
|
null.scm \
|
||||||
|
set.scm \
|
||||||
|
signal.scm \
|
||||||
|
time.scm \
|
||||||
|
trace.scm
|
||||||
|
|
||||||
|
subpkgdatadir = $(pkgdatadir)/$(VERSION)/lang/elisp/internals
|
||||||
|
subpkgdata_DATA = $(elisp_sources)
|
||||||
|
ETAGS_ARGS = $(subpkgdata_DATA)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(elisp_sources)
|
13
lang/elisp/internals/evaluation.scm
Normal file
13
lang/elisp/internals/evaluation.scm
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
(define-module (lang elisp internals evaluation)
|
||||||
|
#:export (the-elisp-module))
|
||||||
|
|
||||||
|
;;;; {Elisp Evaluation}
|
||||||
|
|
||||||
|
;;;; All elisp evaluation happens within the same module - namely
|
||||||
|
;;;; (lang elisp base). This is necessary both because elisp itself
|
||||||
|
;;;; has no concept of different modules - reflected for example in
|
||||||
|
;;;; its single argument `eval' function - and because Guile's current
|
||||||
|
;;;; implementation of elisp stores elisp function definitions in
|
||||||
|
;;;; slots in global symbol objects.
|
||||||
|
|
||||||
|
(define the-elisp-module (resolve-module '(lang elisp base)))
|
62
lang/elisp/internals/format.scm
Normal file
62
lang/elisp/internals/format.scm
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
(define-module (lang elisp internals format)
|
||||||
|
#:pure
|
||||||
|
#:use-module (ice-9 r5rs)
|
||||||
|
#:use-module ((ice-9 format) #:select ((format . scheme:format)))
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals signal)
|
||||||
|
#:export (format
|
||||||
|
message))
|
||||||
|
|
||||||
|
(define (format control-string . args)
|
||||||
|
|
||||||
|
(define (cons-string str ls)
|
||||||
|
(let loop ((sl (string->list str))
|
||||||
|
(ls ls))
|
||||||
|
(if (null? sl)
|
||||||
|
ls
|
||||||
|
(loop (cdr sl) (cons (car sl) ls)))))
|
||||||
|
|
||||||
|
(let loop ((input (string->list control-string))
|
||||||
|
(args args)
|
||||||
|
(output '())
|
||||||
|
(mid-control #f))
|
||||||
|
(if (null? input)
|
||||||
|
(if mid-control
|
||||||
|
(error "Format string ends in middle of format specifier")
|
||||||
|
(list->string (reverse output)))
|
||||||
|
(if mid-control
|
||||||
|
(case (car input)
|
||||||
|
((#\%)
|
||||||
|
(loop (cdr input)
|
||||||
|
args
|
||||||
|
(cons #\% output)
|
||||||
|
#f))
|
||||||
|
(else
|
||||||
|
(loop (cdr input)
|
||||||
|
(cdr args)
|
||||||
|
(cons-string (case (car input)
|
||||||
|
((#\s) (scheme:format #f "~A" (car args)))
|
||||||
|
((#\d) (number->string (car args)))
|
||||||
|
((#\o) (number->string (car args) 8))
|
||||||
|
((#\x) (number->string (car args) 16))
|
||||||
|
((#\e) (number->string (car args))) ;FIXME
|
||||||
|
((#\f) (number->string (car args))) ;FIXME
|
||||||
|
((#\g) (number->string (car args))) ;FIXME
|
||||||
|
((#\c) (let ((a (car args)))
|
||||||
|
(if (char? a)
|
||||||
|
(string a)
|
||||||
|
(string (integer->char a)))))
|
||||||
|
((#\S) (scheme:format #f "~S" (car args)))
|
||||||
|
(else
|
||||||
|
(error "Invalid format operation %%%c" (car input))))
|
||||||
|
output)
|
||||||
|
#f)))
|
||||||
|
(case (car input)
|
||||||
|
((#\%)
|
||||||
|
(loop (cdr input) args output #t))
|
||||||
|
(else
|
||||||
|
(loop (cdr input) args (cons (car input) output) #f)))))))
|
||||||
|
|
||||||
|
(define (message control-string . args)
|
||||||
|
(display (apply format control-string args))
|
||||||
|
(newline))
|
111
lang/elisp/internals/fset.scm
Normal file
111
lang/elisp/internals/fset.scm
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
(define-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals signal)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:export (fset
|
||||||
|
fref
|
||||||
|
fref/error-if-void
|
||||||
|
elisp-apply
|
||||||
|
interactive-specification
|
||||||
|
not-subr?
|
||||||
|
elisp-export-module))
|
||||||
|
|
||||||
|
(define the-variables-module (resolve-module '(lang elisp variables)))
|
||||||
|
|
||||||
|
;; By default, Guile GC's unreachable symbols. So we need to make
|
||||||
|
;; sure they stay reachable!
|
||||||
|
(define syms '())
|
||||||
|
|
||||||
|
;; elisp-export-module, if non-#f, holds a module to which definitions
|
||||||
|
;; should be exported under their normal symbol names. This is used
|
||||||
|
;; when importing Elisp definitions into Scheme.
|
||||||
|
(define elisp-export-module (make-fluid))
|
||||||
|
|
||||||
|
;; Store the procedure, macro or alias symbol PROC in SYM's function
|
||||||
|
;; slot.
|
||||||
|
(define (fset sym proc)
|
||||||
|
(or (memq sym syms)
|
||||||
|
(set! syms (cons sym syms)))
|
||||||
|
(let ((vcell (symbol-fref sym))
|
||||||
|
(vsym #f)
|
||||||
|
(export-module (fluid-ref elisp-export-module)))
|
||||||
|
;; Playing around with variables and name properties... For the
|
||||||
|
;; reasoning behind this, see the commentary in (lang elisp
|
||||||
|
;; variables).
|
||||||
|
(cond ((procedure? proc)
|
||||||
|
;; A procedure created from Elisp will already have a name
|
||||||
|
;; property attached, with value of the form
|
||||||
|
;; <elisp-defun:NAME> or <elisp-lambda>. Any other
|
||||||
|
;; procedure coming through here must be an Elisp primitive
|
||||||
|
;; definition, so we give it a name of the form
|
||||||
|
;; <elisp-subr:NAME>.
|
||||||
|
(or (procedure-name proc)
|
||||||
|
(set-procedure-property! proc
|
||||||
|
'name
|
||||||
|
(symbol-append '<elisp-subr: sym '>)))
|
||||||
|
(set! vsym (procedure-name proc)))
|
||||||
|
((macro? proc)
|
||||||
|
;; Macros coming through here must be defmacros, as all
|
||||||
|
;; primitive special forms are handled directly by the
|
||||||
|
;; transformer.
|
||||||
|
(set-procedure-property! (macro-transformer proc)
|
||||||
|
'name
|
||||||
|
(symbol-append '<elisp-defmacro: sym '>))
|
||||||
|
(set! vsym (procedure-name (macro-transformer proc))))
|
||||||
|
(else
|
||||||
|
;; An alias symbol.
|
||||||
|
(set! vsym (symbol-append '<elisp-defalias: sym '>))))
|
||||||
|
;; This is the important bit!
|
||||||
|
(if (variable? vcell)
|
||||||
|
(variable-set! vcell proc)
|
||||||
|
(begin
|
||||||
|
(set! vcell (make-variable proc))
|
||||||
|
(symbol-fset! sym vcell)
|
||||||
|
;; Playing with names and variables again - see above.
|
||||||
|
(module-add! the-variables-module vsym vcell)
|
||||||
|
(module-export! the-variables-module (list vsym))))
|
||||||
|
;; Export variable to the export module, if non-#f.
|
||||||
|
(if (and export-module
|
||||||
|
(or (procedure? proc)
|
||||||
|
(macro? proc)))
|
||||||
|
(begin
|
||||||
|
(module-add! export-module sym vcell)
|
||||||
|
(module-export! export-module (list sym))))))
|
||||||
|
|
||||||
|
;; Retrieve the procedure or macro stored in SYM's function slot.
|
||||||
|
;; Note the asymmetry w.r.t. fset: if fref finds an alias symbol, it
|
||||||
|
;; recursively calls fref on that symbol. Returns #f if SYM's
|
||||||
|
;; function slot doesn't contain a valid definition.
|
||||||
|
(define (fref sym)
|
||||||
|
(let ((var (symbol-fref sym)))
|
||||||
|
(if (and var (variable? var))
|
||||||
|
(let ((proc (variable-ref var)))
|
||||||
|
(cond ((symbol? proc)
|
||||||
|
(fref proc))
|
||||||
|
(else
|
||||||
|
proc)))
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
;; Same as fref, but signals an Elisp error if SYM's function
|
||||||
|
;; definition is void.
|
||||||
|
(define (fref/error-if-void sym)
|
||||||
|
(or (fref sym)
|
||||||
|
(signal 'void-function (list sym))))
|
||||||
|
|
||||||
|
;; Maps a procedure to its (interactive ...) spec.
|
||||||
|
(define interactive-specification (make-object-property))
|
||||||
|
|
||||||
|
;; Maps a procedure to #t if it is NOT a built-in.
|
||||||
|
(define not-subr? (make-object-property))
|
||||||
|
|
||||||
|
(define (elisp-apply function . args)
|
||||||
|
(apply apply
|
||||||
|
(cond ((symbol? function)
|
||||||
|
(fref/error-if-void function))
|
||||||
|
((procedure? function)
|
||||||
|
function)
|
||||||
|
((and (pair? function)
|
||||||
|
(eq? (car function) 'lambda))
|
||||||
|
(eval function the-elisp-module))
|
||||||
|
(else
|
||||||
|
(signal 'invalid-function (list function))))
|
||||||
|
args))
|
45
lang/elisp/internals/load.scm
Normal file
45
lang/elisp/internals/load.scm
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
(define-module (lang elisp internals load)
|
||||||
|
#:use-module (ice-9 optargs)
|
||||||
|
#:use-module (lang elisp internals signal)
|
||||||
|
#:use-module (lang elisp internals format)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:export (load-path
|
||||||
|
load))
|
||||||
|
|
||||||
|
(define load-path '("/usr/share/emacs/20.7/lisp/"
|
||||||
|
"/usr/share/emacs/20.7/lisp/emacs-lisp/"))
|
||||||
|
|
||||||
|
(define* (load file #:optional noerror nomessage nosuffix must-suffix)
|
||||||
|
(define (load1 filename)
|
||||||
|
(let ((pathname (let loop ((dirs (if (char=? (string-ref filename 0) #\/)
|
||||||
|
'("")
|
||||||
|
load-path)))
|
||||||
|
(cond ((null? dirs) #f)
|
||||||
|
((file-exists? (string-append (car dirs)
|
||||||
|
filename))
|
||||||
|
(string-append (car dirs) filename))
|
||||||
|
(else (loop (cdr dirs)))))))
|
||||||
|
(if pathname
|
||||||
|
(begin
|
||||||
|
(or nomessage
|
||||||
|
(message "Loading %s..." pathname))
|
||||||
|
(with-input-from-file pathname
|
||||||
|
(lambda ()
|
||||||
|
(let loop ((form (read)))
|
||||||
|
(or (eof-object? form)
|
||||||
|
(begin
|
||||||
|
;; Note that `eval' already incorporates use
|
||||||
|
;; of the specified module's transformer.
|
||||||
|
(eval form the-elisp-module)
|
||||||
|
(loop (read)))))))
|
||||||
|
(or nomessage
|
||||||
|
(message "Loading %s...done" pathname))
|
||||||
|
#t)
|
||||||
|
#f)))
|
||||||
|
(or (and (not nosuffix)
|
||||||
|
(load1 (string-append file ".el")))
|
||||||
|
(and (not must-suffix)
|
||||||
|
(load1 file))
|
||||||
|
noerror
|
||||||
|
(signal 'file-error
|
||||||
|
(list "Cannot open load file" file))))
|
6
lang/elisp/internals/null.scm
Normal file
6
lang/elisp/internals/null.scm
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(define-module (lang elisp internals null)
|
||||||
|
#:export (null))
|
||||||
|
|
||||||
|
(define (null obj)
|
||||||
|
(or (not obj)
|
||||||
|
(null? obj)))
|
9
lang/elisp/internals/set.scm
Normal file
9
lang/elisp/internals/set.scm
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
(define-module (lang elisp internals set)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:use-module (lang elisp internals signal)
|
||||||
|
#:export (set))
|
||||||
|
|
||||||
|
;; Set SYM's variable value to VAL, and return VAL.
|
||||||
|
(define (set sym val)
|
||||||
|
(module-define! the-elisp-module sym val)
|
||||||
|
val)
|
18
lang/elisp/internals/signal.scm
Normal file
18
lang/elisp/internals/signal.scm
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
(define-module (lang elisp internals signal)
|
||||||
|
#:use-module (lang elisp internals format)
|
||||||
|
#:export (signal
|
||||||
|
error
|
||||||
|
wta))
|
||||||
|
|
||||||
|
(define (signal error-symbol data)
|
||||||
|
(scm-error 'elisp-signal
|
||||||
|
#f
|
||||||
|
"Signalling ~A with data ~S"
|
||||||
|
(list error-symbol data)
|
||||||
|
#f))
|
||||||
|
|
||||||
|
(define (error . args)
|
||||||
|
(signal 'error (list (apply format args))))
|
||||||
|
|
||||||
|
(define (wta expected actual pos)
|
||||||
|
(signal 'wrong-type-argument (list expected actual)))
|
14
lang/elisp/internals/time.scm
Normal file
14
lang/elisp/internals/time.scm
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(define-module (lang elisp internals time)
|
||||||
|
#:use-module (ice-9 optargs)
|
||||||
|
#:export (format-time-string))
|
||||||
|
|
||||||
|
(define* (format-time-string format-string #:optional time universal)
|
||||||
|
(strftime format-string
|
||||||
|
((if universal gmtime localtime)
|
||||||
|
(if time
|
||||||
|
(+ (ash (car time) 16)
|
||||||
|
(let ((time-cdr (cdr time)))
|
||||||
|
(if (pair? time-cdr)
|
||||||
|
(car time-cdr)
|
||||||
|
time-cdr)))
|
||||||
|
(current-time)))))
|
28
lang/elisp/internals/trace.scm
Normal file
28
lang/elisp/internals/trace.scm
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
(define-module (lang elisp internals trace)
|
||||||
|
#:export (trc trc-syms trc-all trc-none))
|
||||||
|
|
||||||
|
(define *syms* #f)
|
||||||
|
|
||||||
|
(define (trc-syms . syms)
|
||||||
|
(set! *syms* syms))
|
||||||
|
|
||||||
|
(define (trc-all)
|
||||||
|
(set! *syms* #f))
|
||||||
|
|
||||||
|
(define (trc-none)
|
||||||
|
(set! *syms* '()))
|
||||||
|
|
||||||
|
(define (trc . args)
|
||||||
|
(let ((sym (car args))
|
||||||
|
(args (cdr args)))
|
||||||
|
(if (or (and *syms*
|
||||||
|
(memq sym *syms*))
|
||||||
|
(not *syms*))
|
||||||
|
(begin
|
||||||
|
(write sym)
|
||||||
|
(display ": ")
|
||||||
|
(write args)
|
||||||
|
(newline)))))
|
||||||
|
|
||||||
|
;; Default to no tracing.
|
||||||
|
(trc-none)
|
2
lang/elisp/primitives/.cvsignore
Normal file
2
lang/elisp/primitives/.cvsignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
49
lang/elisp/primitives/Makefile.am
Normal file
49
lang/elisp/primitives/Makefile.am
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
##
|
||||||
|
## Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||||
|
##
|
||||||
|
## This file is part of GUILE.
|
||||||
|
##
|
||||||
|
## GUILE is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as
|
||||||
|
## published by the Free Software Foundation; either version 2, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## GUILE is distributed in the hope that it will be useful, but
|
||||||
|
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with GUILE; see the file COPYING. If not, write
|
||||||
|
## to the Free Software Foundation, Inc., 59 Temple Place, Suite
|
||||||
|
## 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
|
# These should be installed and distributed.
|
||||||
|
|
||||||
|
elisp_sources = \
|
||||||
|
buffers.scm \
|
||||||
|
features.scm \
|
||||||
|
fns.scm \
|
||||||
|
format.scm \
|
||||||
|
guile.scm \
|
||||||
|
keymaps.scm \
|
||||||
|
lists.scm \
|
||||||
|
load.scm \
|
||||||
|
match.scm \
|
||||||
|
numbers.scm \
|
||||||
|
pure.scm \
|
||||||
|
read.scm \
|
||||||
|
signal.scm \
|
||||||
|
strings.scm \
|
||||||
|
symprop.scm \
|
||||||
|
system.scm \
|
||||||
|
time.scm
|
||||||
|
|
||||||
|
subpkgdatadir = $(pkgdatadir)/$(VERSION)/lang/elisp/primitives
|
||||||
|
subpkgdata_DATA = $(elisp_sources)
|
||||||
|
ETAGS_ARGS = $(subpkgdata_DATA)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(elisp_sources)
|
16
lang/elisp/primitives/buffers.scm
Normal file
16
lang/elisp/primitives/buffers.scm
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
(define-module (lang elisp primitives buffers)
|
||||||
|
#:use-module (ice-9 optargs)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'buffer-disable-undo
|
||||||
|
(lambda* (#:optional buffer)
|
||||||
|
'unimplemented))
|
||||||
|
|
||||||
|
(fset 're-search-forward
|
||||||
|
(lambda* (regexp #:optional bound noerror count)
|
||||||
|
'unimplemented))
|
||||||
|
|
||||||
|
(fset 're-search-backward
|
||||||
|
(lambda* (regexp #:optional bound noerror count)
|
||||||
|
'unimplemented))
|
||||||
|
|
25
lang/elisp/primitives/features.scm
Normal file
25
lang/elisp/primitives/features.scm
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
(define-module (lang elisp primitives features)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals load)
|
||||||
|
#:use-module (ice-9 optargs))
|
||||||
|
|
||||||
|
(define-public features '())
|
||||||
|
|
||||||
|
(fset 'provide
|
||||||
|
(lambda (feature)
|
||||||
|
(or (memq feature features)
|
||||||
|
(set! features (cons feature features)))))
|
||||||
|
|
||||||
|
(fset 'featurep
|
||||||
|
(lambda (feature)
|
||||||
|
(memq feature features)))
|
||||||
|
|
||||||
|
(fset 'require
|
||||||
|
(lambda* (feature #:optional file-name noerror)
|
||||||
|
(or (memq feature features)
|
||||||
|
(load (or file-name
|
||||||
|
(symbol->string feature))
|
||||||
|
noerror
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
#t))))
|
45
lang/elisp/primitives/fns.scm
Normal file
45
lang/elisp/primitives/fns.scm
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
(define-module (lang elisp primitives fns)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'fset fset)
|
||||||
|
(fset 'defalias fset)
|
||||||
|
|
||||||
|
(fset 'apply elisp-apply)
|
||||||
|
|
||||||
|
(fset 'funcall
|
||||||
|
(lambda (function . args)
|
||||||
|
(elisp-apply function args)))
|
||||||
|
|
||||||
|
(fset 'interactive-p
|
||||||
|
(lambda ()
|
||||||
|
#f))
|
||||||
|
|
||||||
|
(fset 'commandp
|
||||||
|
(lambda (sym)
|
||||||
|
(if (interactive-spec (fref sym)) #t #f)))
|
||||||
|
|
||||||
|
(fset 'fboundp
|
||||||
|
(lambda (sym)
|
||||||
|
(variable? (symbol-fref sym))))
|
||||||
|
|
||||||
|
(fset 'symbol-function fref/error-if-void)
|
||||||
|
|
||||||
|
(fset 'macroexpand macroexpand)
|
||||||
|
|
||||||
|
(fset 'subrp
|
||||||
|
(lambda (obj)
|
||||||
|
(not (not-subr? obj))))
|
||||||
|
|
||||||
|
(fset 'byte-code-function-p
|
||||||
|
(lambda (object)
|
||||||
|
#f))
|
||||||
|
|
||||||
|
(fset 'run-hooks
|
||||||
|
(lambda (hooks)
|
||||||
|
(cond ((null hooks))
|
||||||
|
((list? hooks)
|
||||||
|
(for-each (lambda (hook)
|
||||||
|
(elisp-apply hook '()))
|
||||||
|
hooks))
|
||||||
|
(else
|
||||||
|
(elisp-apply hooks '())))))
|
6
lang/elisp/primitives/format.scm
Normal file
6
lang/elisp/primitives/format.scm
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(define-module (lang elisp primitives format)
|
||||||
|
#:use-module (lang elisp internals format)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'format format)
|
||||||
|
(fset 'message message)
|
20
lang/elisp/primitives/guile.scm
Normal file
20
lang/elisp/primitives/guile.scm
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
(define-module (lang elisp primitives guile)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
;;; {Importing Guile procedures into Elisp}
|
||||||
|
|
||||||
|
;; It may be worthwhile to import some Guile procedures into the Elisp
|
||||||
|
;; environment. For now, though, we don't do this.
|
||||||
|
|
||||||
|
(if #f
|
||||||
|
(let ((accessible-procedures
|
||||||
|
(apropos-fold (lambda (module name var data)
|
||||||
|
(cons (cons name var) data))
|
||||||
|
'()
|
||||||
|
""
|
||||||
|
(apropos-fold-accessible (current-module)))))
|
||||||
|
(for-each (lambda (name var)
|
||||||
|
(if (procedure? var)
|
||||||
|
(fset name var)))
|
||||||
|
(map car accessible-procedures)
|
||||||
|
(map cdr accessible-procedures))))
|
26
lang/elisp/primitives/keymaps.scm
Normal file
26
lang/elisp/primitives/keymaps.scm
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
(define-module (lang elisp primitives keymaps)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(define (make-sparse-keymap)
|
||||||
|
(list 'keymap))
|
||||||
|
|
||||||
|
(define (define-key keymap key def)
|
||||||
|
(set-cdr! keymap
|
||||||
|
(cons (cons key def) (cdr keymap))))
|
||||||
|
|
||||||
|
(define global-map (make-sparse-keymap))
|
||||||
|
(define esc-map (make-sparse-keymap))
|
||||||
|
(define ctl-x-map (make-sparse-keymap))
|
||||||
|
(define ctl-x-4-map (make-sparse-keymap))
|
||||||
|
(define ctl-x-5-map (make-sparse-keymap))
|
||||||
|
|
||||||
|
;;; {Elisp Exports}
|
||||||
|
|
||||||
|
(fset 'make-sparse-keymap make-sparse-keymap)
|
||||||
|
(fset 'define-key define-key)
|
||||||
|
|
||||||
|
(export global-map
|
||||||
|
esc-map
|
||||||
|
ctl-x-map
|
||||||
|
ctl-x-4-map
|
||||||
|
ctl-x-5-map)
|
108
lang/elisp/primitives/lists.scm
Normal file
108
lang/elisp/primitives/lists.scm
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
(define-module (lang elisp primitives lists)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals null)
|
||||||
|
#:use-module (lang elisp internals signal))
|
||||||
|
|
||||||
|
(fset 'cons
|
||||||
|
(lambda (x y)
|
||||||
|
(cons x (or y '()))))
|
||||||
|
|
||||||
|
(fset 'null null)
|
||||||
|
|
||||||
|
(fset 'not null)
|
||||||
|
|
||||||
|
(fset 'car
|
||||||
|
(lambda (l)
|
||||||
|
(if (null l)
|
||||||
|
#f
|
||||||
|
(car l))))
|
||||||
|
|
||||||
|
(fset 'cdr
|
||||||
|
(lambda (l)
|
||||||
|
(if (null l)
|
||||||
|
#f
|
||||||
|
(cdr l))))
|
||||||
|
|
||||||
|
(fset 'eq
|
||||||
|
(lambda (x y)
|
||||||
|
(or (eq? x y)
|
||||||
|
(and (null x) (null y)))))
|
||||||
|
|
||||||
|
(fset 'equal
|
||||||
|
(lambda (x y)
|
||||||
|
(or (equal? x y)
|
||||||
|
(and (null x) (null y)))))
|
||||||
|
|
||||||
|
(fset 'setcar set-car!)
|
||||||
|
|
||||||
|
(fset 'setcdr
|
||||||
|
(lambda (cell newcdr)
|
||||||
|
(set-cdr! cell
|
||||||
|
(if (null newcdr)
|
||||||
|
'()
|
||||||
|
newcdr))))
|
||||||
|
|
||||||
|
(for-each (lambda (sym proc)
|
||||||
|
(fset sym
|
||||||
|
(lambda (elt list)
|
||||||
|
(if (null list)
|
||||||
|
#f
|
||||||
|
(if (null elt)
|
||||||
|
(or (proc #f list)
|
||||||
|
(proc '() list))
|
||||||
|
(proc elt list))))))
|
||||||
|
'( memq member assq assoc)
|
||||||
|
`(,memq ,member ,assq ,assoc))
|
||||||
|
|
||||||
|
(fset 'length
|
||||||
|
(lambda (x)
|
||||||
|
(cond ((null x) 0)
|
||||||
|
((pair? x) (length x))
|
||||||
|
((vector? x) (vector-length x))
|
||||||
|
((string? x) (string-length x))
|
||||||
|
(else (wta 'sequencep x 1)))))
|
||||||
|
|
||||||
|
(fset 'copy-sequence
|
||||||
|
(lambda (x)
|
||||||
|
(cond ((list? x) (list-copy x))
|
||||||
|
((vector? x) (error "Vector copy not yet implemented"))
|
||||||
|
((string? x) (string-copy x))
|
||||||
|
(else (wta 'sequencep x 1)))))
|
||||||
|
|
||||||
|
(fset 'elt
|
||||||
|
(lambda (obj i)
|
||||||
|
(cond ((pair? obj) (list-ref obj i))
|
||||||
|
((vector? obj) (vector-ref obj i))
|
||||||
|
((string? obj) (char->integer (string-ref obj i))))))
|
||||||
|
|
||||||
|
(fset 'list list)
|
||||||
|
|
||||||
|
(fset 'mapcar
|
||||||
|
(lambda (function sequence)
|
||||||
|
(map (lambda (elt)
|
||||||
|
(elisp-apply function (list elt)))
|
||||||
|
(cond ((null sequence) '())
|
||||||
|
((list? sequence) sequence)
|
||||||
|
((vector? sequence) (vector->list sequence))
|
||||||
|
((string? sequence) (map char->integer (string->list sequence)))
|
||||||
|
(else (wta 'sequencep sequence 2))))))
|
||||||
|
|
||||||
|
(fset 'nth
|
||||||
|
(lambda (n list)
|
||||||
|
(if (or (null list)
|
||||||
|
(>= n (length list)))
|
||||||
|
#f
|
||||||
|
(list-ref list n))))
|
||||||
|
|
||||||
|
(fset 'listp
|
||||||
|
(lambda (object)
|
||||||
|
(or (null object)
|
||||||
|
(list? object))))
|
||||||
|
|
||||||
|
(fset 'consp pair?)
|
||||||
|
|
||||||
|
(fset 'nconc
|
||||||
|
(lambda args
|
||||||
|
(apply append! (map (lambda (arg)
|
||||||
|
(if arg arg '()))
|
||||||
|
args))))
|
17
lang/elisp/primitives/load.scm
Normal file
17
lang/elisp/primitives/load.scm
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
(define-module (lang elisp primitives load)
|
||||||
|
#:use-module (lang elisp internals load)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'load load)
|
||||||
|
(re-export load-path)
|
||||||
|
|
||||||
|
(fset 'eval
|
||||||
|
(lambda (form)
|
||||||
|
(eval form the-elisp-module)))
|
||||||
|
|
||||||
|
(fset 'autoload
|
||||||
|
(lambda args
|
||||||
|
#t))
|
||||||
|
|
||||||
|
(define-public current-load-list #f)
|
68
lang/elisp/primitives/match.scm
Normal file
68
lang/elisp/primitives/match.scm
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
(define-module (lang elisp primitives match)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (ice-9 regex)
|
||||||
|
#:use-module (ice-9 optargs))
|
||||||
|
|
||||||
|
(define last-match #f)
|
||||||
|
|
||||||
|
(fset 'string-match
|
||||||
|
(lambda (regexp string . start)
|
||||||
|
|
||||||
|
(define emacs-string-match
|
||||||
|
|
||||||
|
(if (defined? 'make-emacs-regexp)
|
||||||
|
|
||||||
|
;; This is what we would do if we had an
|
||||||
|
;; Emacs-compatible regexp primitive, here called
|
||||||
|
;; `make-emacs-regexp'.
|
||||||
|
(lambda (pattern str . args)
|
||||||
|
(let ((rx (make-emacs-regexp pattern))
|
||||||
|
(start (if (pair? args) (car args) 0)))
|
||||||
|
(regexp-exec rx str start)))
|
||||||
|
|
||||||
|
;; But we don't have Emacs-compatible regexps, and I
|
||||||
|
;; don't think it's worthwhile at this stage to write
|
||||||
|
;; generic regexp conversion code. So work around the
|
||||||
|
;; discrepancies between Guile/libc and Emacs regexps by
|
||||||
|
;; substituting the regexps that actually occur in the
|
||||||
|
;; elisp code that we want to read.
|
||||||
|
(lambda (pattern str . args)
|
||||||
|
(let loop ((discrepancies '(("^[0-9]+\\.\\([0-9]+\\)" .
|
||||||
|
"^[0-9]+\\.([0-9]+)"))))
|
||||||
|
(or (null? discrepancies)
|
||||||
|
(if (string=? pattern (caar discrepancies))
|
||||||
|
(set! pattern (cdar discrepancies))
|
||||||
|
(loop (cdr discrepancies)))))
|
||||||
|
(apply string-match pattern str args))))
|
||||||
|
|
||||||
|
(let ((match (apply emacs-string-match regexp string start)))
|
||||||
|
(set! last-match
|
||||||
|
(if match
|
||||||
|
(apply append!
|
||||||
|
(map (lambda (n)
|
||||||
|
(list (match:start match n)
|
||||||
|
(match:end match n)))
|
||||||
|
(iota (match:count match))))
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
(if last-match (car last-match) #f)))
|
||||||
|
|
||||||
|
(fset 'match-beginning
|
||||||
|
(lambda (subexp)
|
||||||
|
(list-ref last-match (* 2 subexp))))
|
||||||
|
|
||||||
|
(fset 'match-end
|
||||||
|
(lambda (subexp)
|
||||||
|
(list-ref last-match (+ (* 2 subexp) 1))))
|
||||||
|
|
||||||
|
(fset 'substring substring)
|
||||||
|
|
||||||
|
(fset 'match-data
|
||||||
|
(lambda* (#:optional integers reuse)
|
||||||
|
last-match))
|
||||||
|
|
||||||
|
(fset 'set-match-data
|
||||||
|
(lambda (list)
|
||||||
|
(set! last-match list)))
|
||||||
|
|
||||||
|
(fset 'store-match-data 'set-match-data)
|
42
lang/elisp/primitives/numbers.scm
Normal file
42
lang/elisp/primitives/numbers.scm
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
(define-module (lang elisp primitives numbers)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'logior logior)
|
||||||
|
(fset 'logand logand)
|
||||||
|
(fset 'integerp integer?)
|
||||||
|
(fset '= =)
|
||||||
|
(fset '< <)
|
||||||
|
(fset '> >)
|
||||||
|
(fset '<= <=)
|
||||||
|
(fset '>= >=)
|
||||||
|
(fset '* *)
|
||||||
|
(fset '+ +)
|
||||||
|
(fset '- -)
|
||||||
|
(fset '1- 1-)
|
||||||
|
(fset 'ash ash)
|
||||||
|
|
||||||
|
(fset 'lsh
|
||||||
|
(let ()
|
||||||
|
(define (lsh num shift)
|
||||||
|
(cond ((= shift 0)
|
||||||
|
num)
|
||||||
|
((< shift 0)
|
||||||
|
;; Logical shift to the right. Do an arithmetic
|
||||||
|
;; shift and then mask out the sign bit.
|
||||||
|
(lsh (logand (ash num -1) most-positive-fixnum)
|
||||||
|
(+ shift 1)))
|
||||||
|
(else
|
||||||
|
;; Logical shift to the left. Guile's ash will
|
||||||
|
;; always preserve the sign of the result, which is
|
||||||
|
;; not what we want for lsh, so we need to work
|
||||||
|
;; around this.
|
||||||
|
(let ((new-sign-bit (ash (logand num
|
||||||
|
(logxor most-positive-fixnum
|
||||||
|
(ash most-positive-fixnum -1)))
|
||||||
|
1)))
|
||||||
|
(lsh (logxor new-sign-bit
|
||||||
|
(ash (logand num most-positive-fixnum) 1))
|
||||||
|
(- shift 1))))))
|
||||||
|
lsh))
|
||||||
|
|
||||||
|
(fset 'numberp number?)
|
8
lang/elisp/primitives/pure.scm
Normal file
8
lang/elisp/primitives/pure.scm
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
(define-module (lang elisp primitives pure)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
;; Purification, unexec etc. are not yet implemented...
|
||||||
|
|
||||||
|
(fset 'purecopy identity)
|
||||||
|
|
||||||
|
(define-public purify-flag #f)
|
10
lang/elisp/primitives/read.scm
Normal file
10
lang/elisp/primitives/read.scm
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
(define-module (lang elisp primitives read)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
;;; MEGA HACK!!!!
|
||||||
|
|
||||||
|
(fset 'read (lambda (str)
|
||||||
|
(cond ((string=? str "?\\M-\\^@")
|
||||||
|
-134217728)
|
||||||
|
(else
|
||||||
|
(with-input-from-string str read)))))
|
6
lang/elisp/primitives/signal.scm
Normal file
6
lang/elisp/primitives/signal.scm
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(define-module (lang elisp primitives signal)
|
||||||
|
#:use-module (lang elisp internals signal)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'signal signal)
|
||||||
|
(fset 'error error)
|
31
lang/elisp/primitives/strings.scm
Normal file
31
lang/elisp/primitives/strings.scm
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
(define-module (lang elisp primitives strings)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals signal))
|
||||||
|
|
||||||
|
(fset 'substring substring)
|
||||||
|
|
||||||
|
(fset 'concat
|
||||||
|
(lambda args
|
||||||
|
(apply string-append
|
||||||
|
(map (lambda (arg)
|
||||||
|
(cond
|
||||||
|
((string? arg) arg)
|
||||||
|
((list? arg) (list->string arg))
|
||||||
|
((vector? arg) (list->string (vector->list arg)))
|
||||||
|
(else (error "Wrong type argument for concat"))))
|
||||||
|
args))))
|
||||||
|
|
||||||
|
(fset 'string-to-number string->number)
|
||||||
|
|
||||||
|
(fset 'number-to-string number->string)
|
||||||
|
|
||||||
|
(fset 'string-lessp string<?)
|
||||||
|
(fset 'string< 'string-lessp)
|
||||||
|
|
||||||
|
(fset 'aref
|
||||||
|
(lambda (array idx)
|
||||||
|
(cond ((vector? array) (vector-ref array idx))
|
||||||
|
((string? array) (char->integer (string-ref array idx)))
|
||||||
|
(else (wta 'arrayp array 1)))))
|
||||||
|
|
||||||
|
(fset 'stringp string?)
|
40
lang/elisp/primitives/symprop.scm
Normal file
40
lang/elisp/primitives/symprop.scm
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
(define-module (lang elisp primitives symprop)
|
||||||
|
#:use-module (lang elisp internals set)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:use-module (ice-9 optargs))
|
||||||
|
|
||||||
|
;;; {Elisp Exports}
|
||||||
|
|
||||||
|
(fset 'put set-symbol-property!)
|
||||||
|
|
||||||
|
(fset 'get symbol-property)
|
||||||
|
|
||||||
|
(fset 'set set)
|
||||||
|
|
||||||
|
(fset 'set-default 'set)
|
||||||
|
|
||||||
|
(fset 'boundp
|
||||||
|
(lambda (sym)
|
||||||
|
(module-defined? the-elisp-module sym)))
|
||||||
|
|
||||||
|
(fset 'default-boundp 'boundp)
|
||||||
|
|
||||||
|
(fset 'symbol-value
|
||||||
|
(lambda (sym)
|
||||||
|
(if (module-defined? the-elisp-module sym)
|
||||||
|
(module-ref the-elisp-module sym)
|
||||||
|
(error "Symbol's value as variable is void:" sym))))
|
||||||
|
|
||||||
|
(fset 'default-value 'symbol-value)
|
||||||
|
|
||||||
|
(fset 'symbolp
|
||||||
|
(lambda (object)
|
||||||
|
(or (symbol? object)
|
||||||
|
(keyword? object))))
|
||||||
|
|
||||||
|
(fset 'local-variable-if-set-p
|
||||||
|
(lambda* (variable #:optional buffer)
|
||||||
|
#f))
|
||||||
|
|
||||||
|
(fset 'symbol-name symbol->string)
|
14
lang/elisp/primitives/system.scm
Normal file
14
lang/elisp/primitives/system.scm
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(define-module (lang elisp primitives system)
|
||||||
|
#:use-module (lang elisp internals fset))
|
||||||
|
|
||||||
|
(fset 'system-name
|
||||||
|
(lambda ()
|
||||||
|
(vector-ref (uname) 1)))
|
||||||
|
|
||||||
|
(define-public system-type
|
||||||
|
(let ((uname (vector-ref (uname) 0)))
|
||||||
|
(if (string=? uname "Linux")
|
||||||
|
"gnu/linux"
|
||||||
|
uname)))
|
||||||
|
|
||||||
|
(define-public system-configuration "i386-suse-linux") ;FIXME
|
17
lang/elisp/primitives/time.scm
Normal file
17
lang/elisp/primitives/time.scm
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
(define-module (lang elisp primitives time)
|
||||||
|
#:use-module (lang elisp internals time)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (ice-9 optargs))
|
||||||
|
|
||||||
|
(fset 'current-time
|
||||||
|
(lambda ()
|
||||||
|
(let ((now (current-time)))
|
||||||
|
(list (ash now -16)
|
||||||
|
(logand now (- (ash 1 16) 1))
|
||||||
|
0))))
|
||||||
|
|
||||||
|
(fset 'format-time-string format-time-string)
|
||||||
|
|
||||||
|
(fset 'current-time-string
|
||||||
|
(lambda* (#:optional specified-time)
|
||||||
|
(format-time-string "%a %b %e %T %Y" specified-time)))
|
414
lang/elisp/transform.scm
Normal file
414
lang/elisp/transform.scm
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
(define-module (lang elisp transform)
|
||||||
|
#:use-module (lang elisp internals trace)
|
||||||
|
#:use-module (lang elisp internals fset)
|
||||||
|
#:use-module (lang elisp internals evaluation)
|
||||||
|
#:use-module (ice-9 session)
|
||||||
|
#:export (transformer))
|
||||||
|
|
||||||
|
(define interactive-spec (make-fluid))
|
||||||
|
|
||||||
|
;;; {S-expressions}
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (syntax-error x)
|
||||||
|
(error "Syntax error in expression" x))
|
||||||
|
|
||||||
|
;; Should be made mutating instead of constructing
|
||||||
|
;;
|
||||||
|
(define (transformer x)
|
||||||
|
(cond ((null? x) '())
|
||||||
|
((not (pair? x)) x)
|
||||||
|
((and (pair? (car x))
|
||||||
|
(eq? (caar x) 'quasiquote))
|
||||||
|
(transformer (car x)))
|
||||||
|
((symbol? (car x))
|
||||||
|
(case (car x)
|
||||||
|
((@fop @bind define-module use-modules use-syntax) x)
|
||||||
|
; Escape to Scheme syntax
|
||||||
|
((scheme) (cons 'begin (cdr x)))
|
||||||
|
; Should be handled in reader
|
||||||
|
((quote function) (cons 'quote (cars->nil (cdr x))))
|
||||||
|
((quasiquote) (m-quasiquote x '()))
|
||||||
|
((nil-cond) (transform-1 x))
|
||||||
|
((let) (m-let x '()))
|
||||||
|
((let*) (m-let* x '()))
|
||||||
|
((if) (m-if x '()))
|
||||||
|
((and) (m-and x '()))
|
||||||
|
((or) (m-or x '()))
|
||||||
|
((while) (m-while x '()))
|
||||||
|
;((while) (cons macro-while (cdr x)))
|
||||||
|
((prog1) (m-prog1 x '()))
|
||||||
|
((prog2) (m-prog2 x '()))
|
||||||
|
((progn begin) (cons 'begin (map transformer (cdr x))))
|
||||||
|
((cond) (m-cond x '()))
|
||||||
|
((lambda) (transform-lambda/interactive x '<elisp-lambda>))
|
||||||
|
((defun) (m-defun x '()))
|
||||||
|
((defmacro) (m-defmacro x '()))
|
||||||
|
((setq) (m-setq x '()))
|
||||||
|
((defvar) (m-defvar x '()))
|
||||||
|
((defconst) (m-defconst x '()))
|
||||||
|
((interactive) (fluid-set! interactive-spec x) #f)
|
||||||
|
((unwind-protect) (m-unwind-protect x '()))
|
||||||
|
(else (transform-application x))))
|
||||||
|
(else (syntax-error x))))
|
||||||
|
|
||||||
|
(define (m-unwind-protect exp env)
|
||||||
|
(trc 'unwind-protect (cadr exp))
|
||||||
|
`(let ((%--throw-args #f))
|
||||||
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
,(transformer (cadr exp)))
|
||||||
|
(lambda args
|
||||||
|
(set! %--throw-args args)))
|
||||||
|
,@(transform-list (cddr exp))
|
||||||
|
(if %--throw-args
|
||||||
|
(apply throw %--throw-args))))
|
||||||
|
|
||||||
|
(define (m-quasiquote exp env)
|
||||||
|
(cons 'quasiquote
|
||||||
|
(map transform-inside-qq (cdr exp))))
|
||||||
|
|
||||||
|
(define (transform-inside-qq x)
|
||||||
|
(trc 'transform-inside-qq x)
|
||||||
|
(cond ((not (pair? x)) x)
|
||||||
|
((symbol? (car x))
|
||||||
|
(case (car x)
|
||||||
|
((unquote) (list 'unquote (transformer (cadr x))))
|
||||||
|
((unquote-splicing) (list 'unquote-splicing (transformer (cadr x))))
|
||||||
|
(else (cons (car x) (map transform-inside-qq (cdr x))))))
|
||||||
|
(else
|
||||||
|
(cons (transform-inside-qq (car x)) (transform-inside-qq (cdr x))))))
|
||||||
|
|
||||||
|
(define (transform-1 x)
|
||||||
|
(cons (car x) (map transformer (cdr x))))
|
||||||
|
|
||||||
|
(define (transform-2 x)
|
||||||
|
(cons (car x)
|
||||||
|
(cons (cadr x)
|
||||||
|
(map transformer (cddr x)))))
|
||||||
|
|
||||||
|
(define (transform-3 x)
|
||||||
|
(cons (car x)
|
||||||
|
(cons (cadr x)
|
||||||
|
(cons (caddr x)
|
||||||
|
(map transformer (cdddr x))))))
|
||||||
|
|
||||||
|
(define (transform-list x)
|
||||||
|
(map transformer x))
|
||||||
|
|
||||||
|
;;; Parses a list of elisp formals, e.g. (x y &optional b &rest r) and
|
||||||
|
;;; returns three values: (i) list of symbols for required arguments,
|
||||||
|
;;; (ii) list of symbols for optional arguments, (iii) rest symbol, or
|
||||||
|
;;; #f if there is no rest argument.
|
||||||
|
(define (parse-formals formals)
|
||||||
|
(letrec ((do-required
|
||||||
|
(lambda (required formals)
|
||||||
|
(if (null? formals)
|
||||||
|
(values (reverse required) '() #f)
|
||||||
|
(let ((next-sym (car formals)))
|
||||||
|
(cond ((not (symbol? next-sym))
|
||||||
|
(error "Bad formals (non-symbol in required list)"))
|
||||||
|
((eq? next-sym '&optional)
|
||||||
|
(do-optional required '() (cdr formals)))
|
||||||
|
((eq? next-sym '&rest)
|
||||||
|
(do-rest required '() (cdr formals)))
|
||||||
|
(else
|
||||||
|
(do-required (cons next-sym required)
|
||||||
|
(cdr formals))))))))
|
||||||
|
(do-optional
|
||||||
|
(lambda (required optional formals)
|
||||||
|
(if (null? formals)
|
||||||
|
(values (reverse required) (reverse optional) #f)
|
||||||
|
(let ((next-sym (car formals)))
|
||||||
|
(cond ((not (symbol? next-sym))
|
||||||
|
(error "Bad formals (non-symbol in optional list)"))
|
||||||
|
((eq? next-sym '&rest)
|
||||||
|
(do-rest required optional (cdr formals)))
|
||||||
|
(else
|
||||||
|
(do-optional required
|
||||||
|
(cons next-sym optional)
|
||||||
|
(cdr formals))))))))
|
||||||
|
(do-rest
|
||||||
|
(lambda (required optional formals)
|
||||||
|
(if (= (length formals) 1)
|
||||||
|
(let ((next-sym (car formals)))
|
||||||
|
(if (symbol? next-sym)
|
||||||
|
(values (reverse required) (reverse optional) next-sym)
|
||||||
|
(error "Bad formals (non-symbol rest formal)")))
|
||||||
|
(error "Bad formals (more than one rest formal)")))))
|
||||||
|
|
||||||
|
(do-required '() (cond ((list? formals)
|
||||||
|
formals)
|
||||||
|
((symbol? formals)
|
||||||
|
(list '&rest formals))
|
||||||
|
(else
|
||||||
|
(error "Bad formals (not a list or a single symbol)"))))))
|
||||||
|
|
||||||
|
(define (transform-lambda/interactive exp name)
|
||||||
|
(fluid-set! interactive-spec #f)
|
||||||
|
(let* ((x (transform-lambda exp))
|
||||||
|
(is (fluid-ref interactive-spec)))
|
||||||
|
`(let ((%--lambda ,x))
|
||||||
|
(set-procedure-property! %--lambda 'name ',name)
|
||||||
|
(set! (,not-subr? %--lambda) #t)
|
||||||
|
,@(if is
|
||||||
|
`((set! (,interactive-specification %--lambda) ',is))
|
||||||
|
'())
|
||||||
|
%--lambda)))
|
||||||
|
|
||||||
|
(define (transform-lambda exp)
|
||||||
|
(call-with-values (lambda () (parse-formals (cadr exp)))
|
||||||
|
(lambda (required optional rest)
|
||||||
|
(let ((num-required (length required))
|
||||||
|
(num-optional (length optional)))
|
||||||
|
`(lambda %--args
|
||||||
|
(let ((%--num-args (length %--args)))
|
||||||
|
(cond ((< %--num-args ,num-required)
|
||||||
|
(error "Wrong number of args (not enough required args)"))
|
||||||
|
,@(if rest
|
||||||
|
'()
|
||||||
|
`(((> %--num-args ,(+ num-required num-optional))
|
||||||
|
(error "Wrong number of args (too many args)"))))
|
||||||
|
(else
|
||||||
|
(@bind ,(append (map (lambda (i)
|
||||||
|
(list (list-ref required i)
|
||||||
|
`(list-ref %--args ,i)))
|
||||||
|
(iota num-required))
|
||||||
|
(map (lambda (i)
|
||||||
|
(let ((i+nr (+ i num-required)))
|
||||||
|
(list (list-ref optional i)
|
||||||
|
`(if (> %--num-args ,i+nr)
|
||||||
|
(list-ref %--args ,i+nr)
|
||||||
|
#f))))
|
||||||
|
(iota num-optional))
|
||||||
|
(if rest
|
||||||
|
(list (list rest
|
||||||
|
`(if (> %--num-args
|
||||||
|
,(+ num-required
|
||||||
|
num-optional))
|
||||||
|
(list-tail %--args
|
||||||
|
,(+ num-required
|
||||||
|
num-optional))
|
||||||
|
'())))
|
||||||
|
'()))
|
||||||
|
,@(transform-list (cddr exp)))))))
|
||||||
|
))))
|
||||||
|
|
||||||
|
(define (m-defun exp env)
|
||||||
|
(trc 'defun (cadr exp))
|
||||||
|
`(begin (,fset ',(cadr exp)
|
||||||
|
,(transform-lambda/interactive (cdr exp)
|
||||||
|
(symbol-append '<elisp-defun:
|
||||||
|
(cadr exp)
|
||||||
|
'>)))
|
||||||
|
',(cadr exp)))
|
||||||
|
|
||||||
|
(define (m-defmacro exp env)
|
||||||
|
(trc 'defmacro (cadr exp))
|
||||||
|
(call-with-values (lambda () (parse-formals (caddr exp)))
|
||||||
|
(lambda (required optional rest)
|
||||||
|
(let ((num-required (length required))
|
||||||
|
(num-optional (length optional)))
|
||||||
|
`(begin (,fset ',(cadr exp)
|
||||||
|
(procedure->memoizing-macro
|
||||||
|
(lambda (exp1 env1)
|
||||||
|
(,trc 'using ',(cadr exp))
|
||||||
|
(let* ((%--args (cdr exp1))
|
||||||
|
(%--num-args (length %--args)))
|
||||||
|
(cond ((< %--num-args ,num-required)
|
||||||
|
(error "Wrong number of args (not enough required args)"))
|
||||||
|
,@(if rest
|
||||||
|
'()
|
||||||
|
`(((> %--num-args ,(+ num-required num-optional))
|
||||||
|
(error "Wrong number of args (too many args)"))))
|
||||||
|
(else (,transformer
|
||||||
|
(@bind ,(append (map (lambda (i)
|
||||||
|
(list (list-ref required i)
|
||||||
|
`(list-ref %--args ,i)))
|
||||||
|
(iota num-required))
|
||||||
|
(map (lambda (i)
|
||||||
|
(let ((i+nr (+ i num-required)))
|
||||||
|
(list (list-ref optional i)
|
||||||
|
`(if (> %--num-args ,i+nr)
|
||||||
|
(list-ref %--args ,i+nr)
|
||||||
|
#f))))
|
||||||
|
(iota num-optional))
|
||||||
|
(if rest
|
||||||
|
(list (list rest
|
||||||
|
`(if (> %--num-args
|
||||||
|
,(+ num-required
|
||||||
|
num-optional))
|
||||||
|
(list-tail %--args
|
||||||
|
,(+ num-required
|
||||||
|
num-optional))
|
||||||
|
'())))
|
||||||
|
'()))
|
||||||
|
,@(transform-list (cdddr exp)))))))))))))))
|
||||||
|
|
||||||
|
(define (transform-application x)
|
||||||
|
`(@fop ,(car x)
|
||||||
|
(,transformer-macro ,@(cdr x))))
|
||||||
|
|
||||||
|
(define transformer-macro
|
||||||
|
(procedure->memoizing-macro
|
||||||
|
(lambda (exp env)
|
||||||
|
(cons 'list (map transformer (cdr exp))))))
|
||||||
|
|
||||||
|
; (cons '@fop
|
||||||
|
; (cons (car x)
|
||||||
|
; (map transformer (cdr x)))))
|
||||||
|
|
||||||
|
(define (cars->nil ls)
|
||||||
|
(cond ((not (pair? ls)) ls)
|
||||||
|
((null? (car ls)) (cons '() (cars->nil (cdr ls))))
|
||||||
|
(else (cons (cars->nil (car ls))
|
||||||
|
(cars->nil (cdr ls))))))
|
||||||
|
|
||||||
|
;;; {Special forms}
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (m-setq exp env)
|
||||||
|
(cons 'begin
|
||||||
|
(let loop ((sets (cdr exp)) (last-sym #f))
|
||||||
|
(if (null? sets)
|
||||||
|
(list last-sym)
|
||||||
|
(cons `(module-define! ,the-elisp-module
|
||||||
|
',(car sets)
|
||||||
|
,(transformer (cadr sets)))
|
||||||
|
(loop (cddr sets) (car sets)))))))
|
||||||
|
|
||||||
|
;(define (m-setq exp env)
|
||||||
|
; (let* ((binder (car (last-pair env)))
|
||||||
|
; (varvals (let loop ((ls (cdr exp)))
|
||||||
|
; (if (null? ls)
|
||||||
|
; '()
|
||||||
|
; ;; Ensure existence only at macro expansion time
|
||||||
|
; (let ((var (or (binder (car ls) #f)
|
||||||
|
; (binder (car ls) #t))))
|
||||||
|
; (if (not (variable-bound? var))
|
||||||
|
; (variable-set! var #f))
|
||||||
|
; (cons (list 'set! (car ls) (transformer (cadr ls)))
|
||||||
|
; (loop (cddr ls))))))))
|
||||||
|
; (cond ((null? varvals) '())
|
||||||
|
; ((null? (cdr varvals)) (car varvals))
|
||||||
|
; (else (cons 'begin varvals)))))
|
||||||
|
|
||||||
|
(define (m-let exp env)
|
||||||
|
`(@bind ,(map (lambda (binding)
|
||||||
|
(trc 'let binding)
|
||||||
|
(if (pair? binding)
|
||||||
|
`(,(car binding) ,(transformer (cadr binding)))
|
||||||
|
`(,binding #f)))
|
||||||
|
(cadr exp))
|
||||||
|
,@(transform-list (cddr exp))))
|
||||||
|
|
||||||
|
(define (m-let* exp env)
|
||||||
|
(if (null? (cadr exp))
|
||||||
|
`(begin ,@(transform-list (cddr exp)))
|
||||||
|
(car (let loop ((bindings (cadr exp)))
|
||||||
|
(if (null? bindings)
|
||||||
|
(transform-list (cddr exp))
|
||||||
|
`((@bind (,(let ((binding (car bindings)))
|
||||||
|
(if (pair? binding)
|
||||||
|
`(,(car binding) ,(transformer (cadr binding)))
|
||||||
|
`(,binding #f))))
|
||||||
|
,@(loop (cdr bindings)))))))))
|
||||||
|
|
||||||
|
(define (m-prog1 exp env)
|
||||||
|
`(,let ((%res1 ,(transformer (cadr exp))))
|
||||||
|
,@(transform-list (cddr exp))
|
||||||
|
%res1))
|
||||||
|
|
||||||
|
(define (m-prog2 exp env)
|
||||||
|
`(begin ,(transformer (cadr exp))
|
||||||
|
(,let ((%res2 ,(transformer (caddr exp))))
|
||||||
|
,@(transform-list (cdddr exp))
|
||||||
|
%res2)))
|
||||||
|
|
||||||
|
(define <-- *unspecified*)
|
||||||
|
|
||||||
|
(define (m-if exp env)
|
||||||
|
(let ((else-case (cdddr exp)))
|
||||||
|
(cond ((null? else-case)
|
||||||
|
`(nil-cond ,(transformer (cadr exp)) ,(transformer (caddr exp)) #f))
|
||||||
|
((null? (cdr else-case))
|
||||||
|
`(nil-cond ,(transformer (cadr exp))
|
||||||
|
,(transformer (caddr exp))
|
||||||
|
,(transformer (car else-case))))
|
||||||
|
(else
|
||||||
|
`(nil-cond ,(transformer (cadr exp))
|
||||||
|
,(transformer (caddr exp))
|
||||||
|
(begin ,@(transform-list else-case)))))))
|
||||||
|
|
||||||
|
(define (m-and exp env)
|
||||||
|
(cond ((null? (cdr exp)) #t)
|
||||||
|
((null? (cddr exp)) (transformer (cadr exp)))
|
||||||
|
(else
|
||||||
|
(cons 'nil-cond
|
||||||
|
(let loop ((args (cdr exp)))
|
||||||
|
(if (null? (cdr args))
|
||||||
|
(list (transformer (car args)))
|
||||||
|
(cons (list 'not (transformer (car args)))
|
||||||
|
(cons #f
|
||||||
|
(loop (cdr args))))))))))
|
||||||
|
|
||||||
|
(define (m-or exp env)
|
||||||
|
(cond ((null? (cdr exp)) #f)
|
||||||
|
((null? (cddr exp)) (transformer (cadr exp)))
|
||||||
|
(else
|
||||||
|
(cons 'nil-cond
|
||||||
|
(let loop ((args (cdr exp)))
|
||||||
|
(if (null? (cdr args))
|
||||||
|
(list (transformer (car args)))
|
||||||
|
(cons (transformer (car args))
|
||||||
|
(cons <--
|
||||||
|
(loop (cdr args))))))))))
|
||||||
|
|
||||||
|
(define m-cond
|
||||||
|
(lambda (exp env)
|
||||||
|
(if (null? (cdr exp))
|
||||||
|
#f
|
||||||
|
(cons
|
||||||
|
'nil-cond
|
||||||
|
(let loop ((clauses (cdr exp)))
|
||||||
|
(if (null? clauses)
|
||||||
|
'(#f)
|
||||||
|
(let ((clause (car clauses)))
|
||||||
|
(if (eq? (car clause) #t)
|
||||||
|
(cond ((null? (cdr clause)) '(t))
|
||||||
|
((null? (cddr clause))
|
||||||
|
(list (transformer (cadr clause))))
|
||||||
|
(else `((begin ,@(transform-list (cdr clause))))))
|
||||||
|
(cons (transformer (car clause))
|
||||||
|
(cons (cond ((null? (cdr clause)) <--)
|
||||||
|
((null? (cddr clause))
|
||||||
|
(transformer (cadr clause)))
|
||||||
|
(else
|
||||||
|
`(begin ,@(transform-list (cdr clause)))))
|
||||||
|
(loop (cdr clauses))))))))))))
|
||||||
|
|
||||||
|
(define (m-while exp env)
|
||||||
|
`(,let %while ()
|
||||||
|
(nil-cond ,(transformer (cadr exp))
|
||||||
|
(begin ,@(transform-list (cddr exp)) (%while))
|
||||||
|
#f)))
|
||||||
|
|
||||||
|
(define (m-defvar exp env)
|
||||||
|
(trc 'defvar (cadr exp))
|
||||||
|
(if (null? (cddr exp))
|
||||||
|
`',(cadr exp)
|
||||||
|
`(begin (if (not (defined? ',(cadr exp)))
|
||||||
|
(,macro-setq ,(cadr exp) ,(caddr exp)))
|
||||||
|
',(cadr exp))))
|
||||||
|
|
||||||
|
(define (m-defconst exp env)
|
||||||
|
(trc 'defconst (cadr exp))
|
||||||
|
`(begin ,(m-setq (list (car exp) (cadr exp) (caddr exp)) env)
|
||||||
|
',(cadr exp)))
|
||||||
|
|
||||||
|
;(export-mmacros
|
||||||
|
; '(setq defun let let* if and or cond while prog1 prog2 progn)
|
||||||
|
; (list m-setq m-defun m-let m-let* m-if m-and m-or m-cond m-while m-prog1 m-prog2 begin))
|
||||||
|
|
||||||
|
(define macro-setq (procedure->memoizing-macro m-setq))
|
||||||
|
(define macro-while (procedure->memoizing-macro m-while))
|
42
lang/elisp/variables.scm
Normal file
42
lang/elisp/variables.scm
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
(define-module (lang elisp variables))
|
||||||
|
|
||||||
|
;;; The only purpose of this module is to provide a place where the
|
||||||
|
;;; variables holding Elisp function definitions can be bound to
|
||||||
|
;;; symbols.
|
||||||
|
;;;
|
||||||
|
;;; This can be useful when looking at unmemoized procedure source
|
||||||
|
;;; code for Elisp functions and macros. Elisp function and macro
|
||||||
|
;;; symbols get memoized into variables. When the unmemoizer tries to
|
||||||
|
;;; unmemoize a variables, it does so by looking for a symbol that is
|
||||||
|
;;; bound to that variable, starting from the module in which the
|
||||||
|
;;; function or macro was defined and then trying the interfaces on
|
||||||
|
;;; that module's uses list. If it can't find any such symbol, it
|
||||||
|
;;; returns the symbol '???.
|
||||||
|
;;;
|
||||||
|
;;; Normally we don't want to bind Elisp function definition variables
|
||||||
|
;;; to symbols that are visible from the Elisp evaluation module (lang
|
||||||
|
;;; elisp base), because they would pollute the namespace available
|
||||||
|
;;; to Elisp variables. On the other hand, if we are trying to debug
|
||||||
|
;;; something, and looking at unmemoized source code, it's far more
|
||||||
|
;;; informative if that code has symbols that indicate the Elisp
|
||||||
|
;;; function being called than if it just says ??? everywhere.
|
||||||
|
;;;
|
||||||
|
;;; So we have a compromise, which achieves a reasonable balance of
|
||||||
|
;;; correctness (for general operation) and convenience (for
|
||||||
|
;;; debugging).
|
||||||
|
;;;
|
||||||
|
;;; 1. We bind Elisp function definition variables to symbols in this
|
||||||
|
;;; module (lang elisp variables).
|
||||||
|
;;;
|
||||||
|
;;; 2. By default, the Elisp evaluation module (lang elisp base) does
|
||||||
|
;;; not use (lang elisp variables), so the Elisp variable namespace
|
||||||
|
;;; stays clean.
|
||||||
|
;;;
|
||||||
|
;;; 3. When debugging, a simple (named-module-use! '(lang elisp base)
|
||||||
|
;;; '(lang elisp variables)) makes the function definition symbols
|
||||||
|
;;; visible in (lang elisp base) so that the unmemoizer can find
|
||||||
|
;;; them, which makes the unmemoized source code much easier to read.
|
||||||
|
;;;
|
||||||
|
;;; 4. To reduce the effects of namespace pollution even after step 3,
|
||||||
|
;;; the symbols that we bind are all prefixed with `<elisp' and
|
||||||
|
;;; suffixed with `>'.
|
|
@ -5,6 +5,7 @@ SCM_TESTS = tests/alist.test \
|
||||||
tests/c-api.test \
|
tests/c-api.test \
|
||||||
tests/chars.test \
|
tests/chars.test \
|
||||||
tests/common-list.test \
|
tests/common-list.test \
|
||||||
|
tests/elisp.test \
|
||||||
tests/environments.test \
|
tests/environments.test \
|
||||||
tests/eval.test \
|
tests/eval.test \
|
||||||
tests/exceptions.test \
|
tests/exceptions.test \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue