mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-14 17:50:22 +02:00
elisp updates
(Best-ability ChangeLog annotation added by Christine Lemmer-Webber.) * module/language/elisp/bindings.scm (get-lexical-binding) (get-function-binding): Use cadr instead of fluid-ref on slot. (with-fluids**): New procedure. (with-symbol-bindings, with-function-bindings): Use with-fluids**. Also stop using "make-fluid", use "(list #f #f)" instead as default lexical-bindings hashtable value. (with-lexical-bindings): Drop the error checking for invalid targets. * module/language/elisp/boot.el (defun, save-excursion) (save-current-buffer, save-restriction, track-mouse, setq-default) (catch, condition-case): New macros. (omega, eval, gensym, interactive, autoload-do-load, fset, prin1) (backtrace-frame, backtrace, %set-eager-macroexpansion-mode): New functions. (null, consp, listp, car, cdr, make-symbol, signal): Wrap in eval-and-compile. (prog1, cond, or, while): Update to make use of gensym. (unwind-protect): Switch from funcall to %funcall. (%functionp): Rename from functionp. (%indirect-function): Update to use %functionp instead of functionp. Add check for if object is null, signaling void-function. Instead of calling symbol-function directly, call via %funcall from the module "(language elisp runtime)". (fset): Significant additions and refactoring. (gload): Renamed from fload. (defvaralias, nthcdr, nth, eq): Move functions to a different location. (eq): Also stop using null. (dolist): Remove quasiquoting, build list manually. (random): Fix indentation. (progn, eval-when-compile, if, defconst, defvar, setq, let, flet) (labels, let*, function, defmacro, quote): Protect as special operators by raising error if invoked as a function. * module/language/elisp/compile-tree-il.scm: Import "(ice-9 format)". Export compile-%function. (lexical-binding, handle-var-def, defun, valid-symbol-list-arg?) (process-options!): Remove. (reference-variable): Adjust functions passed to access-variable. (global?): Drop module parameter, use value-slot instead. (ensure-globals!, set-variable!, parse-body-1, parse-lambda-list) (compile-lambda, defconst, defvar, let, let*, compile-pair): Refactor. (reference-function): Use '(elisp-functions) instead of function-slot. (bind-lexically?): Drop module parameter, simplify. (make-dynlet): Switch from using make-primcall to make-call. (find-operator): Switch from using resolve-interface/resolve-module to using function-slot. (if, defconst, defvar, let, let*, flet, labels, guile-ref) (guile-private-ref, guile-primitive, defmacro, `, quote, %funcall) (%set-lexical-binding-mode): Add error checking. (setq): Pass in args to report-error. (function): Simplified, now calling %function. (%function): New function, based on prior "function". Refactor, including adding support for matching against a closure. (%set-lexical-binding-mode): Switch from using fluid-set! to set-lexical-binding-mode. (special-operators): New variable. Build from following for-each statement. (compile-tree-il): Drop call to "process-options!" * module/language/elisp/lexer.scm: Import "(language elisp runtime)". (lex): Switch from using "list->string" to "make-lisp-string". * module/language/elisp/runtime.scm: Use modules "(ice-9 format)", "(system base compile)". Remove from export list list, removing ensure-fluid!, symbol-fluid!, set-symbol-fluid!. Add to export list ensure-dynamic!, symbol-name, symbol-plist, set-symbol-plist!, bind-symbol, symbol-desc, proclaim-symbol! special? emacs! unbound, lexical-binding?, set-lexical-binding-mode, log!, eval-elisp, local-eval-elisp, make-lisp-string, lisp-string? (make-list-string, lisp-string?) New function aliases. (value-slot-module, function-slot-module): Adjust module resolution. (nil_, t_): New variables. (ensure-fluid!, symbol-fluid, set-symbol-fluid!): Removed. (lexical-binding, unbound): New variables. (lexical-binding?, set-lexical-binding-mode, unbound, dynamic?) (make-dynamic, dynamic-ref, dynamic-set!, dynamic-unset!) (dynamic-bound?, dynamic-bind, ensure-present!, ensure-desc!) (schemify, symbol-name, symbol-desc, ensure-dynamic!, symbol-dynamic) (set-symbol-plist!, special?, proclaim-special!, emacs!, eval-elisp) (make-string): New procedures. (symbol-value): Use dynamic-ref! instead of fluid-ref!. (set-symbol-value!): Use dynamic-set! instead of fluid-set!. (symbol-function, set-symbol-function!, symbol-bound?) (symbol-fbound?, makunbound!, fmakunbound!): Refactor, including adjusting how module resolution is being done. * module/language/elisp/spec.scm: Import module "(system vm vm)". Setup elisp-symbols, elisp-functions, elisp-plists. Use "set-default-vm-engine!" and "set-vm-engine!" to be set to 'debug. (elisp): Comment out joiner.
This commit is contained in:
parent
ad3d498d31
commit
cf5e02f1a6
6 changed files with 582 additions and 276 deletions
|
@ -61,12 +61,22 @@
|
|||
(let* ((lex (lexical-bindings bindings))
|
||||
(slot (hash-ref lex sym #f)))
|
||||
(if slot
|
||||
(fluid-ref slot)
|
||||
(cadr slot)
|
||||
#f)))
|
||||
|
||||
(define (get-function-binding bindings symbol)
|
||||
(and=> (hash-ref (function-bindings bindings) symbol)
|
||||
fluid-ref))
|
||||
cadr))
|
||||
|
||||
(define (with-fluids** fls vals proc)
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(for-each (lambda (f v) (set-cdr! f (cons v (cdr f))))
|
||||
fls vals))
|
||||
proc
|
||||
(lambda ()
|
||||
(for-each (lambda (f) (set-cdr! f (cdr (cdr f))))
|
||||
fls))))
|
||||
|
||||
;;; Establish a binding or mark a symbol as dynamically bound for the
|
||||
;;; extent of calling proc.
|
||||
|
@ -78,17 +88,14 @@
|
|||
(let ((lex (lexical-bindings bindings)))
|
||||
(for-each (lambda (sym)
|
||||
(if (not (hash-ref lex sym))
|
||||
(hash-set! lex sym (make-fluid))))
|
||||
(hash-set! lex sym (list #f #f))))
|
||||
syms)
|
||||
(with-fluids* (map (lambda (sym) (hash-ref lex sym)) syms)
|
||||
targets
|
||||
proc)))
|
||||
(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)))
|
||||
(with-symbol-bindings bindings syms targets proc))
|
||||
|
||||
(define (with-dynamic-bindings bindings syms proc)
|
||||
(with-symbol-bindings bindings
|
||||
|
@ -100,8 +107,8 @@
|
|||
(let ((fb (function-bindings bindings)))
|
||||
(for-each (lambda (symbol)
|
||||
(if (not (hash-ref fb symbol))
|
||||
(hash-set! fb symbol (make-fluid))))
|
||||
(hash-set! fb symbol (list #f #f))))
|
||||
symbols)
|
||||
(with-fluids* (map (cut hash-ref fb <>) symbols)
|
||||
gensyms
|
||||
thunk)))
|
||||
(with-fluids** (map (cut hash-ref fb <>) symbols)
|
||||
gensyms
|
||||
thunk)))
|
||||
|
|
|
@ -22,11 +22,26 @@
|
|||
(defmacro @ (module symbol)
|
||||
`(guile-ref ,module ,symbol))
|
||||
|
||||
(defmacro defun (name args &rest body)
|
||||
`(let ((proc (function (lambda ,args ,@body))))
|
||||
(%funcall (@ (language elisp runtime) set-symbol-function!)
|
||||
',name
|
||||
proc)
|
||||
(%funcall (@ (guile) set-procedure-property!)
|
||||
proc 'name ',name)
|
||||
',name))
|
||||
|
||||
(defun omega () (omega))
|
||||
|
||||
(defmacro eval-and-compile (&rest body)
|
||||
`(progn
|
||||
(eval-when-compile ,@body)
|
||||
(progn ,@body)))
|
||||
|
||||
(eval-and-compile
|
||||
(defun eval (form)
|
||||
(%funcall (@ (language elisp runtime) eval-elisp) form)))
|
||||
|
||||
(eval-and-compile
|
||||
(defun null (object)
|
||||
(if object nil t))
|
||||
|
@ -40,6 +55,8 @@
|
|||
(if list (%funcall (@ (guile) cdr) list) nil))
|
||||
(defun make-symbol (name)
|
||||
(%funcall (@ (guile) make-symbol) name))
|
||||
(defun gensym ()
|
||||
(%funcall (@ (guile) gensym)))
|
||||
(defun signal (error-symbol data)
|
||||
(%funcall (@ (guile) throw) 'elisp-condition error-symbol data)))
|
||||
|
||||
|
@ -47,12 +64,15 @@
|
|||
`#'(lambda ,@cdr))
|
||||
|
||||
(defmacro prog1 (first &rest body)
|
||||
(let ((temp (make-symbol "prog1-temp")))
|
||||
(let ((temp (gensym)))
|
||||
`(let ((,temp ,first))
|
||||
(declare (lexical ,temp))
|
||||
,@body
|
||||
,temp)))
|
||||
|
||||
(defun interactive (&optional arg)
|
||||
nil)
|
||||
|
||||
(defmacro prog2 (form1 form2 &rest body)
|
||||
`(progn ,form1 (prog1 ,form2 ,@body)))
|
||||
|
||||
|
@ -65,7 +85,7 @@
|
|||
(let ((condition (car first))
|
||||
(body (cdr first)))
|
||||
(if (null body)
|
||||
(let ((temp (make-symbol "cond-temp")))
|
||||
(let ((temp (gensym)))
|
||||
`(let ((,temp ,condition))
|
||||
(declare (lexical ,temp))
|
||||
(if ,temp
|
||||
|
@ -86,7 +106,7 @@
|
|||
(defmacro or (&rest conditions)
|
||||
(cond ((null conditions) nil)
|
||||
((null (cdr conditions)) (car conditions))
|
||||
(t (let ((temp (make-symbol "or-temp")))
|
||||
(t (let ((temp (gensym)))
|
||||
`(let ((,temp ,(car conditions)))
|
||||
(declare (lexical ,temp))
|
||||
(if ,temp
|
||||
|
@ -118,7 +138,7 @@
|
|||
(loop bindings '())))
|
||||
|
||||
(defmacro while (test &rest body)
|
||||
(let ((loop (make-symbol "loop")))
|
||||
(let ((loop (gensym)))
|
||||
`(labels ((,loop ()
|
||||
(if ,test
|
||||
(progn ,@body (,loop))
|
||||
|
@ -126,10 +146,10 @@
|
|||
(,loop))))
|
||||
|
||||
(defmacro unwind-protect (bodyform &rest unwindforms)
|
||||
`(funcall (@ (guile) dynamic-wind)
|
||||
#'(lambda () nil)
|
||||
#'(lambda () ,bodyform)
|
||||
#'(lambda () ,@unwindforms)))
|
||||
`(%funcall (@ (guile) dynamic-wind)
|
||||
#'(lambda () nil)
|
||||
#'(lambda () ,bodyform)
|
||||
#'(lambda () ,@unwindforms)))
|
||||
|
||||
(defmacro when (cond &rest body)
|
||||
`(if ,cond
|
||||
|
@ -142,7 +162,7 @@
|
|||
(defun symbolp (object)
|
||||
(%funcall (@ (guile) symbol?) object))
|
||||
|
||||
(defun functionp (object)
|
||||
(defun %functionp (object)
|
||||
(%funcall (@ (guile) procedure?) object))
|
||||
|
||||
(defun symbol-function (symbol)
|
||||
|
@ -162,10 +182,13 @@
|
|||
|
||||
(defun %indirect-function (object)
|
||||
(cond
|
||||
((functionp object)
|
||||
((%functionp object)
|
||||
object)
|
||||
((null object)
|
||||
(signal 'void-function nil))
|
||||
((symbolp object) ;++ cycle detection
|
||||
(%indirect-function (symbol-function object)))
|
||||
(%indirect-function
|
||||
(%funcall (@ (language elisp runtime) symbol-function) object)))
|
||||
((listp object)
|
||||
(eval `(function ,object)))
|
||||
(t
|
||||
|
@ -182,17 +205,67 @@
|
|||
(%indirect-function function)
|
||||
arguments))
|
||||
|
||||
(defun autoload-do-load (fundef &optional funname macro-only)
|
||||
(and (load (cadr fundef))
|
||||
(%indirect-function funname)))
|
||||
|
||||
(defun fset (symbol definition)
|
||||
(funcall (@ (language elisp runtime) set-symbol-function!)
|
||||
symbol
|
||||
(if (functionp definition)
|
||||
definition
|
||||
definition))
|
||||
|
||||
(defun eq (obj1 obj2)
|
||||
(if obj1
|
||||
(%funcall (@ (guile) eq?) obj1 obj2)
|
||||
(if obj2 nil t)))
|
||||
|
||||
(defun nthcdr (n list)
|
||||
(let ((i 0))
|
||||
(while (< i n)
|
||||
(setq list (cdr list)
|
||||
i (+ i 1)))
|
||||
list))
|
||||
|
||||
(defun nth (n list)
|
||||
(car (nthcdr n list)))
|
||||
|
||||
(defun fset (symbol definition)
|
||||
(funcall (@ (language elisp runtime) set-symbol-function!)
|
||||
symbol
|
||||
(cond
|
||||
((%funcall (@ (guile) procedure?) definition)
|
||||
definition)
|
||||
((and (consp definition)
|
||||
(eq (car definition) 'macro))
|
||||
(if (%funcall (@ (guile) procedure?) (cdr definition))
|
||||
definition
|
||||
(cons 'macro
|
||||
(funcall (@ (language elisp falias) make-falias)
|
||||
(function
|
||||
(lambda (&rest args) (apply (cdr definition) args)))
|
||||
(cdr definition)))))
|
||||
((and (consp definition)
|
||||
(eq (car definition) 'autoload))
|
||||
(if (or (eq (nth 4 definition) 'macro)
|
||||
(eq (nth 4 definition) t))
|
||||
(cons 'macro
|
||||
(funcall
|
||||
(@ (language elisp falias) make-falias)
|
||||
(function (lambda (&rest args)
|
||||
(apply (cdr (autoload-do-load definition symbol nil)) args)))
|
||||
definition))
|
||||
(funcall
|
||||
(@ (language elisp falias) make-falias)
|
||||
(function (lambda (&rest args)
|
||||
(apply (autoload-do-load definition symbol nil) args)))
|
||||
definition)))
|
||||
(t
|
||||
(funcall (@ (language elisp falias) make-falias)
|
||||
#'(lambda (&rest args) (apply definition args))
|
||||
definition)))
|
||||
(function (lambda (&rest args) (apply definition args)))
|
||||
definition))))
|
||||
definition)
|
||||
|
||||
(defun load (file)
|
||||
(defun gload (file)
|
||||
(funcall (@ (system base compile) compile-file)
|
||||
file
|
||||
(funcall (@ (guile) symbol->keyword) 'from)
|
||||
|
@ -203,11 +276,6 @@
|
|||
|
||||
;;; Equality predicates
|
||||
|
||||
(defun eq (obj1 obj2)
|
||||
(if obj1
|
||||
(funcall (@ (guile) eq?) obj1 obj2)
|
||||
(null obj2)))
|
||||
|
||||
(defun eql (obj1 obj2)
|
||||
(if obj1
|
||||
(funcall (@ (guile) eqv?) obj1 obj2)
|
||||
|
@ -231,13 +299,13 @@
|
|||
(fset 'fboundp (@ (language elisp runtime) symbol-fbound?))
|
||||
(fset 'intern (@ (guile) string->symbol))
|
||||
|
||||
(defun defvaralias (new-alias base-variable &optional docstring)
|
||||
(let ((fluid (funcall (@ (language elisp runtime) symbol-fluid)
|
||||
base-variable)))
|
||||
(funcall (@ (language elisp runtime) set-symbol-fluid!)
|
||||
new-alias
|
||||
fluid)
|
||||
base-variable))
|
||||
;(defun defvaralias (new-alias base-variable &optional docstring)
|
||||
; (let ((fluid (funcall (@ (language elisp runtime) symbol-fluid)
|
||||
; base-variable)))
|
||||
; (funcall (@ (language elisp runtime) set-symbol-fluid!)
|
||||
; new-alias
|
||||
; fluid)
|
||||
; base-variable))
|
||||
|
||||
;;; Numerical type predicates
|
||||
|
||||
|
@ -344,16 +412,6 @@
|
|||
newcdr)
|
||||
(signal 'wrong-type-argument `(consp ,cell))))
|
||||
|
||||
(defun nthcdr (n list)
|
||||
(let ((i 0))
|
||||
(while (< i n)
|
||||
(setq list (cdr list)
|
||||
i (+ i 1)))
|
||||
list))
|
||||
|
||||
(defun nth (n list)
|
||||
(car (nthcdr n list)))
|
||||
|
||||
(defun %member (elt list test)
|
||||
(cond
|
||||
((null list) nil)
|
||||
|
@ -400,10 +458,11 @@
|
|||
|
||||
(defmacro dolist (spec &rest body)
|
||||
(apply #'(lambda (var list &optional result)
|
||||
`(mapc #'(lambda (,var)
|
||||
,@body
|
||||
,result)
|
||||
,list))
|
||||
(list 'progn
|
||||
(list 'mapc
|
||||
(cons 'lambda (cons (list var) body))
|
||||
list)
|
||||
result))
|
||||
spec))
|
||||
|
||||
;;; Strings
|
||||
|
@ -582,6 +641,9 @@
|
|||
(defun print (object)
|
||||
(funcall (@ (guile) write) object))
|
||||
|
||||
(defun prin1 (object)
|
||||
(funcall (@ (guile) write) object))
|
||||
|
||||
(defun terpri ()
|
||||
(funcall (@ (guile) newline)))
|
||||
|
||||
|
@ -607,11 +669,90 @@
|
|||
(@ (guile) *random-state*)))
|
||||
|
||||
(defun random (&optional limit)
|
||||
(if (eq limit t)
|
||||
(setq %random-state
|
||||
(funcall (@ (guile) random-state-from-platform))))
|
||||
(funcall (@ (guile) random)
|
||||
(if (wholenump limit)
|
||||
limit
|
||||
(@ (guile) most-positive-fixnum))
|
||||
%random-state))
|
||||
(if (eq limit t)
|
||||
(setq %random-state
|
||||
(funcall (@ (guile) random-state-from-platform))))
|
||||
(funcall (@ (guile) random)
|
||||
(if (wholenump limit)
|
||||
limit
|
||||
(@ (guile) most-positive-fixnum))
|
||||
%random-state))
|
||||
|
||||
(defmacro save-excursion (&rest body)
|
||||
`(call-with-save-excursion #'(lambda () ,@body)))
|
||||
|
||||
(defmacro save-current-buffer (&rest body)
|
||||
`(call-with-save-current-buffer #'(lambda () ,@body)))
|
||||
|
||||
(defmacro save-restriction (&rest body)
|
||||
`(call-with-save-restriction #'(lambda () ,@body)))
|
||||
|
||||
(defmacro track-mouse (&rest body)
|
||||
`(call-with-track-mouse #'(lambda () ,@body)))
|
||||
|
||||
(defmacro setq-default (var value &rest args)
|
||||
`(progn (set-default ',var ,value)
|
||||
,(if (null args)
|
||||
var
|
||||
`(setq-default ,@args))))
|
||||
|
||||
(defmacro catch (tag &rest body)
|
||||
`(call-with-catch ,tag #'(lambda () ,@body)))
|
||||
|
||||
(defmacro condition-case (var bodyform &rest args)
|
||||
(if (consp args)
|
||||
(let* ((handler (car args))
|
||||
(handlers (cdr args))
|
||||
(handler-conditions (car handler))
|
||||
(handler-body (cdr handler)))
|
||||
`(call-with-handler ',var
|
||||
',handler-conditions
|
||||
#'(lambda () ,@handler-body)
|
||||
#'(lambda ()
|
||||
(condition-case ,var
|
||||
,bodyform
|
||||
,@handlers))))
|
||||
bodyform))
|
||||
|
||||
(defun backtrace-frame (nframes)
|
||||
(let* ((stack (funcall (@ (guile) make-stack) t))
|
||||
(frame (stack-ref stack nframes))
|
||||
(proc (funcall (@ (guile) frame-procedure) frame))
|
||||
(pname (or (and (%functionp proc)
|
||||
(funcall (@ (guile) procedure-name) proc))
|
||||
proc))
|
||||
(args (funcall (@ (guile) frame-arguments) frame)))
|
||||
(cons t (cons pname args))))
|
||||
|
||||
(defun backtrace ()
|
||||
(interactive)
|
||||
(let* ((stack (funcall (@ (guile) make-stack) t))
|
||||
(frame (funcall (@ (guile) stack-ref) stack 1))
|
||||
(space (funcall (@ (guile) integer->char) 32)))
|
||||
(while frame
|
||||
(princ (string 32 32))
|
||||
(let ((proc (funcall (@ (guile) frame-procedure) frame)))
|
||||
(prin1 (or (and (%functionp proc)
|
||||
(funcall (@ (guile) procedure-name) proc))
|
||||
proc)))
|
||||
(prin1 (funcall (@ (guile) frame-arguments) frame))
|
||||
(terpri)
|
||||
(setq frame (funcall (@ (guile) frame-previous) frame)))
|
||||
nil))
|
||||
|
||||
(defun %set-eager-macroexpansion-mode (ignore)
|
||||
nil)
|
||||
|
||||
(defun progn (&rest args) (error "Special operator"))
|
||||
(defun eval-when-compile (&rest args) (error "Special operator"))
|
||||
(defun if (&rest args) (error "Special operator"))
|
||||
(defun defconst (&rest args) (error "Special operator"))
|
||||
(defun defvar (&rest args) (error "Special operator"))
|
||||
(defun setq (&rest args) (error "Special operator"))
|
||||
(defun let (&rest args) (error "Special operator"))
|
||||
(defun flet (&rest args) (error "Special operator"))
|
||||
(defun labels (&rest args) (error "Special operator"))
|
||||
(defun let* (&rest args) (error "Special operator"))
|
||||
(defun function (&rest args) (error "Special operator"))
|
||||
(defun defmacro (&rest args) (error "Special operator"))
|
||||
(defun quote (&rest args) (error "Special operator"))
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#:use-module (srfi srfi-8)
|
||||
#:use-module (srfi srfi-11)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (ice-9 format)
|
||||
#:export (compile-tree-il
|
||||
compile-progn
|
||||
compile-eval-when-compile
|
||||
|
@ -44,6 +45,7 @@
|
|||
compile-guile-ref
|
||||
compile-guile-private-ref
|
||||
compile-guile-primitive
|
||||
compile-%function
|
||||
compile-function
|
||||
compile-defmacro
|
||||
compile-defun
|
||||
|
@ -61,8 +63,6 @@
|
|||
|
||||
(define bindings-data (make-fluid))
|
||||
|
||||
(define lexical-binding (make-fluid))
|
||||
|
||||
;;; Find the source properties of some parsed expression if there are
|
||||
;;; any associated with it.
|
||||
|
||||
|
@ -122,28 +122,29 @@
|
|||
loc
|
||||
symbol
|
||||
(lambda (lexical)
|
||||
(make-lexical-ref loc lexical lexical))
|
||||
(if (symbol? lexical)
|
||||
(make-lexical-ref loc symbol lexical)
|
||||
(make-call loc lexical '())))
|
||||
(lambda ()
|
||||
(call-primitive loc
|
||||
'fluid-ref
|
||||
(make-module-ref loc value-slot symbol #t)))))
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'symbol-value #t)
|
||||
(list (make-const loc symbol))))))
|
||||
|
||||
(define (global? module symbol)
|
||||
(module-variable module symbol))
|
||||
(define (global? symbol)
|
||||
(module-variable value-slot symbol))
|
||||
|
||||
(define (ensure-globals! loc names body)
|
||||
(if (and (every (cut global? (resolve-module value-slot) <>) names)
|
||||
(if (and (every global? names)
|
||||
(every symbol-interned? names))
|
||||
body
|
||||
(list->seq
|
||||
loc
|
||||
`(,@(map
|
||||
(lambda (name)
|
||||
(ensure-fluid! value-slot name)
|
||||
(symbol-desc name)
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'ensure-fluid! #t)
|
||||
(list (make-const loc value-slot)
|
||||
(make-const loc name))))
|
||||
(make-module-ref loc runtime 'symbol-desc #t)
|
||||
(list (make-const loc name))))
|
||||
names)
|
||||
,body))))
|
||||
|
||||
|
@ -152,15 +153,17 @@
|
|||
loc
|
||||
symbol
|
||||
(lambda (lexical)
|
||||
(make-lexical-set loc lexical lexical value))
|
||||
(if (symbol? lexical)
|
||||
(make-lexical-set loc symbol lexical value)
|
||||
(make-call loc lexical (list value))))
|
||||
(lambda ()
|
||||
(ensure-globals!
|
||||
loc
|
||||
(list symbol)
|
||||
(call-primitive loc
|
||||
'fluid-set!
|
||||
(make-module-ref loc value-slot symbol #t)
|
||||
value)))))
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'set-symbol-value! #t)
|
||||
(list (make-const loc symbol)
|
||||
value))))))
|
||||
|
||||
(define (access-function loc symbol handle-lexical handle-global)
|
||||
(cond
|
||||
|
@ -174,7 +177,8 @@
|
|||
loc
|
||||
symbol
|
||||
(lambda (gensym) (make-lexical-ref loc symbol gensym))
|
||||
(lambda () (make-module-ref loc function-slot symbol #t))))
|
||||
(lambda ()
|
||||
(make-module-ref loc '(elisp-functions) symbol #t))))
|
||||
|
||||
(define (set-function! loc symbol value)
|
||||
(access-function
|
||||
|
@ -187,15 +191,12 @@
|
|||
(make-module-ref loc runtime 'set-symbol-function! #t)
|
||||
(list (make-const loc symbol) value)))))
|
||||
|
||||
(define (bind-lexically? sym module decls)
|
||||
(or (eq? module function-slot)
|
||||
(let ((decl (assq-ref decls sym)))
|
||||
(and (equal? module value-slot)
|
||||
(or
|
||||
(eq? decl 'lexical)
|
||||
(and
|
||||
(fluid-ref lexical-binding)
|
||||
(not (global? (resolve-module module) sym))))))))
|
||||
(define (bind-lexically? sym decls)
|
||||
(let ((decl (assq-ref decls sym)))
|
||||
(or (eq? decl 'lexical)
|
||||
(and
|
||||
(lexical-binding?)
|
||||
(not (special? sym))))))
|
||||
|
||||
(define (parse-let-binding loc binding)
|
||||
(pmatch binding
|
||||
|
@ -234,11 +235,14 @@
|
|||
(pmatch lst
|
||||
(((declare . ,x) . ,tail)
|
||||
(loop tail (append-reverse x decls) intspec doc))
|
||||
(((interactive . ,x) . ,tail)
|
||||
(((interactive) . ,tail)
|
||||
(guard lambda? (not intspec))
|
||||
(loop tail decls x doc))
|
||||
(loop tail decls (cons 'interactive-form #nil) doc))
|
||||
(((interactive ,x) . ,tail)
|
||||
(guard lambda? (not intspec))
|
||||
(loop tail decls (cons 'interactive-form x) doc))
|
||||
((,x . ,tail)
|
||||
(guard lambda? (string? x) (not doc) (not (null? tail)))
|
||||
(guard lambda? (or (string? x) (lisp-string? x)) (not doc) (not (null? tail)))
|
||||
(loop tail decls intspec x))
|
||||
(else
|
||||
(values (append-map parse-declaration decls)
|
||||
|
@ -257,13 +261,14 @@
|
|||
;;; optional and rest arguments.
|
||||
|
||||
(define (parse-lambda-list lst)
|
||||
(define (%match lst null optional rest symbol)
|
||||
(define (%match lst null optional rest symbol list*)
|
||||
(pmatch lst
|
||||
(() (null))
|
||||
(nil (null))
|
||||
((&optional . ,tail) (optional tail))
|
||||
((&rest . ,tail) (rest tail))
|
||||
((,arg . ,tail) (guard (symbol? arg)) (symbol arg tail))
|
||||
((,arg . ,tail) (guard (list? arg)) (list* arg tail))
|
||||
(else (fail))))
|
||||
(define (return rreq ropt rest)
|
||||
(values #t (reverse rreq) (reverse ropt) rest))
|
||||
|
@ -274,24 +279,28 @@
|
|||
(lambda () (return rreq '() #f))
|
||||
(lambda (tail) (parse-opt tail rreq '()))
|
||||
(lambda (tail) (parse-rest tail rreq '()))
|
||||
(lambda (arg tail) (parse-req tail (cons arg rreq)))))
|
||||
(lambda (arg tail) (parse-req tail (cons arg rreq)))
|
||||
(lambda (arg tail) (fail))))
|
||||
(define (parse-opt lst rreq ropt)
|
||||
(%match lst
|
||||
(lambda () (return rreq ropt #f))
|
||||
(lambda (tail) (fail))
|
||||
(lambda (tail) (parse-rest tail rreq ropt))
|
||||
(lambda (arg tail) (parse-opt tail rreq (cons (list arg) ropt)))
|
||||
(lambda (arg tail) (parse-opt tail rreq (cons arg ropt)))))
|
||||
(define (parse-rest lst rreq ropt)
|
||||
(%match lst
|
||||
(lambda () (fail))
|
||||
(lambda (tail) (fail))
|
||||
(lambda (tail) (fail))
|
||||
(lambda (arg tail) (parse-post-rest tail rreq ropt arg))))
|
||||
(lambda (arg tail) (parse-post-rest tail rreq ropt arg))
|
||||
(lambda (arg tail) (fail))))
|
||||
(define (parse-post-rest lst rreq ropt rest)
|
||||
(%match lst
|
||||
(lambda () (return rreq ropt rest))
|
||||
(lambda () (fail))
|
||||
(lambda () (fail))
|
||||
(lambda (arg tail) (fail))
|
||||
(lambda (arg tail) (fail))))
|
||||
(parse-req lst '()))
|
||||
|
||||
|
@ -308,30 +317,30 @@
|
|||
(let lp ((f f) (v v))
|
||||
(if (null? f)
|
||||
body
|
||||
(make-primcall
|
||||
src 'with-fluid*
|
||||
(list (make-lexical-ref #f 'fluid (car f))
|
||||
(make-lexical-ref #f 'val (car v))
|
||||
(make-lambda
|
||||
src '()
|
||||
(make-lambda-case
|
||||
src '() #f #f #f '() '()
|
||||
(lp (cdr f) (cdr v))
|
||||
#f))))))))))
|
||||
(make-call src
|
||||
(make-module-ref src runtime 'bind-symbol #t)
|
||||
(list (make-lexical-ref #f 'fluid (car f))
|
||||
(make-lexical-ref #f 'val (car v))
|
||||
(make-lambda
|
||||
src '()
|
||||
(make-lambda-case
|
||||
src '() #f #f #f '() '()
|
||||
(lp (cdr f) (cdr v))
|
||||
#f))))))))))
|
||||
|
||||
(define (compile-lambda loc meta args body)
|
||||
(receive (valid? req-ids opt-ids rest-id)
|
||||
(receive (valid? req-ids opts rest-id)
|
||||
(parse-lambda-list args)
|
||||
(if valid?
|
||||
(let* ((all-ids (append req-ids
|
||||
opt-ids
|
||||
(and opts (map car opts))
|
||||
(or (and=> rest-id list) '())))
|
||||
(all-vars (map (lambda (ignore) (gensym)) all-ids)))
|
||||
(let*-values (((decls intspec doc forms)
|
||||
(parse-lambda-body body))
|
||||
((lexical dynamic)
|
||||
(partition
|
||||
(compose (cut bind-lexically? <> value-slot decls)
|
||||
(compose (cut bind-lexically? <> decls)
|
||||
car)
|
||||
(map list all-ids all-vars)))
|
||||
((lexical-ids lexical-vars) (unzip2 lexical))
|
||||
|
@ -361,50 +370,42 @@
|
|||
tree-il
|
||||
(make-dynlet
|
||||
loc
|
||||
(map (cut make-module-ref loc value-slot <> #t)
|
||||
dynamic-ids)
|
||||
(map (cut make-const loc <>) dynamic-ids)
|
||||
(map (cut make-lexical-ref loc <> <>)
|
||||
dynamic-ids
|
||||
dynamic-vars)
|
||||
tree-il))))
|
||||
(make-simple-lambda loc
|
||||
meta
|
||||
(append (if intspec
|
||||
(list intspec)
|
||||
'())
|
||||
(if doc
|
||||
(list (cons 'emacs-documentation doc))
|
||||
'())
|
||||
meta)
|
||||
req-ids
|
||||
opt-ids
|
||||
(map (const (nil-value loc))
|
||||
opt-ids)
|
||||
(map car opts)
|
||||
(map (lambda (x)
|
||||
(if (pair? (cdr x))
|
||||
(compile-expr (car (cdr x)))
|
||||
(make-const loc #nil)))
|
||||
opts)
|
||||
rest-id
|
||||
all-vars
|
||||
full-body)))))))))
|
||||
(report-error "invalid function" `(lambda ,args ,@body)))))
|
||||
|
||||
;;; 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
|
||||
;;; handling the docstring somehow.
|
||||
|
||||
(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)))
|
||||
|
||||
;;; Handle macro and special operator bindings.
|
||||
|
||||
(define (find-operator name type)
|
||||
(and
|
||||
(symbol? name)
|
||||
(module-defined? (resolve-interface function-slot) name)
|
||||
(let ((op (module-ref (resolve-module function-slot) name)))
|
||||
(module-defined? function-slot name)
|
||||
(let ((op (module-ref function-slot name)))
|
||||
(if (and (pair? op) (eq? (car op) type))
|
||||
(cdr op)
|
||||
#f))))
|
||||
|
||||
;;; See if a (backquoted) expression contains any unquotes.
|
||||
|
||||
(define (contains-unquotes? expr)
|
||||
(if (pair? expr)
|
||||
(if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
|
||||
|
@ -475,41 +476,47 @@
|
|||
(call-primitive loc 'not
|
||||
(call-primitive loc 'nil? (compile-expr cond)))
|
||||
(compile-expr then)
|
||||
(compile-expr `(progn ,@else))))))
|
||||
(compile-expr `(progn ,@else))))
|
||||
(else (report-error loc "Bad if" args))))
|
||||
|
||||
(defspecial defconst (loc args)
|
||||
(pmatch args
|
||||
((,sym ,value . ,doc)
|
||||
(if (handle-var-def loc sym doc)
|
||||
(make-seq loc
|
||||
(set-variable! loc sym (compile-expr value))
|
||||
(make-const loc sym))))))
|
||||
(make-seq
|
||||
loc
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'proclaim-special! #t)
|
||||
(list (make-const loc sym)))
|
||||
(make-seq loc
|
||||
(set-variable! loc sym (compile-expr value))
|
||||
(make-const loc sym))))
|
||||
(else (report-error loc "Bad defconst" args))))
|
||||
|
||||
(defspecial defvar (loc args)
|
||||
(pmatch args
|
||||
((,sym) (make-const loc sym))
|
||||
((,sym)
|
||||
(make-seq loc
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'proclaim-special! #t)
|
||||
(list (make-const loc sym)))
|
||||
(make-const loc sym)))
|
||||
((,sym ,value . ,doc)
|
||||
(if (handle-var-def loc sym doc)
|
||||
(make-seq
|
||||
loc
|
||||
(make-conditional
|
||||
loc
|
||||
(make-conditional
|
||||
loc
|
||||
(call-primitive
|
||||
loc
|
||||
'module-bound?
|
||||
(call-primitive loc
|
||||
'resolve-interface
|
||||
(make-const loc value-slot))
|
||||
(make-const loc sym))
|
||||
(call-primitive loc
|
||||
'fluid-bound?
|
||||
(make-module-ref loc value-slot sym #t))
|
||||
(make-const loc #f))
|
||||
(make-void loc)
|
||||
(set-variable! loc sym (compile-expr value)))
|
||||
(make-const loc sym))))))
|
||||
(make-seq
|
||||
loc
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'proclaim-special! #t)
|
||||
(list (make-const loc sym)))
|
||||
(make-seq
|
||||
loc
|
||||
(make-conditional
|
||||
loc
|
||||
(make-call loc
|
||||
(make-module-ref loc runtime 'symbol-bound? #t)
|
||||
(list (make-const loc sym)))
|
||||
(make-void loc)
|
||||
(set-variable! loc sym (compile-expr value)))
|
||||
(make-const loc sym))))
|
||||
(else (report-error loc "Bad defvar" args))))
|
||||
|
||||
(defspecial setq (loc args)
|
||||
(define (car* x) (if (null? x) '() (car x)))
|
||||
|
@ -524,7 +531,7 @@
|
|||
(let ((sym (car args))
|
||||
(val (compile-expr (cadr* args))))
|
||||
(if (not (symbol? sym))
|
||||
(report-error loc "expected symbol in setq")
|
||||
(report-error loc "expected symbol in setq" args)
|
||||
(cons
|
||||
(set-variable! loc sym val)
|
||||
(loop (cddr* args)
|
||||
|
@ -537,7 +544,7 @@
|
|||
(receive (decls forms) (parse-body body)
|
||||
(receive (lexical dynamic)
|
||||
(partition
|
||||
(compose (cut bind-lexically? <> value-slot decls)
|
||||
(compose (cut bind-lexically? <> decls)
|
||||
car)
|
||||
bindings)
|
||||
(let ((make-values (lambda (for)
|
||||
|
@ -549,12 +556,7 @@
|
|||
(map car dynamic)
|
||||
(if (null? lexical)
|
||||
(make-dynlet loc
|
||||
(map (compose (cut make-module-ref
|
||||
loc
|
||||
value-slot
|
||||
<>
|
||||
#t)
|
||||
car)
|
||||
(map (compose (cut make-const loc <>) car)
|
||||
dynamic)
|
||||
(map (compose compile-expr cdr)
|
||||
dynamic)
|
||||
|
@ -577,13 +579,10 @@
|
|||
(make-body)
|
||||
(make-dynlet loc
|
||||
(map
|
||||
(compose
|
||||
(cut make-module-ref
|
||||
loc
|
||||
value-slot
|
||||
<>
|
||||
#t)
|
||||
car)
|
||||
(compose (cut make-const
|
||||
loc
|
||||
<>)
|
||||
car)
|
||||
dynamic)
|
||||
(map
|
||||
(lambda (sym)
|
||||
|
@ -592,7 +591,8 @@
|
|||
sym
|
||||
sym))
|
||||
dynamic-syms)
|
||||
(make-body))))))))))))))))
|
||||
(make-body))))))))))))))
|
||||
(else (report-error loc "bad let args"))))
|
||||
|
||||
(defspecial let* (loc args)
|
||||
(pmatch args
|
||||
|
@ -604,7 +604,7 @@
|
|||
(compile-expr `(progn ,@forms))
|
||||
(let ((sym (caar tail))
|
||||
(value (compile-expr (cdar tail))))
|
||||
(if (bind-lexically? sym value-slot decls)
|
||||
(if (bind-lexically? sym decls)
|
||||
(let ((target (gensym)))
|
||||
(make-let loc
|
||||
`(,target)
|
||||
|
@ -619,9 +619,10 @@
|
|||
loc
|
||||
(list sym)
|
||||
(make-dynlet loc
|
||||
(list (make-module-ref loc value-slot sym #t))
|
||||
(list (make-const loc sym))
|
||||
(list value)
|
||||
(iterate (cdr tail)))))))))))))
|
||||
(iterate (cdr tail)))))))))))
|
||||
(else (report-error loc "Bad let*" args))))
|
||||
|
||||
(defspecial flet (loc args)
|
||||
(pmatch args
|
||||
|
@ -640,7 +641,8 @@
|
|||
names
|
||||
gensyms
|
||||
(map compile-expr vals)
|
||||
(compile-expr `(progn ,@forms)))))))))))
|
||||
(compile-expr `(progn ,@forms)))))))))
|
||||
(else (report-error loc "bad flet" args))))
|
||||
|
||||
(defspecial labels (loc args)
|
||||
(pmatch args
|
||||
|
@ -660,7 +662,8 @@
|
|||
names
|
||||
gensyms
|
||||
(map compile-expr vals)
|
||||
(compile-expr `(progn ,@forms)))))))))))
|
||||
(compile-expr `(progn ,@forms)))))))))
|
||||
(else (report-error loc "bad labels" args))))
|
||||
|
||||
;;; guile-ref allows building TreeIL's module references from within
|
||||
;;; elisp as a way to access data within the Guile universe. The module
|
||||
|
@ -670,12 +673,14 @@
|
|||
(defspecial guile-ref (loc args)
|
||||
(pmatch args
|
||||
((,module ,sym) (guard (and (list? module) (symbol? sym)))
|
||||
(make-module-ref loc module sym #t))))
|
||||
(make-module-ref loc module sym #t))
|
||||
(else (report-error loc "bad guile-ref" args))))
|
||||
|
||||
(defspecial guile-private-ref (loc args)
|
||||
(pmatch args
|
||||
((,module ,sym) (guard (and (list? module) (symbol? sym)))
|
||||
(make-module-ref loc module sym #f))))
|
||||
(make-module-ref loc module sym #f))
|
||||
(else (report-error loc "bad guile-private-ref" args))))
|
||||
|
||||
;;; guile-primitive allows to create primitive references, which are
|
||||
;;; still a little faster.
|
||||
|
@ -683,14 +688,46 @@
|
|||
(defspecial guile-primitive (loc args)
|
||||
(pmatch args
|
||||
((,sym)
|
||||
(make-primitive-ref loc sym))))
|
||||
(make-primitive-ref loc sym))
|
||||
(else (report-error loc "bad guile-primitive" args))))
|
||||
|
||||
(defspecial function (loc args)
|
||||
(defspecial %function (loc args)
|
||||
(pmatch args
|
||||
(((lambda ,args . ,body))
|
||||
(compile-lambda loc '() args body))
|
||||
(((closure ,env ,args . ,body))
|
||||
(let ((bindings (map (lambda (x) (list (car x) (cdr x)))
|
||||
(filter pair? env))))
|
||||
(compile-expr
|
||||
(let ((form `(let ,bindings
|
||||
(declare ,@(map (lambda (x) (list 'lexical x))
|
||||
bindings))
|
||||
(function (lambda ,args
|
||||
(declare
|
||||
(lexical
|
||||
,@(filter-map
|
||||
(lambda (x)
|
||||
(cond
|
||||
((memq x '(&optional &rest))
|
||||
#f)
|
||||
((symbol? x)
|
||||
x)
|
||||
((list? x)
|
||||
(car x))))
|
||||
args)))
|
||||
,@body)))))
|
||||
form))))
|
||||
((,sym) (guard (symbol? sym))
|
||||
(reference-function loc sym))))
|
||||
(reference-function loc sym))
|
||||
((,x)
|
||||
(make-const loc x))
|
||||
(else (report-error loc "bad function" args))))
|
||||
|
||||
(defspecial function (loc args)
|
||||
(pmatch args
|
||||
((,sym) (guard (symbol? sym))
|
||||
(make-const loc sym))
|
||||
(else ((cdr compile-%function) loc args))))
|
||||
|
||||
(defspecial defmacro (loc args)
|
||||
(pmatch args
|
||||
|
@ -715,44 +752,60 @@
|
|||
(with-native-target
|
||||
(lambda ()
|
||||
(compile tree-il #:from 'tree-il #:to 'value)))
|
||||
tree-il)))))
|
||||
|
||||
(defspecial defun (loc args)
|
||||
(pmatch args
|
||||
((,name ,args . ,body)
|
||||
(if (not (symbol? name))
|
||||
(report-error loc "expected symbol as function name" name)
|
||||
(make-seq loc
|
||||
(set-function! loc
|
||||
name
|
||||
(compile-lambda loc
|
||||
`((name . ,name))
|
||||
args
|
||||
body))
|
||||
(make-const loc name))))))
|
||||
tree-il)))
|
||||
(else (report-error loc "bad defmacro" args))))
|
||||
|
||||
(defspecial #{`}# (loc args)
|
||||
(pmatch args
|
||||
((,val)
|
||||
(process-backquote loc val))))
|
||||
(process-backquote loc val))
|
||||
(else (report-error loc "bad backquote" args))))
|
||||
|
||||
(defspecial quote (loc args)
|
||||
(pmatch args
|
||||
((,val)
|
||||
(make-const loc val))))
|
||||
(make-const loc val))
|
||||
(else (report-error loc "bad quote" args))))
|
||||
|
||||
(defspecial %funcall (loc args)
|
||||
(pmatch args
|
||||
((,function . ,arguments)
|
||||
(make-call loc
|
||||
(compile-expr function)
|
||||
(map compile-expr arguments)))))
|
||||
(map compile-expr arguments)))
|
||||
(else (report-error loc "bad %funcall" args))))
|
||||
|
||||
(defspecial %set-lexical-binding-mode (loc args)
|
||||
(pmatch args
|
||||
((,val)
|
||||
(fluid-set! lexical-binding val)
|
||||
(make-void loc))))
|
||||
(set-lexical-binding-mode val)
|
||||
(make-void loc))
|
||||
(else (report-error loc "bad %set-lexical-binding-mode" args))))
|
||||
|
||||
(define special-operators (make-hash-table))
|
||||
|
||||
(for-each
|
||||
(lambda (pair) (hashq-set! special-operators (car pair) (cddr pair)))
|
||||
`((progn . ,compile-progn)
|
||||
(eval-when-compile . ,compile-eval-when-compile)
|
||||
(if . ,compile-if)
|
||||
(defconst . ,compile-defconst)
|
||||
(defvar . ,compile-defvar)
|
||||
(setq . ,compile-setq)
|
||||
(let . ,compile-let)
|
||||
(flet . ,compile-flet)
|
||||
(labels . ,compile-labels)
|
||||
(let* . ,compile-let*)
|
||||
(guile-ref . ,compile-guile-ref)
|
||||
(guile-private-ref . ,compile-guile-private-ref)
|
||||
(guile-primitive . ,compile-guile-primitive)
|
||||
(%function . ,compile-%function)
|
||||
(function . ,compile-function)
|
||||
(defmacro . ,compile-defmacro)
|
||||
(#{`}# . ,#{compile-`}#)
|
||||
(quote . ,compile-quote)
|
||||
(%funcall . ,compile-%funcall)
|
||||
(%set-lexical-binding-mode . ,compile-%set-lexical-binding-mode)))
|
||||
|
||||
;;; Compile a compound expression to Tree-IL.
|
||||
|
||||
|
@ -760,14 +813,14 @@
|
|||
(let ((operator (car expr))
|
||||
(arguments (cdr expr)))
|
||||
(cond
|
||||
((find-operator operator 'special-operator)
|
||||
=> (lambda (special-operator-function)
|
||||
(special-operator-function loc arguments)))
|
||||
((find-operator operator 'macro)
|
||||
=> (lambda (macro-function)
|
||||
(compile-expr (apply macro-function arguments))))
|
||||
((hashq-ref special-operators operator)
|
||||
=> (lambda (special-operator-function)
|
||||
(special-operator-function loc arguments)))
|
||||
(else
|
||||
(compile-expr `(%funcall (function ,operator) ,@arguments))))))
|
||||
(compile-expr `(%funcall (%function ,operator) ,@arguments))))))
|
||||
|
||||
;;; Compile a symbol expression. This is a variable reference or maybe
|
||||
;;; some special value like nil.
|
||||
|
@ -789,31 +842,9 @@
|
|||
(compile-pair loc expr))
|
||||
(else (make-const loc expr)))))
|
||||
|
||||
;;; Process the compiler options.
|
||||
;;; FIXME: Why is '(()) passed as options by the REPL?
|
||||
|
||||
(define (valid-symbol-list-arg? value)
|
||||
(or (eq? value 'all)
|
||||
(and (list? value) (and-map symbol? value))))
|
||||
|
||||
(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
|
||||
((#:warnings #:to-file?) ; ignore
|
||||
#f)
|
||||
(else (report-error #f
|
||||
"Invalid compiler option"
|
||||
key)))))))
|
||||
|
||||
(define (compile-tree-il expr env opts)
|
||||
(values
|
||||
(with-fluids ((bindings-data (make-bindings)))
|
||||
(process-options! opts)
|
||||
(compile-expr expr))
|
||||
env
|
||||
env))
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
(define-module (language elisp lexer)
|
||||
#:use-module (ice-9 regex)
|
||||
#:use-module (language elisp runtime)
|
||||
#:export (get-lexer get-lexer/1))
|
||||
|
||||
;;; This is the lexical analyzer for the elisp reader. It is
|
||||
|
@ -316,7 +317,9 @@
|
|||
(let ((cur (read-char port)))
|
||||
(case cur
|
||||
((#\")
|
||||
(return 'string (list->string (reverse result-chars))))
|
||||
(return 'string
|
||||
(make-lisp-string
|
||||
(list->string (reverse result-chars)))))
|
||||
((#\\)
|
||||
(let ((escaped (read-char port)))
|
||||
(case escaped
|
||||
|
|
|
@ -19,22 +19,39 @@
|
|||
;;; Code:
|
||||
|
||||
(define-module (language elisp runtime)
|
||||
#:use-module (ice-9 format)
|
||||
#:use-module ((system base compile)
|
||||
#:select (compile))
|
||||
#:export (nil-value
|
||||
t-value
|
||||
value-slot-module
|
||||
function-slot-module
|
||||
elisp-bool
|
||||
ensure-fluid!
|
||||
symbol-fluid
|
||||
set-symbol-fluid!
|
||||
ensure-dynamic!
|
||||
symbol-name
|
||||
symbol-value
|
||||
set-symbol-value!
|
||||
symbol-function
|
||||
set-symbol-function!
|
||||
symbol-plist
|
||||
set-symbol-plist!
|
||||
symbol-bound?
|
||||
symbol-fbound?
|
||||
bind-symbol
|
||||
makunbound!
|
||||
fmakunbound!)
|
||||
fmakunbound!
|
||||
symbol-desc
|
||||
proclaim-special!
|
||||
special?
|
||||
emacs!
|
||||
unbound
|
||||
lexical-binding?
|
||||
set-lexical-binding-mode
|
||||
log!
|
||||
eval-elisp
|
||||
local-eval-elisp
|
||||
make-lisp-string
|
||||
lisp-string?)
|
||||
#:export-syntax (defspecial prim))
|
||||
|
||||
;;; This module provides runtime support for the Elisp front-end.
|
||||
|
@ -45,13 +62,21 @@
|
|||
|
||||
(define t-value #t)
|
||||
|
||||
(define make-lisp-string identity)
|
||||
(define lisp-string? string?)
|
||||
|
||||
;;; Modules for the binding slots.
|
||||
;;; Note: Naming those value-slot and/or function-slot clashes with the
|
||||
;;; submodules of these names!
|
||||
|
||||
(define value-slot-module '(language elisp runtime value-slot))
|
||||
(define value-slot-module (resolve-module '(elisp-symbols)))
|
||||
|
||||
(define function-slot-module '(language elisp runtime function-slot))
|
||||
(define function-slot-module (resolve-module '(elisp-functions)))
|
||||
|
||||
(define plist-slot-module (resolve-module '(elisp-plists)))
|
||||
|
||||
(define nil_ 'nil)
|
||||
(define t_ 't)
|
||||
|
||||
;;; Routines for access to elisp dynamically bound symbols. This is
|
||||
;;; used for runtime access using functions like symbol-value or set,
|
||||
|
@ -59,75 +84,163 @@
|
|||
;;; always access the dynamic binding and can not be used for the
|
||||
;;; lexical!
|
||||
|
||||
(define (ensure-fluid! module sym)
|
||||
(let ((intf (resolve-interface module))
|
||||
(resolved (resolve-module module)))
|
||||
(if (not (module-defined? intf sym))
|
||||
(let ((fluid (make-unbound-fluid)))
|
||||
(module-define! resolved sym fluid)
|
||||
(module-export! resolved `(,sym))))))
|
||||
(define lexical-binding #t)
|
||||
|
||||
(define (symbol-fluid symbol)
|
||||
(let ((module (resolve-module value-slot-module)))
|
||||
(ensure-fluid! value-slot-module symbol) ;++ implicit special proclamation
|
||||
(module-ref module symbol)))
|
||||
(define (lexical-binding?)
|
||||
lexical-binding)
|
||||
|
||||
(define (set-symbol-fluid! symbol fluid)
|
||||
(let ((module (resolve-module value-slot-module)))
|
||||
(module-define! module symbol fluid)
|
||||
(module-export! module (list symbol)))
|
||||
fluid)
|
||||
(define (set-lexical-binding-mode x)
|
||||
(set! lexical-binding x))
|
||||
|
||||
(define unbound (make-symbol "unbound"))
|
||||
|
||||
(define dynamic? vector?)
|
||||
(define (make-dynamic)
|
||||
(vector #f 4 0 0 unbound))
|
||||
(define (dynamic-ref x)
|
||||
(vector-ref x 4))
|
||||
(define (dynamic-set! x v)
|
||||
(vector-set! x 4 v))
|
||||
(define (dynamic-unset! x)
|
||||
(vector-set! x 4 unbound))
|
||||
(define (dynamic-bound? x)
|
||||
(not (eq? (vector-ref x 4) unbound)))
|
||||
(define (dynamic-bind x v thunk)
|
||||
(let ((old (vector-ref x 4)))
|
||||
(dynamic-wind
|
||||
(lambda () (vector-set! x 4 v))
|
||||
thunk
|
||||
(lambda () (vector-set! x 4 old)))))
|
||||
|
||||
(define-inlinable (ensure-present! module sym thunk)
|
||||
(or (module-local-variable module sym)
|
||||
(let ((variable (make-variable (thunk))))
|
||||
(module-add! module sym variable)
|
||||
variable)))
|
||||
|
||||
(define-inlinable (ensure-desc! module sym)
|
||||
(ensure-present! module
|
||||
sym
|
||||
(lambda ()
|
||||
(let ((x (make-dynamic)))
|
||||
(vector-set! x 0 sym)
|
||||
x))))
|
||||
|
||||
(define-inlinable (schemify symbol)
|
||||
(case symbol
|
||||
((#nil) nil_)
|
||||
((#t) t_)
|
||||
(else symbol)))
|
||||
|
||||
(define (symbol-name symbol)
|
||||
(symbol->string (schemify symbol)))
|
||||
|
||||
(define (symbol-desc symbol)
|
||||
(let ((symbol (schemify symbol)))
|
||||
(let ((module value-slot-module))
|
||||
(variable-ref (ensure-desc! module symbol)))))
|
||||
|
||||
(define (ensure-dynamic! sym)
|
||||
(vector-set! (symbol-desc sym) 3 1))
|
||||
|
||||
(define (symbol-dynamic symbol)
|
||||
(ensure-dynamic! symbol)
|
||||
(symbol-desc symbol))
|
||||
|
||||
(define (symbol-value symbol)
|
||||
(fluid-ref (symbol-fluid symbol)))
|
||||
(dynamic-ref (symbol-desc symbol)))
|
||||
|
||||
(define (set-symbol-value! symbol value)
|
||||
(fluid-set! (symbol-fluid symbol) value)
|
||||
(dynamic-set! (symbol-desc symbol) value)
|
||||
value)
|
||||
|
||||
(define (symbol-function symbol)
|
||||
(let ((module (resolve-module function-slot-module)))
|
||||
(set! symbol (schemify symbol))
|
||||
(ensure-present! function-slot-module symbol (lambda () #nil))
|
||||
(let ((module function-slot-module))
|
||||
(module-ref module symbol)))
|
||||
|
||||
(define (set-symbol-function! symbol value)
|
||||
(let ((module (resolve-module function-slot-module)))
|
||||
(set! symbol (schemify symbol))
|
||||
(ensure-present! function-slot-module symbol (lambda () #nil))
|
||||
(let ((module function-slot-module))
|
||||
(module-define! module symbol value)
|
||||
(module-export! module (list symbol)))
|
||||
value)
|
||||
|
||||
(define (symbol-plist symbol)
|
||||
(set! symbol (schemify symbol))
|
||||
(ensure-present! plist-slot-module symbol (lambda () #nil))
|
||||
(let ((module plist-slot-module))
|
||||
(module-ref module symbol)))
|
||||
|
||||
(define (set-symbol-plist! symbol value)
|
||||
(set! symbol (schemify symbol))
|
||||
(ensure-present! plist-slot-module symbol (lambda () #nil))
|
||||
(let ((module plist-slot-module))
|
||||
(module-define! module symbol value)
|
||||
(module-export! module (list symbol)))
|
||||
value)
|
||||
|
||||
(define (symbol-bound? symbol)
|
||||
(set! symbol (schemify symbol))
|
||||
(and
|
||||
(module-bound? (resolve-interface value-slot-module) symbol)
|
||||
(let ((var (module-variable (resolve-module value-slot-module)
|
||||
(module-bound? value-slot-module symbol)
|
||||
(let ((var (module-variable value-slot-module
|
||||
symbol)))
|
||||
(and (variable-bound? var)
|
||||
(if (fluid? (variable-ref var))
|
||||
(fluid-bound? (variable-ref var))
|
||||
(if (dynamic? (variable-ref var))
|
||||
(dynamic-bound? (variable-ref var))
|
||||
#t)))))
|
||||
|
||||
(define (symbol-fbound? symbol)
|
||||
(set! symbol (schemify symbol))
|
||||
(and
|
||||
(module-bound? (resolve-interface function-slot-module) symbol)
|
||||
(module-bound? function-slot-module symbol)
|
||||
(variable-bound?
|
||||
(module-variable (resolve-module function-slot-module)
|
||||
symbol))))
|
||||
(module-variable function-slot-module symbol))
|
||||
(variable-ref (module-variable function-slot-module symbol))))
|
||||
|
||||
(define (bind-symbol symbol value thunk)
|
||||
(dynamic-bind (symbol-desc symbol) value thunk))
|
||||
|
||||
(define (makunbound! symbol)
|
||||
(if (module-bound? (resolve-interface value-slot-module) symbol)
|
||||
(let ((var (module-variable (resolve-module value-slot-module)
|
||||
(if (module-bound? value-slot-module symbol)
|
||||
(let ((var (module-variable value-slot-module
|
||||
symbol)))
|
||||
(if (and (variable-bound? var) (fluid? (variable-ref var)))
|
||||
(fluid-unset! (variable-ref var))
|
||||
(if (and (variable-bound? var) (dynamic? (variable-ref var)))
|
||||
(dynamic-unset! (variable-ref var))
|
||||
(variable-unset! var))))
|
||||
symbol)
|
||||
|
||||
(define (fmakunbound! symbol)
|
||||
(if (module-bound? (resolve-interface function-slot-module) symbol)
|
||||
(variable-unset! (module-variable
|
||||
(resolve-module function-slot-module)
|
||||
symbol)))
|
||||
(if (module-bound? function-slot-module symbol)
|
||||
(variable-unset! (module-variable function-slot-module symbol)))
|
||||
symbol)
|
||||
|
||||
(define (special? sym)
|
||||
(eqv? (vector-ref (symbol-desc sym) 3) 1))
|
||||
|
||||
(define (proclaim-special! sym)
|
||||
(vector-set! (symbol-desc sym) 3 1)
|
||||
#nil)
|
||||
|
||||
(define (emacs! ref set boundp bind)
|
||||
(set! symbol-value ref)
|
||||
(set! set-symbol-value! set)
|
||||
(set! symbol-bound? boundp)
|
||||
(set! bind-symbol bind)
|
||||
(set! lexical-binding? (lambda () (symbol-value 'lexical-binding)))
|
||||
(set! set-lexical-binding-mode (lambda (x) (set-symbol-value! 'lexical-binding x))))
|
||||
|
||||
(define (eval-elisp form)
|
||||
(compile form #:from 'elisp #:to 'value))
|
||||
|
||||
(set-symbol-value! nil_ #nil)
|
||||
(set-symbol-value! t_ #t)
|
||||
|
||||
(define (make-string s) s)
|
||||
|
||||
;;; Define a predefined macro for use in the function-slot module.
|
||||
|
||||
(define (make-id template-id . data)
|
||||
|
|
|
@ -24,14 +24,25 @@
|
|||
#:use-module (system base language)
|
||||
#:use-module (system base compile)
|
||||
#:use-module (system base target)
|
||||
#:use-module (system vm vm)
|
||||
#:export (elisp))
|
||||
|
||||
(save-module-excursion
|
||||
(lambda ()
|
||||
(define-module (elisp-symbols) #:pure #:filename #f)
|
||||
(define-module (elisp-functions) #:pure #:filename #f)
|
||||
(define-module (elisp-plists) #:pure #:filename #f)))
|
||||
|
||||
(define-language elisp
|
||||
#:title "Emacs Lisp"
|
||||
#:reader (lambda (port env) (read-elisp port))
|
||||
;;#:joiner (lambda (exps env) (cons 'progn exps))
|
||||
#:printer write
|
||||
#:compilers `((tree-il . ,compile-tree-il)))
|
||||
|
||||
(set-default-vm-engine! 'debug)
|
||||
(set-vm-engine! 'debug)
|
||||
|
||||
;; Compile and load the Elisp boot code for the native host
|
||||
;; architecture. We must specifically ask for native compilation here,
|
||||
;; because this module might be loaded in a dynamic environment where
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue