; * lisp/emacs-lisp/cconv.el (cconv-convert): Reindent.

This commit is contained in:
Mattias Engdegård 2023-12-20 17:08:41 +01:00
parent 57fd0f47f6
commit 25dc93c5c1

View file

@ -330,303 +330,308 @@ places where they originally did not directly appear."
;; so we never touch it(unless we enter to the other closure).
;;(if (listp form) (print (car form)) form)
(macroexp--with-extended-form-stack form
(pcase form
(`(,(and letsym (or 'let* 'let)) ,binders . ,body)
(pcase form
(`(,(and letsym (or 'let* 'let)) ,binders . ,body)
; let and let* special forms
(let ((binders-new '())
(new-env env)
(new-extend extend))
(let ((binders-new '())
(new-env env)
(new-extend extend))
(dolist (binder binders)
(let* ((value nil)
(var (if (not (consp binder))
(prog1 binder (setq binder (list binder)))
(when (cddr binder)
(byte-compile-warn-x
binder
"Malformed `%S' binding: %S"
letsym binder))
(setq value (cadr binder))
(car binder))))
(cond
;; Ignore bindings without a valid name.
((not (symbolp var))
(byte-compile-warn-x var "attempt to let-bind nonvariable `%S'" var))
((or (booleanp var) (keywordp var))
(byte-compile-warn-x var "attempt to let-bind constant `%S'" var))
(t
(let ((new-val
(pcase (cconv--var-classification binder form)
;; Check if var is a candidate for lambda lifting.
((and :lambda-candidate
(guard
(progn
(cl-assert (and (eq (car value) 'function)
(eq (car (cadr value)) 'lambda)))
(cl-assert (equal (cddr (cadr value))
(caar cconv-freevars-alist)))
;; Peek at the freevars to decide whether
;; to λ-lift.
(let* ((fvs (cdr (car cconv-freevars-alist)))
(fun (cadr value))
(funargs (cadr fun))
(funcvars (append fvs funargs)))
(dolist (binder binders)
(let* ((value nil)
(var (if (not (consp binder))
(prog1 binder (setq binder (list binder)))
(when (cddr binder)
(byte-compile-warn-x
binder
"Malformed `%S' binding: %S"
letsym binder))
(setq value (cadr binder))
(car binder))))
(cond
;; Ignore bindings without a valid name.
((not (symbolp var))
(byte-compile-warn-x
var "attempt to let-bind nonvariable `%S'" var))
((or (booleanp var) (keywordp var))
(byte-compile-warn-x
var "attempt to let-bind constant `%S'" var))
(t
(let ((new-val
(pcase (cconv--var-classification binder form)
;; Check if var is a candidate for lambda lifting.
((and :lambda-candidate
(guard
(progn
(cl-assert
(and (eq (car value) 'function)
(eq (car (cadr value)) 'lambda)))
(cl-assert (equal (cddr (cadr value))
(caar cconv-freevars-alist)))
;; Peek at the freevars to decide whether
;; to λ-lift.
(let* ((fvs (cdr (car cconv-freevars-alist)))
(fun (cadr value))
(funargs (cadr fun))
(funcvars (append fvs funargs)))
; lambda lifting condition
(and fvs (>= cconv-liftwhen
(length funcvars)))))))
(and fvs (>= cconv-liftwhen
(length funcvars)))))))
; Lift.
(let* ((fvs (cdr (pop cconv-freevars-alist)))
(fun (cadr value))
(funargs (cadr fun))
(funcvars (append fvs funargs))
(funcbody (cddr fun))
(funcbody-env ()))
(push `(,var . (apply-partially ,var . ,fvs)) new-env)
(dolist (fv fvs)
(cl-pushnew fv new-extend)
(if (and (eq 'car-safe (car-safe
(cdr (assq fv env))))
(not (memq fv funargs)))
(push `(,fv . (car-safe ,fv)) funcbody-env)))
`(function (lambda ,funcvars .
,(cconv--convert-funcbody
funargs funcbody funcbody-env value)))))
(let* ((fvs (cdr (pop cconv-freevars-alist)))
(fun (cadr value))
(funargs (cadr fun))
(funcvars (append fvs funargs))
(funcbody (cddr fun))
(funcbody-env ()))
(push `(,var . (apply-partially ,var . ,fvs))
new-env)
(dolist (fv fvs)
(cl-pushnew fv new-extend)
(if (and (eq 'car-safe (car-safe
(cdr (assq fv env))))
(not (memq fv funargs)))
(push `(,fv . (car-safe ,fv)) funcbody-env)))
`(function
(lambda ,funcvars
. ,(cconv--convert-funcbody
funargs funcbody funcbody-env value)))))
;; Check if it needs to be turned into a "ref-cell".
(:captured+mutated
;; Declared variable is mutated and captured.
(push `(,var . (car-safe ,var)) new-env)
`(list ,(cconv-convert value env extend)))
;; Check if it needs to be turned into a "ref-cell".
(:captured+mutated
;; Declared variable is mutated and captured.
(push `(,var . (car-safe ,var)) new-env)
`(list ,(cconv-convert value env extend)))
;; Check if it needs to be turned into a "ref-cell".
(:unused
;; Declared variable is unused.
(if (assq var new-env)
(push `(,var) new-env)) ;FIXME:Needed?
(let* ((Ignore (if (symbol-with-pos-p var)
(position-symbol 'ignore var)
'ignore))
(newval `(,Ignore
,(cconv-convert value env extend)))
(msg (cconv--warn-unused-msg var "variable")))
(if (null msg) newval
(macroexp--warn-wrap var msg newval 'lexical))))
;; Check if it needs to be turned into a "ref-cell".
(:unused
;; Declared variable is unused.
(if (assq var new-env)
(push `(,var) new-env)) ;FIXME:Needed?
(let* ((Ignore (if (symbol-with-pos-p var)
(position-symbol 'ignore var)
'ignore))
(newval `(,Ignore
,(cconv-convert value env extend)))
(msg (cconv--warn-unused-msg var "variable")))
(if (null msg) newval
(macroexp--warn-wrap var msg newval 'lexical))))
;; Normal default case.
(_
(if (assq var new-env) (push `(,var) new-env))
(cconv-convert value env extend)))))
;; Normal default case.
(_
(if (assq var new-env) (push `(,var) new-env))
(cconv-convert value env extend)))))
(when (and (eq letsym 'let*) (memq var new-extend))
;; One of the lambda-lifted vars is shadowed, so add
;; a reference to the outside binding and arrange to use
;; that reference.
(let ((var-def (cconv--lifted-arg var env))
(closedsym (make-symbol (format "closed-%s" var))))
(setq new-env (cconv--remap-llv new-env var closedsym))
;; FIXME: `closedsym' doesn't need to be added to `extend'
;; but adding it makes it easier to write the assertion at
;; the beginning of this function.
(setq new-extend (cons closedsym (remq var new-extend)))
(push `(,closedsym ,var-def) binders-new)))
(when (and (eq letsym 'let*) (memq var new-extend))
;; One of the lambda-lifted vars is shadowed, so add
;; a reference to the outside binding and arrange to use
;; that reference.
(let ((var-def (cconv--lifted-arg var env))
(closedsym (make-symbol (format "closed-%s" var))))
(setq new-env (cconv--remap-llv new-env var closedsym))
;; FIXME: `closedsym' doesn't need to be added to `extend'
;; but adding it makes it easier to write the assertion at
;; the beginning of this function.
(setq new-extend (cons closedsym (remq var new-extend)))
(push `(,closedsym ,var-def) binders-new)))
;; We push the element after redefined free variables are
;; processed. This is important to avoid the bug when free
;; variable and the function have the same name.
(push (list var new-val) binders-new)
;; We push the element after redefined free variables are
;; processed. This is important to avoid the bug when free
;; variable and the function have the same name.
(push (list var new-val) binders-new)
(when (eq letsym 'let*)
(setq env new-env)
(setq extend new-extend))))))
) ; end of dolist over binders
(when (eq letsym 'let*)
(setq env new-env)
(setq extend new-extend))))))
) ; end of dolist over binders
(when (not (eq letsym 'let*))
;; We can't do the cconv--remap-llv at the same place for let and
;; let* because in the case of `let', the shadowing may occur
;; before we know that the var will be in `new-extend' (bug#24171).
(dolist (binder binders-new)
(when (memq (car-safe binder) new-extend)
;; One of the lambda-lifted vars is shadowed.
(let* ((var (car-safe binder))
(var-def (cconv--lifted-arg var env))
(closedsym (make-symbol (format "closed-%s" var))))
(setq new-env (cconv--remap-llv new-env var closedsym))
(setq new-extend (cons closedsym (remq var new-extend)))
(push `(,closedsym ,var-def) binders-new)))))
(when (not (eq letsym 'let*))
;; We can't do the cconv--remap-llv at the same place for let and
;; let* because in the case of `let', the shadowing may occur
;; before we know that the var will be in `new-extend' (bug#24171).
(dolist (binder binders-new)
(when (memq (car-safe binder) new-extend)
;; One of the lambda-lifted vars is shadowed.
(let* ((var (car-safe binder))
(var-def (cconv--lifted-arg var env))
(closedsym (make-symbol (format "closed-%s" var))))
(setq new-env (cconv--remap-llv new-env var closedsym))
(setq new-extend (cons closedsym (remq var new-extend)))
(push `(,closedsym ,var-def) binders-new)))))
`(,letsym ,(nreverse binders-new)
. ,(mapcar (lambda (form)
(cconv-convert
form new-env new-extend))
body))))
`(,letsym ,(nreverse binders-new)
. ,(mapcar (lambda (form)
(cconv-convert
form new-env new-extend))
body))))
;end of let let* forms
; first element is lambda expression
(`(,(and `(lambda . ,_) fun) . ,args)
;; FIXME: it's silly to create a closure just to call it.
;; Running byte-optimize-form earlier would resolve this.
`(funcall
,(cconv-convert `(function ,fun) env extend)
,@(mapcar (lambda (form)
(cconv-convert form env extend))
args)))
; first element is lambda expression
(`(,(and `(lambda . ,_) fun) . ,args)
;; FIXME: it's silly to create a closure just to call it.
;; Running byte-optimize-form earlier would resolve this.
`(funcall
,(cconv-convert `(function ,fun) env extend)
,@(mapcar (lambda (form)
(cconv-convert form env extend))
args)))
(`(cond . ,cond-forms) ; cond special form
`(,(car form) . ,(mapcar (lambda (branch)
(mapcar (lambda (form)
(cconv-convert form env extend))
branch))
cond-forms)))
(`(cond . ,cond-forms) ; cond special form
`(,(car form) . ,(mapcar (lambda (branch)
(mapcar (lambda (form)
(cconv-convert form env extend))
branch))
cond-forms)))
(`(function (lambda ,args . ,body) . ,rest)
(let* ((docstring (if (eq :documentation (car-safe (car body)))
(cconv-convert (cadr (pop body)) env extend)))
(bf (if (stringp (car body)) (cdr body) body))
(if (when (eq 'interactive (car-safe (car bf)))
(gethash form cconv--interactive-form-funs)))
(wrapped (pcase if (`#'(lambda (&rest _cconv--dummy) .,_) t) (_ nil)))
(cif (when if (cconv-convert if env extend)))
(cf nil))
;; TODO: Because we need to non-destructively modify body, this code
;; is particularly ugly. This should ideally be moved to
;; cconv--convert-function.
(pcase cif
('nil (setq bf nil))
(`#',f
(pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
(setq bf `((,f1 . (,(if wrapped (nth 2 f) cif) . ,f2)) . ,f3)))
(setq cif nil))
;; The interactive form needs special treatment, so the form
;; inside the `interactive' won't be used any further.
(_ (pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
(setq bf `((,f1 . (nil . ,f2)) . ,f3)))))
(when bf
;; If we modified bf, re-build body and form as
;; copies with the modified bits.
(setq body (if (stringp (car body))
(cons (car body) bf)
bf)
form `(function (lambda ,args . ,body) . ,rest))
;; Also, remove the current old entry on the alist, replacing
;; it with the new one.
(let ((entry (pop cconv-freevars-alist)))
(push (cons body (cdr entry)) cconv-freevars-alist)))
(setq cf (cconv--convert-function args body env form docstring))
(if (not cif)
;; Normal case, the interactive form needs no special treatment.
cf
`(cconv--interactive-helper
,cf ,(if wrapped cif `(list 'quote ,cif))))))
(`(function (lambda ,args . ,body) . ,rest)
(let* ((docstring (if (eq :documentation (car-safe (car body)))
(cconv-convert (cadr (pop body)) env extend)))
(bf (if (stringp (car body)) (cdr body) body))
(if (when (eq 'interactive (car-safe (car bf)))
(gethash form cconv--interactive-form-funs)))
(wrapped (pcase if (`#'(lambda (&rest _cconv--dummy) .,_) t)))
(cif (when if (cconv-convert if env extend)))
(cf nil))
;; TODO: Because we need to non-destructively modify body, this code
;; is particularly ugly. This should ideally be moved to
;; cconv--convert-function.
(pcase cif
('nil (setq bf nil))
(`#',f
(pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
(setq bf `((,f1 . (,(if wrapped (nth 2 f) cif) . ,f2)) . ,f3)))
(setq cif nil))
;; The interactive form needs special treatment, so the form
;; inside the `interactive' won't be used any further.
(_ (pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
(setq bf `((,f1 . (nil . ,f2)) . ,f3)))))
(when bf
;; If we modified bf, re-build body and form as
;; copies with the modified bits.
(setq body (if (stringp (car body))
(cons (car body) bf)
bf)
form `(function (lambda ,args . ,body) . ,rest))
;; Also, remove the current old entry on the alist, replacing
;; it with the new one.
(let ((entry (pop cconv-freevars-alist)))
(push (cons body (cdr entry)) cconv-freevars-alist)))
(setq cf (cconv--convert-function args body env form docstring))
(if (not cif)
;; Normal case, the interactive form needs no special treatment.
cf
`(cconv--interactive-helper
,cf ,(if wrapped cif `(list 'quote ,cif))))))
(`(internal-make-closure . ,_)
(byte-compile-report-error
"Internal error in compiler: cconv called twice?"))
(`(internal-make-closure . ,_)
(byte-compile-report-error
"Internal error in compiler: cconv called twice?"))
(`(quote . ,_) form)
(`(function . ,_) form)
(`(quote . ,_) form)
(`(function . ,_) form)
;defconst, defvar
(`(,(and sym (or 'defconst 'defvar)) ,definedsymbol . ,forms)
`(,sym ,definedsymbol
. ,(when (consp forms)
(cons (cconv-convert (car forms) env extend)
;; The rest (i.e. docstring, of any) is not evaluated,
;; and may be an invalid expression (e.g. ($# . 678)).
(cdr forms)))))
(`(,(and sym (or 'defconst 'defvar)) ,definedsymbol . ,forms)
`(,sym ,definedsymbol
. ,(when (consp forms)
(cons (cconv-convert (car forms) env extend)
;; The rest (i.e. docstring, of any) is not evaluated,
;; and may be an invalid expression (e.g. ($# . 678)).
(cdr forms)))))
; condition-case
(`(condition-case ,var ,protected-form . ,handlers)
(let* ((class (and var (cconv--var-classification (list var) form)))
(newenv
(cond ((eq class :captured+mutated)
(cons `(,var . (car-safe ,var)) env))
((assq var env) (cons `(,var) env))
(t env)))
(msg (when (eq class :unused)
(cconv--warn-unused-msg var "variable")))
(newprotform (cconv-convert protected-form env extend)))
`(,(car form) ,var
,(if msg
(macroexp--warn-wrap var msg newprotform 'lexical)
newprotform)
,@(mapcar
(lambda (handler)
`(,(car handler)
,@(let ((body
(mapcar (lambda (form)
(cconv-convert form newenv extend))
(cdr handler))))
(if (not (eq class :captured+mutated))
body
`((let ((,var (list ,var))) ,@body))))))
handlers))))
(`(condition-case ,var ,protected-form . ,handlers)
(let* ((class (and var (cconv--var-classification (list var) form)))
(newenv
(cond ((eq class :captured+mutated)
(cons `(,var . (car-safe ,var)) env))
((assq var env) (cons `(,var) env))
(t env)))
(msg (when (eq class :unused)
(cconv--warn-unused-msg var "variable")))
(newprotform (cconv-convert protected-form env extend)))
`(,(car form) ,var
,(if msg
(macroexp--warn-wrap var msg newprotform 'lexical)
newprotform)
,@(mapcar
(lambda (handler)
`(,(car handler)
,@(let ((body
(mapcar (lambda (form)
(cconv-convert form newenv extend))
(cdr handler))))
(if (not (eq class :captured+mutated))
body
`((let ((,var (list ,var))) ,@body))))))
handlers))))
(`(unwind-protect ,form1 . ,body)
`(,(car form) ,(cconv-convert form1 env extend)
:fun-body ,(cconv--convert-function () body env form1)))
(`(unwind-protect ,form1 . ,body)
`(,(car form) ,(cconv-convert form1 env extend)
:fun-body ,(cconv--convert-function () body env form1)))
(`(setq ,var ,expr)
(let ((var-new (or (cdr (assq var env)) var))
(value (cconv-convert expr env extend)))
(pcase var-new
((pred symbolp) `(,(car form) ,var-new ,value))
(`(car-safe ,iexp) `(setcar ,iexp ,value))
;; This "should never happen", but for variables which are
;; mutated+captured+unused, we may end up trying to `setq'
;; on a closed-over variable, so just drop the setq.
(_ ;; (byte-compile-report-error
;; (format "Internal error in cconv of (setq %s ..)"
;; sym-new))
value))))
(`(setq ,var ,expr)
(let ((var-new (or (cdr (assq var env)) var))
(value (cconv-convert expr env extend)))
(pcase var-new
((pred symbolp) `(,(car form) ,var-new ,value))
(`(car-safe ,iexp) `(setcar ,iexp ,value))
;; This "should never happen", but for variables which are
;; mutated+captured+unused, we may end up trying to `setq'
;; on a closed-over variable, so just drop the setq.
(_ ;; (byte-compile-report-error
;; (format "Internal error in cconv of (setq %s ..)"
;; sym-new))
value))))
(`(,(and (or 'funcall 'apply) callsym) ,fun . ,args)
;; These are not special forms but we treat them separately for the needs
;; of lambda lifting.
(let ((mapping (cdr (assq fun env))))
(pcase mapping
(`(apply-partially ,_ . ,(and fvs `(,_ . ,_)))
(cl-assert (eq (cadr mapping) fun))
`(,callsym ,fun
,@(mapcar (lambda (fv)
(let ((exp (or (cdr (assq fv env)) fv)))
(pcase exp
(`(car-safe ,iexp . ,_) iexp)
(_ exp))))
fvs)
,@(mapcar (lambda (arg)
(cconv-convert arg env extend))
args)))
(_ `(,callsym ,@(mapcar (lambda (arg)
(`(,(and (or 'funcall 'apply) callsym) ,fun . ,args)
;; These are not special forms but we treat them separately for the needs
;; of lambda lifting.
(let ((mapping (cdr (assq fun env))))
(pcase mapping
(`(apply-partially ,_ . ,(and fvs `(,_ . ,_)))
(cl-assert (eq (cadr mapping) fun))
`(,callsym ,fun
,@(mapcar (lambda (fv)
(let ((exp (or (cdr (assq fv env)) fv)))
(pcase exp
(`(car-safe ,iexp . ,_) iexp)
(_ exp))))
fvs)
,@(mapcar (lambda (arg)
(cconv-convert arg env extend))
(cons fun args)))))))
args)))
(_ `(,callsym ,@(mapcar (lambda (arg)
(cconv-convert arg env extend))
(cons fun args)))))))
;; The form (if any) is converted beforehand as part of the `lambda' case.
(`(interactive . ,_) form)
;; The form (if any) is converted beforehand as part of the `lambda' case.
(`(interactive . ,_) form)
;; `declare' should now be macro-expanded away (and if they're not, we're
;; in trouble because they *can* contain code nowadays).
;; (`(declare . ,_) form) ;The args don't contain code.
;; `declare' should now be macro-expanded away (and if they're not, we're
;; in trouble because they *can* contain code nowadays).
;; (`(declare . ,_) form) ;The args don't contain code.
(`(oclosure--fix-type (ignore . ,vars) ,exp)
(dolist (var vars)
(let ((x (assq var env)))
(pcase (cdr x)
(`(car-safe . ,_) (error "Slot %S should not be mutated" var))
(_ (cl-assert (null (cdr x)))))))
(cconv-convert exp env extend))
(`(oclosure--fix-type (ignore . ,vars) ,exp)
(dolist (var vars)
(let ((x (assq var env)))
(pcase (cdr x)
(`(car-safe . ,_) (error "Slot %S should not be mutated" var))
(_ (cl-assert (null (cdr x)))))))
(cconv-convert exp env extend))
(`(,func . ,forms)
(if (symbolp func)
;; First element is function or whatever function-like forms are:
;; or, and, if, catch, progn, prog1, while, until
`(,func . ,(mapcar (lambda (form)
(cconv-convert form env extend))
forms))
(byte-compile-warn-x form "Malformed function `%S'" func)
nil))
(`(,func . ,forms)
(if (symbolp func)
;; First element is function or whatever function-like forms are:
;; or, and, if, catch, progn, prog1, while, until
`(,func . ,(mapcar (lambda (form)
(cconv-convert form env extend))
forms))
(byte-compile-warn-x form "Malformed function `%S'" func)
nil))
(_ (or (cdr (assq form env)) form)))))
(_ (or (cdr (assq form env)) form)))))
(defvar byte-compile-lexical-variables)