-;;; Guile Emacs Lisp
+;;; Guile Emacs Lisp -*- lexical-binding: t -*-
;;; Copyright (C) 2011 Free Software Foundation, Inc.
(defmacro @ (module symbol)
`(guile-ref ,module ,symbol))
+(defmacro @@ (module symbol)
+ `(guile-private-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)))
+(defmacro %define-compiler-macro (name args &rest body)
+ `(eval-and-compile
+ (%funcall
+ (@ (language elisp runtime) set-symbol-plist!)
+ ',name
+ (%funcall
+ (@ (guile) cons*)
+ '%compiler-macro
+ #'(lambda ,args ,@body)
+ (%funcall (@ (language elisp runtime) symbol-plist) ',name)))
+ ',name))
+
+(defmacro defsubst (name args &rest body)
+ `(progn
+ (defun ,name ,args ,@body)
+ (eval-and-compile
+ (%define-compiler-macro ,name (form)
+ (%funcall (@ (guile) cons*)
+ '%funcall
+ (%funcall
+ (@ (guile) list)
+ 'function
+ (%funcall (@ (guile) cons*) 'lambda ',args ',body))
+ (%funcall (@ (guile) cdr) form))))))
+
(eval-and-compile
- (defun funcall (function &rest arguments)
- (apply function arguments))
- (defun fset (symbol definition)
- (funcall (@ (language elisp runtime) set-symbol-function!)
- symbol
- definition))
- (defun null (object)
+ (defun eval (form)
+ (%funcall (@ (language elisp runtime) eval-elisp) form)))
+
+(eval-and-compile
+ (defsubst null (object)
+ (declare (lexical object))
(if object nil t))
- (fset 'consp (@ (guile) pair?))
+ (defsubst consp (x)
+ (declare (lexical x))
+ (%funcall (@ (guile) pair?) x))
+ (defsubst atom (x)
+ (declare (lexical x))
+ (null (consp x)))
(defun listp (object)
+ (declare (lexical object))
(if object (consp object) t))
- (defun car (list)
- (if list (funcall (@ (guile) car) list) nil))
- (defun cdr (list)
- (if list (funcall (@ (guile) cdr) list) nil))
- (fset 'make-symbol (@ (guile) make-symbol))
- (defun signal (&rest args)
- (funcall (@ (guile) throw) 'elisp-error args)))
+ (defsubst car (list)
+ (declare (lexical list))
+ (if list (%funcall (@ (guile) car) list) nil))
+ (defsubst cdr (list)
+ (declare (lexical list))
+ (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)))
(defmacro lambda (&rest cdr)
`#'(lambda ,@cdr))
(defmacro prog1 (first &rest body)
- (let ((temp (make-symbol "prog1-temp")))
- `(lexical-let ((,temp ,first))
+ (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)))
(let ((condition (car first))
(body (cdr first)))
(if (null body)
- (let ((temp (make-symbol "cond-temp")))
- `(lexical-let ((,temp ,condition))
+ (let ((temp (gensym)))
+ `(let ((,temp ,condition))
+ (declare (lexical ,temp))
(if ,temp
,temp
(cond ,@rest))))
(defmacro or (&rest conditions)
(cond ((null conditions) nil)
((null (cdr conditions)) (car conditions))
- (t (let ((temp (make-symbol "or-temp")))
- `(lexical-let ((,temp ,(car conditions)))
+ (t (let ((temp (gensym)))
+ `(let ((,temp ,(car conditions)))
+ (declare (lexical ,temp))
(if ,temp
,temp
(or ,@(cdr conditions))))))))
-(defmacro catch (tag &rest body)
- (let* ((temp (make-symbol "catch-temp"))
- (elisp-key (make-symbol "catch-elisp-key"))
- (key (make-symbol "catch-key"))
- (value (make-symbol "catch-value")))
- `(lexical-let ((,temp ,tag))
- (funcall (@ (guile) catch)
- 'elisp-exception
- #'(lambda () ,@body)
- #'(lambda (,key ,elisp-key ,value)
- (if (eq ,elisp-key ,temp)
- ,value
- (funcall (@ (guile) throw)
- ,key
- ,elisp-key
- ,value)))))))
+(defmacro lexical-let (bindings &rest body)
+ (labels ((loop (list vars)
+ (if (null list)
+ `(let ,bindings
+ (declare (lexical ,@vars))
+ ,@body)
+ (loop (cdr list)
+ (if (consp (car list))
+ `(,(car (car list)) ,@vars)
+ `(,(car list) ,@vars))))))
+ (loop bindings '())))
+
+(defmacro lexical-let* (bindings &rest body)
+ (labels ((loop (list vars)
+ (if (null list)
+ `(let* ,bindings
+ (declare (lexical ,@vars))
+ ,@body)
+ (loop (cdr list)
+ (if (consp (car list))
+ (cons (car (car list)) vars)
+ (cons (car list) vars))))))
+ (loop bindings '())))
+
+(defmacro while (test &rest body)
+ (let ((loop (gensym)))
+ `(labels ((,loop ()
+ (if ,test
+ (progn ,@body (,loop))
+ nil)))
+ (,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)))
-(defun throw (tag value)
- (funcall (@ (guile) throw) 'elisp-exception tag value))
+(defmacro when (cond &rest body)
+ `(if ,cond
+ (progn ,@body)))
+
+(defmacro unless (cond &rest body)
+ `(when (not ,cond)
+ ,@body))
+
+(defun symbolp (object)
+ (%funcall (@ (guile) symbol?) object))
+
+(defun %functionp (object)
+ (%funcall (@ (guile) procedure?) object))
+
+(defun symbol-function (symbol)
+ (let ((f (%funcall (@ (language elisp runtime) symbol-function)
+ symbol)))
+ (if (%funcall (@ (language elisp falias) falias?) f)
+ (%funcall (@ (language elisp falias) falias-object) f)
+ f)))
(defun eval (form)
- (funcall (@ (system base compile) compile)
- form
- (funcall (@ (guile) symbol->keyword) 'from)
- 'elisp
- (funcall (@ (guile) symbol->keyword) 'to)
- 'value))
+ (%funcall (@ (system base compile) compile)
+ form
+ (%funcall (@ (guile) symbol->keyword) 'from)
+ 'elisp
+ (%funcall (@ (guile) symbol->keyword) 'to)
+ 'value))
+
+(defun %indirect-function (object)
+ (cond
+ ((%functionp object)
+ object)
+ ((null object)
+ (signal 'void-function nil))
+ ((symbolp object) ;++ cycle detection
+ (%indirect-function
+ (%funcall (@ (language elisp runtime) symbol-function) object)))
+ ((listp object)
+ (eval `(function ,object)))
+ (t
+ (signal 'invalid-function `(,object)))))
+
+(defun apply (function &rest arguments)
+ (%funcall (@ (guile) apply)
+ (@ (guile) apply)
+ (%indirect-function function)
+ arguments))
+
+(defun funcall (function &rest arguments)
+ (%funcall (@ (guile) apply)
+ (%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
+ 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 load (file)
+(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)
+ (function (lambda (&rest args) (apply definition args)))
+ definition))))
+ definition)
+
+(defun gload (file)
(funcall (@ (system base compile) compile-file)
file
(funcall (@ (guile) symbol->keyword) 'from)
;;; Equality predicates
-(fset 'eq (@ (guile) eq?))
-(fset 'equal (@ (guile) equal?))
+(defun eql (obj1 obj2)
+ (if obj1
+ (funcall (@ (guile) eqv?) obj1 obj2)
+ (null obj2)))
+
+(defun equal (obj1 obj2)
+ (if obj1
+ (funcall (@ (guile) equal?) obj1 obj2)
+ (null obj2)))
;;; Symbols
-(fset 'symbolp (@ (guile) symbol?))
+;;; `symbolp' and `symbol-function' are defined above.
+
+(fset 'symbol-name (@ (guile) symbol->string))
(fset 'symbol-value (@ (language elisp runtime) symbol-value))
-(fset 'symbol-function (@ (language elisp runtime) symbol-function))
(fset 'set (@ (language elisp runtime) set-symbol-value!))
(fset 'makunbound (@ (language elisp runtime) makunbound!))
(fset 'fmakunbound (@ (language elisp runtime) fmakunbound!))
(fset 'boundp (@ (language elisp runtime) symbol-bound?))
(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
(null (funcall (@ (guile) integer?) object)))))
(defun integerp (object)
- (and (funcall (@ (guile) exact?) object)
- (funcall (@ (guile) integer?) object)))
+ (and (funcall (@ (guile) integer?) object)
+ (funcall (@ (guile) exact?) object)))
(defun numberp (object)
(funcall (@ (guile) real?) object))
(defun wholenump (object)
- (and (funcall (@ (guile) exact?) object)
- (funcall (@ (guile) integer?) object)
- (>= object 0)))
+ (and (integerp object) (>= object 0)))
(defun zerop (object)
(= object 0))
(fset 'make-list (@ (guile) make-list))
(fset 'append (@ (guile) append))
(fset 'reverse (@ (guile) reverse))
+(fset 'nreverse (@ (guile) reverse!))
(defun car-safe (object)
(if (consp object)
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 %member (elt list test)
+ (cond
+ ((null list) nil)
+ ((consp list)
+ (if (funcall test elt (car list))
+ list
+ (%member elt (cdr list) test)))
+ (t (signal 'wrong-type-argument `(listp ,list)))))
-(defun nth (n list)
- (car (nthcdr n list)))
+(defun member (elt list)
+ (%member elt list #'equal))
+
+(defun memql (elt list)
+ (%member elt list #'eql))
+
+(defun memq (elt list)
+ (%member elt list #'eq))
+
+(defun assoc (key list)
+ (funcall (@ (srfi srfi-1) assoc) key list #'equal))
+
+(defun assq (key list)
+ (funcall (@ (srfi srfi-1) assoc) key list #'eq))
+
+(defun rplaca (cell newcar)
+ (funcall (@ (guile) set-car!) cell newcar)
+ newcar)
+
+(defun rplacd (cell newcdr)
+ (funcall (@ (guile) set-cdr!) cell newcdr)
+ newcdr)
+
+(defun caar (x)
+ (car (car x)))
+
+(defun cadr (x)
+ (car (cdr x)))
+
+(defun cdar (x)
+ (cdr (car x)))
+
+(defun cddr (x)
+ (cdr (cdr x)))
+
+(defmacro dolist (spec &rest body)
+ (apply #'(lambda (var list &optional result)
+ (list 'progn
+ (list 'mapc
+ (cons 'lambda (cons (list var) body))
+ list)
+ result))
+ spec))
;;; Strings
(funcall (@ (guile) list->string)
(mapcar (@ (guile) integer->char) characters)))
+(defun stringp (object)
+ (funcall (@ (guile) string?) object))
+
+(defun string-equal (s1 s2)
+ (let ((s1 (if (symbolp s1) (symbol-name s1) s1))
+ (s2 (if (symbolp s2) (symbol-name s2) s2)))
+ (funcall (@ (guile) string=?) s1 s2)))
+
+(fset 'string= 'string-equal)
+
+(defun substring (string from &optional to)
+ (apply (@ (guile) substring) string from (if to (list to) nil)))
+
+(defun upcase (obj)
+ (funcall (@ (guile) string-upcase) obj))
+
+(defun downcase (obj)
+ (funcall (@ (guile) string-downcase) obj))
+
+(defun string-match (regexp string &optional start)
+ (let ((m (funcall (@ (ice-9 regex) string-match)
+ regexp
+ string
+ (or start 0))))
+ (if m
+ (funcall (@ (ice-9 regex) match:start) m 0)
+ nil)))
+
+;; Vectors
+
+(defun make-vector (length init)
+ (funcall (@ (guile) make-vector) length init))
+
;;; Sequences
-(fset 'length (@ (guile) length))
+(defun length (sequence)
+ (funcall (if (listp sequence)
+ (@ (guile) length)
+ (@ (guile) generalized-vector-length))
+ sequence))
(defun mapcar (function sequence)
(funcall (@ (guile) map) function sequence))
+(defun mapc (function sequence)
+ (funcall (@ (guile) for-each) function sequence)
+ sequence)
+
+(defun aref (array idx)
+ (funcall (@ (guile) generalized-vector-ref) array idx))
+
+(defun aset (array idx newelt)
+ (funcall (@ (guile) generalized-vector-set!) array idx newelt)
+ newelt)
+
+(defun concat (&rest sequences)
+ (apply (@ (guile) string-append) sequences))
+
;;; Property lists
(defun %plist-member (plist property test)
- (catch 'loop
- (while plist
- (if (funcall test (car plist) property)
- (throw 'loop (cdr plist))
- (setq plist (cddr plist))))))
+ (cond
+ ((null plist) nil)
+ ((consp plist)
+ (if (funcall test (car plist) property)
+ (cdr plist)
+ (%plist-member (cdr (cdr plist)) property test)))
+ (t (signal 'wrong-type-argument `(listp ,plist)))))
(defun %plist-get (plist property test)
(car (%plist-member plist property test)))
(defun %plist-put (plist property value test)
- (lexical-let ((x (%plist-member plist property test)))
+ (let ((x (%plist-member plist property test)))
(if x
(progn (setcar x value) plist)
(cons property (cons value plist)))))
(defun put (symbol propname value)
(setplist symbol (plist-put (symbol-plist symbol) propname value)))
+
+;;; Nonlocal exits
+
+(defmacro condition-case (var bodyform &rest handlers)
+ (let ((key (make-symbol "key"))
+ (error-symbol (make-symbol "error-symbol"))
+ (data (make-symbol "data"))
+ (conditions (make-symbol "conditions")))
+ (flet ((handler->cond-clause (handler)
+ `((or ,@(mapcar #'(lambda (c) `(memq ',c ,conditions))
+ (if (consp (car handler))
+ (car handler)
+ (list (car handler)))))
+ ,@(cdr handler))))
+ `(funcall (@ (guile) catch)
+ 'elisp-condition
+ #'(lambda () ,bodyform)
+ #'(lambda (,key ,error-symbol ,data)
+ (declare (lexical ,key ,error-symbol ,data))
+ (let ((,conditions
+ (get ,error-symbol 'error-conditions))
+ ,@(if var
+ `((,var (cons ,error-symbol ,data)))
+ '()))
+ (declare (lexical ,conditions
+ ,@(if var `(,var) '())))
+ (cond ,@(mapcar #'handler->cond-clause handlers)
+ (t (signal ,error-symbol ,data)))))))))
+
+(put 'error 'error-conditions '(error))
+(put 'wrong-type-argument 'error-conditions '(wrong-type-argument error))
+(put 'invalid-function 'error-conditions '(invalid-function error))
+(put 'no-catch 'error-conditions '(no-catch error))
+(put 'throw 'error-conditions '(throw))
+
+(defvar %catch nil)
+
+(defmacro catch (tag &rest body)
+ (let ((tag-value (make-symbol "tag-value"))
+ (c (make-symbol "c"))
+ (data (make-symbol "data")))
+ `(let ((,tag-value ,tag))
+ (declare (lexical ,tag-value))
+ (condition-case ,c
+ (let ((%catch t))
+ ,@body)
+ (throw
+ (let ((,data (cdr ,c)))
+ (declare (lexical ,data))
+ (if (eq (car ,data) ,tag-value)
+ (car (cdr ,data))
+ (apply #'throw ,data))))))))
+
+(defun throw (tag value)
+ (signal (if %catch 'throw 'no-catch) (list tag value)))
+
+;;; I/O
+
+(defun princ (object)
+ (funcall (@ (guile) display) object))
+
+(defun print (object)
+ (funcall (@ (guile) write) object))
+
+(defun prin1 (object)
+ (funcall (@ (guile) write) object))
+
+(defun terpri ()
+ (funcall (@ (guile) newline)))
+
+(defun format* (stream string &rest args)
+ (apply (@ (guile) format) stream string args))
+
+(defun send-string-to-terminal (string)
+ (princ string))
+
+(defun read-from-minibuffer (prompt &rest ignore)
+ (princ prompt)
+ (let ((value (funcall (@ (ice-9 rdelim) read-line))))
+ (if (funcall (@ (guile) eof-object?) value)
+ ""
+ value)))
+
+(defun prin1-to-string (object)
+ (format* nil "~S" object))
+
+;; Random number generation
+
+(defvar %random-state (funcall (@ (guile) copy-random-state)
+ (@ (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))
+
+(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)