mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Merge remote-tracking branch 'origin/stable-2.0'
Conflicts: configure.ac libguile/fluids.c libguile/gc.c libguile/gc.h libguile/objcodes.c libguile/procprop.c libguile/vm.c module/ice-9/psyntax-pp.scm module/ice-9/psyntax.scm
This commit is contained in:
commit
b2208d2e98
54 changed files with 10211 additions and 9681 deletions
23
README
23
README
|
@ -239,25 +239,28 @@ switches specific to Guile you may find useful in some circumstances.
|
|||
|
||||
Cross building Guile =====================================================
|
||||
|
||||
As of guile-1.5.x, the build process uses compiled C files for
|
||||
snarfing, and (indirectly, through libtool) for linking, and uses the
|
||||
guile executable for generating documentation.
|
||||
As of Guile 2.0.x, the build process produces a library, libguile-2.0,
|
||||
along with Guile "object files" containing bytecode to be interpreted by
|
||||
Guile's virtual machine. The bytecode format depends on the endianness
|
||||
and word size of the host CPU.
|
||||
|
||||
When cross building guile, you first need to configure, build and
|
||||
install guile for your build host.
|
||||
Thus, when cross building Guile, you first need to configure, build and
|
||||
install it for your build host.
|
||||
|
||||
Then, you may configure guile for cross building, eg:
|
||||
Then, you may configure Guile for cross building:
|
||||
|
||||
./configure --host=i686-pc-cygwin --disable-shared
|
||||
|
||||
A C compiler for the build system is required. The default is
|
||||
"PATH=/usr/bin:$PATH cc". If that doesn't suit it can be specified
|
||||
with the CC_FOR_BUILD variable in the usual way, for instance
|
||||
A C compiler for the build system is required. If that doesn't suit it
|
||||
can be specified with the CC_FOR_BUILD variable in the usual way, for
|
||||
instance:
|
||||
|
||||
./configure --host=m68k-unknown-linux-gnu CC_FOR_BUILD=/my/local/gcc
|
||||
|
||||
Guile for the build system can be specified similarly with the
|
||||
GUILE_FOR_BUILD variable, it defaults to just "guile".
|
||||
GUILE_FOR_BUILD variable, which defaults to whatever `guile' executable
|
||||
is found in $PATH. It must have the exact same version has the Guile
|
||||
that you intend to cross-build.
|
||||
|
||||
|
||||
Using Guile Without Installing It =========================================
|
||||
|
|
50
acinclude.m4
50
acinclude.m4
|
@ -530,6 +530,56 @@ AC_DEFUN([GUILE_UNISTRING_ICONVEH_VALUES], [
|
|||
GUILE_UNISTRING_CONSTANT([iconveh_escape_sequence])
|
||||
])
|
||||
|
||||
dnl GUILE_CHECK_VERSION
|
||||
dnl
|
||||
dnl Ensure that $GUILE_FOR_BUILD has the same version as ourselves.
|
||||
AC_DEFUN([GUILE_CHECK_VERSION], [
|
||||
if ! "$GUILE_FOR_BUILD" --version > /dev/null 2>&1; then
|
||||
AC_MSG_ERROR([failed to run `$GUILE_FOR_BUILD'])
|
||||
fi
|
||||
|
||||
dnl Use MAJOR.MINOR.MICRO instead of (version) so that developers can
|
||||
dnl freely shoot themselves in the foot by using, say, 2.0.3.80 and
|
||||
dnl 2.0.3.42.
|
||||
AC_CACHE_CHECK([the version of $GUILE_FOR_BUILD],
|
||||
[ac_cv_guile_for_build_version],
|
||||
[ac_cv_guile_for_build_version="`"$GUILE_FOR_BUILD" \
|
||||
-c '(format #t "~a.~a.~a" (major-version) (minor-version) (micro-version))'`"
|
||||
])
|
||||
|
||||
if test "$ac_cv_guile_for_build_version" != \
|
||||
"$GUILE_MAJOR_VERSION.$GUILE_MINOR_VERSION.$GUILE_MICRO_VERSION"
|
||||
then
|
||||
AC_MSG_ERROR([building Guile $PACKAGE_VERSION but `$GUILE_FOR_BUILD' has version $ac_cv_guile_for_build_version"])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl GUILE_CHECK_GUILE_FOR_BUILD
|
||||
dnl
|
||||
dnl When cross-compiling, ensure that $GUILE_FOR_BUILD is suitable.
|
||||
AC_DEFUN([GUILE_CHECK_GUILE_FOR_BUILD], [
|
||||
if test "$cross_compiling" = "yes"; then
|
||||
if test "x$GUILE_FOR_BUILD" = "x"; then
|
||||
AC_PATH_PROG([GUILE_FOR_BUILD], [guile], [not-found])
|
||||
if test "$GUILE_FOR_BUILD" = "not-found"; then
|
||||
AC_MSG_ERROR([a native Guile $PACKAGE_VERSION is required to cross-build Guile])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_CHECKING([guile for build])
|
||||
AC_MSG_RESULT([$GUILE_FOR_BUILD])
|
||||
|
||||
dnl Since there is currently no distinction between the run-time
|
||||
dnl search path, %load-path, and the compiler's search path,
|
||||
dnl $GUILE_FOR_BUILD must be a native build of the very same version.
|
||||
GUILE_CHECK_VERSION
|
||||
else
|
||||
GUILE_FOR_BUILD='this-value-will-never-be-used'
|
||||
fi
|
||||
|
||||
AC_ARG_VAR([GUILE_FOR_BUILD], [guile for the build system])
|
||||
AM_SUBST_NOTMAKE([GUILE_FOR_BUILD])
|
||||
])
|
||||
|
||||
dnl Declare file $1 to be a script that needs configuring,
|
||||
dnl and arrange to make it executable in the process.
|
||||
AC_DEFUN([GUILE_CONFIG_SCRIPT],[AC_CONFIG_FILES([$1],[chmod +x $1])])
|
||||
|
|
|
@ -26,6 +26,9 @@ AM_V_GUILEC_0 = @echo " GUILEC" $@;
|
|||
|
||||
SUFFIXES = .scm .go
|
||||
.scm.go:
|
||||
$(AM_V_GUILEC)GUILE_AUTO_COMPILE=0 \
|
||||
$(AM_V_GUILEC)GUILE_AUTO_COMPILE=0 \
|
||||
$(top_builddir)/meta/uninstalled-env \
|
||||
guild compile $(GUILE_WARNINGS) -o "$@" "$<"
|
||||
guild compile --target="$(host)" $(GUILE_WARNINGS) \
|
||||
-L "$(abs_srcdir)" -L "$(abs_builddir)" \
|
||||
-L "$(abs_top_srcdir)/guile-readline" \
|
||||
-o "$@" "$<"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;;;; benchmark-suite/lib.scm --- generic support for benchmarking
|
||||
;;;; Copyright (C) 2002, 2006 Free Software Foundation, Inc.
|
||||
;;;; Copyright (C) 2002, 2006, 2011 Free Software Foundation, Inc.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -348,8 +348,7 @@
|
|||
(append (current-benchmark-prefix) (list name)))
|
||||
|
||||
;;; A fluid containing the current benchmark prefix, as a list.
|
||||
(define prefix-fluid (make-fluid))
|
||||
(fluid-set! prefix-fluid '())
|
||||
(define prefix-fluid (make-fluid '()))
|
||||
(define (current-benchmark-prefix)
|
||||
(fluid-ref prefix-fluid))
|
||||
|
||||
|
|
17
configure.ac
17
configure.ac
|
@ -1259,7 +1259,7 @@ save_LIBS="$LIBS"
|
|||
LIBS="$BDW_GC_LIBS $LIBS"
|
||||
CFLAGS="$BDW_GC_CFLAGS $CFLAGS"
|
||||
|
||||
AC_CHECK_FUNCS([GC_do_blocking GC_call_with_gc_active GC_pthread_exit GC_pthread_cancel GC_allow_register_threads GC_pthread_sigmask GC_set_start_callback GC_get_suspend_signal GC_move_disappearing_link])
|
||||
AC_CHECK_FUNCS([GC_do_blocking GC_call_with_gc_active GC_pthread_exit GC_pthread_cancel GC_allow_register_threads GC_pthread_sigmask GC_set_start_callback GC_get_suspend_signal GC_move_disappearing_link GC_get_heap_usage_safe GC_get_free_space_divisor])
|
||||
|
||||
# Though the `GC_do_blocking ()' symbol is present in GC 7.1, it is not
|
||||
# declared, and has a different type (returning void instead of
|
||||
|
@ -1511,20 +1511,7 @@ AC_SUBST(CCLD_FOR_BUILD)
|
|||
HOST_CC="$CC_FOR_BUILD"
|
||||
AC_SUBST(HOST_CC)
|
||||
|
||||
if test "$cross_compiling" = "yes"; then
|
||||
AC_MSG_CHECKING(guile for build)
|
||||
GUILE_FOR_BUILD="${GUILE_FOR_BUILD-guile}"
|
||||
else
|
||||
GUILE_FOR_BUILD='this-value-will-never-be-used'
|
||||
fi
|
||||
|
||||
## AC_MSG_CHECKING("if we are cross compiling")
|
||||
## AC_MSG_RESULT($cross_compiling)
|
||||
if test "$cross_compiling" = "yes"; then
|
||||
AC_MSG_RESULT($GUILE_FOR_BUILD)
|
||||
fi
|
||||
AC_ARG_VAR(GUILE_FOR_BUILD,[guile for build system])
|
||||
AM_SUBST_NOTMAKE(GUILE_FOR_BUILD)
|
||||
GUILE_CHECK_GUILE_FOR_BUILD
|
||||
|
||||
## If we're using GCC, ask for aggressive warnings.
|
||||
GCC_CFLAGS=""
|
||||
|
|
|
@ -4546,7 +4546,8 @@ Fill bytevector @var{bv} with @var{fill}, a byte.
|
|||
@deffnx {C Function} scm_bytevector_copy_x (source, source_start, target, target_start, len)
|
||||
Copy @var{len} bytes from @var{source} into @var{target}, starting
|
||||
reading from @var{source-start} (a positive index within @var{source})
|
||||
and start writing at @var{target-start}.
|
||||
and start writing at @var{target-start}. It is permitted for the
|
||||
@var{source} and @var{target} regions to overlap.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} bytevector-copy bv
|
||||
|
|
|
@ -640,6 +640,13 @@ Use @var{lang} as the source language of @var{file}. If this option is omitted,
|
|||
Use @var{lang} as the target language of @var{file}. If this option is omitted,
|
||||
@code{objcode} is assumed.
|
||||
|
||||
@item -T @var{target}
|
||||
@itemx --target=@var{target}
|
||||
Produce bytecode for @var{target} instead of @var{%host-type}
|
||||
(@pxref{Build Config, %host-type}). Target must be a valid GNU triplet,
|
||||
such as @code{armv5tel-unknown-linux-gnueabi} (@pxref{Specifying Target
|
||||
Triplets,,, autoconf, GNU Autoconf Manual}).
|
||||
|
||||
@end table
|
||||
|
||||
Each @var{file} is assumed to be UTF-8-encoded, unless it contains a
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@c -*-texinfo-*-
|
||||
@c This is part of the GNU Guile Reference Manual.
|
||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2010
|
||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2010, 2011
|
||||
@c Free Software Foundation, Inc.
|
||||
@c See the file guile.texi for copying conditions.
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
|||
@chapter Introduction
|
||||
|
||||
Guile is an implementation of the Scheme programming language. Scheme
|
||||
(@url{schemers.org}) is an elegant and conceptually simple dialect of
|
||||
Lisp, originated by Guy Steele and Gerald Sussman, and since evolved
|
||||
by the series of reports known as RnRS (the
|
||||
(@url{http://schemers.org/}) is an elegant and conceptually simple
|
||||
dialect of Lisp, originated by Guy Steele and Gerald Sussman, and since
|
||||
evolved by the series of reports known as RnRS (the
|
||||
@tex
|
||||
Revised$^n$
|
||||
@end tex
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@c -*-texinfo-*-
|
||||
@c This is part of the GNU Guile Reference Manual.
|
||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004
|
||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2011
|
||||
@c Free Software Foundation, Inc.
|
||||
@c See the file guile.texi for copying conditions.
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
|||
@itemize @bullet
|
||||
|
||||
@item
|
||||
The website @url{http://www.schemers.org} is a good starting point for
|
||||
The website @url{http://www.schemers.org/} is a good starting point for
|
||||
all things Scheme.
|
||||
|
||||
@item
|
||||
|
|
|
@ -16,7 +16,7 @@ Guile has support for a number of SRFIs. This chapter gives an overview
|
|||
over the available SRFIs and some usage hints. For complete
|
||||
documentation, design rationales and further examples, we advise you to
|
||||
get the relevant SRFI documents from the SRFI home page
|
||||
@url{http://srfi.schemers.org}.
|
||||
@url{http://srfi.schemers.org/}.
|
||||
|
||||
@menu
|
||||
* About SRFI Usage:: What to know about Guile's SRFI support.
|
||||
|
|
|
@ -847,7 +847,7 @@ indicating any etag, or a list of entity tags.
|
|||
Indicates that a response should proceed if and only if the resource has
|
||||
been modified since the given date.
|
||||
@example
|
||||
(parse-header if-modified-since "Tue, 15 Nov 1994 08:12:31 GMT")
|
||||
(parse-header 'if-modified-since "Tue, 15 Nov 1994 08:12:31 GMT")
|
||||
@result{} #<date ...>
|
||||
@end example
|
||||
@end deftypevr
|
||||
|
|
|
@ -596,9 +596,9 @@ SCM_DEFINE (scm_bytevector_copy_x, "bytevector-copy!", 5, 0, 0,
|
|||
if (SCM_UNLIKELY (c_target_start + c_len > c_target_len))
|
||||
scm_out_of_range (FUNC_NAME, target_start);
|
||||
|
||||
memcpy (c_target + c_target_start,
|
||||
c_source + c_source_start,
|
||||
c_len);
|
||||
memmove (c_target + c_target_start,
|
||||
c_source + c_source_start,
|
||||
c_len);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ grow_dynamic_state (SCM state)
|
|||
/* Assume the assignment below is atomic. */
|
||||
len = allocated_fluids_len;
|
||||
|
||||
new_fluids = scm_c_make_vector (len, SCM_BOOL_F);
|
||||
new_fluids = scm_c_make_vector (len, SCM_UNDEFINED);
|
||||
|
||||
for (i = 0; i < old_len; i++)
|
||||
SCM_SIMPLE_VECTOR_SET (new_fluids, i,
|
||||
|
@ -103,14 +103,14 @@ scm_i_with_fluids_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
|
|||
|
||||
/* Return a new fluid. */
|
||||
static SCM
|
||||
new_fluid ()
|
||||
new_fluid (SCM init)
|
||||
{
|
||||
SCM fluid;
|
||||
size_t trial, n;
|
||||
|
||||
/* Fluids are pointerless cells: the first word is the type tag; the second
|
||||
word is the fluid number. */
|
||||
fluid = SCM_PACK_POINTER (scm_gc_malloc_pointerless (sizeof (scm_t_cell), "fluid"));
|
||||
/* Fluids hold the type tag and the fluid number in the first word,
|
||||
and the default value in the second word. */
|
||||
fluid = scm_cell (scm_tc7_fluid, SCM_UNPACK (init));
|
||||
SCM_SET_CELL_TYPE (fluid, scm_tc7_fluid);
|
||||
|
||||
scm_dynwind_begin (0);
|
||||
|
@ -157,7 +157,7 @@ new_fluid ()
|
|||
}
|
||||
|
||||
allocated_fluids[n] = SCM_UNPACK_POINTER (fluid);
|
||||
SCM_SET_CELL_WORD_1 (fluid, (scm_t_bits) n);
|
||||
SCM_SET_CELL_WORD_0 (fluid, (scm_tc7_fluid | (n << 8)));
|
||||
|
||||
GC_GENERAL_REGISTER_DISAPPEARING_LINK (&allocated_fluids[n],
|
||||
SCM_HEAP_OBJECT_BASE (fluid));
|
||||
|
@ -166,13 +166,19 @@ new_fluid ()
|
|||
|
||||
/* Now null out values. We could (and probably should) do this when
|
||||
the fluid is collected instead of now. */
|
||||
scm_i_reset_fluid (n, SCM_BOOL_F);
|
||||
scm_i_reset_fluid (n);
|
||||
|
||||
return fluid;
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_make_fluid, "make-fluid", 0, 0, 0,
|
||||
(),
|
||||
SCM
|
||||
scm_make_fluid (void)
|
||||
{
|
||||
return new_fluid (SCM_BOOL_F);
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_make_fluid_with_default, "make-fluid", 0, 1, 0,
|
||||
(SCM dflt),
|
||||
"Return a newly created fluid.\n"
|
||||
"Fluids are objects that can hold one\n"
|
||||
"value per dynamic state. That is, modifications to this value are\n"
|
||||
|
@ -180,9 +186,9 @@ SCM_DEFINE (scm_make_fluid, "make-fluid", 0, 0, 0,
|
|||
"the modifying code. When a new dynamic state is constructed, it\n"
|
||||
"inherits the values from its parent. Because each thread normally executes\n"
|
||||
"with its own dynamic state, you can use fluids for thread local storage.")
|
||||
#define FUNC_NAME s_scm_make_fluid
|
||||
#define FUNC_NAME s_scm_make_fluid_with_default
|
||||
{
|
||||
return new_fluid ();
|
||||
return new_fluid (SCM_UNBNDP (dflt) ? SCM_BOOL_F : dflt);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
@ -191,9 +197,7 @@ SCM_DEFINE (scm_make_unbound_fluid, "make-unbound-fluid", 0, 0, 0,
|
|||
"Make a fluid that is initially unbound.")
|
||||
#define FUNC_NAME s_scm_make_unbound_fluid
|
||||
{
|
||||
SCM f = new_fluid ();
|
||||
scm_fluid_set_x (f, SCM_UNDEFINED);
|
||||
return f;
|
||||
return new_fluid (SCM_UNDEFINED);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
@ -217,6 +221,7 @@ scm_is_fluid (SCM obj)
|
|||
static SCM
|
||||
fluid_ref (SCM fluid)
|
||||
{
|
||||
SCM ret;
|
||||
SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
|
||||
|
||||
if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
|
||||
|
@ -227,7 +232,11 @@ fluid_ref (SCM fluid)
|
|||
fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
|
||||
}
|
||||
|
||||
return SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
|
||||
ret = SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
|
||||
if (SCM_UNBNDP (ret))
|
||||
return SCM_I_FLUID_DEFAULT (fluid);
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
|
||||
|
@ -274,6 +283,9 @@ SCM_DEFINE (scm_fluid_unset_x, "fluid-unset!", 1, 0, 0,
|
|||
"Unset the value associated with @var{fluid}.")
|
||||
#define FUNC_NAME s_scm_fluid_unset_x
|
||||
{
|
||||
/* FIXME: really unset the default value, too? The current test
|
||||
suite demands it, but I would prefer not to. */
|
||||
SCM_SET_CELL_OBJECT_1 (fluid, SCM_UNDEFINED);
|
||||
return scm_fluid_set_x (fluid, SCM_UNDEFINED);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
|
|
@ -56,10 +56,12 @@
|
|||
|
||||
#define SCM_FLUID_P(x) (SCM_HAS_TYP7 (x, scm_tc7_fluid))
|
||||
#ifdef BUILDING_LIBGUILE
|
||||
#define SCM_I_FLUID_NUM(x) ((size_t)SCM_CELL_WORD_1(x))
|
||||
#define SCM_I_FLUID_NUM(x) ((size_t)(SCM_CELL_WORD_0 (x) >> 8))
|
||||
#define SCM_I_FLUID_DEFAULT(x) (SCM_CELL_OBJECT_1 (x))
|
||||
#endif
|
||||
|
||||
SCM_API SCM scm_make_fluid (void);
|
||||
SCM_API SCM scm_make_fluid_with_default (SCM dflt);
|
||||
SCM_API SCM scm_make_unbound_fluid (void);
|
||||
SCM_API int scm_is_fluid (SCM obj);
|
||||
SCM_API SCM scm_fluid_p (SCM fl);
|
||||
|
|
|
@ -1124,7 +1124,7 @@ SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
|
|||
"type should match @var{return-type} and @var{arg-types}.\n")
|
||||
#define FUNC_NAME s_scm_procedure_to_pointer
|
||||
{
|
||||
SCM pointer;
|
||||
SCM cif_pointer, pointer;
|
||||
ffi_cif *cif;
|
||||
ffi_status err;
|
||||
void *closure, *executable;
|
||||
|
@ -1141,8 +1141,17 @@ SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
|
|||
SCM_MISC_ERROR ("`ffi_prep_closure_loc' failed", SCM_EOL);
|
||||
}
|
||||
|
||||
/* CIF points to GC-managed memory and it should remain as long as
|
||||
POINTER (see below) is live. Wrap it in a Scheme pointer to then
|
||||
hold a weak reference on it. */
|
||||
cif_pointer = scm_from_pointer (cif, NULL);
|
||||
|
||||
if (closure == executable)
|
||||
pointer = scm_from_pointer (executable, ffi_closure_free);
|
||||
{
|
||||
pointer = scm_from_pointer (executable, ffi_closure_free);
|
||||
register_weak_reference (pointer,
|
||||
scm_list_2 (proc, cif_pointer));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CLOSURE needs to be freed eventually. However, since
|
||||
|
@ -1155,7 +1164,8 @@ SCM_DEFINE (scm_procedure_to_pointer, "procedure->pointer", 3, 0, 0,
|
|||
pointer = scm_from_pointer (executable, NULL);
|
||||
friend = scm_from_pointer (closure, ffi_closure_free);
|
||||
|
||||
register_weak_reference (pointer, friend);
|
||||
register_weak_reference (pointer,
|
||||
scm_list_3 (proc, cif_pointer, friend));
|
||||
}
|
||||
|
||||
return pointer;
|
||||
|
|
|
@ -88,12 +88,14 @@ scm_realloc (void *mem, size_t size)
|
|||
{
|
||||
void *ptr;
|
||||
|
||||
scm_gc_register_allocation (size);
|
||||
|
||||
SCM_SYSCALL (ptr = realloc (mem, size));
|
||||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
/* Time is hard: trigger a full, ``stop-the-world'' GC, and try again. */
|
||||
GC_gcollect ();
|
||||
GC_gcollect_and_unmap ();
|
||||
|
||||
SCM_SYSCALL (ptr = realloc (mem, size));
|
||||
if (ptr)
|
||||
|
|
220
libguile/gc.c
220
libguile/gc.c
|
@ -27,6 +27,7 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __ia64__
|
||||
#include <ucontext.h>
|
||||
|
@ -187,6 +188,32 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0,
|
|||
|
||||
#endif /* SCM_DEBUG_CELL_ACCESSES == 1 */
|
||||
|
||||
|
||||
|
||||
/* Compatibility. */
|
||||
|
||||
#ifndef HAVE_GC_GET_HEAP_USAGE_SAFE
|
||||
static void
|
||||
GC_get_heap_usage_safe (GC_word *pheap_size, GC_word *pfree_bytes,
|
||||
GC_word *punmapped_bytes, GC_word *pbytes_since_gc,
|
||||
GC_word *ptotal_bytes)
|
||||
{
|
||||
*pheap_size = GC_get_heap_size ();
|
||||
*pfree_bytes = GC_get_free_bytes ();
|
||||
*punmapped_bytes = GC_get_unmapped_bytes ();
|
||||
*pbytes_since_gc = GC_get_bytes_since_gc ();
|
||||
*ptotal_bytes = GC_get_total_bytes ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GC_GET_FREE_SPACE_DIVISOR
|
||||
static GC_word
|
||||
GC_get_free_space_divisor (void)
|
||||
{
|
||||
return GC_free_space_divisor;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Hooks. */
|
||||
scm_t_c_hook scm_before_gc_c_hook;
|
||||
|
@ -209,6 +236,9 @@ unsigned long scm_gc_ports_collected = 0;
|
|||
static long gc_time_taken = 0;
|
||||
static long gc_start_time = 0;
|
||||
|
||||
static unsigned long free_space_divisor;
|
||||
static unsigned long minimum_free_space_divisor;
|
||||
static double target_free_space_divisor;
|
||||
|
||||
static unsigned long protected_obj_count = 0;
|
||||
|
||||
|
@ -270,14 +300,12 @@ SCM_DEFINE (scm_gc_stats, "gc-stats", 0, 0, 0,
|
|||
#define FUNC_NAME s_scm_gc_stats
|
||||
{
|
||||
SCM answer;
|
||||
size_t heap_size, free_bytes, bytes_since_gc, total_bytes;
|
||||
GC_word heap_size, free_bytes, unmapped_bytes, bytes_since_gc, total_bytes;
|
||||
size_t gc_times;
|
||||
|
||||
heap_size = GC_get_heap_size ();
|
||||
free_bytes = GC_get_free_bytes ();
|
||||
bytes_since_gc = GC_get_bytes_since_gc ();
|
||||
total_bytes = GC_get_total_bytes ();
|
||||
gc_times = GC_gc_no;
|
||||
GC_get_heap_usage_safe (&heap_size, &free_bytes, &unmapped_bytes,
|
||||
&bytes_since_gc, &total_bytes);
|
||||
gc_times = GC_gc_no;
|
||||
|
||||
answer =
|
||||
scm_list_n (scm_cons (sym_gc_time_taken, scm_from_long (gc_time_taken)),
|
||||
|
@ -579,7 +607,10 @@ void
|
|||
scm_storage_prehistory ()
|
||||
{
|
||||
GC_all_interior_pointers = 0;
|
||||
GC_set_free_space_divisor (scm_getenv_int ("GC_FREE_SPACE_DIVISOR", 3));
|
||||
free_space_divisor = scm_getenv_int ("GC_FREE_SPACE_DIVISOR", 3);
|
||||
minimum_free_space_divisor = free_space_divisor;
|
||||
target_free_space_divisor = free_space_divisor;
|
||||
GC_set_free_space_divisor (free_space_divisor);
|
||||
|
||||
GC_INIT ();
|
||||
|
||||
|
@ -723,7 +754,8 @@ accumulate_gc_timer (void * hook_data SCM_UNUSED,
|
|||
void *data SCM_UNUSED)
|
||||
{
|
||||
if (gc_start_time)
|
||||
{ long now = scm_c_get_internal_run_time ();
|
||||
{
|
||||
long now = scm_c_get_internal_run_time ();
|
||||
gc_time_taken += now - gc_start_time;
|
||||
gc_start_time = 0;
|
||||
}
|
||||
|
@ -731,6 +763,168 @@ accumulate_gc_timer (void * hook_data SCM_UNUSED,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Return some idea of the memory footprint of a process, in bytes.
|
||||
Currently only works on Linux systems. */
|
||||
static size_t
|
||||
get_image_size (void)
|
||||
{
|
||||
unsigned long size, resident, share;
|
||||
size_t ret = 0;
|
||||
|
||||
FILE *fp = fopen ("/proc/self/statm", "r");
|
||||
|
||||
if (fp && fscanf (fp, "%lu %lu %lu", &size, &resident, &share) == 3)
|
||||
ret = resident * 4096;
|
||||
|
||||
if (fp)
|
||||
fclose (fp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* These are discussed later. */
|
||||
static size_t bytes_until_gc;
|
||||
static scm_i_pthread_mutex_t bytes_until_gc_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Make GC run more frequently when the process image size is growing,
|
||||
measured against the number of bytes allocated through the GC.
|
||||
|
||||
If Guile is allocating at a GC-managed heap size H, libgc will tend
|
||||
to limit the process image size to H*N. But if at the same time the
|
||||
user program is mallocating at a rate M bytes per GC-allocated byte,
|
||||
then the process stabilizes at H*N*M -- assuming that collecting data
|
||||
will result in malloc'd data being freed. It doesn't take a very
|
||||
large M for this to be a bad situation. To limit the image size,
|
||||
Guile should GC more often -- the bigger the M, the more often.
|
||||
|
||||
Numeric functions that produce bigger and bigger integers are
|
||||
pessimal, because M is an increasing function of time. Here is an
|
||||
example of such a function:
|
||||
|
||||
(define (factorial n)
|
||||
(define (fac n acc)
|
||||
(if (<= n 1)
|
||||
acc
|
||||
(fac (1- n) (* n acc))))
|
||||
(fac n 1))
|
||||
|
||||
It is possible for a process to grow for reasons that will not be
|
||||
solved by faster GC. In that case M will be estimated as
|
||||
artificially high for a while, and so GC will happen more often on
|
||||
the Guile side. But when it stabilizes, Guile can ease back the GC
|
||||
frequency.
|
||||
|
||||
The key is to measure process image growth, not mallocation rate.
|
||||
For maximum effectiveness, Guile reacts quickly to process growth,
|
||||
and exponentially backs down when the process stops growing.
|
||||
|
||||
See http://thread.gmane.org/gmane.lisp.guile.devel/12552/focus=12936
|
||||
for further discussion.
|
||||
*/
|
||||
static void *
|
||||
adjust_gc_frequency (void * hook_data SCM_UNUSED,
|
||||
void *fn_data SCM_UNUSED,
|
||||
void *data SCM_UNUSED)
|
||||
{
|
||||
static size_t prev_image_size = 0;
|
||||
static size_t prev_bytes_alloced = 0;
|
||||
size_t image_size;
|
||||
size_t bytes_alloced;
|
||||
|
||||
scm_i_pthread_mutex_lock (&bytes_until_gc_lock);
|
||||
bytes_until_gc = GC_get_heap_size ();
|
||||
scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
|
||||
|
||||
image_size = get_image_size ();
|
||||
bytes_alloced = GC_get_total_bytes ();
|
||||
|
||||
#define HEURISTICS_DEBUG 0
|
||||
|
||||
#if HEURISTICS_DEBUG
|
||||
fprintf (stderr, "prev image / alloced: %lu / %lu\n", prev_image_size, prev_bytes_alloced);
|
||||
fprintf (stderr, " image / alloced: %lu / %lu\n", image_size, bytes_alloced);
|
||||
fprintf (stderr, "divisor %lu / %f\n", free_space_divisor, target_free_space_divisor);
|
||||
#endif
|
||||
|
||||
if (prev_image_size && bytes_alloced != prev_bytes_alloced)
|
||||
{
|
||||
double growth_rate, new_target_free_space_divisor;
|
||||
double decay_factor = 0.5;
|
||||
double hysteresis = 0.1;
|
||||
|
||||
growth_rate = ((double) image_size - prev_image_size)
|
||||
/ ((double)bytes_alloced - prev_bytes_alloced);
|
||||
|
||||
#if HEURISTICS_DEBUG
|
||||
fprintf (stderr, "growth rate %f\n", growth_rate);
|
||||
#endif
|
||||
|
||||
new_target_free_space_divisor = minimum_free_space_divisor;
|
||||
|
||||
if (growth_rate > 0)
|
||||
new_target_free_space_divisor *= 1.0 + growth_rate;
|
||||
|
||||
#if HEURISTICS_DEBUG
|
||||
fprintf (stderr, "new divisor %f\n", new_target_free_space_divisor);
|
||||
#endif
|
||||
|
||||
if (new_target_free_space_divisor < target_free_space_divisor)
|
||||
/* Decay down. */
|
||||
target_free_space_divisor =
|
||||
(decay_factor * target_free_space_divisor
|
||||
+ (1.0 - decay_factor) * new_target_free_space_divisor);
|
||||
else
|
||||
/* Jump up. */
|
||||
target_free_space_divisor = new_target_free_space_divisor;
|
||||
|
||||
#if HEURISTICS_DEBUG
|
||||
fprintf (stderr, "new target divisor %f\n", target_free_space_divisor);
|
||||
#endif
|
||||
|
||||
if (free_space_divisor + 0.5 + hysteresis < target_free_space_divisor
|
||||
|| free_space_divisor - 0.5 - hysteresis > target_free_space_divisor)
|
||||
{
|
||||
free_space_divisor = lround (target_free_space_divisor);
|
||||
#if HEURISTICS_DEBUG
|
||||
fprintf (stderr, "new divisor %lu\n", free_space_divisor);
|
||||
#endif
|
||||
GC_set_free_space_divisor (free_space_divisor);
|
||||
}
|
||||
}
|
||||
|
||||
prev_image_size = image_size;
|
||||
prev_bytes_alloced = bytes_alloced;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The adjust_gc_frequency routine handles transients in the process
|
||||
image size. It can't handle instense non-GC-managed steady-state
|
||||
allocation though, as it decays the FSD at steady-state down to its
|
||||
minimum value.
|
||||
|
||||
The only real way to handle continuous, high non-GC allocation is to
|
||||
let the GC know about it. This routine can handle non-GC allocation
|
||||
rates that are similar in size to the GC-managed heap size.
|
||||
*/
|
||||
|
||||
void
|
||||
scm_gc_register_allocation (size_t size)
|
||||
{
|
||||
scm_i_pthread_mutex_lock (&bytes_until_gc_lock);
|
||||
if (bytes_until_gc - size > bytes_until_gc)
|
||||
{
|
||||
bytes_until_gc = GC_get_heap_size ();
|
||||
scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
|
||||
GC_gcollect ();
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_until_gc -= size;
|
||||
scm_i_pthread_mutex_unlock (&bytes_until_gc_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -833,6 +1027,16 @@ scm_init_gc ()
|
|||
scm_c_hook_add (&scm_before_gc_c_hook, start_gc_timer, NULL, 0);
|
||||
scm_c_hook_add (&scm_after_gc_c_hook, accumulate_gc_timer, NULL, 0);
|
||||
|
||||
#if HAVE_GC_GET_HEAP_USAGE_SAFE
|
||||
/* GC_get_heap_usage does not take a lock, and so can run in the GC
|
||||
start hook. */
|
||||
scm_c_hook_add (&scm_before_gc_c_hook, adjust_gc_frequency, NULL, 0);
|
||||
#else
|
||||
/* GC_get_heap_usage might take a lock (and did from 7.2alpha1 to
|
||||
7.2alpha7), so call it in the after_gc_hook. */
|
||||
scm_c_hook_add (&scm_after_gc_c_hook, adjust_gc_frequency, NULL, 0);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GC_SET_START_CALLBACK
|
||||
GC_set_start_callback (run_before_gc_c_hook);
|
||||
#endif
|
||||
|
|
|
@ -157,6 +157,8 @@ SCM_INTERNAL void scm_i_gc (const char *what);
|
|||
SCM_API void scm_gc_mark (SCM p);
|
||||
SCM_API void scm_gc_sweep (void);
|
||||
|
||||
SCM_API void scm_gc_register_allocation (size_t size);
|
||||
|
||||
SCM_API void *scm_malloc (size_t size) SCM_MALLOC;
|
||||
SCM_API void *scm_calloc (size_t size) SCM_MALLOC;
|
||||
SCM_API void *scm_realloc (void *mem, size_t size);
|
||||
|
|
|
@ -1043,8 +1043,7 @@ scm_init_load ()
|
|||
scm_loc_fresh_auto_compile
|
||||
= SCM_VARIABLE_LOC (scm_c_define ("%fresh-auto-compile", SCM_BOOL_F));
|
||||
|
||||
the_reader = scm_make_fluid ();
|
||||
scm_fluid_set_x (the_reader, SCM_BOOL_F);
|
||||
the_reader = scm_make_fluid_with_default (SCM_BOOL_F);
|
||||
scm_c_define("current-reader", the_reader);
|
||||
|
||||
scm_c_define ("load-compiled",
|
||||
|
|
|
@ -292,7 +292,7 @@ memoize (SCM exp, SCM env)
|
|||
int nreq, nopt, ntotal;
|
||||
|
||||
req = REF (exp, LAMBDA_CASE, REQ);
|
||||
rest = REF (exp, LAMBDA_CASE, REST);
|
||||
rest = scm_not (scm_not (REF (exp, LAMBDA_CASE, REST)));
|
||||
opt = REF (exp, LAMBDA_CASE, OPT);
|
||||
kw = REF (exp, LAMBDA_CASE, KW);
|
||||
inits = REF (exp, LAMBDA_CASE, INITS);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <alignof.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#include <full-read.h>
|
||||
|
||||
|
@ -45,11 +46,55 @@
|
|||
The length of the header must be a multiple of 8 bytes. */
|
||||
verify (((sizeof (SCM_OBJCODE_COOKIE) - 1) & 7) == 0);
|
||||
|
||||
/* Endianness and word size of the compilation target. */
|
||||
static SCM target_endianness_var = SCM_BOOL_F;
|
||||
static SCM target_word_size_var = SCM_BOOL_F;
|
||||
|
||||
|
||||
/*
|
||||
* Objcode type
|
||||
*/
|
||||
|
||||
/* Endianness of the build machine. */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define NATIVE_ENDIANNESS 'B'
|
||||
#else
|
||||
# define NATIVE_ENDIANNESS 'L'
|
||||
#endif
|
||||
|
||||
/* Return the endianness of the compilation target. */
|
||||
static char
|
||||
target_endianness (void)
|
||||
{
|
||||
if (scm_is_true (target_endianness_var))
|
||||
return scm_is_eq (scm_call_0 (scm_variable_ref (target_endianness_var)),
|
||||
scm_endianness_big) ? 'B' : 'L';
|
||||
else
|
||||
return NATIVE_ENDIANNESS;
|
||||
}
|
||||
|
||||
/* Return the word size in bytes of the compilation target. */
|
||||
static size_t
|
||||
target_word_size (void)
|
||||
{
|
||||
if (scm_is_true (target_word_size_var))
|
||||
return scm_to_size_t (scm_call_0
|
||||
(scm_variable_ref (target_word_size_var)));
|
||||
else
|
||||
return sizeof (void *);
|
||||
}
|
||||
|
||||
/* Convert X, which is in byte order ENDIANNESS, to its native
|
||||
representation. */
|
||||
static inline uint32_t
|
||||
to_native_order (uint32_t x, char endianness)
|
||||
{
|
||||
if (endianness == NATIVE_ENDIANNESS)
|
||||
return x;
|
||||
else
|
||||
return bswap_32 (x);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_cookie (char *cookie, struct stat *st, int map_fd, void *map_addr)
|
||||
#define FUNC_NAME "make_objcode_from_file"
|
||||
|
@ -183,7 +228,7 @@ make_objcode_from_file (int fd)
|
|||
|
||||
verify_cookie (cookie, &st, -1, NULL);
|
||||
|
||||
return scm_bytecode_to_objcode (bv);
|
||||
return scm_bytecode_to_native_objcode (bv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -254,12 +299,12 @@ SCM_DEFINE (scm_objcode_meta, "objcode-meta", 1, 0, 0,
|
|||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 0, 0,
|
||||
(SCM bytecode),
|
||||
"")
|
||||
#define FUNC_NAME s_scm_bytecode_to_objcode
|
||||
/* Turn BYTECODE into objcode encoded for ENDIANNESS and WORD_SIZE. */
|
||||
static SCM
|
||||
bytecode_to_objcode (SCM bytecode, char endianness, size_t word_size)
|
||||
#define FUNC_NAME "bytecode->objcode"
|
||||
{
|
||||
size_t size;
|
||||
size_t size, len, metalen;
|
||||
const scm_t_uint8 *c_bytecode;
|
||||
struct scm_objcode *data;
|
||||
|
||||
|
@ -268,14 +313,17 @@ SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 0, 0,
|
|||
|
||||
size = SCM_BYTEVECTOR_LENGTH (bytecode);
|
||||
c_bytecode = (const scm_t_uint8*)SCM_BYTEVECTOR_CONTENTS (bytecode);
|
||||
|
||||
|
||||
SCM_ASSERT_RANGE (0, bytecode, size >= sizeof(struct scm_objcode));
|
||||
data = (struct scm_objcode*)c_bytecode;
|
||||
|
||||
if (data->len + data->metalen != (size - sizeof (*data)))
|
||||
len = to_native_order (data->len, endianness);
|
||||
metalen = to_native_order (data->metalen, endianness);
|
||||
|
||||
if (len + metalen != (size - sizeof (*data)))
|
||||
scm_misc_error (FUNC_NAME, "bad bytevector size (~a != ~a)",
|
||||
scm_list_2 (scm_from_size_t (size),
|
||||
scm_from_uint32 (sizeof (*data) + data->len + data->metalen)));
|
||||
scm_from_uint32 (sizeof (*data) + len + metalen)));
|
||||
|
||||
/* foolishly, we assume that as long as bytecode is around, that c_bytecode
|
||||
will be of the same length; perhaps a bad assumption? */
|
||||
|
@ -284,6 +332,27 @@ SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 0, 0,
|
|||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 0, 0,
|
||||
(SCM bytecode),
|
||||
"")
|
||||
#define FUNC_NAME s_scm_bytecode_to_objcode
|
||||
{
|
||||
/* Assume we're called from Scheme, which known that to do with
|
||||
`target-type'. */
|
||||
return bytecode_to_objcode (bytecode, target_endianness (),
|
||||
target_word_size ());
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
/* Like `bytecode->objcode', but ignore the `target-type' fluid. This
|
||||
is useful for native compilation that happens lazily---e.g., direct
|
||||
calls to this function from libguile itself. */
|
||||
SCM
|
||||
scm_bytecode_to_native_objcode (SCM bytecode)
|
||||
{
|
||||
return bytecode_to_objcode (bytecode, NATIVE_ENDIANNESS, sizeof (void *));
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_load_objcode, "load-objcode", 1, 0, 0,
|
||||
(SCM file),
|
||||
"")
|
||||
|
@ -324,41 +393,37 @@ SCM_DEFINE (scm_write_objcode, "write-objcode", 2, 0, 0,
|
|||
"")
|
||||
#define FUNC_NAME s_scm_write_objcode
|
||||
{
|
||||
static SCM target_endianness_var = SCM_BOOL_F;
|
||||
static SCM target_word_size_var = SCM_BOOL_F;
|
||||
|
||||
char cookie[sizeof (SCM_OBJCODE_COOKIE) - 1];
|
||||
char endianness;
|
||||
char word_size;
|
||||
char endianness, word_size;
|
||||
size_t total_size;
|
||||
|
||||
SCM_VALIDATE_OBJCODE (1, objcode);
|
||||
SCM_VALIDATE_OUTPUT_PORT (2, port);
|
||||
|
||||
if (scm_is_false (target_endianness_var))
|
||||
target_endianness_var =
|
||||
scm_c_public_variable ("system base target", "target-endianness");
|
||||
if (scm_is_false (target_word_size_var))
|
||||
target_word_size_var =
|
||||
scm_c_public_variable ("system base target", "target-word-size");
|
||||
|
||||
endianness =
|
||||
scm_is_eq (scm_call_0 (scm_variable_ref (target_endianness_var)),
|
||||
scm_endianness_big) ? 'B' : 'L';
|
||||
switch (scm_to_int (scm_call_0 (scm_variable_ref (target_word_size_var))))
|
||||
endianness = target_endianness ();
|
||||
switch (target_word_size ())
|
||||
{
|
||||
case 4: word_size = '4'; break;
|
||||
case 8: word_size = '8'; break;
|
||||
default: abort ();
|
||||
case 4:
|
||||
word_size = '4';
|
||||
break;
|
||||
case 8:
|
||||
word_size = '8';
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
memcpy (cookie, SCM_OBJCODE_COOKIE, strlen (SCM_OBJCODE_COOKIE));
|
||||
cookie[SCM_OBJCODE_ENDIANNESS_OFFSET] = endianness;
|
||||
cookie[SCM_OBJCODE_WORD_SIZE_OFFSET] = word_size;
|
||||
|
||||
total_size =
|
||||
to_native_order (SCM_OBJCODE_LEN (objcode), target_endianness ())
|
||||
+ to_native_order (SCM_OBJCODE_META_LEN (objcode), target_endianness ());
|
||||
|
||||
scm_c_write_unlocked (port, cookie, strlen (SCM_OBJCODE_COOKIE));
|
||||
scm_c_write_unlocked (port, SCM_OBJCODE_DATA (objcode),
|
||||
sizeof (struct scm_objcode)
|
||||
+ SCM_OBJCODE_TOTAL_LEN (objcode));
|
||||
+ total_size);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
|
@ -398,6 +463,11 @@ scm_init_objcodes (void)
|
|||
|
||||
scm_c_define ("word-size", scm_from_size_t (sizeof(SCM)));
|
||||
scm_c_define ("byte-order", scm_from_uint16 (SCM_BYTE_ORDER));
|
||||
|
||||
target_endianness_var = scm_c_public_variable ("system base target",
|
||||
"target-endianness");
|
||||
target_word_size_var = scm_c_public_variable ("system base target",
|
||||
"target-word-size");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -60,11 +60,12 @@ struct scm_objcode
|
|||
#define SCM_OBJCODE_NATIVE_CODE(x) (SCM_CELL_WORD_3 (x))
|
||||
#define SCM_SET_OBJCODE_NATIVE_CODE(x, code) (SCM_SET_CELL_WORD_3 (x, code))
|
||||
|
||||
SCM scm_c_make_objcode_slice (SCM parent, const scm_t_uint8 *ptr);
|
||||
SCM_API SCM scm_c_make_objcode_slice (SCM parent, const scm_t_uint8 *ptr);
|
||||
SCM_API SCM scm_load_objcode (SCM file);
|
||||
SCM_API SCM scm_objcode_p (SCM obj);
|
||||
SCM_API SCM scm_objcode_meta (SCM objcode);
|
||||
SCM_API SCM scm_bytecode_to_objcode (SCM bytecode);
|
||||
SCM_INTERNAL SCM scm_bytecode_to_native_objcode (SCM bytecode);
|
||||
SCM_API SCM scm_objcode_to_bytecode (SCM objcode);
|
||||
SCM_API SCM scm_write_objcode (SCM objcode, SCM port);
|
||||
|
||||
|
|
|
@ -2762,13 +2762,13 @@ scm_init_ports ()
|
|||
#include "libguile/ports.x"
|
||||
|
||||
/* Use Latin-1 as the default port encoding. */
|
||||
SCM_VARIABLE_SET (default_port_encoding_var, scm_make_fluid ());
|
||||
scm_fluid_set_x (SCM_VARIABLE_REF (default_port_encoding_var), SCM_BOOL_F);
|
||||
SCM_VARIABLE_SET (default_port_encoding_var,
|
||||
scm_make_fluid_with_default (SCM_BOOL_F));
|
||||
scm_port_encoding_init = 1;
|
||||
|
||||
SCM_VARIABLE_SET (scm_conversion_strategy, scm_make_fluid ());
|
||||
scm_fluid_set_x (SCM_VARIABLE_REF (scm_conversion_strategy),
|
||||
scm_from_int ((int) SCM_FAILED_CONVERSION_QUESTION_MARK));
|
||||
SCM_VARIABLE_SET (scm_conversion_strategy,
|
||||
scm_make_fluid_with_default
|
||||
(scm_from_int ((int) SCM_FAILED_CONVERSION_QUESTION_MARK)));
|
||||
scm_conversion_strategy_init = 1;
|
||||
|
||||
}
|
||||
|
|
|
@ -43,9 +43,23 @@ SCM_GLOBAL_SYMBOL (scm_sym_name, "name");
|
|||
|
||||
static SCM overrides;
|
||||
|
||||
static SCM arity_overrides;
|
||||
|
||||
int
|
||||
scm_i_procedure_arity (SCM proc, int *req, int *opt, int *rest)
|
||||
{
|
||||
SCM o;
|
||||
|
||||
o = scm_weak_table_refq (arity_overrides, proc, SCM_BOOL_F);
|
||||
|
||||
if (scm_is_true (o))
|
||||
{
|
||||
*req = scm_to_int (scm_car (o));
|
||||
*opt = scm_to_int (scm_cadr (o));
|
||||
*rest = scm_is_true (scm_caddr (o));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (!SCM_PROGRAM_P (proc))
|
||||
{
|
||||
if (SCM_STRUCTP (proc))
|
||||
|
@ -63,9 +77,27 @@ scm_i_procedure_arity (SCM proc, int *req, int *opt, int *rest)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return scm_i_program_arity (proc, req, opt, rest);
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_set_procedure_minimum_arity_x, "set-procedure-minimum-arity!",
|
||||
4, 0, 0, (SCM proc, SCM req, SCM opt, SCM rest),
|
||||
"")
|
||||
#define FUNC_NAME s_scm_set_procedure_minimum_arity_x
|
||||
{
|
||||
int t SCM_UNUSED;
|
||||
|
||||
SCM_VALIDATE_PROC (1, proc);
|
||||
SCM_VALIDATE_INT_COPY (2, req, t);
|
||||
SCM_VALIDATE_INT_COPY (3, opt, t);
|
||||
SCM_VALIDATE_BOOL (4, rest);
|
||||
|
||||
scm_weak_table_putq_x (arity_overrides, proc, scm_list_3 (req, opt, rest));
|
||||
return SCM_UNDEFINED;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_procedure_minimum_arity, "procedure-minimum-arity", 1, 0, 0,
|
||||
(SCM proc),
|
||||
"Return the \"minimum arity\" of a procedure.\n\n"
|
||||
|
@ -171,6 +203,7 @@ void
|
|||
scm_init_procprop ()
|
||||
{
|
||||
overrides = scm_c_make_weak_table (0, SCM_WEAK_TABLE_KIND_KEY);
|
||||
arity_overrides = scm_c_make_weak_table (0, SCM_WEAK_TABLE_KIND_KEY);
|
||||
#include "libguile/procprop.x"
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ SCM_API SCM scm_sym_system_procedure;
|
|||
|
||||
|
||||
SCM_INTERNAL int scm_i_procedure_arity (SCM proc, int *req, int *opt, int *rest);
|
||||
SCM_API SCM scm_set_procedure_minimum_arity_x (SCM proc, SCM req, SCM opt,
|
||||
SCM rest);
|
||||
SCM_API SCM scm_procedure_minimum_arity (SCM proc);
|
||||
SCM_API SCM scm_procedure_properties (SCM proc);
|
||||
SCM_API SCM scm_set_procedure_properties_x (SCM proc, SCM alist);
|
||||
|
|
|
@ -1740,8 +1740,7 @@ scm_init_read ()
|
|||
{
|
||||
SCM read_hash_procs;
|
||||
|
||||
read_hash_procs = scm_make_fluid ();
|
||||
scm_fluid_set_x (read_hash_procs, SCM_EOL);
|
||||
read_hash_procs = scm_make_fluid_with_default (SCM_EOL);
|
||||
|
||||
scm_i_read_hash_procedures =
|
||||
SCM_VARIABLE_LOC (scm_c_define ("%read-hash-procedures", read_hash_procs));
|
||||
|
|
|
@ -477,7 +477,7 @@ static SCM scm_i_default_dynamic_state;
|
|||
|
||||
/* Run when a fluid is collected. */
|
||||
void
|
||||
scm_i_reset_fluid (size_t n, SCM val)
|
||||
scm_i_reset_fluid (size_t n)
|
||||
{
|
||||
scm_i_thread *t;
|
||||
|
||||
|
@ -488,7 +488,7 @@ scm_i_reset_fluid (size_t n, SCM val)
|
|||
SCM v = SCM_I_DYNAMIC_STATE_FLUIDS (t->dynamic_state);
|
||||
|
||||
if (n < SCM_SIMPLE_VECTOR_LENGTH (v))
|
||||
SCM_SIMPLE_VECTOR_SET (v, n, val);
|
||||
SCM_SIMPLE_VECTOR_SET (v, n, SCM_UNDEFINED);
|
||||
}
|
||||
scm_i_pthread_mutex_unlock (&thread_admin_mutex);
|
||||
}
|
||||
|
@ -1001,6 +1001,7 @@ SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 1, 1, 0,
|
|||
SCM_ASSERT (SCM_UNBNDP (handler) || scm_is_true (scm_procedure_p (handler)),
|
||||
handler, SCM_ARG2, FUNC_NAME);
|
||||
|
||||
GC_collect_a_little ();
|
||||
data.parent = scm_current_dynamic_state ();
|
||||
data.thunk = thunk;
|
||||
data.handler = handler;
|
||||
|
|
|
@ -136,7 +136,7 @@ SCM_API SCM scm_spawn_thread (scm_t_catch_body body, void *body_data,
|
|||
SCM_API void *scm_without_guile (void *(*func)(void *), void *data);
|
||||
SCM_API void *scm_with_guile (void *(*func)(void *), void *data);
|
||||
|
||||
SCM_INTERNAL void scm_i_reset_fluid (size_t, SCM);
|
||||
SCM_INTERNAL void scm_i_reset_fluid (size_t);
|
||||
SCM_INTERNAL void scm_threads_prehistory (void *);
|
||||
SCM_INTERNAL void scm_init_threads (void);
|
||||
SCM_INTERNAL void scm_init_thread_procs (void);
|
||||
|
|
|
@ -1660,6 +1660,8 @@ VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
|
|||
else
|
||||
{
|
||||
SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
|
||||
if (scm_is_eq (val, SCM_UNDEFINED))
|
||||
val = SCM_I_FLUID_DEFAULT (*sp);
|
||||
if (SCM_UNLIKELY (scm_is_eq (val, SCM_UNDEFINED)))
|
||||
{
|
||||
finish_args = *sp;
|
||||
|
|
|
@ -393,7 +393,7 @@ really_make_boot_program (long nargs)
|
|||
u8vec = scm_c_take_gc_bytevector ((scm_t_int8*)bp,
|
||||
sizeof (struct scm_objcode) + sizeof (text),
|
||||
SCM_BOOL_F);
|
||||
ret = scm_make_program (scm_bytecode_to_objcode (u8vec),
|
||||
ret = scm_make_program (scm_bytecode_to_native_objcode (u8vec),
|
||||
SCM_BOOL_F, SCM_BOOL_F);
|
||||
SCM_SET_CELL_WORD_0 (ret, SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_BOOT);
|
||||
|
||||
|
|
|
@ -46,62 +46,72 @@ top_builddir="@top_builddir_absolute@"
|
|||
exit 1
|
||||
}
|
||||
|
||||
if [ x"$GUILE_LOAD_PATH" = x ]
|
||||
# When cross-compiling, let $GUILE_FOR_BUILD use its own .go files since
|
||||
# the ones that are being built may be incompatible ($GUILE_FOR_BUILD is
|
||||
# typically used to run `guild compile --target=$host'.) Likewise,
|
||||
# $GUILE_FOR_BUILD must use its own source files when booting; for
|
||||
# instance, $srcdir/module/ice-9/boot-9.scm must not be in its search
|
||||
# path, because it would then end up using its C evaluator to run the
|
||||
# compiler.
|
||||
if test "@cross_compiling@" = "no"
|
||||
then
|
||||
GUILE_LOAD_PATH="${top_srcdir}/module:${top_srcdir}/guile-readline:${top_srcdir}"
|
||||
if test "${top_srcdir}" != "${top_builddir}"; then
|
||||
GUILE_LOAD_PATH="$GUILE_LOAD_PATH:${top_builddir}/module:${top_builddir}/guile-readline:${top_builddir}"
|
||||
if [ x"$GUILE_LOAD_PATH" = x ]
|
||||
then
|
||||
GUILE_LOAD_PATH="${top_srcdir}/module:${top_srcdir}/guile-readline:${top_srcdir}"
|
||||
if test "${top_srcdir}" != "${top_builddir}"; then
|
||||
GUILE_LOAD_PATH="$GUILE_LOAD_PATH:${top_builddir}/module:${top_builddir}/guile-readline:${top_builddir}"
|
||||
fi
|
||||
else
|
||||
for d in "/module" "/guile-readline" ""
|
||||
do
|
||||
# This hair prevents double inclusion.
|
||||
# The ":" prevents prefix aliasing.
|
||||
case x"$GUILE_LOAD_PATH" in
|
||||
x*${top_srcdir}${d}:*) ;;
|
||||
x*${top_srcdir}${d}) ;;
|
||||
*) GUILE_LOAD_PATH="${top_srcdir}${d}:$GUILE_LOAD_PATH" ;;
|
||||
esac
|
||||
case x"$GUILE_LOAD_PATH" in
|
||||
x*${top_builddir}${d}:*) ;;
|
||||
x*${top_builddir}${d}) ;;
|
||||
*) GUILE_LOAD_PATH="${top_builddir}${d}:$GUILE_LOAD_PATH" ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
else
|
||||
for d in "/module" "/guile-readline" ""
|
||||
do
|
||||
# This hair prevents double inclusion.
|
||||
# The ":" prevents prefix aliasing.
|
||||
case x"$GUILE_LOAD_PATH" in
|
||||
x*${top_srcdir}${d}:*) ;;
|
||||
x*${top_srcdir}${d}) ;;
|
||||
*) GUILE_LOAD_PATH="${top_srcdir}${d}:$GUILE_LOAD_PATH" ;;
|
||||
esac
|
||||
case x"$GUILE_LOAD_PATH" in
|
||||
x*${top_builddir}${d}:*) ;;
|
||||
x*${top_builddir}${d}) ;;
|
||||
*) GUILE_LOAD_PATH="${top_builddir}${d}:$GUILE_LOAD_PATH" ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
export GUILE_LOAD_PATH
|
||||
export GUILE_LOAD_PATH
|
||||
|
||||
if [ x"$GUILE_LOAD_COMPILED_PATH" = x ]
|
||||
then
|
||||
GUILE_LOAD_COMPILED_PATH="${top_builddir}/module:${top_builddir}/guile-readline:${top_builddir}"
|
||||
else
|
||||
for d in "/module" "/guile-readline" ""
|
||||
do
|
||||
# This hair prevents double inclusion.
|
||||
# The ":" prevents prefix aliasing.
|
||||
case x"$GUILE_LOAD_COMPILED_PATH" in
|
||||
x*${top_builddir}${d}:*) ;;
|
||||
x*${top_builddir}${d}) ;;
|
||||
*) GUILE_LOAD_COMPILED_PATH="${top_builddir}${d}:$GUILE_LOAD_COMPILED_PATH" ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
export GUILE_LOAD_COMPILED_PATH
|
||||
if test "x$GUILE_LOAD_COMPILED_PATH" = "x"
|
||||
then
|
||||
GUILE_LOAD_COMPILED_PATH="${top_builddir}/module:${top_builddir}/guile-readline:${top_builddir}"
|
||||
else
|
||||
for d in "/module" "/guile-readline" ""
|
||||
do
|
||||
# This hair prevents double inclusion.
|
||||
# The ":" prevents prefix aliasing.
|
||||
case x"$GUILE_LOAD_COMPILED_PATH" in
|
||||
x*${top_builddir}${d}:*) ;;
|
||||
x*${top_builddir}${d}) ;;
|
||||
*) GUILE_LOAD_COMPILED_PATH="${top_builddir}${d}:$GUILE_LOAD_COMPILED_PATH" ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
export GUILE_LOAD_COMPILED_PATH
|
||||
|
||||
# Don't look in installed dirs for guile modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_PATH=
|
||||
export GUILE_SYSTEM_PATH
|
||||
fi
|
||||
# Don't look in installed dirs for compiled guile modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_COMPILED_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_COMPILED_PATH=
|
||||
export GUILE_SYSTEM_COMPILED_PATH
|
||||
fi
|
||||
# Don't look in installed dirs for dlopen-able modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_EXTENSIONS_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_EXTENSIONS_PATH=
|
||||
export GUILE_SYSTEM_EXTENSIONS_PATH
|
||||
# Don't look in installed dirs for guile modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_PATH=
|
||||
export GUILE_SYSTEM_PATH
|
||||
fi
|
||||
# Don't look in installed dirs for compiled guile modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_COMPILED_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_COMPILED_PATH=
|
||||
export GUILE_SYSTEM_COMPILED_PATH
|
||||
fi
|
||||
# Don't look in installed dirs for dlopen-able modules
|
||||
if ( env | grep -v '^GUILE_SYSTEM_EXTENSIONS_PATH=' > /dev/null ); then
|
||||
GUILE_SYSTEM_EXTENSIONS_PATH=
|
||||
export GUILE_SYSTEM_EXTENSIONS_PATH
|
||||
fi
|
||||
fi
|
||||
|
||||
# handle LTDL_LIBRARY_PATH (no clobber)
|
||||
|
|
|
@ -79,10 +79,14 @@ ice-9/psyntax-pp.scm.gen:
|
|||
|
||||
.PHONY: ice-9/psyntax-pp.scm.gen
|
||||
|
||||
# Keep this rule in sync with that in `am/guilec'.
|
||||
ice-9/psyntax-pp.go: ice-9/psyntax.scm ice-9/psyntax-pp.scm
|
||||
$(AM_V_GUILEC) GUILE_AUTO_COMPILE=0 \
|
||||
$(top_builddir)/meta/uninstalled-env \
|
||||
guild compile $(GUILE_WARNINGS) -o "ice-9/psyntax-pp.go" "$(srcdir)/ice-9/psyntax.scm"
|
||||
$(AM_V_GUILEC)GUILE_AUTO_COMPILE=0 \
|
||||
$(top_builddir)/meta/uninstalled-env \
|
||||
guild compile --target="$(host)" $(GUILE_WARNINGS) \
|
||||
-L "$(abs_srcdir)" -L "$(abs_builddir)" \
|
||||
-L "$(abs_top_srcdir)/guile-readline" \
|
||||
-o "ice-9/psyntax-pp.go" "$(srcdir)/ice-9/psyntax.scm"
|
||||
|
||||
SCHEME_LANG_SOURCES = \
|
||||
language/scheme/spec.scm \
|
||||
|
|
|
@ -69,23 +69,6 @@
|
|||
|
||||
(define with-throw-handler #f)
|
||||
(let ()
|
||||
;; Ideally we'd like to be able to give these default values for all threads,
|
||||
;; even threads not created by Guile; but alack, that does not currently seem
|
||||
;; possible. So wrap the getters in thunks.
|
||||
(define %running-exception-handlers (make-fluid))
|
||||
(define %exception-handler (make-fluid))
|
||||
|
||||
(define (running-exception-handlers)
|
||||
(or (fluid-ref %running-exception-handlers)
|
||||
(begin
|
||||
(fluid-set! %running-exception-handlers '())
|
||||
'())))
|
||||
(define (exception-handler)
|
||||
(or (fluid-ref %exception-handler)
|
||||
(begin
|
||||
(fluid-set! %exception-handler default-exception-handler)
|
||||
default-exception-handler)))
|
||||
|
||||
(define (default-exception-handler k . args)
|
||||
(cond
|
||||
((eq? k 'quit)
|
||||
|
@ -98,18 +81,21 @@
|
|||
(format (current-error-port) "guile: uncaught throw to ~a: ~a\n" k args)
|
||||
(primitive-exit 1))))
|
||||
|
||||
(define %running-exception-handlers (make-fluid '()))
|
||||
(define %exception-handler (make-fluid default-exception-handler))
|
||||
|
||||
(define (default-throw-handler prompt-tag catch-k)
|
||||
(let ((prev (exception-handler)))
|
||||
(let ((prev (fluid-ref %exception-handler)))
|
||||
(lambda (thrown-k . args)
|
||||
(if (or (eq? thrown-k catch-k) (eqv? catch-k #t))
|
||||
(apply abort-to-prompt prompt-tag thrown-k args)
|
||||
(apply prev thrown-k args)))))
|
||||
|
||||
(define (custom-throw-handler prompt-tag catch-k pre)
|
||||
(let ((prev (exception-handler)))
|
||||
(let ((prev (fluid-ref %exception-handler)))
|
||||
(lambda (thrown-k . args)
|
||||
(if (or (eq? thrown-k catch-k) (eqv? catch-k #t))
|
||||
(let ((running (running-exception-handlers)))
|
||||
(let ((running (fluid-ref %running-exception-handlers)))
|
||||
(with-fluids ((%running-exception-handlers (cons pre running)))
|
||||
(if (not (memq pre running))
|
||||
(apply pre thrown-k args))
|
||||
|
@ -192,9 +178,9 @@ for key @var{key}, then invoke @var{thunk}."
|
|||
|
||||
If there is no handler at all, Guile prints an error and then exits."
|
||||
(if (not (symbol? key))
|
||||
((exception-handler) 'wrong-type-arg "throw"
|
||||
((fluid-ref %exception-handler) 'wrong-type-arg "throw"
|
||||
"Wrong type argument in position ~a: ~a" (list 1 key) (list key))
|
||||
(apply (exception-handler) key args)))))
|
||||
(apply (fluid-ref %exception-handler) key args)))))
|
||||
|
||||
|
||||
|
||||
|
@ -1404,8 +1390,7 @@ VALUE."
|
|||
;;; Reader code for various "#c" forms.
|
||||
;;;
|
||||
|
||||
(define read-eval? (make-fluid))
|
||||
(fluid-set! read-eval? #f)
|
||||
(define read-eval? (make-fluid #f))
|
||||
(read-hash-extend #\.
|
||||
(lambda (c port)
|
||||
(if (fluid-ref read-eval?)
|
||||
|
@ -2843,14 +2828,14 @@ module '(ice-9 q) '(make-q q-length))}."
|
|||
;;; {Running Repls}
|
||||
;;;
|
||||
|
||||
(define *repl-stack* (make-fluid))
|
||||
(define *repl-stack* (make-fluid '()))
|
||||
|
||||
;; Programs can call `batch-mode?' to see if they are running as part of a
|
||||
;; script or if they are running interactively. REPL implementations ensure that
|
||||
;; `batch-mode?' returns #f during their extent.
|
||||
;;
|
||||
(define (batch-mode?)
|
||||
(null? (or (fluid-ref *repl-stack*) '())))
|
||||
(null? (fluid-ref *repl-stack*)))
|
||||
|
||||
;; Programs can re-enter batch mode, for example after a fork, by calling
|
||||
;; `ensure-batch-mode!'. It's not a great interface, though; it would be better
|
||||
|
@ -2889,7 +2874,26 @@ module '(ice-9 q) '(make-q q-length))}."
|
|||
(define repl-reader
|
||||
(lambda* (prompt #:optional (reader (fluid-ref current-reader)))
|
||||
(if (not (char-ready?))
|
||||
(display (if (string? prompt) prompt (prompt))))
|
||||
(begin
|
||||
(display (if (string? prompt) prompt (prompt)))
|
||||
;; An interesting situation. The printer resets the column to
|
||||
;; 0 by printing a newline, but we then advance it by printing
|
||||
;; the prompt. However the port-column of the output port
|
||||
;; does not typically correspond with the actual column on the
|
||||
;; screen, because the input is is echoed back! Since the
|
||||
;; input is line-buffered and thus ends with a newline, the
|
||||
;; output will really start on column zero. So, here we zero
|
||||
;; it out. See bug 9664.
|
||||
;;
|
||||
;; Note that for similar reasons, the output-line will not
|
||||
;; reflect the actual line on the screen. But given the
|
||||
;; possibility of multiline input, the fix is not as
|
||||
;; straightforward, so we don't bother.
|
||||
;;
|
||||
;; Also note that the readline implementation papers over
|
||||
;; these concerns, because it's readline itself printing the
|
||||
;; prompt, and not Guile.
|
||||
(set-port-column! (current-output-port) 0)))
|
||||
(force-output)
|
||||
(run-hook before-read-hook)
|
||||
((or reader read) (current-input-port))))
|
||||
|
@ -3241,8 +3245,7 @@ module '(ice-9 q) '(make-q q-length))}."
|
|||
;;;
|
||||
|
||||
(define* (make-mutable-parameter init #:optional (converter identity))
|
||||
(let ((fluid (make-fluid)))
|
||||
(fluid-set! fluid (converter init))
|
||||
(let ((fluid (make-fluid (converter init))))
|
||||
(case-lambda
|
||||
(() (fluid-ref fluid))
|
||||
((val) (fluid-set! fluid (converter val))))))
|
||||
|
|
|
@ -235,109 +235,127 @@
|
|||
(inits (if tail (caddr tail) '()))
|
||||
(alt (and tail (cadddr tail))))
|
||||
(make-general-closure env body nreq rest nopt kw inits alt))))
|
||||
(lambda %args
|
||||
(let lp ((env env)
|
||||
(nreq* nreq)
|
||||
(args %args))
|
||||
(if (> nreq* 0)
|
||||
;; First, bind required arguments.
|
||||
(if (null? args)
|
||||
(if alt
|
||||
(apply alt-proc %args)
|
||||
(scm-error 'wrong-number-of-args
|
||||
"eval" "Wrong number of arguments"
|
||||
'() #f))
|
||||
(lp (cons (car args) env)
|
||||
(1- nreq*)
|
||||
(cdr args)))
|
||||
;; Move on to optional arguments.
|
||||
(if (not kw)
|
||||
;; Without keywords, bind optionals from arguments.
|
||||
(let lp ((env env)
|
||||
(nopt nopt)
|
||||
(args args)
|
||||
(inits inits))
|
||||
(if (zero? nopt)
|
||||
(if rest?
|
||||
(eval body (cons args env))
|
||||
(if (null? args)
|
||||
(eval body env)
|
||||
(if alt
|
||||
(apply alt-proc %args)
|
||||
(scm-error 'wrong-number-of-args
|
||||
"eval" "Wrong number of arguments"
|
||||
'() #f))))
|
||||
(if (null? args)
|
||||
(lp (cons (eval (car inits) env) env)
|
||||
(1- nopt) args (cdr inits))
|
||||
(lp (cons (car args) env)
|
||||
(1- nopt) (cdr args) (cdr inits)))))
|
||||
;; With keywords, we stop binding optionals at the first
|
||||
;; keyword.
|
||||
(let lp ((env env)
|
||||
(nopt* nopt)
|
||||
(args args)
|
||||
(inits inits))
|
||||
(if (> nopt* 0)
|
||||
(if (or (null? args) (keyword? (car args)))
|
||||
(lp (cons (eval (car inits) env) env)
|
||||
(1- nopt*) args (cdr inits))
|
||||
(lp (cons (car args) env)
|
||||
(1- nopt*) (cdr args) (cdr inits)))
|
||||
;; Finished with optionals.
|
||||
(let* ((aok (car kw))
|
||||
(kw (cdr kw))
|
||||
(kw-base (+ nopt nreq (if rest? 1 0)))
|
||||
(imax (let lp ((imax (1- kw-base)) (kw kw))
|
||||
(if (null? kw)
|
||||
imax
|
||||
(lp (max (cdar kw) imax)
|
||||
(cdr kw)))))
|
||||
;; Fill in kwargs with "undefined" vals.
|
||||
(env (let lp ((i kw-base)
|
||||
;; Also, here we bind the rest
|
||||
;; arg, if any.
|
||||
(env (if rest? (cons args env) env)))
|
||||
(if (<= i imax)
|
||||
(lp (1+ i) (cons unbound-arg env))
|
||||
env))))
|
||||
;; Now scan args for keywords.
|
||||
(let lp ((args args))
|
||||
(if (and (pair? args) (pair? (cdr args))
|
||||
(keyword? (car args)))
|
||||
(let ((kw-pair (assq (car args) kw))
|
||||
(v (cadr args)))
|
||||
(if kw-pair
|
||||
;; Found a known keyword; set its value.
|
||||
(list-set! env (- imax (cdr kw-pair)) v)
|
||||
;; Unknown keyword.
|
||||
(if (not aok)
|
||||
(scm-error 'keyword-argument-error
|
||||
"eval" "Unrecognized keyword"
|
||||
'() #f)))
|
||||
(lp (cddr args)))
|
||||
(if (pair? args)
|
||||
(if rest?
|
||||
;; Be lenient parsing rest args.
|
||||
(lp (cdr args))
|
||||
(scm-error 'keyword-argument-error
|
||||
"eval" "Invalid keyword"
|
||||
'() #f))
|
||||
;; Finished parsing keywords. Fill in
|
||||
;; uninitialized kwargs by evalling init
|
||||
;; expressions in their appropriate
|
||||
;; environment.
|
||||
(let lp ((i (- imax kw-base))
|
||||
(inits inits))
|
||||
(if (pair? inits)
|
||||
(let ((tail (list-tail env i)))
|
||||
(if (eq? (car tail) unbound-arg)
|
||||
(set-car! tail
|
||||
(eval (car inits)
|
||||
(cdr tail))))
|
||||
(lp (1- i) (cdr inits)))
|
||||
;; Finally, eval the body.
|
||||
(eval body env))))))))))))))
|
||||
(define (set-procedure-arity! proc)
|
||||
(let lp ((alt alt) (nreq nreq) (nopt nopt) (rest? rest?))
|
||||
(if (not alt)
|
||||
(set-procedure-minimum-arity! proc nreq nopt rest?)
|
||||
(let* ((nreq* (cadr alt))
|
||||
(rest?* (if (null? (cddr alt)) #f (caddr alt)))
|
||||
(tail (and (pair? (cddr alt)) (pair? (cdddr alt)) (cdddr alt)))
|
||||
(nopt* (if tail (car tail) 0))
|
||||
(alt* (and tail (cadddr tail))))
|
||||
(if (or (< nreq* nreq)
|
||||
(and (= nreq* nreq)
|
||||
(if rest?
|
||||
(and rest?* (> nopt* nopt))
|
||||
(or rest?* (> nopt* nopt)))))
|
||||
(lp alt* nreq* nopt* rest?*)
|
||||
(lp alt* nreq nopt rest?)))))
|
||||
proc)
|
||||
(set-procedure-arity!
|
||||
(lambda %args
|
||||
(let lp ((env env)
|
||||
(nreq* nreq)
|
||||
(args %args))
|
||||
(if (> nreq* 0)
|
||||
;; First, bind required arguments.
|
||||
(if (null? args)
|
||||
(if alt
|
||||
(apply alt-proc %args)
|
||||
(scm-error 'wrong-number-of-args
|
||||
"eval" "Wrong number of arguments"
|
||||
'() #f))
|
||||
(lp (cons (car args) env)
|
||||
(1- nreq*)
|
||||
(cdr args)))
|
||||
;; Move on to optional arguments.
|
||||
(if (not kw)
|
||||
;; Without keywords, bind optionals from arguments.
|
||||
(let lp ((env env)
|
||||
(nopt nopt)
|
||||
(args args)
|
||||
(inits inits))
|
||||
(if (zero? nopt)
|
||||
(if rest?
|
||||
(eval body (cons args env))
|
||||
(if (null? args)
|
||||
(eval body env)
|
||||
(if alt
|
||||
(apply alt-proc %args)
|
||||
(scm-error 'wrong-number-of-args
|
||||
"eval" "Wrong number of arguments"
|
||||
'() #f))))
|
||||
(if (null? args)
|
||||
(lp (cons (eval (car inits) env) env)
|
||||
(1- nopt) args (cdr inits))
|
||||
(lp (cons (car args) env)
|
||||
(1- nopt) (cdr args) (cdr inits)))))
|
||||
;; With keywords, we stop binding optionals at the first
|
||||
;; keyword.
|
||||
(let lp ((env env)
|
||||
(nopt* nopt)
|
||||
(args args)
|
||||
(inits inits))
|
||||
(if (> nopt* 0)
|
||||
(if (or (null? args) (keyword? (car args)))
|
||||
(lp (cons (eval (car inits) env) env)
|
||||
(1- nopt*) args (cdr inits))
|
||||
(lp (cons (car args) env)
|
||||
(1- nopt*) (cdr args) (cdr inits)))
|
||||
;; Finished with optionals.
|
||||
(let* ((aok (car kw))
|
||||
(kw (cdr kw))
|
||||
(kw-base (+ nopt nreq (if rest? 1 0)))
|
||||
(imax (let lp ((imax (1- kw-base)) (kw kw))
|
||||
(if (null? kw)
|
||||
imax
|
||||
(lp (max (cdar kw) imax)
|
||||
(cdr kw)))))
|
||||
;; Fill in kwargs with "undefined" vals.
|
||||
(env (let lp ((i kw-base)
|
||||
;; Also, here we bind the rest
|
||||
;; arg, if any.
|
||||
(env (if rest? (cons args env) env)))
|
||||
(if (<= i imax)
|
||||
(lp (1+ i) (cons unbound-arg env))
|
||||
env))))
|
||||
;; Now scan args for keywords.
|
||||
(let lp ((args args))
|
||||
(if (and (pair? args) (pair? (cdr args))
|
||||
(keyword? (car args)))
|
||||
(let ((kw-pair (assq (car args) kw))
|
||||
(v (cadr args)))
|
||||
(if kw-pair
|
||||
;; Found a known keyword; set its value.
|
||||
(list-set! env (- imax (cdr kw-pair)) v)
|
||||
;; Unknown keyword.
|
||||
(if (not aok)
|
||||
(scm-error 'keyword-argument-error
|
||||
"eval" "Unrecognized keyword"
|
||||
'() #f)))
|
||||
(lp (cddr args)))
|
||||
(if (pair? args)
|
||||
(if rest?
|
||||
;; Be lenient parsing rest args.
|
||||
(lp (cdr args))
|
||||
(scm-error 'keyword-argument-error
|
||||
"eval" "Invalid keyword"
|
||||
'() #f))
|
||||
;; Finished parsing keywords. Fill in
|
||||
;; uninitialized kwargs by evalling init
|
||||
;; expressions in their appropriate
|
||||
;; environment.
|
||||
(let lp ((i (- imax kw-base))
|
||||
(inits inits))
|
||||
(if (pair? inits)
|
||||
(let ((tail (list-tail env i)))
|
||||
(if (eq? (car tail) unbound-arg)
|
||||
(set-car! tail
|
||||
(eval (car inits)
|
||||
(cdr tail))))
|
||||
(lp (1- i) (cdr inits)))
|
||||
;; Finally, eval the body.
|
||||
(eval body env)))))))))))))))
|
||||
|
||||
;; The "engine". EXP is a memoized expression.
|
||||
(define (eval exp env)
|
||||
|
@ -404,7 +422,10 @@
|
|||
(memoize-variable-access! exp #f))))
|
||||
|
||||
(('define (name . x))
|
||||
(define! name (eval x env)))
|
||||
(let ((x (eval x env)))
|
||||
(if (and (procedure? x) (not (procedure-property x 'name)))
|
||||
(set-procedure-property! x 'name name))
|
||||
(define! name x)))
|
||||
|
||||
(('toplevel-set! (var-or-sym . x))
|
||||
(variable-set!
|
||||
|
|
|
@ -164,9 +164,9 @@
|
|||
#:use-module (ice-9 optargs)
|
||||
#:export (getopt-long option-ref))
|
||||
|
||||
(define %program-name (make-fluid))
|
||||
(define %program-name (make-fluid "guile"))
|
||||
(define (program-name)
|
||||
(or (fluid-ref %program-name) "guile"))
|
||||
(fluid-ref %program-name))
|
||||
|
||||
(define (fatal-error fmt . args)
|
||||
(format (current-error-port) "~a: " (program-name))
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -952,17 +952,17 @@
|
|||
|
||||
;; expanding
|
||||
|
||||
(define chi-sequence
|
||||
(define expand-sequence
|
||||
(lambda (body r w s mod)
|
||||
(build-sequence s
|
||||
(let dobody ((body body) (r r) (w w) (mod mod))
|
||||
(if (null? body)
|
||||
'()
|
||||
(let ((first (chi (car body) r w mod)))
|
||||
(let ((first (expand (car body) r w mod)))
|
||||
(cons first (dobody (cdr body) r w mod))))))))
|
||||
|
||||
;; At top-level, we allow mixed definitions and expressions. Like
|
||||
;; chi-body we expand in two passes.
|
||||
;; expand-body we expand in two passes.
|
||||
;;
|
||||
;; First, from left to right, we expand just enough to know what
|
||||
;; expressions are definitions, syntax definitions, and splicing
|
||||
|
@ -975,7 +975,7 @@
|
|||
;; expansions of all normal definitions and expressions in the
|
||||
;; sequence.
|
||||
;;
|
||||
(define chi-top-sequence
|
||||
(define expand-top-sequence
|
||||
(lambda (body r w s m esew mod)
|
||||
(let* ((r (cons '("placeholder" . (placeholder)) r))
|
||||
(ribcage (make-empty-ribcage))
|
||||
|
@ -1027,11 +1027,11 @@
|
|||
(record-definition! id var)
|
||||
(list
|
||||
(if (eq? m 'c&e)
|
||||
(let ((x (build-global-definition s var (chi e r w mod))))
|
||||
(let ((x (build-global-definition s var (expand e r w mod))))
|
||||
(top-level-eval-hook x mod)
|
||||
(lambda () x))
|
||||
(lambda ()
|
||||
(build-global-definition s var (chi e r w mod)))))))
|
||||
(build-global-definition s var (expand e r w mod)))))))
|
||||
((define-syntax-form define-syntax-parameter-form)
|
||||
(let* ((id (wrap value w mod))
|
||||
(label (gen-label))
|
||||
|
@ -1043,23 +1043,23 @@
|
|||
((c)
|
||||
(cond
|
||||
((memq 'compile esew)
|
||||
(let ((e (chi-install-global var type (chi e r w mod))))
|
||||
(let ((e (expand-install-global var type (expand e r w mod))))
|
||||
(top-level-eval-hook e mod)
|
||||
(if (memq 'load esew)
|
||||
(list (lambda () e))
|
||||
'())))
|
||||
((memq 'load esew)
|
||||
(list (lambda ()
|
||||
(chi-install-global var type (chi e r w mod)))))
|
||||
(expand-install-global var type (expand e r w mod)))))
|
||||
(else '())))
|
||||
((c&e)
|
||||
(let ((e (chi-install-global var type (chi e r w mod))))
|
||||
(let ((e (expand-install-global var type (expand e r w mod))))
|
||||
(top-level-eval-hook e mod)
|
||||
(list (lambda () e))))
|
||||
(else
|
||||
(if (memq 'eval esew)
|
||||
(top-level-eval-hook
|
||||
(chi-install-global var type (chi e r w mod))
|
||||
(expand-install-global var type (expand e r w mod))
|
||||
mod))
|
||||
'()))))
|
||||
((begin-form)
|
||||
|
@ -1067,13 +1067,13 @@
|
|||
((_ e1 ...)
|
||||
(parse #'(e1 ...) r w s m esew mod))))
|
||||
((local-syntax-form)
|
||||
(chi-local-syntax value e r w s mod
|
||||
(expand-local-syntax value e r w s mod
|
||||
(lambda (forms r w s mod)
|
||||
(parse forms r w s m esew mod))))
|
||||
((eval-when-form)
|
||||
(syntax-case e ()
|
||||
((_ (x ...) e1 e2 ...)
|
||||
(let ((when-list (chi-when-list e #'(x ...) w))
|
||||
(let ((when-list (parse-when-list e #'(x ...)))
|
||||
(body #'(e1 e2 ...)))
|
||||
(define (recurse m esew)
|
||||
(parse body r w s m esew mod))
|
||||
|
@ -1085,7 +1085,7 @@
|
|||
(begin
|
||||
(if (memq 'expand when-list)
|
||||
(top-level-eval-hook
|
||||
(chi-top-sequence body r w s 'e '(eval) mod)
|
||||
(expand-top-sequence body r w s 'e '(eval) mod)
|
||||
mod))
|
||||
'())))
|
||||
((memq 'load when-list)
|
||||
|
@ -1100,7 +1100,7 @@
|
|||
(memq 'expand when-list)
|
||||
(and (eq? m 'c&e) (memq 'eval when-list)))
|
||||
(top-level-eval-hook
|
||||
(chi-top-sequence body r w s 'e '(eval) mod)
|
||||
(expand-top-sequence body r w s 'e '(eval) mod)
|
||||
mod)
|
||||
'())
|
||||
(else
|
||||
|
@ -1108,18 +1108,18 @@
|
|||
(else
|
||||
(list
|
||||
(if (eq? m 'c&e)
|
||||
(let ((x (chi-expr type value e r w s mod)))
|
||||
(let ((x (expand-expr type value e r w s mod)))
|
||||
(top-level-eval-hook x mod)
|
||||
(lambda () x))
|
||||
(lambda ()
|
||||
(chi-expr type value e r w s mod)))))))))
|
||||
(expand-expr type value e r w s mod)))))))))
|
||||
(let ((exps (map (lambda (x) (x))
|
||||
(reverse (parse body r w s m esew mod)))))
|
||||
(if (null? exps)
|
||||
(build-void s)
|
||||
(build-sequence s exps))))))
|
||||
|
||||
(define chi-install-global
|
||||
(define expand-install-global
|
||||
(lambda (name type e)
|
||||
(build-global-definition
|
||||
no-source
|
||||
|
@ -1135,24 +1135,21 @@
|
|||
(build-data no-source 'macro)
|
||||
e))))))
|
||||
|
||||
(define chi-when-list
|
||||
(lambda (e when-list w)
|
||||
(define parse-when-list
|
||||
(lambda (e when-list)
|
||||
;; `when-list' is syntax'd version of list of situations. We
|
||||
;; could match these keywords lexically, via free-id=?, but then
|
||||
;; we twingle the definition of eval-when to the bindings of
|
||||
;; eval, load, expand, and compile, which is totally unintended.
|
||||
;; So do a symbolic match instead.
|
||||
(let f ((when-list when-list) (situations '()))
|
||||
(if (null? when-list)
|
||||
situations
|
||||
(f (cdr when-list)
|
||||
(cons (let ((x (syntax->datum (car when-list))))
|
||||
(if (memq x '(compile load eval expand))
|
||||
x
|
||||
(syntax-violation 'eval-when
|
||||
"invalid situation"
|
||||
e (wrap (car when-list) w #f))))
|
||||
situations))))))
|
||||
(let ((result (strip when-list empty-wrap)))
|
||||
(let lp ((l result))
|
||||
(if (null? l)
|
||||
result
|
||||
(if (memq (car l) '(compile load eval expand))
|
||||
(lp (cdr l))
|
||||
(syntax-violation 'eval-when "invalid situation" e
|
||||
(car l))))))))
|
||||
|
||||
;; syntax-type returns six values: type, value, e, w, s, and mod. The
|
||||
;; first two are described in the table below.
|
||||
|
@ -1203,7 +1200,7 @@
|
|||
((macro)
|
||||
(if for-car?
|
||||
(values type value e w s mod)
|
||||
(syntax-type (chi-macro value e r w s rib mod)
|
||||
(syntax-type (expand-macro value e r w s rib mod)
|
||||
r empty-wrap s rib mod #f)))
|
||||
((global)
|
||||
;; Toplevel definitions may resolve to bindings with
|
||||
|
@ -1225,7 +1222,7 @@
|
|||
(values 'global-call (make-syntax-object fval w fmod)
|
||||
e w s mod))
|
||||
((macro)
|
||||
(syntax-type (chi-macro fval e r w s rib mod)
|
||||
(syntax-type (expand-macro fval e r w s rib mod)
|
||||
r empty-wrap s rib mod for-car?))
|
||||
((module-ref)
|
||||
(call-with-values (lambda () (fval e r w))
|
||||
|
@ -1279,14 +1276,14 @@
|
|||
((self-evaluating? e) (values 'constant #f e w s mod))
|
||||
(else (values 'other #f e w s mod)))))
|
||||
|
||||
(define chi
|
||||
(define expand
|
||||
(lambda (e r w mod)
|
||||
(call-with-values
|
||||
(lambda () (syntax-type e r w (source-annotation e) #f mod #f))
|
||||
(lambda (type value e w s mod)
|
||||
(chi-expr type value e r w s mod)))))
|
||||
(expand-expr type value e r w s mod)))))
|
||||
|
||||
(define chi-expr
|
||||
(define expand-expr
|
||||
(lambda (type value e r w s mod)
|
||||
(case type
|
||||
((lexical)
|
||||
|
@ -1297,9 +1294,9 @@
|
|||
((module-ref)
|
||||
(call-with-values (lambda () (value e r w))
|
||||
(lambda (e r w s mod)
|
||||
(chi e r w mod))))
|
||||
(expand e r w mod))))
|
||||
((lexical-call)
|
||||
(chi-call
|
||||
(expand-call
|
||||
(let ((id (car e)))
|
||||
(build-lexical-reference 'fun (source-annotation id)
|
||||
(if (syntax-object? id)
|
||||
|
@ -1308,7 +1305,7 @@
|
|||
value))
|
||||
e r w s mod))
|
||||
((global-call)
|
||||
(chi-call
|
||||
(expand-call
|
||||
(build-global-reference (source-annotation (car e))
|
||||
(if (syntax-object? value)
|
||||
(syntax-object-expression value)
|
||||
|
@ -1319,19 +1316,19 @@
|
|||
e r w s mod))
|
||||
((constant) (build-data s (strip (source-wrap e w s mod) empty-wrap)))
|
||||
((global) (build-global-reference s value mod))
|
||||
((call) (chi-call (chi (car e) r w mod) e r w s mod))
|
||||
((call) (expand-call (expand (car e) r w mod) e r w s mod))
|
||||
((begin-form)
|
||||
(syntax-case e ()
|
||||
((_ e1 e2 ...) (chi-sequence #'(e1 e2 ...) r w s mod))))
|
||||
((_ e1 e2 ...) (expand-sequence #'(e1 e2 ...) r w s mod))))
|
||||
((local-syntax-form)
|
||||
(chi-local-syntax value e r w s mod chi-sequence))
|
||||
(expand-local-syntax value e r w s mod expand-sequence))
|
||||
((eval-when-form)
|
||||
(syntax-case e ()
|
||||
((_ (x ...) e1 e2 ...)
|
||||
(let ((when-list (chi-when-list e #'(x ...) w)))
|
||||
(let ((when-list (parse-when-list e #'(x ...))))
|
||||
(if (memq 'eval when-list)
|
||||
(chi-sequence #'(e1 e2 ...) r w s mod)
|
||||
(chi-void))))))
|
||||
(expand-sequence #'(e1 e2 ...) r w s mod)
|
||||
(expand-void))))))
|
||||
((define-form define-syntax-form define-syntax-parameter-form)
|
||||
(syntax-violation #f "definition in expression context"
|
||||
e (wrap value w mod)))
|
||||
|
@ -1344,12 +1341,12 @@
|
|||
(else (syntax-violation #f "unexpected syntax"
|
||||
(source-wrap e w s mod))))))
|
||||
|
||||
(define chi-call
|
||||
(define expand-call
|
||||
(lambda (x e r w s mod)
|
||||
(syntax-case e ()
|
||||
((e0 e1 ...)
|
||||
(build-call s x
|
||||
(map (lambda (e) (chi e r w mod)) #'(e1 ...)))))))
|
||||
(map (lambda (e) (expand e r w mod)) #'(e1 ...)))))))
|
||||
|
||||
;; (What follows is my interpretation of what's going on here -- Andy)
|
||||
;;
|
||||
|
@ -1384,7 +1381,7 @@
|
|||
;; really nice if we could also annotate introduced expressions with the
|
||||
;; locations corresponding to the macro definition, but that is not yet
|
||||
;; possible.
|
||||
(define chi-macro
|
||||
(define expand-macro
|
||||
(lambda (p e r w s rib mod)
|
||||
(define rebuild-macro-output
|
||||
(lambda (x m)
|
||||
|
@ -1425,7 +1422,7 @@
|
|||
(rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
|
||||
(new-mark))))
|
||||
|
||||
(define chi-body
|
||||
(define expand-body
|
||||
;; In processing the forms of the body, we create a new, empty wrap.
|
||||
;; This wrap is augmented (destructively) each time we discover that
|
||||
;; the next form is a definition. This is done:
|
||||
|
@ -1509,19 +1506,19 @@
|
|||
(f (cdr forms)))))
|
||||
ids labels var-ids vars vals bindings))))
|
||||
((local-syntax-form)
|
||||
(chi-local-syntax value e er w s mod
|
||||
(lambda (forms er w s mod)
|
||||
(parse (let f ((forms forms))
|
||||
(if (null? forms)
|
||||
(cdr body)
|
||||
(cons (cons er (wrap (car forms) w mod))
|
||||
(f (cdr forms)))))
|
||||
ids labels var-ids vars vals bindings))))
|
||||
(expand-local-syntax value e er w s mod
|
||||
(lambda (forms er w s mod)
|
||||
(parse (let f ((forms forms))
|
||||
(if (null? forms)
|
||||
(cdr body)
|
||||
(cons (cons er (wrap (car forms) w mod))
|
||||
(f (cdr forms)))))
|
||||
ids labels var-ids vars vals bindings))))
|
||||
(else ; found a non-definition
|
||||
(if (null? ids)
|
||||
(build-sequence no-source
|
||||
(map (lambda (x)
|
||||
(chi (cdr x) (car x) empty-wrap mod))
|
||||
(expand (cdr x) (car x) empty-wrap mod))
|
||||
(cons (cons er (source-wrap e w s mod))
|
||||
(cdr body))))
|
||||
(begin
|
||||
|
@ -1540,7 +1537,7 @@
|
|||
(macros-only-env er))))
|
||||
(set-cdr! b
|
||||
(eval-local-transformer
|
||||
(chi (cddr b) r-cache empty-wrap mod)
|
||||
(expand (cddr b) r-cache empty-wrap mod)
|
||||
mod))
|
||||
(if (eq? (car b) 'syntax-parameter)
|
||||
(set-cdr! b (list (cdr b))))
|
||||
|
@ -1551,15 +1548,15 @@
|
|||
(reverse (map syntax->datum var-ids))
|
||||
(reverse vars)
|
||||
(map (lambda (x)
|
||||
(chi (cdr x) (car x) empty-wrap mod))
|
||||
(expand (cdr x) (car x) empty-wrap mod))
|
||||
(reverse vals))
|
||||
(build-sequence no-source
|
||||
(map (lambda (x)
|
||||
(chi (cdr x) (car x) empty-wrap mod))
|
||||
(expand (cdr x) (car x) empty-wrap mod))
|
||||
(cons (cons er (source-wrap e w s mod))
|
||||
(cdr body)))))))))))))))))
|
||||
|
||||
(define chi-local-syntax
|
||||
(define expand-local-syntax
|
||||
(lambda (rec? e r w s mod k)
|
||||
(syntax-case e ()
|
||||
((_ ((id val) ...) e1 e2 ...)
|
||||
|
@ -1576,7 +1573,7 @@
|
|||
(map (lambda (x)
|
||||
(make-binding 'macro
|
||||
(eval-local-transformer
|
||||
(chi x trans-r w mod)
|
||||
(expand x trans-r w mod)
|
||||
mod)))
|
||||
#'(val ...)))
|
||||
r)
|
||||
|
@ -1593,7 +1590,7 @@
|
|||
p
|
||||
(syntax-violation #f "nonprocedure transformer" p)))))
|
||||
|
||||
(define chi-void
|
||||
(define expand-void
|
||||
(lambda ()
|
||||
(build-void no-source)))
|
||||
|
||||
|
@ -1623,7 +1620,7 @@
|
|||
orig-args))))
|
||||
(req orig-args '())))
|
||||
|
||||
(define chi-simple-lambda
|
||||
(define expand-simple-lambda
|
||||
(lambda (e r w s mod req rest meta body)
|
||||
(let* ((ids (if rest (append req (list rest)) req))
|
||||
(vars (map gen-var ids))
|
||||
|
@ -1632,10 +1629,10 @@
|
|||
s
|
||||
(map syntax->datum req) (and rest (syntax->datum rest)) vars
|
||||
meta
|
||||
(chi-body body (source-wrap e w s mod)
|
||||
(extend-var-env labels vars r)
|
||||
(make-binding-wrap ids labels w)
|
||||
mod)))))
|
||||
(expand-body body (source-wrap e w s mod)
|
||||
(extend-var-env labels vars r)
|
||||
(make-binding-wrap ids labels w)
|
||||
mod)))))
|
||||
|
||||
(define lambda*-formals
|
||||
(lambda (orig-args)
|
||||
|
@ -1718,16 +1715,16 @@
|
|||
orig-args))))
|
||||
(req orig-args '())))
|
||||
|
||||
(define chi-lambda-case
|
||||
(define expand-lambda-case
|
||||
(lambda (e r w s mod get-formals clauses)
|
||||
(define (expand-req req opt rest kw body)
|
||||
(define (parse-req req opt rest kw body)
|
||||
(let ((vars (map gen-var req))
|
||||
(labels (gen-labels req)))
|
||||
(let ((r* (extend-var-env labels vars r))
|
||||
(w* (make-binding-wrap req labels w)))
|
||||
(expand-opt (map syntax->datum req)
|
||||
opt rest kw body (reverse vars) r* w* '() '()))))
|
||||
(define (expand-opt req opt rest kw body vars r* w* out inits)
|
||||
(parse-opt (map syntax->datum req)
|
||||
opt rest kw body (reverse vars) r* w* '() '()))))
|
||||
(define (parse-opt req opt rest kw body vars r* w* out inits)
|
||||
(cond
|
||||
((pair? opt)
|
||||
(syntax-case (car opt) ()
|
||||
|
@ -1736,27 +1733,27 @@
|
|||
(l (gen-labels (list v)))
|
||||
(r** (extend-var-env l (list v) r*))
|
||||
(w** (make-binding-wrap (list #'id) l w*)))
|
||||
(expand-opt req (cdr opt) rest kw body (cons v vars)
|
||||
r** w** (cons (syntax->datum #'id) out)
|
||||
(cons (chi #'i r* w* mod) inits))))))
|
||||
(parse-opt req (cdr opt) rest kw body (cons v vars)
|
||||
r** w** (cons (syntax->datum #'id) out)
|
||||
(cons (expand #'i r* w* mod) inits))))))
|
||||
(rest
|
||||
(let* ((v (gen-var rest))
|
||||
(l (gen-labels (list v)))
|
||||
(r* (extend-var-env l (list v) r*))
|
||||
(w* (make-binding-wrap (list rest) l w*)))
|
||||
(expand-kw req (if (pair? out) (reverse out) #f)
|
||||
(syntax->datum rest)
|
||||
(if (pair? kw) (cdr kw) kw)
|
||||
body (cons v vars) r* w*
|
||||
(if (pair? kw) (car kw) #f)
|
||||
'() inits)))
|
||||
(parse-kw req (if (pair? out) (reverse out) #f)
|
||||
(syntax->datum rest)
|
||||
(if (pair? kw) (cdr kw) kw)
|
||||
body (cons v vars) r* w*
|
||||
(if (pair? kw) (car kw) #f)
|
||||
'() inits)))
|
||||
(else
|
||||
(expand-kw req (if (pair? out) (reverse out) #f) #f
|
||||
(if (pair? kw) (cdr kw) kw)
|
||||
body vars r* w*
|
||||
(if (pair? kw) (car kw) #f)
|
||||
'() inits))))
|
||||
(define (expand-kw req opt rest kw body vars r* w* aok out inits)
|
||||
(parse-kw req (if (pair? out) (reverse out) #f) #f
|
||||
(if (pair? kw) (cdr kw) kw)
|
||||
body vars r* w*
|
||||
(if (pair? kw) (car kw) #f)
|
||||
'() inits))))
|
||||
(define (parse-kw req opt rest kw body vars r* w* aok out inits)
|
||||
(cond
|
||||
((pair? kw)
|
||||
(syntax-case (car kw) ()
|
||||
|
@ -1765,31 +1762,31 @@
|
|||
(l (gen-labels (list v)))
|
||||
(r** (extend-var-env l (list v) r*))
|
||||
(w** (make-binding-wrap (list #'id) l w*)))
|
||||
(expand-kw req opt rest (cdr kw) body (cons v vars)
|
||||
r** w** aok
|
||||
(cons (list (syntax->datum #'k)
|
||||
(syntax->datum #'id)
|
||||
v)
|
||||
out)
|
||||
(cons (chi #'i r* w* mod) inits))))))
|
||||
(parse-kw req opt rest (cdr kw) body (cons v vars)
|
||||
r** w** aok
|
||||
(cons (list (syntax->datum #'k)
|
||||
(syntax->datum #'id)
|
||||
v)
|
||||
out)
|
||||
(cons (expand #'i r* w* mod) inits))))))
|
||||
(else
|
||||
(expand-body req opt rest
|
||||
(if (or aok (pair? out)) (cons aok (reverse out)) #f)
|
||||
body (reverse vars) r* w* (reverse inits) '()))))
|
||||
(define (expand-body req opt rest kw body vars r* w* inits meta)
|
||||
(parse-body req opt rest
|
||||
(if (or aok (pair? out)) (cons aok (reverse out)) #f)
|
||||
body (reverse vars) r* w* (reverse inits) '()))))
|
||||
(define (parse-body req opt rest kw body vars r* w* inits meta)
|
||||
(syntax-case body ()
|
||||
((docstring e1 e2 ...) (string? (syntax->datum #'docstring))
|
||||
(expand-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
|
||||
(append meta
|
||||
`((documentation
|
||||
. ,(syntax->datum #'docstring))))))
|
||||
(parse-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
|
||||
(append meta
|
||||
`((documentation
|
||||
. ,(syntax->datum #'docstring))))))
|
||||
((#((k . v) ...) e1 e2 ...)
|
||||
(expand-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
|
||||
(append meta (syntax->datum #'((k . v) ...)))))
|
||||
(parse-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
|
||||
(append meta (syntax->datum #'((k . v) ...)))))
|
||||
((e1 e2 ...)
|
||||
(values meta req opt rest kw inits vars
|
||||
(chi-body #'(e1 e2 ...) (source-wrap e w s mod)
|
||||
r* w* mod)))))
|
||||
(expand-body #'(e1 e2 ...) (source-wrap e w s mod)
|
||||
r* w* mod)))))
|
||||
|
||||
(syntax-case clauses ()
|
||||
(() (values '() #f))
|
||||
|
@ -1797,12 +1794,12 @@
|
|||
(call-with-values (lambda () (get-formals #'args))
|
||||
(lambda (req opt rest kw)
|
||||
(call-with-values (lambda ()
|
||||
(expand-req req opt rest kw #'(e1 e2 ...)))
|
||||
(parse-req req opt rest kw #'(e1 e2 ...)))
|
||||
(lambda (meta req opt rest kw inits vars body)
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(chi-lambda-case e r w s mod get-formals
|
||||
#'((args* e1* e2* ...) ...)))
|
||||
(expand-lambda-case e r w s mod get-formals
|
||||
#'((args* e1* e2* ...) ...)))
|
||||
(lambda (meta* else*)
|
||||
(values
|
||||
(append meta meta*)
|
||||
|
@ -1900,9 +1897,9 @@
|
|||
(map (lambda (x)
|
||||
(make-binding
|
||||
'macro
|
||||
(eval-local-transformer (chi x trans-r w mod) mod)))
|
||||
(eval-local-transformer (expand x trans-r w mod) mod)))
|
||||
#'(val ...)))))
|
||||
(chi-body #'(e1 e2 ...)
|
||||
(expand-body #'(e1 e2 ...)
|
||||
(source-wrap e w s mod)
|
||||
(extend-env names bindings r)
|
||||
w
|
||||
|
@ -2094,7 +2091,7 @@
|
|||
((#((k . v) ...) e1 e2 ...)
|
||||
(lp #'(e1 e2 ...)
|
||||
(append meta (syntax->datum #'((k . v) ...)))))
|
||||
(_ (chi-simple-lambda e r w s mod req rest meta body)))))))
|
||||
(_ (expand-simple-lambda e r w s mod req rest meta body)))))))
|
||||
(_ (syntax-violation 'lambda "bad lambda" e)))))
|
||||
|
||||
(global-extend 'core 'lambda*
|
||||
|
@ -2103,8 +2100,8 @@
|
|||
((_ args e1 e2 ...)
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(chi-lambda-case e r w s mod
|
||||
lambda*-formals #'((args e1 e2 ...))))
|
||||
(expand-lambda-case e r w s mod
|
||||
lambda*-formals #'((args e1 e2 ...))))
|
||||
(lambda (meta lcase)
|
||||
(build-case-lambda s meta lcase))))
|
||||
(_ (syntax-violation 'lambda "bad lambda*" e)))))
|
||||
|
@ -2115,9 +2112,9 @@
|
|||
((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(chi-lambda-case e r w s mod
|
||||
lambda-formals
|
||||
#'((args e1 e2 ...) (args* e1* e2* ...) ...)))
|
||||
(expand-lambda-case e r w s mod
|
||||
lambda-formals
|
||||
#'((args e1 e2 ...) (args* e1* e2* ...) ...)))
|
||||
(lambda (meta lcase)
|
||||
(build-case-lambda s meta lcase))))
|
||||
(_ (syntax-violation 'case-lambda "bad case-lambda" e)))))
|
||||
|
@ -2128,16 +2125,16 @@
|
|||
((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(chi-lambda-case e r w s mod
|
||||
lambda*-formals
|
||||
#'((args e1 e2 ...) (args* e1* e2* ...) ...)))
|
||||
(expand-lambda-case e r w s mod
|
||||
lambda*-formals
|
||||
#'((args e1 e2 ...) (args* e1* e2* ...) ...)))
|
||||
(lambda (meta lcase)
|
||||
(build-case-lambda s meta lcase))))
|
||||
(_ (syntax-violation 'case-lambda "bad case-lambda*" e)))))
|
||||
|
||||
(global-extend 'core 'let
|
||||
(let ()
|
||||
(define (chi-let e r w s mod constructor ids vals exps)
|
||||
(define (expand-let e r w s mod constructor ids vals exps)
|
||||
(if (not (valid-bound-ids? ids))
|
||||
(syntax-violation 'let "duplicate bound variable" e)
|
||||
(let ((labels (gen-labels ids))
|
||||
|
@ -2147,25 +2144,25 @@
|
|||
(constructor s
|
||||
(map syntax->datum ids)
|
||||
new-vars
|
||||
(map (lambda (x) (chi x r w mod)) vals)
|
||||
(chi-body exps (source-wrap e nw s mod)
|
||||
nr nw mod))))))
|
||||
(map (lambda (x) (expand x r w mod)) vals)
|
||||
(expand-body exps (source-wrap e nw s mod)
|
||||
nr nw mod))))))
|
||||
(lambda (e r w s mod)
|
||||
(syntax-case e ()
|
||||
((_ ((id val) ...) e1 e2 ...)
|
||||
(and-map id? #'(id ...))
|
||||
(chi-let e r w s mod
|
||||
build-let
|
||||
#'(id ...)
|
||||
#'(val ...)
|
||||
#'(e1 e2 ...)))
|
||||
(expand-let e r w s mod
|
||||
build-let
|
||||
#'(id ...)
|
||||
#'(val ...)
|
||||
#'(e1 e2 ...)))
|
||||
((_ f ((id val) ...) e1 e2 ...)
|
||||
(and (id? #'f) (and-map id? #'(id ...)))
|
||||
(chi-let e r w s mod
|
||||
build-named-let
|
||||
#'(f id ...)
|
||||
#'(val ...)
|
||||
#'(e1 e2 ...)))
|
||||
(expand-let e r w s mod
|
||||
build-named-let
|
||||
#'(f id ...)
|
||||
#'(val ...)
|
||||
#'(e1 e2 ...)))
|
||||
(_ (syntax-violation 'let "bad let" (source-wrap e w s mod)))))))
|
||||
|
||||
|
||||
|
@ -2184,9 +2181,9 @@
|
|||
(build-letrec s #f
|
||||
(map syntax->datum ids)
|
||||
new-vars
|
||||
(map (lambda (x) (chi x r w mod)) #'(val ...))
|
||||
(chi-body #'(e1 e2 ...)
|
||||
(source-wrap e w s mod) r w mod)))))))
|
||||
(map (lambda (x) (expand x r w mod)) #'(val ...))
|
||||
(expand-body #'(e1 e2 ...)
|
||||
(source-wrap e w s mod) r w mod)))))))
|
||||
(_ (syntax-violation 'letrec "bad letrec" (source-wrap e w s mod))))))
|
||||
|
||||
|
||||
|
@ -2205,9 +2202,9 @@
|
|||
(build-letrec s #t
|
||||
(map syntax->datum ids)
|
||||
new-vars
|
||||
(map (lambda (x) (chi x r w mod)) #'(val ...))
|
||||
(chi-body #'(e1 e2 ...)
|
||||
(source-wrap e w s mod) r w mod)))))))
|
||||
(map (lambda (x) (expand x r w mod)) #'(val ...))
|
||||
(expand-body #'(e1 e2 ...)
|
||||
(source-wrap e w s mod) r w mod)))))))
|
||||
(_ (syntax-violation 'letrec* "bad letrec*" (source-wrap e w s mod))))))
|
||||
|
||||
|
||||
|
@ -2223,14 +2220,14 @@
|
|||
(case type
|
||||
((lexical)
|
||||
(build-lexical-assignment s (syntax->datum #'id) value
|
||||
(chi #'val r w mod)))
|
||||
(expand #'val r w mod)))
|
||||
((global)
|
||||
(build-global-assignment s value (chi #'val r w mod) id-mod))
|
||||
(build-global-assignment s value (expand #'val r w mod) id-mod))
|
||||
((macro)
|
||||
(if (procedure-property value 'variable-transformer)
|
||||
;; As syntax-type does, call chi-macro with
|
||||
;; As syntax-type does, call expand-macro with
|
||||
;; the mod of the expression. Hmm.
|
||||
(chi (chi-macro value e r w s #f mod) r empty-wrap mod)
|
||||
(expand (expand-macro value e r w s #f mod) r empty-wrap mod)
|
||||
(syntax-violation 'set! "not a variable transformer"
|
||||
(wrap e w mod)
|
||||
(wrap #'id w id-mod))))
|
||||
|
@ -2245,7 +2242,7 @@
|
|||
(lambda (type value ee ww ss modmod)
|
||||
(case type
|
||||
((module-ref)
|
||||
(let ((val (chi #'val r w mod)))
|
||||
(let ((val (expand #'val r w mod)))
|
||||
(call-with-values (lambda () (value #'(head tail ...) r w))
|
||||
(lambda (e r w s* mod)
|
||||
(syntax-case e ()
|
||||
|
@ -2254,8 +2251,8 @@
|
|||
val mod)))))))
|
||||
(else
|
||||
(build-call s
|
||||
(chi #'(setter head) r w mod)
|
||||
(map (lambda (e) (chi e r w mod))
|
||||
(expand #'(setter head) r w mod)
|
||||
(map (lambda (e) (expand e r w mod))
|
||||
#'(tail ... val))))))))
|
||||
(_ (syntax-violation 'set! "bad set!" (source-wrap e w s mod))))))
|
||||
|
||||
|
@ -2301,15 +2298,15 @@
|
|||
((_ test then)
|
||||
(build-conditional
|
||||
s
|
||||
(chi #'test r w mod)
|
||||
(chi #'then r w mod)
|
||||
(expand #'test r w mod)
|
||||
(expand #'then r w mod)
|
||||
(build-void no-source)))
|
||||
((_ test then else)
|
||||
(build-conditional
|
||||
s
|
||||
(chi #'test r w mod)
|
||||
(chi #'then r w mod)
|
||||
(chi #'else r w mod))))))
|
||||
(expand #'test r w mod)
|
||||
(expand #'then r w mod)
|
||||
(expand #'else r w mod))))))
|
||||
|
||||
(global-extend 'core 'with-fluids
|
||||
(lambda (e r w s mod)
|
||||
|
@ -2317,10 +2314,10 @@
|
|||
((_ ((fluid val) ...) b b* ...)
|
||||
(build-dynlet
|
||||
s
|
||||
(map (lambda (x) (chi x r w mod)) #'(fluid ...))
|
||||
(map (lambda (x) (chi x r w mod)) #'(val ...))
|
||||
(chi-body #'(b b* ...)
|
||||
(source-wrap e w s mod) r w mod))))))
|
||||
(map (lambda (x) (expand x r w mod)) #'(fluid ...))
|
||||
(map (lambda (x) (expand x r w mod)) #'(val ...))
|
||||
(expand-body #'(b b* ...)
|
||||
(source-wrap e w s mod) r w mod))))))
|
||||
|
||||
(global-extend 'begin 'begin '())
|
||||
|
||||
|
@ -2410,7 +2407,7 @@
|
|||
no-source
|
||||
'apply
|
||||
(list (build-simple-lambda no-source (map syntax->datum ids) #f new-vars '()
|
||||
(chi exp
|
||||
(expand exp
|
||||
(extend-env
|
||||
labels
|
||||
(map (lambda (var level)
|
||||
|
@ -2467,14 +2464,14 @@
|
|||
(and-map (lambda (x) (not (free-id=? #'pat x)))
|
||||
(cons #'(... ...) keys)))
|
||||
(if (free-id=? #'pad #'_)
|
||||
(chi #'exp r empty-wrap mod)
|
||||
(expand #'exp r empty-wrap mod)
|
||||
(let ((labels (list (gen-label)))
|
||||
(var (gen-var #'pat)))
|
||||
(build-call no-source
|
||||
(build-simple-lambda
|
||||
no-source (list (syntax->datum #'pat)) #f (list var)
|
||||
'()
|
||||
(chi #'exp
|
||||
(expand #'exp
|
||||
(extend-env labels
|
||||
(list (make-binding 'syntax `(,var . 0)))
|
||||
r)
|
||||
|
@ -2505,10 +2502,10 @@
|
|||
#'(key ...) #'(m ...)
|
||||
r
|
||||
mod))
|
||||
(list (chi #'val r empty-wrap mod))))
|
||||
(list (expand #'val r empty-wrap mod))))
|
||||
(syntax-violation 'syntax-case "invalid literals list" e))))))))
|
||||
|
||||
;; The portable macroexpand seeds chi-top's mode m with 'e (for
|
||||
;; The portable macroexpand seeds expand-top's mode m with 'e (for
|
||||
;; evaluating) and esew (which stands for "eval syntax expanders
|
||||
;; when") with '(eval). In Chez Scheme, m is set to 'c instead of e
|
||||
;; if we are compiling a file, and esew is set to
|
||||
|
@ -2519,8 +2516,8 @@
|
|||
;; the object file if we are compiling a file.
|
||||
(set! macroexpand
|
||||
(lambda* (x #:optional (m 'e) (esew '(eval)))
|
||||
(chi-top-sequence (list x) null-env top-wrap #f m esew
|
||||
(cons 'hygiene (module-name (current-module))))))
|
||||
(expand-top-sequence (list x) null-env top-wrap #f m esew
|
||||
(cons 'hygiene (module-name (current-module))))))
|
||||
|
||||
(set! identifier?
|
||||
(lambda (x)
|
||||
|
|
|
@ -66,9 +66,7 @@
|
|||
;;;
|
||||
|
||||
(define block-growth-factor
|
||||
(let ((f (make-fluid)))
|
||||
(fluid-set! f 2)
|
||||
f))
|
||||
(make-fluid 2))
|
||||
|
||||
(define-syntax-rule (define-inline (name formals ...) body ...)
|
||||
;; Work around the lack of an inliner.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; Guile Emacs Lisp
|
||||
|
||||
;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
;;;
|
||||
;;; This library is free software; you can redistribute it and/or
|
||||
;;; modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -131,8 +131,8 @@
|
|||
((_ name value)
|
||||
(with-syntax ((scheme-name (make-id #'name 'macro- #'name)))
|
||||
#'(begin
|
||||
(define-public scheme-name (make-fluid))
|
||||
(fluid-set! scheme-name (cons 'macro value))))))))
|
||||
(define-public scheme-name
|
||||
(make-fluid (cons 'macro value)))))))))
|
||||
|
||||
(define-syntax defspecial
|
||||
(lambda (x)
|
||||
|
@ -140,10 +140,10 @@
|
|||
((_ name args body ...)
|
||||
(with-syntax ((scheme-name (make-id #'name 'compile- #'name)))
|
||||
#'(begin
|
||||
(define scheme-name (make-fluid))
|
||||
(fluid-set! scheme-name
|
||||
(cons 'special-operator
|
||||
(lambda args body ...)))))))))
|
||||
(define scheme-name
|
||||
(make-fluid
|
||||
(cons 'special-operator
|
||||
(lambda args body ...))))))))))
|
||||
|
||||
;;; Call a guile-primitive that may be rebound for elisp and thus needs
|
||||
;;; absolute addressing.
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
(define-module (scripts compile)
|
||||
#:use-module ((system base compile) #:select (compile-file))
|
||||
#:use-module (system base target)
|
||||
#:use-module (system base message)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-13)
|
||||
|
@ -88,7 +89,12 @@
|
|||
(lambda (opt name arg result)
|
||||
(if (assoc-ref result 'to)
|
||||
(fail "`--to' option cannot be specified more than once")
|
||||
(alist-cons 'to (string->symbol arg) result))))))
|
||||
(alist-cons 'to (string->symbol arg) result))))
|
||||
(option '(#\T "target") #t #f
|
||||
(lambda (opt name arg result)
|
||||
(if (assoc-ref result 'target)
|
||||
(fail "`--target' option cannot be specified more than once")
|
||||
(alist-cons 'target arg result))))))
|
||||
|
||||
(define (parse-args args)
|
||||
"Parse argument list @var{args} and return an alist with all the relevant
|
||||
|
@ -109,7 +115,7 @@ options."
|
|||
|
||||
(define (show-version)
|
||||
(format #t "compile (GNU Guile) ~A~%" (version))
|
||||
(format #t "Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
(format #t "Copyright (C) 2009, 2011 Free Software Foundation, Inc.
|
||||
License LGPLv3+: GNU LGPL version 3 or later <http://gnu.org/licenses/lgpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.~%"))
|
||||
|
@ -134,6 +140,7 @@ There is NO WARRANTY, to the extent permitted by law.~%"))
|
|||
o)))
|
||||
(from (or (assoc-ref options 'from) 'scheme))
|
||||
(to (or (assoc-ref options 'to) 'objcode))
|
||||
(target (or (assoc-ref options 'target) %host-type))
|
||||
(input-files (assoc-ref options 'input-files))
|
||||
(output-file (assoc-ref options 'output-file))
|
||||
(load-path (assoc-ref options 'load-path)))
|
||||
|
@ -152,6 +159,7 @@ Compile each Guile source file FILE into a Guile object.
|
|||
|
||||
-f, --from=LANG specify a source language other than `scheme'
|
||||
-t, --to=LANG specify a target language other than `objcode'
|
||||
-T, --target=TRIPLET produce bytecode for host TRIPLET
|
||||
|
||||
Note that auto-compilation will be turned off.
|
||||
|
||||
|
@ -171,11 +179,13 @@ Report bugs to <~A>.~%"
|
|||
(for-each (lambda (file)
|
||||
(format #t "wrote `~A'\n"
|
||||
(with-fluids ((*current-warning-prefix* ""))
|
||||
(compile-file file
|
||||
#:output-file output-file
|
||||
#:from from
|
||||
#:to to
|
||||
#:opts compile-opts))))
|
||||
(with-target target
|
||||
(lambda ()
|
||||
(compile-file file
|
||||
#:output-file output-file
|
||||
#:from from
|
||||
#:to to
|
||||
#:opts compile-opts))))))
|
||||
input-files)))
|
||||
|
||||
(define main compile)
|
||||
|
|
|
@ -57,37 +57,41 @@
|
|||
(define get-conv-tag (lambda () 'get-conv)) ;; arbitrary unique (as per eq?) value
|
||||
|
||||
(define (make-parameter/helper val conv)
|
||||
(let ((value (make-fluid))
|
||||
(conv conv))
|
||||
(begin
|
||||
(fluid-set! value (conv val))
|
||||
(lambda new-value
|
||||
(cond
|
||||
((null? new-value) (fluid-ref value))
|
||||
((eq? (car new-value) get-fluid-tag) value)
|
||||
((eq? (car new-value) get-conv-tag) conv)
|
||||
((null? (cdr new-value)) (fluid-set! value (conv (car new-value))))
|
||||
(else (error "make-parameter expects 0 or 1 arguments" new-value)))))))
|
||||
(let ((fluid (make-fluid (conv val))))
|
||||
(case-lambda
|
||||
(()
|
||||
(fluid-ref fluid))
|
||||
((new-value)
|
||||
(cond
|
||||
((eq? new-value get-fluid-tag) fluid)
|
||||
((eq? new-value get-conv-tag) conv)
|
||||
(else (fluid-set! fluid (conv new-value))))))))
|
||||
|
||||
(define-syntax-rule (parameterize ((?param ?value) ...) ?body ...)
|
||||
(with-parameters* (list ?param ...)
|
||||
(list ?value ...)
|
||||
(lambda () ?body ...)))
|
||||
|
||||
(define (current-input-port . new-value)
|
||||
(if (null? new-value)
|
||||
((@ (guile) current-input-port))
|
||||
(apply set-current-input-port new-value)))
|
||||
(define current-input-port
|
||||
(case-lambda
|
||||
(()
|
||||
((@ (guile) current-input-port)))
|
||||
((new-value)
|
||||
(set-current-input-port new-value))))
|
||||
|
||||
(define (current-output-port . new-value)
|
||||
(if (null? new-value)
|
||||
((@ (guile) current-output-port))
|
||||
(apply set-current-output-port new-value)))
|
||||
(define current-output-port
|
||||
(case-lambda
|
||||
(()
|
||||
((@ (guile) current-output-port)))
|
||||
((new-value)
|
||||
(set-current-output-port new-value))))
|
||||
|
||||
(define (current-error-port . new-value)
|
||||
(if (null? new-value)
|
||||
((@ (guile) current-error-port))
|
||||
(apply set-current-error-port new-value)))
|
||||
(define current-error-port
|
||||
(case-lambda
|
||||
(()
|
||||
((@ (guile) current-error-port)))
|
||||
((new-value)
|
||||
(set-current-error-port new-value))))
|
||||
|
||||
(define port-list
|
||||
(list current-input-port current-output-port current-error-port))
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
;;; Current language
|
||||
;;;
|
||||
|
||||
(define *current-language* (make-fluid))
|
||||
(define *current-language* (make-fluid 'scheme))
|
||||
|
||||
(define (current-language)
|
||||
(or (fluid-ref *current-language*) 'scheme))
|
||||
(fluid-ref *current-language*))
|
||||
|
|
|
@ -56,15 +56,13 @@
|
|||
|
||||
(define *current-warning-port*
|
||||
;; The port where warnings are sent.
|
||||
(make-fluid))
|
||||
(make-fluid (current-error-port)))
|
||||
|
||||
(fluid-set! *current-warning-port* (current-error-port))
|
||||
|
||||
(define *current-warning-prefix*
|
||||
;; Prefix string when emitting a warning.
|
||||
(make-fluid))
|
||||
|
||||
(fluid-set! *current-warning-prefix* ";;; ")
|
||||
(make-fluid ";;; "))
|
||||
|
||||
|
||||
(define-record-type <warning-type>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
(define-module (system base target)
|
||||
#:use-module (rnrs bytevectors)
|
||||
#:use-module (ice-9 regex)
|
||||
#:export (target-type with-target
|
||||
|
||||
target-cpu target-vendor target-os
|
||||
|
@ -33,44 +34,90 @@
|
|||
;;; Target types
|
||||
;;;
|
||||
|
||||
(define %target-type (make-fluid))
|
||||
(define %native-word-size
|
||||
;; The native word size. Note: don't use `word-size' from
|
||||
;; (system vm objcode) to avoid a circular dependency.
|
||||
((@ (system foreign) sizeof) '*))
|
||||
|
||||
(define (target-type)
|
||||
(or (fluid-ref %target-type)
|
||||
%host-type))
|
||||
(define %target-type (make-fluid %host-type))
|
||||
(define %target-endianness (make-fluid (native-endianness)))
|
||||
(define %target-word-size (make-fluid %native-word-size))
|
||||
|
||||
(define (validate-target target)
|
||||
(if (or (not (string? target))
|
||||
(let ((parts (string-split target #\-)))
|
||||
(or (< 3 (length parts))
|
||||
(or (< (length parts) 3)
|
||||
(or-map string-null? parts))))
|
||||
(error "invalid target" target)))
|
||||
|
||||
(define (with-target target thunk)
|
||||
(validate-target target)
|
||||
(with-fluids ((%target-type target))
|
||||
(thunk)))
|
||||
(let ((cpu (triplet-cpu target)))
|
||||
(with-fluids ((%target-type target)
|
||||
(%target-endianness (cpu-endianness cpu))
|
||||
(%target-word-size (cpu-word-size cpu)))
|
||||
(thunk))))
|
||||
|
||||
(define (target-cpu)
|
||||
(let ((t (target-type)))
|
||||
(substring t 0 (string-index t #\-))))
|
||||
(define (cpu-endianness cpu)
|
||||
"Return the endianness for CPU."
|
||||
(if (string=? cpu (triplet-cpu %host-type))
|
||||
(native-endianness)
|
||||
(cond ((string-match "^i[0-9]86$" cpu)
|
||||
(endianness little))
|
||||
((member cpu '("x86_64" "ia64"
|
||||
"powerpcle" "powerpc64le" "mipsel" "mips64el"))
|
||||
(endianness little))
|
||||
((member cpu '("sparc" "sparc64" "powerpc" "powerpc64" "spu"
|
||||
"mips" "mips64"))
|
||||
(endianness big))
|
||||
((string-match "^arm.*el" cpu)
|
||||
(endianness little))
|
||||
(else
|
||||
(error "unknown CPU endianness" cpu)))))
|
||||
|
||||
(define (target-vendor)
|
||||
(let* ((t (target-type))
|
||||
(start (1+ (string-index t #\-))))
|
||||
(define (cpu-word-size cpu)
|
||||
"Return the word size for CPU."
|
||||
(if (string=? cpu (triplet-cpu %host-type))
|
||||
%native-word-size
|
||||
(cond ((string-match "^i[0-9]86$" cpu) 4)
|
||||
((string-match "64$" cpu) 8)
|
||||
((string-match "64[lbe][lbe]$" cpu) 8)
|
||||
((member cpu '("sparc" "powerpc" "mips")) 4)
|
||||
((string-match "^arm.*" cpu) 4)
|
||||
(else "unknown CPU word size" cpu))))
|
||||
|
||||
(define (triplet-cpu t)
|
||||
(substring t 0 (string-index t #\-)))
|
||||
|
||||
(define (triplet-vendor t)
|
||||
(let ((start (1+ (string-index t #\-))))
|
||||
(substring t start (string-index t #\- start))))
|
||||
|
||||
(define (target-os)
|
||||
(let* ((t (target-type))
|
||||
(start (1+ (string-index t #\- (1+ (string-index t #\-))))))
|
||||
(define (triplet-os t)
|
||||
(let ((start (1+ (string-index t #\- (1+ (string-index t #\-))))))
|
||||
(substring t start)))
|
||||
|
||||
|
||||
(define (target-type)
|
||||
"Return the GNU configuration triplet of the target platform."
|
||||
(fluid-ref %target-type))
|
||||
|
||||
(define (target-cpu)
|
||||
"Return the CPU name of the target platform."
|
||||
(triplet-cpu (target-type)))
|
||||
|
||||
(define (target-vendor)
|
||||
"Return the vendor name of the target platform."
|
||||
(triplet-vendor (target-type)))
|
||||
|
||||
(define (target-os)
|
||||
"Return the operating system name of the target platform."
|
||||
(triplet-os (target-type)))
|
||||
|
||||
(define (target-endianness)
|
||||
(if (equal? (target-type) %host-type)
|
||||
(native-endianness)
|
||||
(error "cross-compilation not yet handled" %host-type (target-type))))
|
||||
"Return the endianness object of the target platform."
|
||||
(fluid-ref %target-endianness))
|
||||
|
||||
(define (target-word-size)
|
||||
(if (equal? (target-type) %host-type)
|
||||
((@ (system foreign) sizeof) '*)
|
||||
(error "cross-compilation not yet handled" %host-type (target-type))))
|
||||
"Return the word size, in bytes, of the target platform."
|
||||
(fluid-ref %target-word-size))
|
||||
|
|
|
@ -134,7 +134,9 @@ See <http://www.gnu.org/licenses/lgpl.html>, for more details.")
|
|||
|
||||
(define %make-repl make-repl)
|
||||
(define* (make-repl lang #:optional debug)
|
||||
(%make-repl #:language (lookup-language lang)
|
||||
(%make-repl #:language (if (language? lang)
|
||||
lang
|
||||
(lookup-language lang))
|
||||
#:options (copy-tree repl-default-options)
|
||||
#:tm-stats (times)
|
||||
#:gc-stats (gc-stats)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;;; (texinfo plain-text) -- rendering stexinfo as plain text
|
||||
;;;;
|
||||
;;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
;;;; Copyright (C) 2003,2004,2009 Andy Wingo <wingo at pobox dot com>
|
||||
;;;;
|
||||
;;;; This library is free software; you can redistribute it and/or
|
||||
|
@ -41,9 +41,6 @@
|
|||
(or (arg-ref key %-args)
|
||||
(error "Missing argument:" key %-args)))
|
||||
|
||||
(define *indent* (make-fluid))
|
||||
(define *itemizer* (make-fluid))
|
||||
|
||||
(define (make-ticker str)
|
||||
(lambda () str))
|
||||
(define (make-enumerator n)
|
||||
|
@ -52,9 +49,8 @@
|
|||
(set! n (1+ n))
|
||||
(format #f "~A. " last))))
|
||||
|
||||
(fluid-set! *indent* "")
|
||||
;; Shouldn't be necessary to do this, but just in case.
|
||||
(fluid-set! *itemizer* (make-ticker "* "))
|
||||
(define *indent* (make-fluid ""))
|
||||
(define *itemizer* (make-fluid (make-ticker "* ")))
|
||||
|
||||
(define-macro (with-indent n . body)
|
||||
`(with-fluids ((*indent* (string-append (fluid-ref *indent*)
|
||||
|
|
|
@ -470,7 +470,7 @@ ordered alist."
|
|||
val)
|
||||
|
||||
(define (default-val-validator k val)
|
||||
(string? val))
|
||||
(or (not val) (string? val)))
|
||||
|
||||
(define (default-val-writer k val port)
|
||||
(if (or (string-index val #\;)
|
||||
|
@ -518,9 +518,9 @@ ordered alist."
|
|||
((pair? elt)
|
||||
(let ((k (car elt))
|
||||
(v (cdr elt)))
|
||||
(and (or (string? k) (symbol? k))
|
||||
(and (symbol? k)
|
||||
(valid? k v))))
|
||||
((or (string? elt) (symbol? elt))
|
||||
((symbol? elt)
|
||||
(valid? elt #f))
|
||||
(else #f)))))
|
||||
|
||||
|
@ -611,7 +611,7 @@ ordered alist."
|
|||
(valid? default-val-validator))
|
||||
(list-of? list
|
||||
(lambda (elt)
|
||||
(key-value-list? list valid?))))
|
||||
(key-value-list? elt valid?))))
|
||||
|
||||
(define* (write-param-list list port #:optional
|
||||
(val-writer default-val-writer))
|
||||
|
@ -871,7 +871,10 @@ ordered alist."
|
|||
(cons scheme (parse-key-value-list str default-val-parser delim end)))))))
|
||||
|
||||
(define (validate-credentials val)
|
||||
(and (pair? val) (symbol? (car val)) (key-value-list? (cdr val))))
|
||||
(and (pair? val) (symbol? (car val))
|
||||
(case (car val)
|
||||
((basic) (string? (cdr val)))
|
||||
(else (key-value-list? (cdr val))))))
|
||||
|
||||
(define (write-credentials val port)
|
||||
(display (car val) port)
|
||||
|
@ -1137,7 +1140,7 @@ phrase\"."
|
|||
(lambda (str)
|
||||
(map string->symbol (split-and-trim str)))
|
||||
(lambda (v)
|
||||
(list-of? symbol? v))
|
||||
(list-of? v symbol?))
|
||||
(lambda (v port)
|
||||
(write-list v port display ", "))))
|
||||
|
||||
|
@ -1242,7 +1245,14 @@ phrase\"."
|
|||
((private no-cache)
|
||||
(and v-str (split-header-names v-str)))
|
||||
(else v-str)))
|
||||
default-val-validator
|
||||
(lambda (k v)
|
||||
(case k
|
||||
((max-age max-stale min-fresh s-maxage)
|
||||
(non-negative-integer? v))
|
||||
((private no-cache)
|
||||
(or (not v) (list-of-header-names? v)))
|
||||
(else
|
||||
(not v))))
|
||||
(lambda (k v port)
|
||||
(cond
|
||||
((string? v) (display v port))
|
||||
|
@ -1522,7 +1532,7 @@ phrase\"."
|
|||
(lambda (k v)
|
||||
(if (eq? k 'q)
|
||||
(valid-quality? v)
|
||||
(string? v)))
|
||||
(or (not v) (string? v))))
|
||||
(lambda (k v port)
|
||||
(if (eq? k 'q)
|
||||
(write-quality v port)
|
||||
|
|
|
@ -425,8 +425,7 @@
|
|||
(append (current-test-prefix) (list name)))
|
||||
|
||||
;;; A fluid containing the current test prefix, as a list.
|
||||
(define prefix-fluid (make-fluid))
|
||||
(fluid-set! prefix-fluid '())
|
||||
(define prefix-fluid (make-fluid '()))
|
||||
(define (current-test-prefix)
|
||||
(fluid-ref prefix-fluid))
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
;;;; Assembly to bytecode compilation -*- mode: scheme; coding: utf-8; -*-
|
||||
;;;;
|
||||
;;;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
|
||||
;;;;
|
||||
;;;; This library is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU Lesser General Public
|
||||
;;;; License as published by the Free Software Foundation; either
|
||||
;;;; version 3 of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;;
|
||||
;;;; This library 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
|
||||
;;;; Lesser General Public License for more details.
|
||||
;;;;
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU Lesser General Public
|
||||
;;;; License along with this library; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
@ -19,6 +21,8 @@
|
|||
#:use-module ((rnrs io ports) #:select (open-bytevector-output-port))
|
||||
#:use-module (test-suite lib)
|
||||
#:use-module (system vm instruction)
|
||||
#:use-module (system vm objcode)
|
||||
#:use-module (system base target)
|
||||
#:use-module (language assembly)
|
||||
#:use-module (language assembly compile-bytecode))
|
||||
|
||||
|
@ -114,3 +118,80 @@
|
|||
(uint32 0) ;; metalen
|
||||
make-int8 3
|
||||
return))))
|
||||
|
||||
|
||||
(define (test-triplet cpu vendor os)
|
||||
(let ((triplet (string-append cpu "-" vendor "-" os)))
|
||||
(pass-if (format #f "triplet ~a" triplet)
|
||||
(with-target triplet
|
||||
(lambda ()
|
||||
(and (string=? (target-cpu) cpu)
|
||||
(string=? (target-vendor) vendor)
|
||||
(string=? (target-os) os)))))))
|
||||
|
||||
(define %objcode-cookie-size
|
||||
(string-length "GOOF----LE-8-2.0"))
|
||||
|
||||
(define (test-target triplet endian word-size)
|
||||
(pass-if (format #f "target `~a' honored" triplet)
|
||||
(call-with-values (lambda ()
|
||||
(open-bytevector-output-port))
|
||||
(lambda (p get-objcode)
|
||||
(with-target triplet
|
||||
(lambda ()
|
||||
(let ((b (compile-bytecode
|
||||
'(load-program () 16 #f
|
||||
(assert-nargs-ee/locals 1)
|
||||
(make-int8 77)
|
||||
(toplevel-ref 1)
|
||||
(local-ref 0)
|
||||
(mul)
|
||||
(add)
|
||||
(return)
|
||||
(nop) (nop) (nop)
|
||||
(nop) (nop))
|
||||
#f)))
|
||||
(write-objcode (bytecode->objcode b) p)
|
||||
(let ((cookie (make-bytevector %objcode-cookie-size))
|
||||
(expected (format #f "GOOF----~a-~a-~a"
|
||||
(cond ((eq? endian (endianness little))
|
||||
"LE")
|
||||
((eq? endian (endianness big))
|
||||
"BE")
|
||||
(else
|
||||
(error "unknown endianness"
|
||||
endian)))
|
||||
word-size
|
||||
(effective-version))))
|
||||
(bytevector-copy! (get-objcode) 0 cookie 0
|
||||
%objcode-cookie-size)
|
||||
(string=? (utf8->string cookie) expected)))))))))
|
||||
|
||||
(with-test-prefix "cross-compilation"
|
||||
|
||||
(test-triplet "i586" "pc" "gnu0.3")
|
||||
(test-triplet "x86_64" "unknown" "linux-gnu")
|
||||
(test-triplet "x86_64" "unknown" "kfreebsd-gnu")
|
||||
|
||||
(test-target "i586-pc-gnu0.3" (endianness little) 4)
|
||||
(test-target "x86_64-pc-linux-gnu" (endianness little) 8)
|
||||
(test-target "powerpc-unknown-linux-gnu" (endianness big) 4)
|
||||
(test-target "sparc64-unknown-freebsd8.2" (endianness big) 8)
|
||||
|
||||
(pass-if-exception "unknown target"
|
||||
exception:miscellaneous-error
|
||||
(call-with-values (lambda ()
|
||||
(open-bytevector-output-port))
|
||||
(lambda (p get-objcode)
|
||||
(let* ((b (compile-bytecode '(load-program () 3 #f
|
||||
(make-int8 77)
|
||||
(return))
|
||||
#f))
|
||||
(o (bytecode->objcode b)))
|
||||
(with-target "fcpu-unknown-gnu1.0"
|
||||
(lambda ()
|
||||
(write-objcode o p))))))))
|
||||
|
||||
;; Local Variables:
|
||||
;; eval: (put 'with-target 'scheme-indent-function 1)
|
||||
;; End:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;;; bytevectors.test --- R6RS bytevectors. -*- mode: scheme; coding: utf-8; -*-
|
||||
;;;;
|
||||
;;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
;;;; Ludovic Courtès
|
||||
;;;;
|
||||
;;;; This library is free software; you can redistribute it and/or
|
||||
|
@ -42,7 +42,14 @@
|
|||
(and (bytevector=? (make-bytevector 20 7)
|
||||
(make-bytevector 20 7))
|
||||
(not (bytevector=? (make-bytevector 20 7)
|
||||
(make-bytevector 20 0))))))
|
||||
(make-bytevector 20 0)))))
|
||||
|
||||
(pass-if "bytevector-copy! overlapping"
|
||||
;; See <http://debbugs.gnu.org/10070>.
|
||||
(let ((b (u8-list->bytevector '(1 2 3 4 5 6 7 8))))
|
||||
(bytevector-copy! b 0 b 3 4)
|
||||
(bytevector->u8-list b)
|
||||
(bytevector=? b #vu8(1 2 3 1 2 3 4 8)))))
|
||||
|
||||
|
||||
(with-test-prefix/c&e "2.3 Operations on Bytes and Octets"
|
||||
|
|
|
@ -231,10 +231,10 @@
|
|||
|
||||
(with-test-prefix "define set procedure-name"
|
||||
|
||||
(expect-fail "closure"
|
||||
(pass-if "closure"
|
||||
(eq? 'foo-closure (procedure-name bar-closure)))
|
||||
|
||||
(expect-fail "procedure-with-setter"
|
||||
(expect-fail "procedure-with-setter" ; FIXME: `pass-if' when it's supported
|
||||
(eq? 'foo-pws (procedure-name bar-pws))))
|
||||
|
||||
;;;
|
||||
|
@ -330,78 +330,49 @@
|
|||
0))
|
||||
|
||||
(with-test-prefix "stacks"
|
||||
(with-debugging-evaluator
|
||||
(pass-if "stack involving a primitive"
|
||||
;; The primitive involving the error must appear exactly once on the
|
||||
;; stack.
|
||||
(catch 'result
|
||||
(lambda ()
|
||||
(start-stack 'foo
|
||||
(with-throw-handler 'wrong-type-arg
|
||||
(lambda ()
|
||||
;; Trigger a `wrong-type-arg' exception.
|
||||
(hashq-ref 'wrong 'type 'arg))
|
||||
(lambda _
|
||||
(let* ((stack (make-stack #t))
|
||||
(frames (stack->frames stack)))
|
||||
(throw 'result
|
||||
(count (lambda (frame)
|
||||
(eq? (frame-procedure frame)
|
||||
hashq-ref))
|
||||
frames)))))))
|
||||
(lambda (key result)
|
||||
(= 1 result))))
|
||||
|
||||
(pass-if "stack involving a subr"
|
||||
;; The subr involving the error must appear exactly once on the stack.
|
||||
(catch 'result
|
||||
(lambda ()
|
||||
(throw 'unresolved)
|
||||
(start-stack 'foo
|
||||
(lazy-catch 'wrong-type-arg
|
||||
(lambda ()
|
||||
;; Trigger a `wrong-type-arg' exception.
|
||||
(fluid-ref 'not-a-fluid))
|
||||
(lambda _
|
||||
(let* ((stack (make-stack #t))
|
||||
(frames (stack->frames stack)))
|
||||
(throw 'result
|
||||
(count (lambda (frame)
|
||||
(and (frame-procedure? frame)
|
||||
(eq? (frame-procedure frame)
|
||||
fluid-ref)))
|
||||
frames)))))))
|
||||
(lambda (key result)
|
||||
(= 1 result))))
|
||||
|
||||
(pass-if "stack involving a gsubr"
|
||||
;; The gsubr involving the error must appear exactly once on the stack.
|
||||
;; This is less obvious since gsubr application may require an
|
||||
;; additional `SCM_APPLY ()' call, which should not be visible to the
|
||||
;; application.
|
||||
(catch 'result
|
||||
(lambda ()
|
||||
(throw 'unresolved)
|
||||
(start-stack 'foo
|
||||
(lazy-catch 'wrong-type-arg
|
||||
(lambda ()
|
||||
;; Trigger a `wrong-type-arg' exception.
|
||||
(hashq-ref 'wrong 'type 'arg))
|
||||
(lambda _
|
||||
(let* ((stack (make-stack #t))
|
||||
(frames (stack->frames stack)))
|
||||
(throw 'result
|
||||
(count (lambda (frame)
|
||||
(and (frame-procedure? frame)
|
||||
(eq? (frame-procedure frame)
|
||||
hashq-ref)))
|
||||
frames)))))))
|
||||
(lambda (key result)
|
||||
(= 1 result))))
|
||||
|
||||
(pass-if "arguments of a gsubr stack frame"
|
||||
;; Create a stack with two gsubr frames and make sure the arguments are
|
||||
;; correct.
|
||||
(catch 'result
|
||||
(lambda ()
|
||||
(throw 'unresolved)
|
||||
(start-stack 'foo
|
||||
(lazy-catch 'wrong-type-arg
|
||||
(lambda ()
|
||||
;; Trigger a `wrong-type-arg' exception.
|
||||
(substring 'wrong 'type 'arg))
|
||||
(lambda _
|
||||
(let* ((stack (make-stack #t))
|
||||
(frames (stack->frames stack)))
|
||||
(throw 'result
|
||||
(map (lambda (frame)
|
||||
(cons (frame-procedure frame)
|
||||
(frame-arguments frame)))
|
||||
frames)))))))
|
||||
(lambda (key result)
|
||||
(and (equal? (car result) `(,make-stack #t))
|
||||
(pair? (member `(,substring wrong type arg)
|
||||
(cdr result)))))))))
|
||||
(pass-if "arguments of a primitive stack frame"
|
||||
;; Create a stack with two primitive frames and make sure the
|
||||
;; arguments are correct.
|
||||
(catch 'result
|
||||
(lambda ()
|
||||
(start-stack 'foo
|
||||
(with-throw-handler 'wrong-type-arg
|
||||
(lambda ()
|
||||
;; Trigger a `wrong-type-arg' exception.
|
||||
(substring 'wrong 'type 'arg))
|
||||
(lambda _
|
||||
(let* ((stack (make-stack #t))
|
||||
(frames (stack->frames stack)))
|
||||
(throw 'result
|
||||
(map (lambda (frame)
|
||||
(cons (frame-procedure frame)
|
||||
(frame-arguments frame)))
|
||||
frames)))))))
|
||||
(lambda (key result)
|
||||
(and (equal? (car result) `(,make-stack #t))
|
||||
(pair? (member `(,substring wrong type arg)
|
||||
(cdr result))))))))
|
||||
|
||||
;;;
|
||||
;;; letrec init evaluation
|
||||
|
|
|
@ -254,6 +254,16 @@
|
|||
(map proc* arg1 arg2 arg3)))
|
||||
(throw 'unresolved)))
|
||||
|
||||
(pass-if "procedures returning a pointer"
|
||||
(if (defined? 'procedure->pointer)
|
||||
(let* ((called? #f)
|
||||
(proc (lambda (i) (set! called? #t) (make-pointer i)))
|
||||
(pointer (procedure->pointer '* proc (list int)))
|
||||
(proc* (pointer->procedure '* pointer (list int)))
|
||||
(result (proc* 777)))
|
||||
(and called? (equal? result (make-pointer 777))))
|
||||
(throw 'unresolved)))
|
||||
|
||||
(pass-if "procedures returning void"
|
||||
(if (defined? 'procedure->pointer)
|
||||
(let* ((called? #f)
|
||||
|
@ -262,6 +272,22 @@
|
|||
(proc* (pointer->procedure void pointer '())))
|
||||
(proc*)
|
||||
called?)
|
||||
(throw 'unresolved)))
|
||||
|
||||
(pass-if "procedure is retained"
|
||||
;; The lambda passed to `procedure->pointer' must remain live.
|
||||
(if (defined? 'procedure->pointer)
|
||||
(let* ((ptr (procedure->pointer int
|
||||
(lambda (x) (+ x 7))
|
||||
(list int)))
|
||||
(procs (unfold (cut >= <> 10000)
|
||||
(lambda (i)
|
||||
(pointer->procedure int ptr (list int)))
|
||||
1+
|
||||
0)))
|
||||
(gc) (gc) (gc)
|
||||
(every (cut = <> 9)
|
||||
(map (lambda (f) (f 2)) procs)))
|
||||
(throw 'unresolved))))
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;;;; procprop.test --- Procedure properties -*- mode: scheme; coding: utf-8; -*-
|
||||
;;;; Ludovic Courtès <ludo@gnu.org>
|
||||
;;;;
|
||||
;;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
;;;;
|
||||
;;;; This library is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -26,7 +26,12 @@
|
|||
(eq? 'display (procedure-name display)))
|
||||
|
||||
(pass-if "gsubr"
|
||||
(eq? 'hashq-ref (procedure-name hashq-ref))))
|
||||
(eq? 'hashq-ref (procedure-name hashq-ref)))
|
||||
|
||||
(pass-if "from eval"
|
||||
(eq? 'foobar (procedure-name
|
||||
(eval '(begin (define (foobar) #t) foobar)
|
||||
(current-module))))))
|
||||
|
||||
|
||||
(with-test-prefix "procedure-arity"
|
||||
|
@ -52,4 +57,19 @@
|
|||
|
||||
(pass-if "list"
|
||||
(equal? (procedure-minimum-arity list)
|
||||
'(0 0 #t))))
|
||||
'(0 0 #t)))
|
||||
|
||||
(pass-if "fixed, eval"
|
||||
(equal? (procedure-minimum-arity (eval '(lambda (a b) #t)
|
||||
(current-module)))
|
||||
'(2 0 #f)))
|
||||
|
||||
(pass-if "rest, eval"
|
||||
(equal? (procedure-minimum-arity (eval '(lambda (a b . c) #t)
|
||||
(current-module)))
|
||||
'(2 0 #t)))
|
||||
|
||||
(pass-if "opt, eval"
|
||||
(equal? (procedure-minimum-arity (eval '(lambda* (a b #:optional c) #t)
|
||||
(current-module)))
|
||||
'(2 1 #f))))
|
||||
|
|
|
@ -41,8 +41,9 @@
|
|||
(syntax-rules ()
|
||||
((_ sym str val)
|
||||
(pass-if (format #f "~a: ~s -> ~s" 'sym str val)
|
||||
(equal? (parse-header 'sym str)
|
||||
val)))))
|
||||
(and (equal? (parse-header 'sym str)
|
||||
val)
|
||||
(valid-header? 'sym val))))))
|
||||
|
||||
(define-syntax pass-if-any-error
|
||||
(syntax-rules ()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue