mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
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>
This commit is contained in:
parent
c983a199d8
commit
f4e5e4114d
8 changed files with 1030 additions and 808 deletions
|
@ -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,19 +54,23 @@
|
|||
;;; 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)))
|
||||
(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)
|
||||
|
@ -87,7 +92,8 @@
|
|||
;;; 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)
|
||||
|
@ -100,14 +106,13 @@
|
|||
(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)))
|
||||
(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))))
|
||||
syms)
|
||||
(with-fluids* (map (lambda (sym)
|
||||
(hash-ref lex sym))
|
||||
syms)
|
||||
(with-fluids* (map (lambda (sym) (hash-ref lex sym)) syms)
|
||||
targets
|
||||
proc)))
|
||||
|
||||
|
@ -119,5 +124,6 @@
|
|||
|
||||
(define (with-dynamic-bindings bindings syms proc)
|
||||
(with-symbol-bindings bindings
|
||||
syms (map (lambda (el) #f) syms)
|
||||
syms
|
||||
(map (lambda (el) #f) syms)
|
||||
proc))
|
||||
|
|
|
@ -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,7 +98,8 @@
|
|||
(apply error args))
|
||||
|
||||
(define (runtime-error loc msg . args)
|
||||
(make-application loc (make-primitive-ref loc 'error)
|
||||
(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
|
||||
|
@ -106,7 +109,8 @@
|
|||
;;; this routine.
|
||||
|
||||
(define (generate-ensure-global loc sym module)
|
||||
(make-application loc (make-module-ref loc runtime 'ensure-fluid! #t)
|
||||
(make-application loc
|
||||
(make-module-ref loc runtime 'ensure-fluid! #t)
|
||||
(list (make-const loc module)
|
||||
(make-const loc sym))))
|
||||
|
||||
|
@ -127,13 +131,17 @@
|
|||
;;; 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)
|
||||
(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 loc
|
||||
'()
|
||||
(make-lambda-case #f '() #f #f #f '() '() body #f))))
|
||||
|
||||
;;; Handle access to a variable (reference/setting) correctly depending
|
||||
|
@ -151,12 +159,15 @@
|
|||
;;; 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))
|
||||
(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
|
||||
(call-primitive loc
|
||||
'fluid-ref
|
||||
(make-module-ref loc module sym #t)))))
|
||||
|
||||
;;; Reference a variable and error if the value is void.
|
||||
|
@ -164,9 +175,15 @@
|
|||
(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?
|
||||
(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))
|
||||
|
@ -178,12 +195,15 @@
|
|||
;;; 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))
|
||||
(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!
|
||||
(call-primitive loc
|
||||
'fluid-set!
|
||||
(make-module-ref loc module sym #t)
|
||||
value))))
|
||||
|
||||
|
@ -192,12 +212,15 @@
|
|||
;;; . val2) ...).
|
||||
|
||||
(define (process-let-bindings loc bindings)
|
||||
(map (lambda (b)
|
||||
(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")
|
||||
(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))))))
|
||||
|
@ -243,15 +266,15 @@
|
|||
(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)))))
|
||||
|
@ -261,16 +284,26 @@
|
|||
(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)
|
||||
(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))
|
||||
(let-dynamic loc
|
||||
(map car dynamic)
|
||||
module
|
||||
(map
|
||||
(lambda (sym)
|
||||
(make-lexical-ref loc
|
||||
sym
|
||||
sym))
|
||||
dynamic-syms)
|
||||
(make-body)))))))))))))
|
||||
|
||||
|
@ -282,7 +315,9 @@
|
|||
(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)
|
||||
|
@ -291,13 +326,19 @@
|
|||
(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))))))
|
||||
(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)
|
||||
`(,(caar tail))
|
||||
module
|
||||
`(,value)
|
||||
(iterate (cdr tail))))))))))
|
||||
|
||||
;;; Split the argument list of a lambda expression into required,
|
||||
|
@ -325,8 +366,11 @@
|
|||
(final-optional (reverse optional))
|
||||
(final-lexical (reverse lexical))
|
||||
(final-dynamic (reverse dynamic)))
|
||||
(values final-required final-optional #f
|
||||
final-lexical final-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))
|
||||
|
@ -344,11 +388,16 @@
|
|||
(final-dynamic (reverse (if rest-lexical
|
||||
dynamic
|
||||
(cons rest dynamic)))))
|
||||
(values final-required final-optional rest
|
||||
final-lexical final-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))
|
||||
(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
|
||||
|
@ -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,
|
||||
|
@ -423,55 +473,83 @@
|
|||
(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
|
||||
(with-dynamic-bindings
|
||||
(fluid-ref bindings-data)
|
||||
dynamic
|
||||
(lambda ()
|
||||
(with-lexical-bindings (fluid-ref bindings-data)
|
||||
(with-lexical-bindings
|
||||
(fluid-ref bindings-data)
|
||||
(map car all-lex-pairs)
|
||||
(map cdr all-lex-pairs)
|
||||
(lambda ()
|
||||
(make-lambda loc '()
|
||||
(make-lambda loc
|
||||
'()
|
||||
(make-lambda-case
|
||||
#f required #f
|
||||
#f
|
||||
required
|
||||
#f
|
||||
(if have-real-rest rest-name #f)
|
||||
#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)
|
||||
(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))
|
||||
(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)
|
||||
(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)))
|
||||
(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)
|
||||
optional-sym
|
||||
optional-sym
|
||||
(map (lambda (sym)
|
||||
(nil-value loc))
|
||||
optional-sym)
|
||||
full-body)))
|
||||
#f))))))))))
|
||||
|
||||
|
@ -482,33 +560,58 @@
|
|||
(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-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-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-conditional loc
|
||||
rest-empty
|
||||
(make-void loc)
|
||||
(set-variable! loc rest value-slot
|
||||
(make-lexical-ref loc rest-name rest-sym))))
|
||||
(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")))
|
||||
(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
|
||||
|
@ -570,19 +673,26 @@
|
|||
(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-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)))))
|
||||
(unquote-splicing?
|
||||
(car head)))))
|
||||
(if head-unquote-splicing
|
||||
(call-primitive loc 'append
|
||||
(compile-expr (cadr head)) processed-tail)
|
||||
(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))
|
||||
(report-error loc
|
||||
"non-pair expression contains unquotes"
|
||||
expr))
|
||||
(make-const loc expr)))
|
||||
|
||||
;;; Temporarily update a list of symbols that are handled specially
|
||||
|
@ -623,17 +733,20 @@
|
|||
(make-sequence loc (map compile-expr forms)))
|
||||
|
||||
((if ,condition ,ifclause)
|
||||
(make-conditional loc (compile-expr condition)
|
||||
(make-conditional loc
|
||||
(compile-expr condition)
|
||||
(compile-expr ifclause)
|
||||
(nil-value loc)))
|
||||
|
||||
((if ,condition ,ifclause ,elseclause)
|
||||
(make-conditional loc (compile-expr condition)
|
||||
(make-conditional loc
|
||||
(compile-expr condition)
|
||||
(compile-expr ifclause)
|
||||
(compile-expr elseclause)))
|
||||
|
||||
((if ,condition ,ifclause . ,elses)
|
||||
(make-conditional loc (compile-expr condition)
|
||||
(make-conditional loc
|
||||
(compile-expr condition)
|
||||
(compile-expr ifclause)
|
||||
(make-sequence loc (map compile-expr elses))))
|
||||
|
||||
|
@ -644,20 +757,25 @@
|
|||
((defconst ,sym ,value . ,doc)
|
||||
(if (handle-var-def loc sym doc)
|
||||
(make-sequence loc
|
||||
(list (set-variable! loc sym value-slot (compile-expr value))
|
||||
(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)))))
|
||||
|
||||
|
@ -666,22 +784,33 @@
|
|||
;; large lists of symbol expression pairs are very unlikely.
|
||||
|
||||
((setq . ,args) (guard (not (null? args)))
|
||||
(make-sequence loc
|
||||
(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)
|
||||
(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)
|
||||
(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)))))))))))
|
||||
|
@ -759,7 +888,9 @@
|
|||
(let* ((itersym (gensym))
|
||||
(compiled-body (map compile-expr body))
|
||||
(iter-call (make-application loc
|
||||
(make-lexical-ref loc 'iterate itersym)
|
||||
(make-lexical-ref loc
|
||||
'iterate
|
||||
itersym)
|
||||
(list)))
|
||||
(full-body (make-sequence loc
|
||||
`(,@compiled-body ,iter-call)))
|
||||
|
@ -767,10 +898,22 @@
|
|||
(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-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
|
||||
|
@ -790,8 +933,12 @@
|
|||
(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))
|
||||
(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:
|
||||
|
@ -866,12 +1013,18 @@
|
|||
((#: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)))
|
||||
(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)))))))
|
||||
(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
|
||||
|
@ -887,7 +1040,8 @@
|
|||
(let ((loc (location expr))
|
||||
(compiled (compile-expr expr)))
|
||||
(make-sequence loc
|
||||
`(,@(map-globals-needed (fluid-ref bindings-data)
|
||||
`(,@(map-globals-needed
|
||||
(fluid-ref bindings-data)
|
||||
(lambda (mod sym)
|
||||
(generate-ensure-global loc sym mod)))
|
||||
,compiled))))
|
||||
|
|
|
@ -106,7 +106,10 @@
|
|||
(begin
|
||||
(unread-char cur port)
|
||||
result)
|
||||
(lexer-error port "invalid digit in escape-code" base cur))
|
||||
(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
|
||||
|
@ -116,13 +119,23 @@
|
|||
;;; 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.
|
||||
|
@ -160,8 +173,8 @@
|
|||
((#\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!
|
||||
;; 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
|
||||
|
@ -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,7 +202,8 @@
|
|||
(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)
|
||||
|
@ -202,7 +217,8 @@
|
|||
(need-no-escape? (lambda (c)
|
||||
(or (char-numeric? c)
|
||||
(char-alphabetic? c)
|
||||
(char-set-contains? no-escape-punctuation
|
||||
(char-set-contains?
|
||||
no-escape-punctuation
|
||||
c)))))
|
||||
(cond
|
||||
((eof-object? c) (finish))
|
||||
|
@ -229,13 +245,17 @@
|
|||
(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)
|
||||
|
@ -289,7 +309,8 @@
|
|||
(else
|
||||
(unread-char escaped port)
|
||||
(unread-char cur port)
|
||||
(iterate (cons (integer->char (get-character port #t))
|
||||
(iterate
|
||||
(cons (integer->char (get-character port #t))
|
||||
result-chars))))))
|
||||
(else (iterate (cons cur result-chars)))))))
|
||||
;; Circular markers (either reference or definition).
|
||||
|
@ -316,16 +337,15 @@
|
|||
(else
|
||||
(unread-char c port)
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(get-symbol-or-number port))
|
||||
(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.
|
||||
;; 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
|
||||
|
@ -335,10 +355,11 @@
|
|||
(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
|
||||
;; 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))
|
||||
|
@ -346,7 +367,9 @@
|
|||
((float)
|
||||
(return 'float (let ((num (string->number str)))
|
||||
(if (exact? num)
|
||||
(error "expected inexact float" str num))
|
||||
(error "expected inexact float"
|
||||
str
|
||||
num))
|
||||
num)))
|
||||
(else (error "wrong number/symbol type" type)))))))))))
|
||||
|
||||
|
@ -354,8 +377,7 @@
|
|||
;;; 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
|
||||
|
|
|
@ -152,7 +152,8 @@
|
|||
(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"))
|
||||
(parse-error next
|
||||
"expected exactly one element after dot"))
|
||||
(car tail))))
|
||||
(else
|
||||
;; Do both parses in exactly this sequence!
|
||||
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -28,65 +28,82 @@
|
|||
|
||||
;;; Equivalence and equalness predicates.
|
||||
|
||||
(built-in-func eq (lambda (a b)
|
||||
(built-in-func eq
|
||||
(lambda (a b)
|
||||
(elisp-bool (eq? a b))))
|
||||
|
||||
(built-in-func equal (lambda (a b)
|
||||
(built-in-func equal
|
||||
(lambda (a b)
|
||||
(elisp-bool (equal? a b))))
|
||||
|
||||
;;; Number predicates.
|
||||
|
||||
(built-in-func floatp (lambda (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)
|
||||
(built-in-func integerp
|
||||
(lambda (num)
|
||||
(elisp-bool (and (exact? num)
|
||||
(integer? num)))))
|
||||
|
||||
(built-in-func numberp (lambda (num)
|
||||
(built-in-func numberp
|
||||
(lambda (num)
|
||||
(elisp-bool (real? num))))
|
||||
|
||||
(built-in-func wholenump (lambda (num)
|
||||
(built-in-func wholenump
|
||||
(lambda (num)
|
||||
(elisp-bool (and (exact? num)
|
||||
(integer? num)
|
||||
(prim >= num 0)))))
|
||||
|
||||
(built-in-func zerop (lambda (num)
|
||||
(built-in-func zerop
|
||||
(lambda (num)
|
||||
(elisp-bool (prim = num 0))))
|
||||
|
||||
;;; Number comparisons.
|
||||
|
||||
(built-in-func = (lambda (num1 num2)
|
||||
(built-in-func =
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim = num1 num2))))
|
||||
|
||||
(built-in-func /= (lambda (num1 num2)
|
||||
(built-in-func /=
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim not (prim = num1 num2)))))
|
||||
|
||||
(built-in-func < (lambda (num1 num2)
|
||||
(built-in-func <
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim < num1 num2))))
|
||||
|
||||
(built-in-func <= (lambda (num1 num2)
|
||||
(built-in-func <=
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim <= num1 num2))))
|
||||
|
||||
(built-in-func > (lambda (num1 num2)
|
||||
(built-in-func >
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim > num1 num2))))
|
||||
|
||||
(built-in-func >= (lambda (num1 num2)
|
||||
(built-in-func >=
|
||||
(lambda (num1 num2)
|
||||
(elisp-bool (prim >= num1 num2))))
|
||||
|
||||
(built-in-func max (lambda (. nums)
|
||||
(built-in-func max
|
||||
(lambda (. nums)
|
||||
(prim apply (@ (guile) max) nums)))
|
||||
|
||||
(built-in-func min (lambda (. 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)
|
||||
(built-in-func float
|
||||
(lambda (num)
|
||||
(if (exact? num)
|
||||
(exact->inexact num)
|
||||
num)))
|
||||
|
@ -229,14 +246,19 @@
|
|||
(else
|
||||
(let iterate ((i (prim +
|
||||
from
|
||||
(prim * sep
|
||||
(prim *
|
||||
sep
|
||||
(prim quotient
|
||||
(prim abs (prim - to from))
|
||||
(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)))))))))))
|
||||
(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!
|
||||
|
@ -295,13 +321,15 @@
|
|||
(lambda (func . args)
|
||||
(let ((real-func (cond
|
||||
((symbol? func)
|
||||
(reference-variable-with-check function-slot-module
|
||||
(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)))
|
||||
(runtime-error "list is not a function"
|
||||
func)))
|
||||
(else func))))
|
||||
(prim apply (@ (guile) apply) real-func args))))
|
||||
|
||||
|
|
|
@ -113,7 +113,8 @@
|
|||
|
||||
(built-in-macro dotimes
|
||||
(lambda (args . body)
|
||||
(if (prim or (not (list? args))
|
||||
(if (prim or
|
||||
(not (list? args))
|
||||
(< (length args) 2)
|
||||
(> (length args) 3))
|
||||
(macro-error "invalid dotimes arguments" args)
|
||||
|
@ -131,7 +132,8 @@
|
|||
|
||||
(built-in-macro dolist
|
||||
(lambda (args . body)
|
||||
(if (prim or (not (list? args))
|
||||
(if (prim or
|
||||
(not (list? args))
|
||||
(< (length args) 2)
|
||||
(> (length args) 3))
|
||||
(macro-error "invalid dolist arguments" args)
|
||||
|
@ -175,7 +177,8 @@
|
|||
(elisp-key (gensym))
|
||||
(value (gensym))
|
||||
(arglist `(,dummy-key ,elisp-key ,value)))
|
||||
`(with-always-lexical ,arglist
|
||||
`(with-always-lexical
|
||||
,arglist
|
||||
(lambda ,arglist
|
||||
(if (eq ,elisp-key ,tagsym)
|
||||
,value
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue