2009-11-30 23:32:28 +01:00
|
|
|
|
;;; -*- mode: scheme; coding: utf-8; -*-
|
|
|
|
|
|
|
2010-02-16 23:01:09 +01:00
|
|
|
|
;;;; Copyright (C) 2009, 2010
|
2009-11-30 23:32:28 +01:00
|
|
|
|
;;;; 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
|
|
|
|
|
|
;;;;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;;; Scheme eval, written in Scheme.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Expressions are first expanded, by the syntax expander (i.e.
|
|
|
|
|
|
;;; psyntax), then memoized into internal forms. The evaluator itself
|
|
|
|
|
|
;;; only operates on the internal forms ("memoized expressions").
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Environments are represented as linked lists of the form (VAL ... .
|
|
|
|
|
|
;;; MOD). If MOD is #f, it means the environment was captured before
|
|
|
|
|
|
;;; modules were booted. If MOD is the literal value '(), we are
|
|
|
|
|
|
;;; evaluating at the top level, and so should track changes to the
|
|
|
|
|
|
;;; current module.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Evaluate this in Emacs to make code indentation work right:
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; (put 'memoized-expression-case 'scheme-indent-function 1)
|
2009-11-30 23:32:28 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(eval-when (compile)
|
|
|
|
|
|
(define-syntax capture-env
|
|
|
|
|
|
(syntax-rules ()
|
2010-06-13 20:17:49 +02:00
|
|
|
|
((_ (exp ...))
|
|
|
|
|
|
(let ((env (exp ...)))
|
|
|
|
|
|
(capture-env env)))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
((_ env)
|
|
|
|
|
|
(if (null? env)
|
|
|
|
|
|
(current-module)
|
|
|
|
|
|
(if (not env)
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;; the and current-module checks that modules are booted,
|
|
|
|
|
|
;; and thus the-root-module is defined
|
really boot primitive-eval from scheme.
* libguile/eval.c (scm_primitive_eval, scm_c_primitive_eval):
(scm_init_eval): Rework so that scm_primitive_eval always calls out to
the primitive-eval variable. The previous definition is the default
value, which is probably overridden by scm_init_eval_in_scheme.
* libguile/init.c (scm_i_init_guile): Move ports and load-path up, so we
can debug when initing eval. Call scm_init_eval_in_scheme. Awesome.
* libguile/load.h:
* libguile/load.c (scm_init_eval_in_scheme): New procedure, loads up
ice-9/eval.scm to replace the primitive-eval definition, if everything
is there and up-to-date.
* libguile/modules.c (scm_module_transformer): Export to Scheme, so it's
there for eval.go.
* module/ice-9/boot-9.scm: No need to define module-transformer.
* module/ice-9/eval.scm (capture-env): Only reference the-root-module if
modules are booted.
(primitive-eval): Inline a definition for identity. Throw a more
standard error for "wrong number of arguments".
* module/ice-9/psyntax.scm (chi-install-global): The macro binding for a
syncase macro is now a pair: the transformer, and the module that was
current when the transformer was installed. The latter is used for
hygiene purposes, replacing the use of procedure-module, which didn't
work with the interpreter's shared-code closures.
(chi-macro): Adapt for the binding being a pair, and get the hygiene
from the cdr.
(eval-local-transformer): Adapt to new form of macro bindings.
* module/ice-9/psyntax-pp.scm: Regenerated.
* .gitignore: Ignore eval.go.stamp.
* module/Makefile.am: Reorder for fastest serial compilation, now that
there are no ordering constraints. I did a number of experiments here
and this seems to be the best; but the bulk of the time is compiling
psyntax-pp.scm with eval.scm. Not so great.
* libguile/vm-engine.c (vm-engine): Throw a more standard error for
"wrong type to apply".
* test-suite/tests/gc.test ("gc"): Remove a hack that shouldn't affect
the new evaluator, and throw in another (gc) for good measure.
* test-suite/tests/goops.test ("defining classes"):
* test-suite/tests/hooks.test (proc1): We can't currently check what the
arity is of a closure made by eval.scm -- or more accurately all
closures have 0 required args and no rest args. So punt for now.
* test-suite/tests/syntax.test ("letrec"): The scheme evaluator can't
check that a variable is unbound, currently; perhaps the full "fixing
letrec" expansion could fix this. But barring that, punt.
2009-12-01 23:54:25 +01:00
|
|
|
|
(and (current-module) the-root-module)
|
2009-11-30 23:32:28 +01:00
|
|
|
|
env)))))
|
|
|
|
|
|
|
2010-05-13 17:15:10 +02:00
|
|
|
|
;; Fast case for procedures with fixed arities.
|
|
|
|
|
|
(define-syntax make-fixed-closure
|
2009-12-13 16:18:39 +01:00
|
|
|
|
(lambda (x)
|
2009-12-13 17:05:10 +01:00
|
|
|
|
(define *max-static-argument-count* 8)
|
2009-12-13 16:18:39 +01:00
|
|
|
|
(define (make-formals n)
|
|
|
|
|
|
(map (lambda (i)
|
|
|
|
|
|
(datum->syntax
|
|
|
|
|
|
x
|
|
|
|
|
|
(string->symbol
|
|
|
|
|
|
(string (integer->char (+ (char->integer #\a) i))))))
|
|
|
|
|
|
(iota n)))
|
|
|
|
|
|
(syntax-case x ()
|
2010-05-13 17:15:10 +02:00
|
|
|
|
((_ eval nreq body env) (not (identifier? #'env))
|
2009-12-13 16:18:39 +01:00
|
|
|
|
#'(let ((e env))
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(make-fixed-closure eval nreq body e)))
|
|
|
|
|
|
((_ eval nreq body env)
|
2009-12-13 16:18:39 +01:00
|
|
|
|
#`(case nreq
|
|
|
|
|
|
#,@(map (lambda (nreq)
|
|
|
|
|
|
(let ((formals (make-formals nreq)))
|
|
|
|
|
|
#`((#,nreq)
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(lambda (#,@formals)
|
|
|
|
|
|
(eval body
|
|
|
|
|
|
(cons* #,@(reverse formals) env))))))
|
2009-12-13 16:18:39 +01:00
|
|
|
|
(iota *max-static-argument-count*))
|
|
|
|
|
|
(else
|
|
|
|
|
|
#,(let ((formals (make-formals *max-static-argument-count*)))
|
|
|
|
|
|
#`(lambda (#,@formals . more)
|
|
|
|
|
|
(let lp ((new-env (cons* #,@(reverse formals) env))
|
|
|
|
|
|
(nreq (- nreq #,*max-static-argument-count*))
|
|
|
|
|
|
(args more))
|
|
|
|
|
|
(if (zero? nreq)
|
|
|
|
|
|
(eval body
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(if (null? args)
|
|
|
|
|
|
new-env
|
|
|
|
|
|
(scm-error 'wrong-number-of-args
|
|
|
|
|
|
"eval" "Wrong number of arguments"
|
|
|
|
|
|
'() #f)))
|
2009-12-13 16:18:39 +01:00
|
|
|
|
(if (null? args)
|
|
|
|
|
|
(scm-error 'wrong-number-of-args
|
|
|
|
|
|
"eval" "Wrong number of arguments"
|
|
|
|
|
|
'() #f)
|
|
|
|
|
|
(lp (cons (car args) new-env)
|
|
|
|
|
|
(1- nreq)
|
|
|
|
|
|
(cdr args)))))))))))))
|
|
|
|
|
|
|
2009-12-13 17:05:10 +01:00
|
|
|
|
(define-syntax call
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(define *max-static-call-count* 4)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ eval proc nargs args env) (identifier? #'env)
|
|
|
|
|
|
#`(case nargs
|
|
|
|
|
|
#,@(map (lambda (nargs)
|
|
|
|
|
|
#`((#,nargs)
|
|
|
|
|
|
(proc
|
|
|
|
|
|
#,@(map
|
|
|
|
|
|
(lambda (n)
|
|
|
|
|
|
(let lp ((n n) (args #'args))
|
|
|
|
|
|
(if (zero? n)
|
|
|
|
|
|
#`(eval (car #,args) env)
|
|
|
|
|
|
(lp (1- n) #`(cdr #,args)))))
|
|
|
|
|
|
(iota nargs)))))
|
|
|
|
|
|
(iota *max-static-call-count*))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(apply proc
|
|
|
|
|
|
#,@(map
|
|
|
|
|
|
(lambda (n)
|
|
|
|
|
|
(let lp ((n n) (args #'args))
|
|
|
|
|
|
(if (zero? n)
|
|
|
|
|
|
#`(eval (car #,args) env)
|
|
|
|
|
|
(lp (1- n) #`(cdr #,args)))))
|
|
|
|
|
|
(iota *max-static-call-count*))
|
|
|
|
|
|
(let lp ((exps #,(let lp ((n *max-static-call-count*)
|
|
|
|
|
|
(args #'args))
|
|
|
|
|
|
(if (zero? n)
|
|
|
|
|
|
args
|
|
|
|
|
|
(lp (1- n) #`(cdr #,args)))))
|
|
|
|
|
|
(args '()))
|
|
|
|
|
|
(if (null? exps)
|
|
|
|
|
|
(reverse args)
|
|
|
|
|
|
(lp (cdr exps)
|
|
|
|
|
|
(cons (eval (car exps) env) args)))))))))))
|
|
|
|
|
|
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;; This macro could be more straightforward if the compiler had better
|
|
|
|
|
|
;; copy propagation. As it is we do some copy propagation by hand.
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(define-syntax mx-bind
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ data () body)
|
|
|
|
|
|
#'body)
|
|
|
|
|
|
((_ data (a . b) body) (and (identifier? #'a) (identifier? #'b))
|
|
|
|
|
|
#'(let ((a (car data))
|
|
|
|
|
|
(b (cdr data)))
|
|
|
|
|
|
body))
|
|
|
|
|
|
((_ data (a . b) body) (identifier? #'a)
|
|
|
|
|
|
#'(let ((a (car data))
|
|
|
|
|
|
(xb (cdr data)))
|
|
|
|
|
|
(mx-bind xb b body)))
|
|
|
|
|
|
((_ data (a . b) body)
|
|
|
|
|
|
#'(let ((xa (car data))
|
|
|
|
|
|
(xb (cdr data)))
|
|
|
|
|
|
(mx-bind xa a (mx-bind xb b body))))
|
|
|
|
|
|
((_ data v body) (identifier? #'v)
|
|
|
|
|
|
#'(let ((v data))
|
|
|
|
|
|
body)))))
|
|
|
|
|
|
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;; The resulting nested if statements will be an O(n) dispatch. Once
|
|
|
|
|
|
;; we compile `case' effectively, this situation will improve.
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(define-syntax mx-match
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x (quote)
|
|
|
|
|
|
((_ mx data tag)
|
|
|
|
|
|
#'(error "what" mx))
|
|
|
|
|
|
((_ mx data tag (('type pat) body) c* ...)
|
|
|
|
|
|
#`(if (eqv? tag #,(or (memoized-typecode (syntax->datum #'type))
|
|
|
|
|
|
(error "not a typecode" #'type)))
|
|
|
|
|
|
(mx-bind data pat body)
|
|
|
|
|
|
(mx-match mx data tag c* ...))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax memoized-expression-case
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ mx c ...)
|
|
|
|
|
|
#'(let ((tag (memoized-expression-typecode mx))
|
|
|
|
|
|
(data (memoized-expression-data mx)))
|
|
|
|
|
|
(mx-match mx data tag c ...)))))))
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; On 18 Feb 2010, I did a profile of how often the various memoized expression
|
|
|
|
|
|
;;; types occur when getting to a prompt on a fresh build. Here are the numbers
|
|
|
|
|
|
;;; I got:
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; lexical-ref: 32933054
|
|
|
|
|
|
;;; call: 20281547
|
|
|
|
|
|
;;; toplevel-ref: 13228724
|
|
|
|
|
|
;;; if: 9156156
|
|
|
|
|
|
;;; quote: 6610137
|
|
|
|
|
|
;;; let: 2619707
|
|
|
|
|
|
;;; lambda: 1010921
|
|
|
|
|
|
;;; begin: 948945
|
|
|
|
|
|
;;; lexical-set: 509862
|
|
|
|
|
|
;;; call-with-values: 139668
|
|
|
|
|
|
;;; apply: 49402
|
|
|
|
|
|
;;; module-ref: 14468
|
|
|
|
|
|
;;; define: 1259
|
|
|
|
|
|
;;; toplevel-set: 328
|
|
|
|
|
|
;;; dynwind: 162
|
|
|
|
|
|
;;; with-fluids: 0
|
|
|
|
|
|
;;; call/cc: 0
|
|
|
|
|
|
;;; module-set: 0
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; So until we compile `case' into a computed goto, we'll order the clauses in
|
|
|
|
|
|
;;; `eval' in this order, to put the most frequent cases first.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(define primitive-eval
|
|
|
|
|
|
(let ()
|
2010-05-13 17:15:10 +02:00
|
|
|
|
;; We pre-generate procedures with fixed arities, up to some number of
|
|
|
|
|
|
;; arguments; see make-fixed-closure above.
|
|
|
|
|
|
|
|
|
|
|
|
;; A unique marker for unbound keywords.
|
|
|
|
|
|
(define unbound-arg (list 'unbound-arg))
|
|
|
|
|
|
|
2010-05-13 21:43:35 +02:00
|
|
|
|
;; Procedures with rest, optional, or keyword arguments, potentially with
|
|
|
|
|
|
;; multiple arities, as with case-lambda.
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(define (make-general-closure env body nreq rest? nopt kw inits alt)
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(define alt-proc
|
|
|
|
|
|
(and alt
|
2010-05-19 22:51:31 +02:00
|
|
|
|
(let* ((body (car alt))
|
|
|
|
|
|
(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))
|
|
|
|
|
|
(kw (and tail (cadr tail)))
|
|
|
|
|
|
(inits (if tail (caddr tail) '()))
|
|
|
|
|
|
(alt (and tail (cadddr tail))))
|
|
|
|
|
|
(make-general-closure env body nreq rest nopt kw inits alt))))
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(lambda %args
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(let lp ((env env)
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(nreq* nreq)
|
|
|
|
|
|
(args %args))
|
|
|
|
|
|
(if (> nreq* 0)
|
2010-05-13 17:15:10 +02:00
|
|
|
|
;; First, bind required arguments.
|
|
|
|
|
|
(if (null? args)
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(if alt
|
|
|
|
|
|
(apply alt-proc %args)
|
|
|
|
|
|
(scm-error 'wrong-number-of-args
|
|
|
|
|
|
"eval" "Wrong number of arguments"
|
|
|
|
|
|
'() #f))
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(lp (cons (car args) env)
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(1- nreq*)
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(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)
|
2010-05-13 21:43:35 +02:00
|
|
|
|
(if alt
|
|
|
|
|
|
(apply alt-proc %args)
|
|
|
|
|
|
(scm-error 'wrong-number-of-args
|
|
|
|
|
|
"eval" "Wrong number of arguments"
|
|
|
|
|
|
'() #f))))
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(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))))))))))))))
|
|
|
|
|
|
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;; The "engine". EXP is a memoized expression.
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(define (eval exp env)
|
|
|
|
|
|
(memoized-expression-case exp
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('lexical-ref n)
|
2010-06-13 20:17:49 +02:00
|
|
|
|
(list-ref env n))
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('call (f nargs . args))
|
|
|
|
|
|
(let ((proc (eval f env)))
|
|
|
|
|
|
(call eval proc nargs args env)))
|
|
|
|
|
|
|
|
|
|
|
|
(('toplevel-ref var-or-sym)
|
|
|
|
|
|
(variable-ref
|
|
|
|
|
|
(if (variable? var-or-sym)
|
|
|
|
|
|
var-or-sym
|
2010-06-13 20:17:49 +02:00
|
|
|
|
(memoize-variable-access! exp
|
|
|
|
|
|
(capture-env (if (pair? env)
|
|
|
|
|
|
(cdr (last-pair env))
|
|
|
|
|
|
env))))))
|
2010-02-18 16:59:41 +01:00
|
|
|
|
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(('if (test consequent . alternate))
|
|
|
|
|
|
(if (eval test env)
|
|
|
|
|
|
(eval consequent env)
|
|
|
|
|
|
(eval alternate env)))
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('quote x)
|
|
|
|
|
|
x)
|
|
|
|
|
|
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(('let (inits . body))
|
|
|
|
|
|
(let lp ((inits inits) (new-env (capture-env env)))
|
|
|
|
|
|
(if (null? inits)
|
|
|
|
|
|
(eval body new-env)
|
|
|
|
|
|
(lp (cdr inits)
|
|
|
|
|
|
(cons (eval (car inits) env) new-env)))))
|
|
|
|
|
|
|
2010-05-12 12:17:18 +02:00
|
|
|
|
(('lambda (body nreq . tail))
|
2010-05-13 17:15:10 +02:00
|
|
|
|
(if (null? tail)
|
|
|
|
|
|
(make-fixed-closure eval nreq body (capture-env env))
|
|
|
|
|
|
(if (null? (cdr tail))
|
|
|
|
|
|
(make-general-closure (capture-env env) body nreq (car tail)
|
|
|
|
|
|
0 #f '() #f)
|
|
|
|
|
|
(apply make-general-closure (capture-env env) body nreq tail))))
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('begin (first . rest))
|
|
|
|
|
|
(let lp ((first first) (rest rest))
|
|
|
|
|
|
(if (null? rest)
|
|
|
|
|
|
(eval first env)
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(eval first env)
|
|
|
|
|
|
(lp (car rest) (cdr rest))))))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
|
|
|
|
|
|
(('lexical-set! (n . x))
|
|
|
|
|
|
(let ((val (eval x env)))
|
2010-06-13 20:17:49 +02:00
|
|
|
|
(list-set! env n val)))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('call-with-values (producer . consumer))
|
|
|
|
|
|
(call-with-values (eval producer env)
|
|
|
|
|
|
(eval consumer env)))
|
|
|
|
|
|
|
|
|
|
|
|
(('apply (f args))
|
|
|
|
|
|
(apply (eval f env) (eval args env)))
|
|
|
|
|
|
|
|
|
|
|
|
(('module-ref var-or-spec)
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(variable-ref
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(if (variable? var-or-spec)
|
|
|
|
|
|
var-or-spec
|
|
|
|
|
|
(memoize-variable-access! exp #f))))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('define (name . x))
|
|
|
|
|
|
(define! name (eval x env)))
|
|
|
|
|
|
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(('toplevel-set! (var-or-sym . x))
|
|
|
|
|
|
(variable-set!
|
|
|
|
|
|
(if (variable? var-or-sym)
|
|
|
|
|
|
var-or-sym
|
2010-06-13 20:17:49 +02:00
|
|
|
|
(memoize-variable-access! exp
|
|
|
|
|
|
(capture-env (if (pair? env)
|
|
|
|
|
|
(cdr (last-pair env))
|
|
|
|
|
|
env))))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(eval x env)))
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('dynwind (in exp . out))
|
|
|
|
|
|
(dynamic-wind (eval in env)
|
|
|
|
|
|
(lambda () (eval exp env))
|
|
|
|
|
|
(eval out env)))
|
|
|
|
|
|
|
2010-02-18 17:10:29 +01:00
|
|
|
|
(('with-fluids (fluids vals . exp))
|
|
|
|
|
|
(let* ((fluids (map (lambda (x) (eval x env)) fluids))
|
|
|
|
|
|
(vals (map (lambda (x) (eval x env)) vals)))
|
2010-02-25 00:32:40 +01:00
|
|
|
|
(let lp ((fluids fluids) (vals vals))
|
|
|
|
|
|
(if (null? fluids)
|
|
|
|
|
|
(eval exp env)
|
|
|
|
|
|
(with-fluids (((car fluids) (car vals)))
|
|
|
|
|
|
(lp (cdr fluids) (cdr vals)))))))
|
2010-02-18 17:10:29 +01:00
|
|
|
|
|
prompt as part of guile's primitive language
* libguile/control.h:
* libguile/control.c: Remove scm_atcontrol and scm_atprompt.
(scm_c_make_prompt): Remove handler arg, as the handler is inline.
(scm_abort): New primitive, exported to Scheme as `abort'. The
compiler will also recognize calls to `abort', but this is the base
case.
(scm_init_control): Remove scm_register_control, just have this
function, which adds `abort' to the `(guile)' module.
* libguile/eval.c (eval): Add SCM_M_PROMPT case.
* libguile/init.c (scm_i_init_guile): Change scm_register_control call
into a nice orderly scm_init_control call.
* libguile/memoize.h: (scm_sym_at_prompt, SCM_M_PROMPT):
* libguile/memoize.c (MAKMEMO_PROMPT, scm_m_at_prompt, unmemoize): Add
prompt support to the memoizer.
* libguile/vm-i-system.c (prompt): Fix to not expect a handler on the
stack.
* module/ice-9/boot-9.scm (prompt): Add definition in terms of @prompt.
* module/ice-9/control.scm: Simplify, and don't play with the compiler
here, now that prompt and abort are primitive.
* module/ice-9/eval.scm (primitive-eval): Add a prompt case.
* module/language/tree-il/primitives.scm
(*interesting-primitive-names*): Add @prompt and prompt.
2010-02-19 22:44:24 +01:00
|
|
|
|
(('prompt (tag exp . handler))
|
|
|
|
|
|
(@prompt (eval tag env)
|
|
|
|
|
|
(eval exp env)
|
|
|
|
|
|
(eval handler env)))
|
|
|
|
|
|
|
2010-02-18 16:59:41 +01:00
|
|
|
|
(('call/cc proc)
|
|
|
|
|
|
(call/cc (eval proc env)))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
|
|
|
|
|
|
(('module-set! (x . var-or-spec))
|
|
|
|
|
|
(variable-set!
|
|
|
|
|
|
(if (variable? var-or-spec)
|
|
|
|
|
|
var-or-spec
|
|
|
|
|
|
(memoize-variable-access! exp #f))
|
|
|
|
|
|
(eval x env)))))
|
|
|
|
|
|
|
2009-12-03 00:15:02 +01:00
|
|
|
|
;; primitive-eval
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(lambda (exp)
|
2009-12-03 00:15:02 +01:00
|
|
|
|
"Evaluate @var{exp} in the current module."
|
2009-11-30 23:32:28 +01:00
|
|
|
|
(eval
|
2010-05-20 12:25:52 +02:00
|
|
|
|
(memoize-expression
|
|
|
|
|
|
(if (macroexpanded? exp)
|
|
|
|
|
|
exp
|
|
|
|
|
|
((module-transformer (current-module)) exp)))
|
2009-11-30 23:32:28 +01:00
|
|
|
|
'()))))
|