summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Templeton <bpt@hcoop.net>2010-06-07 16:38:23 -0400
committerAndy Wingo <wingo@pobox.com>2010-12-07 13:21:01 +0100
commitf4e5e4114dad35276355470aa4096af3ec0b7d1c (patch)
tree23ecabfadb13573315b65c6c935e848d7c86b1fe
parentc983a199d8a941d7183e10b7a1d1ecb2e3ede837 (diff)
reindent
* module/language/elisp/bindings.scm: * module/language/elisp/compile-tree-il.scm: * module/language/elisp/lexer.scm: * module/language/elisp/parser.scm: * module/language/elisp/runtime.scm: * module/language/elisp/runtime/function-slot.scm: * module/language/elisp/runtime/macro-slot.scm: * module/language/elisp/spec.scm: Reindent. Signed-off-by: Andy Wingo <wingo@pobox.com>
-rw-r--r--module/language/elisp/bindings.scm74
-rw-r--r--module/language/elisp/compile-tree-il.scm812
-rw-r--r--module/language/elisp/lexer.scm426
-rw-r--r--module/language/elisp/parser.scm118
-rw-r--r--module/language/elisp/runtime.scm29
-rw-r--r--module/language/elisp/runtime/function-slot.scm224
-rw-r--r--module/language/elisp/runtime/macro-slot.scm147
-rw-r--r--module/language/elisp/spec.scm8
8 files changed, 1030 insertions, 808 deletions
diff --git a/module/language/elisp/bindings.scm b/module/language/elisp/bindings.scm
index b12e6f509..6ff56fdcd 100644
--- a/module/language/elisp/bindings.scm
+++ b/module/language/elisp/bindings.scm
@@ -20,8 +20,10 @@
(define-module (language elisp bindings)
#:export (make-bindings
- mark-global-needed! map-globals-needed
- with-lexical-bindings with-dynamic-bindings
+ mark-global-needed!
+ map-globals-needed
+ with-lexical-bindings
+ with-dynamic-bindings
get-lexical-binding))
;;; This module defines routines to handle analysis of symbol bindings
@@ -40,8 +42,7 @@
;;; Record type used to hold the data necessary.
(define bindings-type
- (make-record-type 'bindings
- '(needed-globals lexical-bindings)))
+ (make-record-type 'bindings '(needed-globals lexical-bindings)))
;;; Construct an 'empty' instance of the bindings data structure to be
;;; used at the start of a fresh compilation.
@@ -53,45 +54,50 @@
;;; slot-module.
(define (mark-global-needed! bindings sym module)
- (let* ((old-needed ((record-accessor bindings-type 'needed-globals) bindings))
+ (let* ((old-needed ((record-accessor bindings-type 'needed-globals)
+ bindings))
(old-in-module (or (assoc-ref old-needed module) '()))
(new-in-module (if (memq sym old-in-module)
- old-in-module
- (cons sym old-in-module)))
+ old-in-module
+ (cons sym old-in-module)))
(new-needed (assoc-set! old-needed module new-in-module)))
- ((record-modifier bindings-type 'needed-globals) bindings new-needed)))
+ ((record-modifier bindings-type 'needed-globals)
+ bindings
+ new-needed)))
;;; Cycle through all globals needed in order to generate the code for
;;; their creation or some other analysis.
(define (map-globals-needed bindings proc)
- (let ((needed ((record-accessor bindings-type 'needed-globals) bindings)))
+ (let ((needed ((record-accessor bindings-type 'needed-globals)
+ bindings)))
(let iterate-modules ((mod-tail needed)
(mod-result '()))
(if (null? mod-tail)
- mod-result
- (iterate-modules
- (cdr mod-tail)
- (let* ((aentry (car mod-tail))
- (module (car aentry))
- (symbols (cdr aentry)))
- (let iterate-symbols ((sym-tail symbols)
- (sym-result mod-result))
- (if (null? sym-tail)
- sym-result
- (iterate-symbols (cdr sym-tail)
- (cons (proc module (car sym-tail))
- sym-result))))))))))
+ mod-result
+ (iterate-modules
+ (cdr mod-tail)
+ (let* ((aentry (car mod-tail))
+ (module (car aentry))
+ (symbols (cdr aentry)))
+ (let iterate-symbols ((sym-tail symbols)
+ (sym-result mod-result))
+ (if (null? sym-tail)
+ sym-result
+ (iterate-symbols (cdr sym-tail)
+ (cons (proc module (car sym-tail))
+ sym-result))))))))))
;;; Get the current lexical binding (gensym it should refer to in the
;;; current scope) for a symbol or #f if it is dynamically bound.
(define (get-lexical-binding bindings sym)
- (let* ((lex ((record-accessor bindings-type 'lexical-bindings) bindings))
+ (let* ((lex ((record-accessor bindings-type 'lexical-bindings)
+ bindings))
(slot (hash-ref lex sym #f)))
(if slot
- (fluid-ref slot)
- #f)))
+ (fluid-ref slot)
+ #f)))
;;; Establish a binding or mark a symbol as dynamically bound for the
;;; extent of calling proc.
@@ -99,25 +105,25 @@
(define (with-symbol-bindings bindings syms targets proc)
(if (or (not (list? syms))
(not (and-map symbol? syms)))
- (error "can't bind non-symbols" syms))
- (let ((lex ((record-accessor bindings-type 'lexical-bindings) bindings)))
+ (error "can't bind non-symbols" syms))
+ (let ((lex ((record-accessor bindings-type 'lexical-bindings)
+ bindings)))
(for-each (lambda (sym)
(if (not (hash-ref lex sym))
- (hash-set! lex sym (make-fluid))))
+ (hash-set! lex sym (make-fluid))))
syms)
- (with-fluids* (map (lambda (sym)
- (hash-ref lex sym))
- syms)
+ (with-fluids* (map (lambda (sym) (hash-ref lex sym)) syms)
targets
proc)))
(define (with-lexical-bindings bindings syms targets proc)
(if (or (not (list? targets))
(not (and-map symbol? targets)))
- (error "invalid targets for lexical binding" targets)
- (with-symbol-bindings bindings syms targets proc)))
+ (error "invalid targets for lexical binding" targets)
+ (with-symbol-bindings bindings syms targets proc)))
(define (with-dynamic-bindings bindings syms proc)
(with-symbol-bindings bindings
- syms (map (lambda (el) #f) syms)
+ syms
+ (map (lambda (el) #f) syms)
proc))
diff --git a/module/language/elisp/compile-tree-il.scm b/module/language/elisp/compile-tree-il.scm
index af5096c20..8e7b14ab7 100644
--- a/module/language/elisp/compile-tree-il.scm
+++ b/module/language/elisp/compile-tree-il.scm
@@ -56,9 +56,11 @@
;;; Values to use for Elisp's nil and t.
-(define (nil-value loc) (make-const loc (@ (language elisp runtime) nil-value)))
+(define (nil-value loc)
+ (make-const loc (@ (language elisp runtime) nil-value)))
-(define (t-value loc) (make-const loc (@ (language elisp runtime) t-value)))
+(define (t-value loc)
+ (make-const loc (@ (language elisp runtime) t-value)))
;;; Modules that contain the value and function slot bindings.
@@ -96,8 +98,9 @@
(apply error args))
(define (runtime-error loc msg . args)
- (make-application loc (make-primitive-ref loc 'error)
- (cons (make-const loc msg) args)))
+ (make-application loc
+ (make-primitive-ref loc 'error)
+ (cons (make-const loc msg) args)))
;;; Generate code to ensure a global symbol is there for further use of
;;; a given symbol. In general during the compilation, those needed are
@@ -106,9 +109,10 @@
;;; this routine.
(define (generate-ensure-global loc sym module)
- (make-application loc (make-module-ref loc runtime 'ensure-fluid! #t)
- (list (make-const loc module)
- (make-const loc sym))))
+ (make-application loc
+ (make-module-ref loc runtime 'ensure-fluid! #t)
+ (list (make-const loc module)
+ (make-const loc sym))))
;;; See if we should do a void-check for a given variable. That means,
;;; check that this check is not disabled via the compiler options for
@@ -127,14 +131,18 @@
;;; setting/reverting their values with a dynamic-wind.
(define (let-dynamic loc syms module vals body)
- (call-primitive loc 'with-fluids*
- (make-application loc (make-primitive-ref loc 'list)
- (map (lambda (sym)
- (make-module-ref loc module sym #t))
- syms))
- (make-application loc (make-primitive-ref loc 'list) vals)
- (make-lambda loc '()
- (make-lambda-case #f '() #f #f #f '() '() body #f))))
+ (call-primitive
+ loc
+ 'with-fluids*
+ (make-application loc
+ (make-primitive-ref loc 'list)
+ (map (lambda (sym)
+ (make-module-ref loc module sym #t))
+ syms))
+ (make-application loc (make-primitive-ref loc 'list) vals)
+ (make-lambda loc
+ '()
+ (make-lambda-case #f '() #f #f #f '() '() body #f))))
;;; Handle access to a variable (reference/setting) correctly depending
;;; on whether it is currently lexically or dynamically bound. lexical
@@ -143,65 +151,80 @@
(define (access-variable loc sym module handle-lexical handle-dynamic)
(let ((lexical (get-lexical-binding (fluid-ref bindings-data) sym)))
(if (and lexical (equal? module value-slot))
- (handle-lexical lexical)
- (handle-dynamic))))
+ (handle-lexical lexical)
+ (handle-dynamic))))
;;; Generate code to reference a variable. For references in the
;;; value-slot module, we may want to generate a lexical reference
;;; instead if the variable has a lexical binding.
(define (reference-variable loc sym module)
- (access-variable loc sym module
- (lambda (lexical)
- (make-lexical-ref loc lexical lexical))
- (lambda ()
- (mark-global-needed! (fluid-ref bindings-data) sym module)
- (call-primitive loc 'fluid-ref
- (make-module-ref loc module sym #t)))))
+ (access-variable
+ loc
+ sym
+ module
+ (lambda (lexical) (make-lexical-ref loc lexical lexical))
+ (lambda ()
+ (mark-global-needed! (fluid-ref bindings-data) sym module)
+ (call-primitive loc
+ 'fluid-ref
+ (make-module-ref loc module sym #t)))))
;;; Reference a variable and error if the value is void.
(define (reference-with-check loc sym module)
(if (want-void-check? sym module)
- (let ((var (gensym)))
- (make-let loc '(value) `(,var) `(,(reference-variable loc sym module))
- (make-conditional loc
- (call-primitive loc 'eq?
+ (let ((var (gensym)))
+ (make-let
+ loc
+ '(value)
+ `(,var)
+ `(,(reference-variable loc sym module))
+ (make-conditional
+ loc
+ (call-primitive loc
+ 'eq?
(make-module-ref loc runtime 'void #t)
(make-lexical-ref loc 'value var))
(runtime-error loc "variable is void:" (make-const loc sym))
(make-lexical-ref loc 'value var))))
- (reference-variable loc sym module)))
+ (reference-variable loc sym module)))
;;; Generate code to set a variable. Just as with reference-variable, in
;;; case of a reference to value-slot, we want to generate a lexical set
;;; when the variable has a lexical binding.
(define (set-variable! loc sym module value)
- (access-variable loc sym module
- (lambda (lexical)
- (make-lexical-set loc lexical lexical value))
- (lambda ()
- (mark-global-needed! (fluid-ref bindings-data) sym module)
- (call-primitive loc 'fluid-set!
- (make-module-ref loc module sym #t)
- value))))
+ (access-variable
+ loc
+ sym
+ module
+ (lambda (lexical) (make-lexical-set loc lexical lexical value))
+ (lambda ()
+ (mark-global-needed! (fluid-ref bindings-data) sym module)
+ (call-primitive loc
+ 'fluid-set!
+ (make-module-ref loc module sym #t)
+ value))))
;;; Process the bindings part of a let or let* expression; that is,
;;; check for correctness and bring it to the form ((sym1 . val1) (sym2
;;; . val2) ...).
(define (process-let-bindings loc bindings)
- (map (lambda (b)
- (if (symbol? b)
- (cons b 'nil)
- (if (or (not (list? b))
- (not (= (length b) 2)))
- (report-error loc "expected symbol or list of 2 elements in let")
+ (map
+ (lambda (b)
+ (if (symbol? b)
+ (cons b 'nil)
+ (if (or (not (list? b))
+ (not (= (length b) 2)))
+ (report-error
+ loc
+ "expected symbol or list of 2 elements in let")
(if (not (symbol? (car b)))
- (report-error loc "expected symbol in let")
- (cons (car b) (cadr b))))))
- bindings))
+ (report-error loc "expected symbol in let")
+ (cons (car b) (cadr b))))))
+ bindings))
;;; Split the let bindings into a list to be done lexically and one
;;; dynamically. A symbol will be bound lexically if and only if: We're
@@ -222,10 +245,10 @@
(lexical '())
(dynamic '()))
(if (null? tail)
- (values (reverse lexical) (reverse dynamic))
- (if (bind-lexically? (caar tail) module)
- (iterate (cdr tail) (cons (car tail) lexical) dynamic)
- (iterate (cdr tail) lexical (cons (car tail) dynamic))))))
+ (values (reverse lexical) (reverse dynamic))
+ (if (bind-lexically? (caar tail) module)
+ (iterate (cdr tail) (cons (car tail) lexical) dynamic)
+ (iterate (cdr tail) lexical (cons (car tail) dynamic))))))
;;; Compile let and let* expressions. The code here is used both for
;;; let/let* and flet/flet*, just with a different bindings module.
@@ -243,36 +266,46 @@
(define (generate-let loc module bindings body)
(let ((bind (process-let-bindings loc bindings)))
(call-with-values
- (lambda ()
- (split-let-bindings bind module))
+ (lambda () (split-let-bindings bind module))
(lambda (lexical dynamic)
(for-each (lambda (sym)
- (mark-global-needed! (fluid-ref bindings-data) sym module))
+ (mark-global-needed! (fluid-ref bindings-data)
+ sym
+ module))
(map car dynamic))
(let ((make-values (lambda (for)
- (map (lambda (el)
- (compile-expr (cdr el)))
+ (map (lambda (el) (compile-expr (cdr el)))
for)))
(make-body (lambda ()
(make-sequence loc (map compile-expr body)))))
(if (null? lexical)
- (let-dynamic loc (map car dynamic) module
- (make-values dynamic) (make-body))
- (let* ((lexical-syms (map (lambda (el) (gensym)) lexical))
- (dynamic-syms (map (lambda (el) (gensym)) dynamic))
- (all-syms (append lexical-syms dynamic-syms))
- (vals (append (make-values lexical) (make-values dynamic))))
- (make-let loc all-syms all-syms vals
- (with-lexical-bindings (fluid-ref bindings-data)
- (map car lexical) lexical-syms
- (lambda ()
- (if (null? dynamic)
- (make-body)
- (let-dynamic loc (map car dynamic) module
- (map (lambda (sym)
- (make-lexical-ref loc sym sym))
- dynamic-syms)
- (make-body)))))))))))))
+ (let-dynamic loc (map car dynamic) module
+ (make-values dynamic) (make-body))
+ (let* ((lexical-syms (map (lambda (el) (gensym)) lexical))
+ (dynamic-syms (map (lambda (el) (gensym)) dynamic))
+ (all-syms (append lexical-syms dynamic-syms))
+ (vals (append (make-values lexical)
+ (make-values dynamic))))
+ (make-let loc
+ all-syms
+ all-syms
+ vals
+ (with-lexical-bindings
+ (fluid-ref bindings-data)
+ (map car lexical) lexical-syms
+ (lambda ()
+ (if (null? dynamic)
+ (make-body)
+ (let-dynamic loc
+ (map car dynamic)
+ module
+ (map
+ (lambda (sym)
+ (make-lexical-ref loc
+ sym
+ sym))
+ dynamic-syms)
+ (make-body)))))))))))))
;;; Let* is compiled to a cascaded set of "small lets" for each binding
;;; in turn so that each one already sees the preceding bindings.
@@ -282,23 +315,31 @@
(begin
(for-each (lambda (sym)
(if (not (bind-lexically? sym module))
- (mark-global-needed! (fluid-ref bindings-data) sym module)))
+ (mark-global-needed! (fluid-ref bindings-data)
+ sym
+ module)))
(map car bind))
(let iterate ((tail bind))
(if (null? tail)
- (make-sequence loc (map compile-expr body))
- (let ((sym (caar tail))
- (value (compile-expr (cdar tail))))
- (if (bind-lexically? sym module)
- (let ((target (gensym)))
- (make-let loc `(,target) `(,target) `(,value)
- (with-lexical-bindings (fluid-ref bindings-data)
- `(,sym) `(,target)
- (lambda ()
- (iterate (cdr tail))))))
- (let-dynamic loc
- `(,(caar tail)) module `(,value)
- (iterate (cdr tail))))))))))
+ (make-sequence loc (map compile-expr body))
+ (let ((sym (caar tail))
+ (value (compile-expr (cdar tail))))
+ (if (bind-lexically? sym module)
+ (let ((target (gensym)))
+ (make-let loc
+ `(,target)
+ `(,target)
+ `(,value)
+ (with-lexical-bindings
+ (fluid-ref bindings-data)
+ `(,sym)
+ `(,target)
+ (lambda () (iterate (cdr tail))))))
+ (let-dynamic loc
+ `(,(caar tail))
+ module
+ `(,value)
+ (iterate (cdr tail))))))))))
;;; Split the argument list of a lambda expression into required,
;;; optional and rest arguments and also check it is actually valid.
@@ -320,43 +361,51 @@
(lexical '())
(dynamic '()))
(cond
- ((null? tail)
- (let ((final-required (reverse required))
- (final-optional (reverse optional))
- (final-lexical (reverse lexical))
- (final-dynamic (reverse dynamic)))
- (values final-required final-optional #f
- final-lexical final-dynamic)))
- ((and (eq? mode 'required)
- (eq? (car tail) '&optional))
- (iterate (cdr tail) 'optional required optional lexical dynamic))
- ((eq? (car tail) '&rest)
- (if (or (null? (cdr tail))
- (not (null? (cddr tail))))
- (report-error loc "expected exactly one symbol after &rest")
- (let* ((rest (cadr tail))
- (rest-lexical (bind-arg-lexical? rest))
- (final-required (reverse required))
- (final-optional (reverse optional))
- (final-lexical (reverse (if rest-lexical
- (cons rest lexical)
- lexical)))
- (final-dynamic (reverse (if rest-lexical
- dynamic
- (cons rest dynamic)))))
- (values final-required final-optional rest
- final-lexical final-dynamic))))
- (else
- (if (not (symbol? (car tail)))
- (report-error loc "expected symbol in argument list, got" (car tail))
+ ((null? tail)
+ (let ((final-required (reverse required))
+ (final-optional (reverse optional))
+ (final-lexical (reverse lexical))
+ (final-dynamic (reverse dynamic)))
+ (values final-required
+ final-optional
+ #f
+ final-lexical
+ final-dynamic)))
+ ((and (eq? mode 'required)
+ (eq? (car tail) '&optional))
+ (iterate (cdr tail) 'optional required optional lexical dynamic))
+ ((eq? (car tail) '&rest)
+ (if (or (null? (cdr tail))
+ (not (null? (cddr tail))))
+ (report-error loc "expected exactly one symbol after &rest")
+ (let* ((rest (cadr tail))
+ (rest-lexical (bind-arg-lexical? rest))
+ (final-required (reverse required))
+ (final-optional (reverse optional))
+ (final-lexical (reverse (if rest-lexical
+ (cons rest lexical)
+ lexical)))
+ (final-dynamic (reverse (if rest-lexical
+ dynamic
+ (cons rest dynamic)))))
+ (values final-required
+ final-optional
+ rest
+ final-lexical
+ final-dynamic))))
+ (else
+ (if (not (symbol? (car tail)))
+ (report-error loc
+ "expected symbol in argument list, got"
+ (car tail))
(let* ((arg (car tail))
(bind-lexical (bind-arg-lexical? arg))
(new-lexical (if bind-lexical
- (cons arg lexical)
- lexical))
+ (cons arg lexical)
+ lexical))
(new-dynamic (if bind-lexical
- dynamic
- (cons arg dynamic))))
+ dynamic
+ (cons arg dynamic))))
(case mode
((required) (iterate (cdr tail) mode
(cons arg required) optional
@@ -365,7 +414,8 @@
required (cons arg optional)
new-lexical new-dynamic))
(else
- (error "invalid mode in split-lambda-arguments" mode)))))))))
+ (error "invalid mode in split-lambda-arguments"
+ mode)))))))))
;;; Compile a lambda expression. Things get a little complicated because
;;; TreeIL does not allow optional arguments but only one rest argument,
@@ -401,12 +451,12 @@
(define (compile-lambda loc args body)
(if (not (list? args))
- (report-error loc "expected list for argument-list" args))
+ (report-error loc "expected list for argument-list" args))
(if (null? body)
- (report-error loc "function body might not be empty"))
+ (report-error loc "function body might not be empty"))
(call-with-values
- (lambda ()
- (split-lambda-arguments loc args))
+ (lambda ()
+ (split-lambda-arguments loc args))
(lambda (required optional rest lexical dynamic)
(let* ((make-sym (lambda (sym) (gensym)))
(required-sym (map make-sym required))
@@ -423,57 +473,85 @@
(optional-sym (map make-sym lex-optionals))
(optional-lex-pairs (map cons lex-optionals optional-sym))
(find-required-pairs (lambda (filter)
- (lset-intersection (lambda (name-sym el)
- (eq? (car name-sym)
- el))
- required-pairs filter)))
+ (lset-intersection
+ (lambda (name-sym el)
+ (eq? (car name-sym) el))
+ required-pairs
+ filter)))
(required-lex-pairs (find-required-pairs lexical))
(rest-pair (if rest-lexical `((,rest . ,rest-sym)) '()))
- (all-lex-pairs (append required-lex-pairs optional-lex-pairs
+ (all-lex-pairs (append required-lex-pairs
+ optional-lex-pairs
rest-pair)))
(for-each (lambda (sym)
(mark-global-needed! (fluid-ref bindings-data)
- sym value-slot))
+ sym
+ value-slot))
dynamic)
- (with-dynamic-bindings (fluid-ref bindings-data) dynamic
- (lambda ()
- (with-lexical-bindings (fluid-ref bindings-data)
- (map car all-lex-pairs)
- (map cdr all-lex-pairs)
- (lambda ()
- (make-lambda loc '()
- (make-lambda-case
- #f required #f
- (if have-real-rest rest-name #f)
- #f '()
- (if have-real-rest
- (append required-sym (list rest-sym))
- required-sym)
- (let* ((init-req (map (lambda (name-sym)
- (make-lexical-ref loc (car name-sym)
- (cdr name-sym)))
- (find-required-pairs dynamic)))
- (init-nils (map (lambda (sym) (nil-value loc))
+ (with-dynamic-bindings
+ (fluid-ref bindings-data)
+ dynamic
+ (lambda ()
+ (with-lexical-bindings
+ (fluid-ref bindings-data)
+ (map car all-lex-pairs)
+ (map cdr all-lex-pairs)
+ (lambda ()
+ (make-lambda loc
+ '()
+ (make-lambda-case
+ #f
+ required
+ #f
+ (if have-real-rest rest-name #f)
+ #f
+ '()
+ (if have-real-rest
+ (append required-sym (list rest-sym))
+ required-sym)
+ (let* ((init-req
+ (map (lambda (name-sym)
+ (make-lexical-ref
+ loc
+ (car name-sym)
+ (cdr name-sym)))
+ (find-required-pairs dynamic)))
+ (init-nils
+ (map (lambda (sym) (nil-value loc))
(if rest-dynamic
- `(,@dyn-optionals ,rest-sym)
- dyn-optionals)))
- (init (append init-req init-nils))
- (func-body (make-sequence loc
- `(,(process-optionals loc optional
- rest-name rest-sym)
- ,(process-rest loc rest
- rest-name rest-sym)
- ,@(map compile-expr body))))
- (dynlet (let-dynamic loc dynamic value-slot
- init func-body))
- (full-body (if (null? dynamic) func-body dynlet)))
- (if (null? optional-sym)
- full-body
- (make-let loc
- optional-sym optional-sym
- (map (lambda (sym) (nil-value loc)) optional-sym)
- full-body)))
- #f))))))))))
+ `(,@dyn-optionals ,rest-sym)
+ dyn-optionals)))
+ (init (append init-req init-nils))
+ (func-body
+ (make-sequence
+ loc
+ `(,(process-optionals loc
+ optional
+ rest-name
+ rest-sym)
+ ,(process-rest loc
+ rest
+ rest-name
+ rest-sym)
+ ,@(map compile-expr body))))
+ (dynlet (let-dynamic loc
+ dynamic
+ value-slot
+ init
+ func-body))
+ (full-body (if (null? dynamic)
+ func-body
+ dynlet)))
+ (if (null? optional-sym)
+ full-body
+ (make-let loc
+ optional-sym
+ optional-sym
+ (map (lambda (sym)
+ (nil-value loc))
+ optional-sym)
+ full-body)))
+ #f))))))))))
;;; Build the code to handle setting of optional arguments that are
;;; present and updating the rest list.
@@ -481,35 +559,60 @@
(define (process-optionals loc optional rest-name rest-sym)
(let iterate ((tail optional))
(if (null? tail)
- (make-void loc)
- (make-conditional loc
- (call-primitive loc 'null? (make-lexical-ref loc rest-name rest-sym))
(make-void loc)
- (make-sequence loc
- (list (set-variable! loc (car tail) value-slot
- (call-primitive loc 'car
- (make-lexical-ref loc rest-name rest-sym)))
- (make-lexical-set loc rest-name rest-sym
- (call-primitive loc 'cdr
- (make-lexical-ref loc rest-name rest-sym)))
+ (make-conditional
+ loc
+ (call-primitive loc
+ 'null?
+ (make-lexical-ref loc rest-name rest-sym))
+ (make-void loc)
+ (make-sequence
+ loc
+ (list (set-variable! loc
+ (car tail)
+ value-slot
+ (call-primitive loc
+ 'car
+ (make-lexical-ref
+ loc
+ rest-name
+ rest-sym)))
+ (make-lexical-set
+ loc
+ rest-name
+ rest-sym
+ (call-primitive
+ loc
+ 'cdr
+ (make-lexical-ref loc rest-name rest-sym)))
(iterate (cdr tail))))))))
;;; This builds the code to set the rest variable to nil if it is empty.
(define (process-rest loc rest rest-name rest-sym)
- (let ((rest-empty (call-primitive loc 'null?
- (make-lexical-ref loc rest-name rest-sym))))
+ (let ((rest-empty (call-primitive loc
+ 'null?
+ (make-lexical-ref loc
+ rest-name
+ rest-sym))))
(cond
- (rest
- (make-conditional loc rest-empty
- (make-void loc)
- (set-variable! loc rest value-slot
- (make-lexical-ref loc rest-name rest-sym))))
- ((not (null? rest-sym))
- (make-conditional loc rest-empty
- (make-void loc)
- (runtime-error loc "too many arguments and no rest argument")))
- (else (make-void loc)))))
+ (rest
+ (make-conditional loc
+ rest-empty
+ (make-void loc)
+ (set-variable! loc
+ rest
+ value-slot
+ (make-lexical-ref loc
+ rest-name
+ rest-sym))))
+ ((not (null? rest-sym))
+ (make-conditional loc rest-empty
+ (make-void loc)
+ (runtime-error
+ loc
+ "too many arguments and no rest argument")))
+ (else (make-void loc)))))
;;; Handle the common part of defconst and defvar, that is, checking for
;;; a correct doc string and arguments as well as maybe in the future
@@ -517,13 +620,13 @@
(define (handle-var-def loc sym doc)
(cond
- ((not (symbol? sym)) (report-error loc "expected symbol, got" sym))
- ((> (length doc) 1) (report-error loc "too many arguments to defvar"))
- ((and (not (null? doc)) (not (string? (car doc))))
- (report-error loc "expected string as third argument of defvar, got"
- (car doc)))
- ;; TODO: Handle doc string if present.
- (else #t)))
+ ((not (symbol? sym)) (report-error loc "expected symbol, got" sym))
+ ((> (length doc) 1) (report-error loc "too many arguments to defvar"))
+ ((and (not (null? doc)) (not (string? (car doc))))
+ (report-error loc "expected string as third argument of defvar, got"
+ (car doc)))
+ ;; TODO: Handle doc string if present.
+ (else #t)))
;;; Handle macro bindings.
@@ -533,10 +636,10 @@
(define (define-macro! loc sym definition)
(let ((resolved (resolve-module macro-slot)))
(if (is-macro? sym)
- (report-error loc "macro is already defined" sym)
- (begin
- (module-define! resolved sym definition)
- (module-export! resolved (list sym))))))
+ (report-error loc "macro is already defined" sym)
+ (begin
+ (module-define! resolved sym definition)
+ (module-export! resolved (list sym))))))
(define (get-macro sym)
(module-ref (resolve-module macro-slot) sym))
@@ -545,11 +648,11 @@
(define (contains-unquotes? expr)
(if (pair? expr)
- (if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
- #t
- (or (contains-unquotes? (car expr))
- (contains-unquotes? (cdr expr))))
- #f))
+ (if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
+ #t
+ (or (contains-unquotes? (car expr))
+ (contains-unquotes? (cdr expr))))
+ #f))
;;; Process a backquoted expression by building up the needed
;;; cons/append calls. For splicing, it is assumed that the expression
@@ -565,25 +668,32 @@
(define (process-backquote loc expr)
(if (contains-unquotes? expr)
- (if (pair? expr)
- (if (or (unquote-cell? expr) (unquote-splicing-cell? expr))
- (compile-expr (cadr expr))
- (let* ((head (car expr))
- (processed-tail (process-backquote loc (cdr expr)))
- (head-is-list-2 (and (list? head) (= (length head) 2)))
- (head-unquote (and head-is-list-2 (unquote? (car head))))
- (head-unquote-splicing (and head-is-list-2
- (unquote-splicing? (car head)))))
- (if head-unquote-splicing
- (call-primitive loc 'append
- (compile-expr (cadr head)) processed-tail)
- (call-primitive loc 'cons
- (if head-unquote
- (compile-expr (cadr head))
- (process-backquote loc head))
- processed-tail))))
- (report-error loc "non-pair expression contains unquotes" expr))
- (make-const loc expr)))
+ (if (pair? expr)
+ (if (or (unquote-cell? expr) (unquote-splicing-cell? expr))
+ (compile-expr (cadr expr))
+ (let* ((head (car expr))
+ (processed-tail (process-backquote loc (cdr expr)))
+ (head-is-list-2 (and (list? head)
+ (= (length head) 2)))
+ (head-unquote (and head-is-list-2
+ (unquote? (car head))))
+ (head-unquote-splicing (and head-is-list-2
+ (unquote-splicing?
+ (car head)))))
+ (if head-unquote-splicing
+ (call-primitive loc
+ 'append
+ (compile-expr (cadr head))
+ processed-tail)
+ (call-primitive loc 'cons
+ (if head-unquote
+ (compile-expr (cadr head))
+ (process-backquote loc head))
+ processed-tail))))
+ (report-error loc
+ "non-pair expression contains unquotes"
+ expr))
+ (make-const loc expr)))
;;; Temporarily update a list of symbols that are handled specially
;;; (disabled void check or always lexical) for compiling body. We need
@@ -591,20 +701,20 @@
(define (with-added-symbols loc fluid syms body)
(if (null? body)
- (report-error loc "symbol-list construct has empty body"))
+ (report-error loc "symbol-list construct has empty body"))
(if (not (or (eq? syms 'all)
(and (list? syms) (and-map symbol? syms))))
- (report-error loc "invalid symbol list" syms))
+ (report-error loc "invalid symbol list" syms))
(let ((old (fluid-ref fluid))
(make-body (lambda ()
(make-sequence loc (map compile-expr body)))))
(if (eq? old 'all)
- (make-body)
- (let ((new (if (eq? syms 'all)
- 'all
- (append syms old))))
- (with-fluids ((fluid new))
- (make-body))))))
+ (make-body)
+ (let ((new (if (eq? syms 'all)
+ 'all
+ (append syms old))))
+ (with-fluids ((fluid new))
+ (make-body))))))
;;; Compile a symbol expression. This is a variable reference or maybe
;;; some special value like nil.
@@ -623,19 +733,22 @@
(make-sequence loc (map compile-expr forms)))
((if ,condition ,ifclause)
- (make-conditional loc (compile-expr condition)
- (compile-expr ifclause)
- (nil-value loc)))
+ (make-conditional loc
+ (compile-expr condition)
+ (compile-expr ifclause)
+ (nil-value loc)))
((if ,condition ,ifclause ,elseclause)
- (make-conditional loc (compile-expr condition)
- (compile-expr ifclause)
- (compile-expr elseclause)))
+ (make-conditional loc
+ (compile-expr condition)
+ (compile-expr ifclause)
+ (compile-expr elseclause)))
((if ,condition ,ifclause . ,elses)
- (make-conditional loc (compile-expr condition)
- (compile-expr ifclause)
- (make-sequence loc (map compile-expr elses))))
+ (make-conditional loc
+ (compile-expr condition)
+ (compile-expr ifclause)
+ (make-sequence loc (map compile-expr elses))))
;; defconst and defvar are kept here in the compiler (rather than
;; doing them as macros) for if we may want to handle the docstring
@@ -643,48 +756,64 @@
((defconst ,sym ,value . ,doc)
(if (handle-var-def loc sym doc)
- (make-sequence loc
- (list (set-variable! loc sym value-slot (compile-expr value))
- (make-const loc sym)))))
+ (make-sequence loc
+ (list (set-variable! loc
+ sym
+ value-slot
+ (compile-expr value))
+ (make-const loc sym)))))
((defvar ,sym) (make-const loc sym))
((defvar ,sym ,value . ,doc)
(if (handle-var-def loc sym doc)
- (make-sequence loc
- (list (make-conditional loc
- (call-primitive loc 'eq?
+ (make-sequence
+ loc
+ (list (make-conditional
+ loc
+ (call-primitive loc
+ 'eq?
(make-module-ref loc runtime 'void #t)
(reference-variable loc sym value-slot))
- (set-variable! loc sym value-slot
- (compile-expr value))
+ (set-variable! loc sym value-slot (compile-expr value))
(make-void loc))
- (make-const loc sym)))))
+ (make-const loc sym)))))
;; Build a set form for possibly multiple values. The code is not
;; formulated tail recursive because it is clearer this way and
;; large lists of symbol expression pairs are very unlikely.
((setq . ,args) (guard (not (null? args)))
- (make-sequence loc
- (let iterate ((tail args))
- (let ((sym (car tail))
- (tailtail (cdr tail)))
- (if (not (symbol? sym))
- (report-error loc "expected symbol in setq")
- (if (null? tailtail)
- (report-error loc "missing value for symbol in setq" sym)
- (let* ((val (compile-expr (car tailtail)))
- (op (set-variable! loc sym value-slot val)))
- (if (null? (cdr tailtail))
- (let* ((temp (gensym))
- (ref (make-lexical-ref loc temp temp)))
- (list (make-let loc `(,temp) `(,temp) `(,val)
- (make-sequence loc
- (list (set-variable! loc sym value-slot ref)
- ref)))))
- (cons (set-variable! loc sym value-slot val)
- (iterate (cdr tailtail)))))))))))
+ (make-sequence
+ loc
+ (let iterate ((tail args))
+ (let ((sym (car tail))
+ (tailtail (cdr tail)))
+ (if (not (symbol? sym))
+ (report-error loc "expected symbol in setq")
+ (if (null? tailtail)
+ (report-error loc
+ "missing value for symbol in setq"
+ sym)
+ (let* ((val (compile-expr (car tailtail)))
+ (op (set-variable! loc sym value-slot val)))
+ (if (null? (cdr tailtail))
+ (let* ((temp (gensym))
+ (ref (make-lexical-ref loc temp temp)))
+ (list (make-let
+ loc
+ `(,temp)
+ `(,temp)
+ `(,val)
+ (make-sequence
+ loc
+ (list (set-variable! loc
+ sym
+ value-slot
+ ref)
+ ref)))))
+ (cons (set-variable! loc sym value-slot val)
+ (iterate (cdr tailtail)))))))))))
;; All lets (let, flet, lexical-let and let* forms) are done using
;; the generate-let/generate-let* methods.
@@ -759,19 +888,33 @@
(let* ((itersym (gensym))
(compiled-body (map compile-expr body))
(iter-call (make-application loc
- (make-lexical-ref loc 'iterate itersym)
- (list)))
+ (make-lexical-ref loc
+ 'iterate
+ itersym)
+ (list)))
(full-body (make-sequence loc
- `(,@compiled-body ,iter-call)))
+ `(,@compiled-body ,iter-call)))
(lambda-body (make-conditional loc
- (compile-expr condition)
- full-body
- (nil-value loc)))
- (iter-thunk (make-lambda loc '()
- (make-lambda-case #f '() #f #f #f '() '()
- lambda-body #f))))
- (make-letrec loc #f '(iterate) (list itersym) (list iter-thunk)
- iter-call)))
+ (compile-expr condition)
+ full-body
+ (nil-value loc)))
+ (iter-thunk (make-lambda loc
+ '()
+ (make-lambda-case #f
+ '()
+ #f
+ #f
+ #f
+ '()
+ '()
+ lambda-body
+ #f))))
+ (make-letrec loc
+ #f
+ '(iterate)
+ (list itersym)
+ (list iter-thunk)
+ iter-call)))
;; Either (lambda ...) or (function (lambda ...)) denotes a
;; lambda-expression that should be compiled.
@@ -788,23 +931,27 @@
((defun ,name ,args . ,body)
(if (not (symbol? name))
- (report-error loc "expected symbol as function name" name)
- (make-sequence loc
- (list (set-variable! loc name function-slot
- (compile-lambda loc args body))
- (make-const loc name)))))
+ (report-error loc "expected symbol as function name" name)
+ (make-sequence loc
+ (list (set-variable! loc
+ name
+ function-slot
+ (compile-lambda loc
+ args
+ body))
+ (make-const loc name)))))
;; Define a macro (this is done directly at compile-time!). FIXME:
;; Recursive macros don't work!
((defmacro ,name ,args . ,body)
(if (not (symbol? name))
- (report-error loc "expected symbol as macro name" name)
- (let* ((tree-il (with-fluids ((bindings-data (make-bindings)))
- (compile-lambda loc args body)))
- (object (compile tree-il #:from 'tree-il #:to 'value)))
- (define-macro! loc name object)
- (make-const loc name))))
+ (report-error loc "expected symbol as macro name" name)
+ (let* ((tree-il (with-fluids ((bindings-data (make-bindings)))
+ (compile-lambda loc args body)))
+ (object (compile tree-il #:from 'tree-il #:to 'value)))
+ (define-macro! loc name object)
+ (make-const loc name))))
;; XXX: Maybe we could implement backquotes in macros, too.
@@ -829,24 +976,24 @@
((,func . ,args)
(make-application loc
- (if (symbol? func)
- (reference-with-check loc func function-slot)
- (compile-expr func))
- (map compile-expr args)))
+ (if (symbol? func)
+ (reference-with-check loc func function-slot)
+ (compile-expr func))
+ (map compile-expr args)))
(else
- (report-error loc "unrecognized elisp" expr))))
+ (report-error loc "unrecognized elisp" expr))))
;;; Compile a single expression to TreeIL.
(define (compile-expr expr)
(let ((loc (location expr)))
(cond
- ((symbol? expr)
- (compile-symbol loc expr))
- ((pair? expr)
- (compile-pair loc expr))
- (else (make-const loc expr)))))
+ ((symbol? expr)
+ (compile-symbol loc expr))
+ ((pair? expr)
+ (compile-pair loc expr))
+ (else (make-const loc expr)))))
;;; Process the compiler options.
;;; FIXME: Why is '(()) passed as options by the REPL?
@@ -858,20 +1005,26 @@
(define (process-options! opt)
(if (and (not (null? opt))
(not (equal? opt '(()))))
- (if (null? (cdr opt))
- (report-error #f "Invalid compiler options" opt)
- (let ((key (car opt))
- (value (cadr opt)))
- (case key
- ((#:disable-void-check)
- (if (valid-symbol-list-arg? value)
- (fluid-set! disable-void-check value)
- (report-error #f "Invalid value for #:disable-void-check" value)))
- ((#:always-lexical)
- (if (valid-symbol-list-arg? value)
- (fluid-set! always-lexical value)
- (report-error #f "Invalid value for #:always-lexical" value)))
- (else (report-error #f "Invalid compiler option" key)))))))
+ (if (null? (cdr opt))
+ (report-error #f "Invalid compiler options" opt)
+ (let ((key (car opt))
+ (value (cadr opt)))
+ (case key
+ ((#:disable-void-check)
+ (if (valid-symbol-list-arg? value)
+ (fluid-set! disable-void-check value)
+ (report-error #f
+ "Invalid value for #:disable-void-check"
+ value)))
+ ((#:always-lexical)
+ (if (valid-symbol-list-arg? value)
+ (fluid-set! always-lexical value)
+ (report-error #f
+ "Invalid value for #:always-lexical"
+ value)))
+ (else (report-error #f
+ "Invalid compiler option"
+ key)))))))
;;; Entry point for compilation to TreeIL. This creates the bindings
;;; data structure, and after compiling the main expression we need to
@@ -880,16 +1033,17 @@
(define (compile-tree-il expr env opts)
(values
- (with-fluids ((bindings-data (make-bindings))
- (disable-void-check '())
- (always-lexical '()))
- (process-options! opts)
- (let ((loc (location expr))
- (compiled (compile-expr expr)))
- (make-sequence loc
- `(,@(map-globals-needed (fluid-ref bindings-data)
- (lambda (mod sym)
- (generate-ensure-global loc sym mod)))
- ,compiled))))
- env
- env))
+ (with-fluids ((bindings-data (make-bindings))
+ (disable-void-check '())
+ (always-lexical '()))
+ (process-options! opts)
+ (let ((loc (location expr))
+ (compiled (compile-expr expr)))
+ (make-sequence loc
+ `(,@(map-globals-needed
+ (fluid-ref bindings-data)
+ (lambda (mod sym)
+ (generate-ensure-global loc sym mod)))
+ ,compiled))))
+ env
+ env))
diff --git a/module/language/elisp/lexer.scm b/module/language/elisp/lexer.scm
index 028f8896e..9c4bf5893 100644
--- a/module/language/elisp/lexer.scm
+++ b/module/language/elisp/lexer.scm
@@ -60,8 +60,8 @@
(define (real-character chr)
(if (< chr 256)
- (integer->char chr)
- #\nul))
+ (integer->char chr)
+ #\nul))
;;; Return the control modified version of a character. This is not
;;; just setting a modifier bit, because ASCII conrol characters must be
@@ -71,11 +71,11 @@
(define (add-control chr)
(let ((real (real-character chr)))
(if (char-alphabetic? real)
- (- (char->integer (char-upcase real)) (char->integer #\@))
- (case real
- ((#\?) 127)
- ((#\@) 0)
- (else (set-char-bit chr 26))))))
+ (- (char->integer (char-upcase real)) (char->integer #\@))
+ (case real
+ ((#\?) 127)
+ ((#\@) 0)
+ (else (set-char-bit chr 26))))))
;;; Parse a charcode given in some base, basically octal or hexadecimal
;;; are needed. A requested number of digits can be given (#f means it
@@ -88,26 +88,29 @@
(let iterate ((result 0)
(procdigs 0))
(if (and digits (>= procdigs digits))
- result
- (let* ((cur (read-char port))
- (value (cond
- ((char-numeric? cur)
- (- (char->integer cur) (char->integer #\0)))
- ((char-alphabetic? cur)
- (let ((code (- (char->integer (char-upcase cur))
- (char->integer #\A))))
- (if (< code 0)
- #f
- (+ code 10))))
- (else #f)))
- (valid (and value (< value base))))
- (if (not valid)
- (if (or (not digits) early-return)
- (begin
- (unread-char cur port)
- result)
- (lexer-error port "invalid digit in escape-code" base cur))
- (iterate (+ (* result base) value) (1+ procdigs)))))))
+ result
+ (let* ((cur (read-char port))
+ (value (cond
+ ((char-numeric? cur)
+ (- (char->integer cur) (char->integer #\0)))
+ ((char-alphabetic? cur)
+ (let ((code (- (char->integer (char-upcase cur))
+ (char->integer #\A))))
+ (if (< code 0)
+ #f
+ (+ code 10))))
+ (else #f)))
+ (valid (and value (< value base))))
+ (if (not valid)
+ (if (or (not digits) early-return)
+ (begin
+ (unread-char cur port)
+ result)
+ (lexer-error port
+ "invalid digit in escape-code"
+ base
+ cur))
+ (iterate (+ (* result base) value) (1+ procdigs)))))))
;;; Read a character and process escape-sequences when necessary. The
;;; special in-string argument defines if this character is part of a
@@ -116,53 +119,63 @@
;;; characters.
(define basic-escape-codes
- '((#\a . 7) (#\b . 8) (#\t . 9)
- (#\n . 10) (#\v . 11) (#\f . 12) (#\r . 13)
- (#\e . 27) (#\s . 32) (#\d . 127)))
+ '((#\a . 7)
+ (#\b . 8)
+ (#\t . 9)
+ (#\n . 10)
+ (#\v . 11)
+ (#\f . 12)
+ (#\r . 13)
+ (#\e . 27)
+ (#\s . 32)
+ (#\d . 127)))
(define (get-character port in-string)
- (let ((meta-bits `((#\A . 22) (#\s . 23) (#\H . 24)
- (#\S . 25) (#\M . ,(if in-string 7 27))))
+ (let ((meta-bits `((#\A . 22)
+ (#\s . 23)
+ (#\H . 24)
+ (#\S . 25)
+ (#\M . ,(if in-string 7 27))))
(cur (read-char port)))
(if (char=? cur #\\)
- ;; Handle an escape-sequence.
- (let* ((escaped (read-char port))
- (esc-code (assq-ref basic-escape-codes escaped))
- (meta (assq-ref meta-bits escaped)))
- (cond
- ;; Meta-check must be before esc-code check because \s- must
- ;; be recognized as the super-meta modifier if a - follows.
- ;; If not, it will be caught as \s -> space escape code.
- ((and meta (is-char? (peek-char port) #\-))
- (if (not (char=? (read-char port) #\-))
- (error "expected - after control sequence"))
- (set-char-bit (get-character port in-string) meta))
- ;; One of the basic control character escape names?
- (esc-code esc-code)
- ;; Handle \ddd octal code if it is one.
- ((and (char>=? escaped #\0) (char<? escaped #\8))
- (begin
- (unread-char escaped port)
- (charcode-escape port 8 3 #t)))
- ;; Check for some escape-codes directly or otherwise use the
- ;; escaped character literally.
- (else
+ ;; Handle an escape-sequence.
+ (let* ((escaped (read-char port))
+ (esc-code (assq-ref basic-escape-codes escaped))
+ (meta (assq-ref meta-bits escaped)))
+ (cond
+ ;; Meta-check must be before esc-code check because \s- must
+ ;; be recognized as the super-meta modifier if a - follows.
+ ;; If not, it will be caught as \s -> space escape code.
+ ((and meta (is-char? (peek-char port) #\-))
+ (if (not (char=? (read-char port) #\-))
+ (error "expected - after control sequence"))
+ (set-char-bit (get-character port in-string) meta))
+ ;; One of the basic control character escape names?
+ (esc-code esc-code)
+ ;; Handle \ddd octal code if it is one.
+ ((and (char>=? escaped #\0) (char<? escaped #\8))
+ (begin
+ (unread-char escaped port)
+ (charcode-escape port 8 3 #t)))
+ ;; Check for some escape-codes directly or otherwise use the
+ ;; escaped character literally.
+ (else
(case escaped
((#\^) (add-control (get-character port in-string)))
((#\C)
(if (is-char? (peek-char port) #\-)
- (begin
- (if (not (char=? (read-char port) #\-))
- (error "expected - after control sequence"))
- (add-control (get-character port in-string)))
- escaped))
+ (begin
+ (if (not (char=? (read-char port) #\-))
+ (error "expected - after control sequence"))
+ (add-control (get-character port in-string)))
+ escaped))
((#\x) (charcode-escape port 16 #f #t))
((#\u) (charcode-escape port 16 4 #f))
((#\U) (charcode-escape port 16 8 #f))
(else (char->integer escaped))))))
- ;; No escape-sequence, just the literal character.
- ;; But remember to get the code instead!
- (char->integer cur))))
+ ;; No escape-sequence, just the literal character. But remember
+ ;; to get the code instead!
+ (char->integer cur))))
;;; Read a symbol or number from a port until something follows that
;;; marks the start of a new token (like whitespace or parentheses).
@@ -176,7 +189,8 @@
(define integer-regex (make-regexp "^[+-]?[0-9]+\\.?$"))
(define float-regex
- (make-regexp "^[+-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)(e[+-]?[0-9]+)?$"))
+ (make-regexp
+ "^[+-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)(e[+-]?[0-9]+)?$"))
;;; A dot is also allowed literally, only a single dort alone is parsed
;;; as the 'dot' terminal for dotted lists.
@@ -188,29 +202,31 @@
(had-escape #f))
(let* ((c (read-char port))
(finish (lambda ()
- (let ((result (list->string (reverse result-chars))))
+ (let ((result (list->string
+ (reverse result-chars))))
(values
- (cond
- ((and (not had-escape)
- (regexp-exec integer-regex result))
- 'integer)
- ((and (not had-escape)
- (regexp-exec float-regex result))
- 'float)
- (else 'symbol))
- result))))
+ (cond
+ ((and (not had-escape)
+ (regexp-exec integer-regex result))
+ 'integer)
+ ((and (not had-escape)
+ (regexp-exec float-regex result))
+ 'float)
+ (else 'symbol))
+ result))))
(need-no-escape? (lambda (c)
(or (char-numeric? c)
(char-alphabetic? c)
- (char-set-contains? no-escape-punctuation
- c)))))
+ (char-set-contains?
+ no-escape-punctuation
+ c)))))
(cond
- ((eof-object? c) (finish))
- ((need-no-escape? c) (iterate (cons c result-chars) had-escape))
- ((char=? c #\\) (iterate (cons (read-char port) result-chars) #t))
- (else
- (unread-char c port)
- (finish))))))
+ ((eof-object? c) (finish))
+ ((need-no-escape? c) (iterate (cons c result-chars) had-escape))
+ ((char=? c #\\) (iterate (cons (read-char port) result-chars) #t))
+ (else
+ (unread-char c port)
+ (finish))))))
;;; Parse a circular structure marker without the leading # (which was
;;; already read and recognized), that is, a number as identifier and
@@ -218,24 +234,28 @@
(define (get-circular-marker port)
(call-with-values
- (lambda ()
- (let iterate ((result 0))
- (let ((cur (read-char port)))
- (if (char-numeric? cur)
- (let ((val (- (char->integer cur) (char->integer #\0))))
- (iterate (+ (* result 10) val)))
- (values result cur)))))
+ (lambda ()
+ (let iterate ((result 0))
+ (let ((cur (read-char port)))
+ (if (char-numeric? cur)
+ (let ((val (- (char->integer cur) (char->integer #\0))))
+ (iterate (+ (* result 10) val)))
+ (values result cur)))))
(lambda (id type)
(case type
((#\#) `(circular-ref . ,id))
((#\=) `(circular-def . ,id))
- (else (lexer-error port "invalid circular marker character" type))))))
+ (else (lexer-error port
+ "invalid circular marker character"
+ type))))))
;;; Main lexer routine, which is given a port and does look for the next
;;; token.
(define (lex port)
- (let ((return (let ((file (if (file-port? port) (port-filename port) #f))
+ (let ((return (let ((file (if (file-port? port)
+ (port-filename port)
+ #f))
(line (1+ (port-line port)))
(column (1+ (port-column port))))
(lambda (token value)
@@ -248,114 +268,116 @@
;; and actually point to the very character to be read.
(c (read-char port)))
(cond
- ;; End of input must be specially marked to the parser.
- ((eof-object? c) '*eoi*)
- ;; Whitespace, just skip it.
- ((char-whitespace? c) (lex port))
- ;; The dot is only the one for dotted lists if followed by
- ;; whitespace. Otherwise it is considered part of a number of
- ;; symbol.
- ((and (char=? c #\.)
- (char-whitespace? (peek-char port)))
- (return 'dot #f))
- ;; Continue checking for literal character values.
- (else
- (case c
- ;; A line comment, skip until end-of-line is found.
- ((#\;)
- (let iterate ()
- (let ((cur (read-char port)))
- (if (or (eof-object? cur) (char=? cur #\newline))
+ ;; End of input must be specially marked to the parser.
+ ((eof-object? c) '*eoi*)
+ ;; Whitespace, just skip it.
+ ((char-whitespace? c) (lex port))
+ ;; The dot is only the one for dotted lists if followed by
+ ;; whitespace. Otherwise it is considered part of a number of
+ ;; symbol.
+ ((and (char=? c #\.)
+ (char-whitespace? (peek-char port)))
+ (return 'dot #f))
+ ;; Continue checking for literal character values.
+ (else
+ (case c
+ ;; A line comment, skip until end-of-line is found.
+ ((#\;)
+ (let iterate ()
+ (let ((cur (read-char port)))
+ (if (or (eof-object? cur) (char=? cur #\newline))
(lex port)
(iterate)))))
- ;; A character literal.
- ((#\?)
- (return 'character (get-character port #f)))
- ;; A literal string. This is mainly a sequence of characters
- ;; just as in the character literals, the only difference is
- ;; that escaped newline and space are to be completely ignored
- ;; and that meta-escapes set bit 7 rather than bit 27.
- ((#\")
- (let iterate ((result-chars '()))
- (let ((cur (read-char port)))
- (case cur
- ((#\")
- (return 'string (list->string (reverse result-chars))))
- ((#\\)
- (let ((escaped (read-char port)))
- (case escaped
- ((#\newline #\space)
- (iterate result-chars))
- (else
- (unread-char escaped port)
- (unread-char cur port)
- (iterate (cons (integer->char (get-character port #t))
- result-chars))))))
- (else (iterate (cons cur result-chars)))))))
- ;; Circular markers (either reference or definition).
- ((#\#)
- (let ((mark (get-circular-marker port)))
- (return (car mark) (cdr mark))))
- ;; Parentheses and other special-meaning single characters.
- ((#\() (return 'paren-open #f))
- ((#\)) (return 'paren-close #f))
- ((#\[) (return 'square-open #f))
- ((#\]) (return 'square-close #f))
- ((#\') (return 'quote #f))
- ((#\`) (return 'backquote #f))
- ;; Unquote and unquote-splicing.
- ((#\,)
- (if (is-char? (peek-char port) #\@)
+ ;; A character literal.
+ ((#\?)
+ (return 'character (get-character port #f)))
+ ;; A literal string. This is mainly a sequence of characters
+ ;; just as in the character literals, the only difference is
+ ;; that escaped newline and space are to be completely ignored
+ ;; and that meta-escapes set bit 7 rather than bit 27.
+ ((#\")
+ (let iterate ((result-chars '()))
+ (let ((cur (read-char port)))
+ (case cur
+ ((#\")
+ (return 'string (list->string (reverse result-chars))))
+ ((#\\)
+ (let ((escaped (read-char port)))
+ (case escaped
+ ((#\newline #\space)
+ (iterate result-chars))
+ (else
+ (unread-char escaped port)
+ (unread-char cur port)
+ (iterate
+ (cons (integer->char (get-character port #t))
+ result-chars))))))
+ (else (iterate (cons cur result-chars)))))))
+ ;; Circular markers (either reference or definition).
+ ((#\#)
+ (let ((mark (get-circular-marker port)))
+ (return (car mark) (cdr mark))))
+ ;; Parentheses and other special-meaning single characters.
+ ((#\() (return 'paren-open #f))
+ ((#\)) (return 'paren-close #f))
+ ((#\[) (return 'square-open #f))
+ ((#\]) (return 'square-close #f))
+ ((#\') (return 'quote #f))
+ ((#\`) (return 'backquote #f))
+ ;; Unquote and unquote-splicing.
+ ((#\,)
+ (if (is-char? (peek-char port) #\@)
(if (not (char=? (read-char port) #\@))
- (error "expected @ in unquote-splicing")
- (return 'unquote-splicing #f))
+ (error "expected @ in unquote-splicing")
+ (return 'unquote-splicing #f))
(return 'unquote #f)))
- ;; Remaining are numbers and symbols. Process input until next
- ;; whitespace is found, and see if it looks like a number
- ;; (float/integer) or symbol and return accordingly.
- (else
- (unread-char c port)
- (call-with-values
- (lambda ()
- (get-symbol-or-number port))
- (lambda (type str)
- (case type
- ((symbol)
- ;; str could be empty if the first character is
- ;; already something not allowed in a symbol (and not
- ;; escaped)! Take care about that, it is an error
- ;; because that character should have been handled
- ;; elsewhere or is invalid in the input.
- (if (zero? (string-length str))
- (begin
- ;; Take it out so the REPL might not get into an
- ;; infinite loop with further reading attempts.
- (read-char port)
- (error "invalid character in input" c))
- (return 'symbol (string->symbol str))))
- ((integer)
- ;; In elisp, something like "1." is an integer, while
- ;; string->number returns an inexact real. Thus we
- ;; need a conversion here, but it should always
- ;; result in an integer!
- (return 'integer
- (let ((num (inexact->exact (string->number str))))
- (if (not (integer? num))
- (error "expected integer" str num))
- num)))
- ((float)
- (return 'float (let ((num (string->number str)))
- (if (exact? num)
- (error "expected inexact float" str num))
- num)))
- (else (error "wrong number/symbol type" type)))))))))))
+ ;; Remaining are numbers and symbols. Process input until next
+ ;; whitespace is found, and see if it looks like a number
+ ;; (float/integer) or symbol and return accordingly.
+ (else
+ (unread-char c port)
+ (call-with-values
+ (lambda () (get-symbol-or-number port))
+ (lambda (type str)
+ (case type
+ ((symbol)
+ ;; str could be empty if the first character is already
+ ;; something not allowed in a symbol (and not escaped)!
+ ;; Take care about that, it is an error because that
+ ;; character should have been handled elsewhere or is
+ ;; invalid in the input.
+ (if (zero? (string-length str))
+ (begin
+ ;; Take it out so the REPL might not get into an
+ ;; infinite loop with further reading attempts.
+ (read-char port)
+ (error "invalid character in input" c))
+ (return 'symbol (string->symbol str))))
+ ((integer)
+ ;; In elisp, something like "1." is an integer, while
+ ;; string->number returns an inexact real. Thus we need
+ ;; a conversion here, but it should always result in an
+ ;; integer!
+ (return
+ 'integer
+ (let ((num (inexact->exact (string->number str))))
+ (if (not (integer? num))
+ (error "expected integer" str num))
+ num)))
+ ((float)
+ (return 'float (let ((num (string->number str)))
+ (if (exact? num)
+ (error "expected inexact float"
+ str
+ num))
+ num)))
+ (else (error "wrong number/symbol type" type)))))))))))
;;; Build a lexer thunk for a port. This is the exported routine which
;;; can be used to create a lexer for the parser to use.
(define (get-lexer port)
- (lambda ()
- (lex port)))
+ (lambda () (lex port)))
;;; Build a special lexer that will only read enough for one expression
;;; and then always return end-of-input. If we find one of the quotation
@@ -367,16 +389,16 @@
(paren-level 0))
(lambda ()
(if finished
- '*eoi*
- (let ((next (lex))
- (quotation #f))
- (case (car next)
- ((paren-open square-open)
- (set! paren-level (1+ paren-level)))
- ((paren-close square-close)
- (set! paren-level (1- paren-level)))
- ((quote backquote unquote unquote-splicing circular-def)
- (set! quotation #t)))
- (if (and (not quotation) (<= paren-level 0))
- (set! finished #t))
- next)))))
+ '*eoi*
+ (let ((next (lex))
+ (quotation #f))
+ (case (car next)
+ ((paren-open square-open)
+ (set! paren-level (1+ paren-level)))
+ ((paren-close square-close)
+ (set! paren-level (1- paren-level)))
+ ((quote backquote unquote unquote-splicing circular-def)
+ (set! quotation #t)))
+ (if (and (not quotation) (<= paren-level 0))
+ (set! finished #t))
+ next)))))
diff --git a/module/language/elisp/parser.scm b/module/language/elisp/parser.scm
index b434465d7..3436abf22 100644
--- a/module/language/elisp/parser.scm
+++ b/module/language/elisp/parser.scm
@@ -54,12 +54,12 @@
(define (circular-ref token)
(if (not (eq? (car token) 'circular-ref))
- (error "invalid token for circular-ref" token))
+ (error "invalid token for circular-ref" token))
(let* ((id (cdr token))
(value (hashq-ref (fluid-ref circular-definitions) id)))
(if value
- value
- (parse-error token "undefined circular reference" id))))
+ value
+ (parse-error token "undefined circular reference" id))))
;;; Returned is a closure that, when invoked, will set the final value.
;;; This means both the variable the promise will return and the
@@ -67,7 +67,7 @@
(define (circular-define! token)
(if (not (eq? (car token) 'circular-def))
- (error "invalid token for circular-define!" token))
+ (error "invalid token for circular-define!" token))
(let ((value #f)
(table (fluid-ref circular-definitions))
(id (cdr token)))
@@ -85,25 +85,25 @@
(define (force-promises! data)
(cond
- ((pair? data)
- (begin
- (if (promise? (car data))
- (set-car! data (force (car data)))
- (force-promises! (car data)))
- (if (promise? (cdr data))
- (set-cdr! data (force (cdr data)))
- (force-promises! (cdr data)))))
- ((vector? data)
- (let ((len (vector-length data)))
- (let iterate ((i 0))
- (if (< i len)
- (let ((el (vector-ref data i)))
- (if (promise? el)
- (vector-set! data i (force el))
- (force-promises! el))
- (iterate (1+ i)))))))
- ;; Else nothing needs to be done.
- ))
+ ((pair? data)
+ (begin
+ (if (promise? (car data))
+ (set-car! data (force (car data)))
+ (force-promises! (car data)))
+ (if (promise? (cdr data))
+ (set-cdr! data (force (cdr data)))
+ (force-promises! (cdr data)))))
+ ((vector? data)
+ (let ((len (vector-length data)))
+ (let iterate ((i 0))
+ (if (< i len)
+ (let ((el (vector-ref data i)))
+ (if (promise? el)
+ (vector-set! data i (force el))
+ (force-promises! el))
+ (iterate (1+ i)))))))
+ ;; Else nothing needs to be done.
+ ))
;;; We need peek-functionality for the next lexer token, this is done
;;; with some single token look-ahead storage. This is handled by a
@@ -116,19 +116,19 @@
(let ((look-ahead #f))
(lambda (action)
(if (eq? action 'finish)
- (if look-ahead
- (error "lexer-buffer is not empty when finished")
- #f)
- (begin
- (if (not look-ahead)
- (set! look-ahead (lex)))
- (case action
- ((peek) look-ahead)
- ((get)
- (let ((result look-ahead))
- (set! look-ahead #f)
- result))
- (else (error "invalid lexer-buffer action" action))))))))
+ (if look-ahead
+ (error "lexer-buffer is not empty when finished")
+ #f)
+ (begin
+ (if (not look-ahead)
+ (set! look-ahead (lex)))
+ (case action
+ ((peek) look-ahead)
+ ((get)
+ (let ((result look-ahead))
+ (set! look-ahead #f)
+ result))
+ (else (error "invalid lexer-buffer action" action))))))))
;;; Get the contents of a list, where the opening parentheses has
;;; already been found. The same code is used for vectors and lists,
@@ -141,24 +141,25 @@
(let* ((next (lex 'peek))
(type (car next)))
(cond
- ((eq? type (if close-square 'square-close 'paren-close))
- (begin
- (if (not (eq? (car (lex 'get)) type))
- (error "got different token than peeked"))
- '()))
- ((and allow-dot (eq? type 'dot))
- (begin
- (if (not (eq? (car (lex 'get)) type))
- (error "got different token than peeked"))
- (let ((tail (get-list lex #f close-square)))
- (if (not (= (length tail) 1))
- (parse-error next "expected exactly one element after dot"))
- (car tail))))
- (else
- ;; Do both parses in exactly this sequence!
- (let* ((head (get-expression lex))
- (tail (get-list lex allow-dot close-square)))
- (cons head tail))))))
+ ((eq? type (if close-square 'square-close 'paren-close))
+ (begin
+ (if (not (eq? (car (lex 'get)) type))
+ (error "got different token than peeked"))
+ '()))
+ ((and allow-dot (eq? type 'dot))
+ (begin
+ (if (not (eq? (car (lex 'get)) type))
+ (error "got different token than peeked"))
+ (let ((tail (get-list lex #f close-square)))
+ (if (not (= (length tail) 1))
+ (parse-error next
+ "expected exactly one element after dot"))
+ (car tail))))
+ (else
+ ;; Do both parses in exactly this sequence!
+ (let* ((head (get-expression lex))
+ (tail (get-list lex allow-dot close-square)))
+ (cons head tail))))))
;;; Parse a single expression from a lexer-buffer. This is the main
;;; routine in our recursive-descent parser.
@@ -173,13 +174,16 @@
(type (car token))
(return (lambda (result)
(if (pair? result)
- (set-source-properties! result (source-properties token)))
+ (set-source-properties!
+ result
+ (source-properties token)))
result)))
(case type
((integer float symbol character string)
(return (cdr token)))
((quote backquote unquote unquote-splicing)
- (return (list (assq-ref quotation-symbols type) (get-expression lex))))
+ (return (list (assq-ref quotation-symbols type)
+ (get-expression lex))))
((paren-open)
(return (get-list lex #t #f)))
((square-open)
@@ -194,7 +198,7 @@
(force-promises! expr)
expr))
(else
- (parse-error token "expected expression, got" token)))))
+ (parse-error token "expected expression, got" token)))))
;;; Define the reader function based on this; build a lexer, a
;;; lexer-buffer, and then parse a single expression to return. We also
diff --git a/module/language/elisp/runtime.scm b/module/language/elisp/runtime.scm
index e0a09434c..9657cf7dd 100644
--- a/module/language/elisp/runtime.scm
+++ b/module/language/elisp/runtime.scm
@@ -20,12 +20,17 @@
(define-module (language elisp runtime)
#:export (void
- nil-value t-value
- value-slot-module function-slot-module
+ nil-value
+ t-value
+ value-slot-module
+ function-slot-module
elisp-bool
- ensure-fluid! reference-variable reference-variable-with-check
+ ensure-fluid!
+ reference-variable
+ reference-variable-with-check
set-variable!
- runtime-error macro-error)
+ runtime-error
+ macro-error)
#:export-syntax (built-in-func built-in-macro prim))
;;; This module provides runtime support for the Elisp front-end.
@@ -61,8 +66,8 @@
(define (elisp-bool b)
(if b
- t-value
- nil-value))
+ t-value
+ nil-value))
;;; Routines for access to elisp dynamically bound symbols. This is
;;; used for runtime access using functions like symbol-value or set,
@@ -74,10 +79,10 @@
(let ((intf (resolve-interface module))
(resolved (resolve-module module)))
(if (not (module-defined? intf sym))
- (let ((fluid (make-fluid)))
- (fluid-set! fluid void)
- (module-define! resolved sym fluid)
- (module-export! resolved `(,sym))))))
+ (let ((fluid (make-fluid)))
+ (fluid-set! fluid void)
+ (module-define! resolved sym fluid)
+ (module-export! resolved `(,sym))))))
(define (reference-variable module sym)
(ensure-fluid! module sym)
@@ -87,8 +92,8 @@
(define (reference-variable-with-check module sym)
(let ((value (reference-variable module sym)))
(if (eq? value void)
- (runtime-error "variable is void:" sym)
- value)))
+ (runtime-error "variable is void:" sym)
+ value)))
(define (set-variable! module sym value)
(ensure-fluid! module sym)
diff --git a/module/language/elisp/runtime/function-slot.scm b/module/language/elisp/runtime/function-slot.scm
index 4121f15c0..c7de493f0 100644
--- a/module/language/elisp/runtime/function-slot.scm
+++ b/module/language/elisp/runtime/function-slot.scm
@@ -28,68 +28,85 @@
;;; Equivalence and equalness predicates.
-(built-in-func eq (lambda (a b)
- (elisp-bool (eq? a b))))
+(built-in-func eq
+ (lambda (a b)
+ (elisp-bool (eq? a b))))
-(built-in-func equal (lambda (a b)
- (elisp-bool (equal? a b))))
+(built-in-func equal
+ (lambda (a b)
+ (elisp-bool (equal? a b))))
;;; Number predicates.
-(built-in-func floatp (lambda (num)
- (elisp-bool (and (real? num)
- (or (inexact? num)
- (prim not (integer? num)))))))
+(built-in-func floatp
+ (lambda (num)
+ (elisp-bool (and (real? num)
+ (or (inexact? num)
+ (prim not (integer? num)))))))
-(built-in-func integerp (lambda (num)
- (elisp-bool (and (exact? num)
- (integer? num)))))
+(built-in-func integerp
+ (lambda (num)
+ (elisp-bool (and (exact? num)
+ (integer? num)))))
-(built-in-func numberp (lambda (num)
- (elisp-bool (real? num))))
+(built-in-func numberp
+ (lambda (num)
+ (elisp-bool (real? num))))
-(built-in-func wholenump (lambda (num)
- (elisp-bool (and (exact? num)
- (integer? num)
- (prim >= num 0)))))
+(built-in-func wholenump
+ (lambda (num)
+ (elisp-bool (and (exact? num)
+ (integer? num)
+ (prim >= num 0)))))
-(built-in-func zerop (lambda (num)
- (elisp-bool (prim = num 0))))
+(built-in-func zerop
+ (lambda (num)
+ (elisp-bool (prim = num 0))))
;;; Number comparisons.
-(built-in-func = (lambda (num1 num2)
- (elisp-bool (prim = num1 num2))))
+(built-in-func =
+ (lambda (num1 num2)
+ (elisp-bool (prim = num1 num2))))
-(built-in-func /= (lambda (num1 num2)
- (elisp-bool (prim not (prim = num1 num2)))))
+(built-in-func /=
+ (lambda (num1 num2)
+ (elisp-bool (prim not (prim = num1 num2)))))
-(built-in-func < (lambda (num1 num2)
- (elisp-bool (prim < num1 num2))))
+(built-in-func <
+ (lambda (num1 num2)
+ (elisp-bool (prim < num1 num2))))
-(built-in-func <= (lambda (num1 num2)
- (elisp-bool (prim <= num1 num2))))
+(built-in-func <=
+ (lambda (num1 num2)
+ (elisp-bool (prim <= num1 num2))))
-(built-in-func > (lambda (num1 num2)
- (elisp-bool (prim > num1 num2))))
+(built-in-func >
+ (lambda (num1 num2)
+ (elisp-bool (prim > num1 num2))))
-(built-in-func >= (lambda (num1 num2)
- (elisp-bool (prim >= num1 num2))))
+(built-in-func >=
+ (lambda (num1 num2)
+ (elisp-bool (prim >= num1 num2))))
-(built-in-func max (lambda (. nums)
- (prim apply (@ (guile) max) nums)))
+(built-in-func max
+ (lambda (. nums)
+ (prim apply (@ (guile) max) nums)))
-(built-in-func min (lambda (. nums)
- (prim apply (@ (guile) min) nums)))
+(built-in-func min
+ (lambda (. nums)
+ (prim apply (@ (guile) min) nums)))
-(built-in-func abs (@ (guile) abs))
+(built-in-func abs
+ (@ (guile) abs))
;;; Number conversion.
-(built-in-func float (lambda (num)
- (if (exact? num)
- (exact->inexact num)
- num)))
+(built-in-func float
+ (lambda (num)
+ (if (exact? num)
+ (exact->inexact num)
+ num)))
;;; TODO: truncate, floor, ceiling, round.
@@ -148,48 +165,48 @@
(built-in-func car
(lambda (el)
(if (null? el)
- nil-value
- (prim car el))))
+ nil-value
+ (prim car el))))
(built-in-func cdr
(lambda (el)
(if (null? el)
- nil-value
- (prim cdr el))))
+ nil-value
+ (prim cdr el))))
(built-in-func car-safe
(lambda (el)
(if (pair? el)
- (prim car el)
- nil-value)))
+ (prim car el)
+ nil-value)))
(built-in-func cdr-safe
(lambda (el)
(if (pair? el)
- (prim cdr el)
- nil-value)))
+ (prim cdr el)
+ nil-value)))
(built-in-func nth
(lambda (n lst)
(if (negative? n)
- (prim car lst)
- (let iterate ((i n)
- (tail lst))
- (cond
- ((null? tail) nil-value)
- ((zero? i) (prim car tail))
- (else (iterate (prim 1- i) (prim cdr tail))))))))
+ (prim car lst)
+ (let iterate ((i n)
+ (tail lst))
+ (cond
+ ((null? tail) nil-value)
+ ((zero? i) (prim car tail))
+ (else (iterate (prim 1- i) (prim cdr tail))))))))
(built-in-func nthcdr
(lambda (n lst)
(if (negative? n)
- lst
- (let iterate ((i n)
- (tail lst))
- (cond
- ((null? tail) nil-value)
- ((zero? i) tail)
- (else (iterate (prim 1- i) (prim cdr tail))))))))
+ lst
+ (let iterate ((i n)
+ (tail lst))
+ (cond
+ ((null? tail) nil-value)
+ ((zero? i) tail)
+ (else (iterate (prim 1- i) (prim cdr tail))))))))
(built-in-func length (@ (guile) length))
@@ -212,31 +229,36 @@
(built-in-func number-sequence
(lambda (from . rest)
(if (prim > (prim length rest) 2)
- (runtime-error "too many arguments for number-sequence"
- (prim cdddr rest))
- (if (null? rest)
- `(,from)
- (let ((to (prim car rest))
- (sep (if (or (null? (prim cdr rest))
- (eq? nil-value (prim cadr rest)))
- 1
- (prim cadr rest))))
- (cond
- ((or (eq? nil-value to) (prim = to from)) `(,from))
- ((and (zero? sep) (prim not (prim = from to)))
- (runtime-error "infinite list in number-sequence"))
- ((prim < (prim * to sep) (prim * from sep)) '())
- (else
- (let iterate ((i (prim +
- from
- (prim * sep
- (prim quotient
- (prim abs (prim - to from))
- (prim abs sep)))))
- (result '()))
- (if (prim = i from)
- (prim cons i result)
- (iterate (prim - i sep) (prim cons i result)))))))))))
+ (runtime-error "too many arguments for number-sequence"
+ (prim cdddr rest))
+ (if (null? rest)
+ `(,from)
+ (let ((to (prim car rest))
+ (sep (if (or (null? (prim cdr rest))
+ (eq? nil-value (prim cadr rest)))
+ 1
+ (prim cadr rest))))
+ (cond
+ ((or (eq? nil-value to) (prim = to from)) `(,from))
+ ((and (zero? sep) (prim not (prim = from to)))
+ (runtime-error "infinite list in number-sequence"))
+ ((prim < (prim * to sep) (prim * from sep)) '())
+ (else
+ (let iterate ((i (prim +
+ from
+ (prim *
+ sep
+ (prim quotient
+ (prim abs
+ (prim -
+ to
+ from))
+ (prim abs sep)))))
+ (result '()))
+ (if (prim = i from)
+ (prim cons i result)
+ (iterate (prim - i sep)
+ (prim cons i result)))))))))))
;;; Changing lists.
@@ -281,12 +303,16 @@
(built-in-func boundp
(lambda (sym)
(elisp-bool (prim not
- (eq? void (reference-variable value-slot-module sym))))))
+ (eq? void
+ (reference-variable value-slot-module
+ sym))))))
(built-in-func fboundp
(lambda (sym)
(elisp-bool (prim not
- (eq? void (reference-variable function-slot-module sym))))))
+ (eq? void
+ (reference-variable function-slot-module
+ sym))))))
;;; Function calls. These must take care of special cases, like using
;;; symbols or raw lambda-lists as functions!
@@ -294,15 +320,17 @@
(built-in-func apply
(lambda (func . args)
(let ((real-func (cond
- ((symbol? func)
- (reference-variable-with-check function-slot-module
- func))
- ((list? func)
- (if (and (prim not (null? func))
- (eq? (prim car func) 'lambda))
- (compile func #:from 'elisp #:to 'value)
- (runtime-error "list is not a function" func)))
- (else func))))
+ ((symbol? func)
+ (reference-variable-with-check
+ function-slot-module
+ func))
+ ((list? func)
+ (if (and (prim not (null? func))
+ (eq? (prim car func) 'lambda))
+ (compile func #:from 'elisp #:to 'value)
+ (runtime-error "list is not a function"
+ func)))
+ (else func))))
(prim apply (@ (guile) apply) real-func args))))
(built-in-func funcall
diff --git a/module/language/elisp/runtime/macro-slot.scm b/module/language/elisp/runtime/macro-slot.scm
index 456c526b5..ceac70cbb 100644
--- a/module/language/elisp/runtime/macro-slot.scm
+++ b/module/language/elisp/runtime/macro-slot.scm
@@ -61,23 +61,23 @@
(lambda (. clauses)
(let iterate ((tail clauses))
(if (null? tail)
- 'nil
- (let ((cur (car tail))
- (rest (iterate (cdr tail))))
- (prim cond
- ((prim or (not (list? cur)) (null? cur))
- (macro-error "invalid clause in cond" cur))
- ((null? (cdr cur))
- (let ((var (gensym)))
- `(without-void-checks (,var)
- (lexical-let ((,var ,(car cur)))
- (if ,var
- ,var
- ,rest)))))
- (else
- `(if ,(car cur)
- (progn ,@(cdr cur))
- ,rest))))))))
+ 'nil
+ (let ((cur (car tail))
+ (rest (iterate (cdr tail))))
+ (prim cond
+ ((prim or (not (list? cur)) (null? cur))
+ (macro-error "invalid clause in cond" cur))
+ ((null? (cdr cur))
+ (let ((var (gensym)))
+ `(without-void-checks (,var)
+ (lexical-let ((,var ,(car cur)))
+ (if ,var
+ ,var
+ ,rest)))))
+ (else
+ `(if ,(car cur)
+ (progn ,@(cdr cur))
+ ,rest))))))))
;;; The and and or forms can also be easily defined with macros.
@@ -103,54 +103,56 @@
x
(let ((var (gensym)))
`(without-void-checks
- (,var)
- (lexical-let ((,var ,x))
- (if ,var
- ,var
- ,(iterate (car tail) (cdr tail)))))))))))
+ (,var)
+ (lexical-let ((,var ,x))
+ (if ,var
+ ,var
+ ,(iterate (car tail) (cdr tail)))))))))))
;;; Define the dotimes and dolist iteration macros.
(built-in-macro dotimes
(lambda (args . body)
- (if (prim or (not (list? args))
- (< (length args) 2)
- (> (length args) 3))
- (macro-error "invalid dotimes arguments" args)
- (let ((var (car args))
- (count (cadr args)))
- (if (not (symbol? var))
- (macro-error "expected symbol as dotimes variable"))
- `(let ((,var 0))
- (while ((guile-primitive <) ,var ,count)
- ,@body
- (setq ,var ((guile-primitive 1+) ,var)))
- ,@(if (= (length args) 3)
- (list (caddr args))
- '()))))))
+ (if (prim or
+ (not (list? args))
+ (< (length args) 2)
+ (> (length args) 3))
+ (macro-error "invalid dotimes arguments" args)
+ (let ((var (car args))
+ (count (cadr args)))
+ (if (not (symbol? var))
+ (macro-error "expected symbol as dotimes variable"))
+ `(let ((,var 0))
+ (while ((guile-primitive <) ,var ,count)
+ ,@body
+ (setq ,var ((guile-primitive 1+) ,var)))
+ ,@(if (= (length args) 3)
+ (list (caddr args))
+ '()))))))
(built-in-macro dolist
(lambda (args . body)
- (if (prim or (not (list? args))
- (< (length args) 2)
- (> (length args) 3))
- (macro-error "invalid dolist arguments" args)
- (let ((var (car args))
- (iter-list (cadr args))
- (tailvar (gensym)))
- (if (not (symbol? var))
- (macro-error "expected symbol as dolist variable")
- `(let (,var)
- (without-void-checks (,tailvar)
- (lexical-let ((,tailvar ,iter-list))
- (while ((guile-primitive not)
- ((guile-primitive null?) ,tailvar))
- (setq ,var ((guile-primitive car) ,tailvar))
- ,@body
- (setq ,tailvar ((guile-primitive cdr) ,tailvar)))
- ,@(if (= (length args) 3)
- (list (caddr args))
- '())))))))))
+ (if (prim or
+ (not (list? args))
+ (< (length args) 2)
+ (> (length args) 3))
+ (macro-error "invalid dolist arguments" args)
+ (let ((var (car args))
+ (iter-list (cadr args))
+ (tailvar (gensym)))
+ (if (not (symbol? var))
+ (macro-error "expected symbol as dolist variable")
+ `(let (,var)
+ (without-void-checks (,tailvar)
+ (lexical-let ((,tailvar ,iter-list))
+ (while ((guile-primitive not)
+ ((guile-primitive null?) ,tailvar))
+ (setq ,var ((guile-primitive car) ,tailvar))
+ ,@body
+ (setq ,tailvar ((guile-primitive cdr) ,tailvar)))
+ ,@(if (= (length args) 3)
+ (list (caddr args))
+ '())))))))))
;;; Exception handling. unwind-protect and catch are implemented as
;;; macros (throw is a built-in function).
@@ -165,22 +167,23 @@
(built-in-macro catch
(lambda (tag . body)
(if (null? body)
- (macro-error "catch with empty body"))
+ (macro-error "catch with empty body"))
(let ((tagsym (gensym)))
`(lexical-let ((,tagsym ,tag))
((guile-primitive catch)
- #t
- (lambda () ,@body)
- ,(let* ((dummy-key (gensym))
- (elisp-key (gensym))
- (value (gensym))
- (arglist `(,dummy-key ,elisp-key ,value)))
- `(with-always-lexical ,arglist
- (lambda ,arglist
- (if (eq ,elisp-key ,tagsym)
+ #t
+ (lambda () ,@body)
+ ,(let* ((dummy-key (gensym))
+ (elisp-key (gensym))
+ (value (gensym))
+ (arglist `(,dummy-key ,elisp-key ,value)))
+ `(with-always-lexical
+ ,arglist
+ (lambda ,arglist
+ (if (eq ,elisp-key ,tagsym)
,value
((guile-primitive throw) ,dummy-key ,elisp-key
- ,value))))))))))
+ ,value))))))))))
;;; unwind-protect is just some weaker construct as dynamic-wind, so
;;; straight-forward to implement.
@@ -188,11 +191,11 @@
(built-in-macro unwind-protect
(lambda (body . clean-ups)
(if (null? clean-ups)
- (macro-error "unwind-protect without cleanup code"))
+ (macro-error "unwind-protect without cleanup code"))
`((guile-primitive dynamic-wind)
- (lambda () nil)
- (lambda () ,body)
- (lambda () ,@clean-ups))))
+ (lambda () nil)
+ (lambda () ,body)
+ (lambda () ,@clean-ups))))
;;; Pop off the first element from a list or push one to it.
diff --git a/module/language/elisp/spec.scm b/module/language/elisp/spec.scm
index 1fc3e06e5..3da368093 100644
--- a/module/language/elisp/spec.scm
+++ b/module/language/elisp/spec.scm
@@ -25,7 +25,7 @@
#:export (elisp))
(define-language elisp
- #:title "Emacs Lisp"
- #:reader (lambda (port env) (read-elisp port))
- #:printer write
- #:compilers `((tree-il . ,compile-tree-il)))
+ #:title "Emacs Lisp"
+ #:reader (lambda (port env) (read-elisp port))
+ #:printer write
+ #:compilers `((tree-il . ,compile-tree-il)))