summaryrefslogtreecommitdiff
path: root/lint.scm
diff options
context:
space:
mode:
Diffstat (limited to 'lint.scm')
-rw-r--r--lint.scm1164
1 files changed, 647 insertions, 517 deletions
diff --git a/lint.scm b/lint.scm
index c3daea5..734d384 100644
--- a/lint.scm
+++ b/lint.scm
@@ -20,7 +20,7 @@
(define *report-doc-strings* #f) ; old-style (CL) doc strings
(define *report-func-as-arg-arity-mismatch* #f) ; as it says... (slow, and this error almost never happens)
(define *report-constant-expressions-in-do* #f) ; kinda dumb
-(define *report-bad-variable-names* '(l ll O ~)) ; bad names -- a list to check such as:
+(define *report-bad-variable-names* '(l ll .. O ~)) ; bad names -- a list to check such as:
;;; '(l ll .. ~ data datum new item info temp tmp temporary val vals value foo bar baz aux dummy O var res retval result count str)
(define *report-built-in-functions-used-as-variables* #f) ; string and length are the most common cases
(define *report-forward-functions* #f) ; functions used before being defined
@@ -99,7 +99,7 @@
defined? denominator dilambda? do dynamic-wind
eof-object? eq? equal? eqv? even? exact->inexact exact? exp expt
float? float-vector float-vector-ref float-vector? floor for-each funclet
- gcd gensym gensym? ; why was gensym omitted earlier?
+ gcd gensym gensym?
hash-table hash-table* hash-table-entries hash-table-ref hash-table? help hook-functions
if imag-part inexact->exact inexact? infinite? inlet input-port?
int-vector int-vector-ref int-vector? iterator-at-end? iterator-sequence integer->char
@@ -171,6 +171,7 @@
catch throw error procedure-documentation procedure-signature help procedure-source funclet
procedure-setter arity aritable? not eq? eqv? equal? morally-equal? gc s7-version emergency-exit
exit dilambda make-hook hook-functions stacktrace tree-leaves tree-memq object->let
+ getenv directory? file-exists?
#_{list} #_{apply_values} #_{append} unquote))
ht))
@@ -321,7 +322,7 @@
(hash-table-set! h d #t))
'(define define* define-constant lambda lambda* curlet require load eval eval-string
define-macro define-macro* define-bacro define-bacro* define-expansion
- definstrument defanimal define-envelope
+ definstrument define-animal define-envelope
define-values define-module define-method
define-syntax define-public define-inlinable define-integrable define^))
h))
@@ -396,10 +397,14 @@
(set! str1 (truncated-list->string f1))
(set! len1 (length str1)))
(when (> len2 target-line-length)
- (set! ((funclet lint-pretty-print) '*pretty-print-left-margin*) pp-left-margin)
- (set! ((funclet lint-pretty-print) '*pretty-print-length*) (- 114 pp-left-margin))
- (set! str2 (lint-pp f2))
- (set! len2 (length str2)))
+ (let ((old-len2 len2))
+ (set! ((funclet lint-pretty-print) '*pretty-print-left-margin*) pp-left-margin)
+ (set! ((funclet lint-pretty-print) '*pretty-print-length*) (- 114 pp-left-margin))
+ (set! str2 (lint-pp f2))
+ (set! len2 (length str2))
+ (when (> len2 (* 10 old-len2)) ; this is aimed at some pathological s7test cases -- never hit otherwise I think
+ (set! str2 (truncated-list->string f2))
+ (set! len2 (length str2)))))
(format #f (if (< (+ len1 len2) target-line-length)
(values "~A -> ~A" str1 str2)
(values "~%~NC~A ->~%~NC~A" pp-left-margin #\space str1 pp-left-margin #\space str2))))))
@@ -714,8 +719,8 @@
(define (tree-equal-member sym tree)
(and (pair? tree)
(or (equal? (car tree) sym)
- (tree-member sym (car tree))
- (tree-member sym (cdr tree)))))
+ (tree-equal-member sym (car tree))
+ (tree-equal-member sym (cdr tree)))))
(define (tree-unquoted-member sym tree)
(and (unquoted-pair? tree)
@@ -1175,7 +1180,8 @@
(when (and (len=1? body)
(pair? (car body))
(case (caar body) ; change body to use if
- ((if) #t) ; only 1 hit for 2 reversal branches
+ ((if)
+ #t) ; only 1 hit for 2 reversal branches, say 20 hits for 2 ifs + repeated return vals (collapsible) -- see tmp
((when)
(set! body `((if ,(cadar body)
,@(if (null? (cdddar body))
@@ -1310,11 +1316,11 @@
(len=3? (cdr tree))
(not (tree-memq res-name (cadr tree)))
(tree-memq res-name (cddr tree)))
- `(if ,(cadr tree)
- ,(if (eq? (caddr tree) res-name)
+ (list 'if (cadr tree)
+ (if (eq? (caddr tree) res-name)
'(values)
(subst (caddr tree)))
- ,(if (eq? (cadddr tree) res-name)
+ (if (eq? (cadddr tree) res-name)
'(values)
(subst (cadddr tree)))))
@@ -1379,6 +1385,7 @@
(set! for-each-case (rewrite-map #t name iter sequence
(copy (unbegin (cadr cdrf)))
initial-value)))))
+
(let ((iters ()))
;; recursion -> for-each
(when (and (null? (cddr nf))
@@ -1408,7 +1415,7 @@
(unbegin (copy (cadr nf) (make-list (- (length (cadr nf)) 1))))
initial-value)))))))
- ;; any number of args here, still if-based as above
+ ;; any number of args here, still if-based as above
;;
;; recursion->do
;; (n ((a b) (c d)) (if .1. (begin .2. (n (+ a 1) (cdr c))) .3.)) -> (do ((a b (+ a 1)) (c d (cdr c))) ((not .1.) .3.) .2.)
@@ -1431,7 +1438,7 @@
(set! result do-body)
(set! do-body old-res)))
- (when (< (tree-leaves result) 30)
+ (when (< (tree-leaves result) 50)
(let ((call (if (eq? (car do-body) name)
do-body
(and (eq? (car do-body) 'begin)
@@ -1518,13 +1525,13 @@
(set! default-value (cadddr value))))
(unless (eq? default-value :unset)
(let ((new-arglist (if (symbol? arglist)
- (if default-value
- `((,(car var1) ,default-value))
- (list (car var1)))
+ (list (if default-value
+ (list (car var1) default-value)
+ (car var1)))
(append (copy arglist (make-list (abs (length arglist))))
- (if default-value ; #f is default
- `((,(car var1) ,default-value))
- (list (car var1))))))
+ (list (if default-value ; #f is default
+ (list (car var1) default-value)
+ (car var1))))))
(new-body (if (null? (cdadr body)) ; 0 other vars
'...
(list (if (or (eq? (car body) 'let)
@@ -1615,6 +1622,7 @@
((rational? c) 'rational?)
((real? c) 'real?)
((number? c) 'number?)
+ ((byte-vector? c) 'byte-vector?)
((string? c) 'string?)
((null? c) 'null?)
((char? c) 'char?)
@@ -1622,10 +1630,9 @@
((keyword? c)
(cond ((assq c markers) => cdr)
(else 'keyword?)))
- ((vector? c) 'vector?)
((float-vector? c) 'float-vector?)
((int-vector? c) 'int-vector?)
- ((byte-vector? c) 'byte-vector?)
+ ((vector? c) 'vector?)
((let? c) 'let?)
((hash-table? c) 'hash-table?)
((input-port? c) 'input-port?)
@@ -1985,13 +1992,7 @@
(or (string=? "compute" (substring sname 0 7)) ; compute-* is as bad as get-*
(string=? "calculate" (substring sname 0 9))))) ; perhaps one exception: computed-goto*
(lint-format "surely there's a better name for this variable than ~A" caller vname)
-#|
- (if (let ((p (char-position #\@ sname))) ; this happens 3 times (in a test suite)!
- (and (integer? p)
- (string->number (substring sname 0 p))
- (string->number (substring sname (+ p 1)))))
- (lint-format "s7 does not implement scheme's polar notation: ~A" caller vname))
-|#
+ ;; polar notation (see tmp) gets 3 hits (in a test suite)!
))))))
@@ -3029,7 +3030,10 @@
(and (null? (cdddr p))
(equal? (caddr p) last)))
(cddr form))
- (set! form `(,op (,(car form) ,@(map cadr (cdr form))) ,last)))))))))
+ (set! form (list op
+ (cons (car form)
+ (map cadr (cdr form)))
+ last)))))))))
;; (or (and A B) (and A C)) -> (and A (or B C))
;; (or (and A B) (and C B)) -> (and (or A C) B)
;; (and (or A B) (or A C)) -> (or A (and B C))
@@ -3095,7 +3099,7 @@
((begin)
(let* ((len1 (- (length val) 1))
(new-last (simplify-boolean (list 'not (list-ref val len1)) () () env)))
- `(,@(copy val (make-list len1)) ,new-last)))))
+ (append (copy val (make-list len1)) (list new-last))))))
((not (equal? val arg))
(list 'not val))
@@ -3348,105 +3352,107 @@
(vals ())
(start #f))
- (define (constant-arg p)
- (if (code-constant? (cadr p))
- (set! vals (cons (cadr p) vals))
- (and (code-constant? (caddr p))
- (set! vals (cons (caddr p) vals)))))
-
- (define (upgrade-eqf)
- (set! eqfnc (case eqfnc
- ((string=? string-ci=? = equal?) 'equal?)
- ((#f eq?) 'eq?)
- (else 'eqv?))))
-
- (define (collect-vals p)
- ;; = can't share: (equal? 1 1.0) -> #f, so (or (not x) (= x 1)) can't be simplified
- ;; except via member+morally-equal? but that brings in float-epsilon and NaN differences.
- ;; We could add both: 1 1.0 as in cond?
- ;;
- ;; another problem: using memx below means the returned value of the expression
- ;; may not match the original (#t -> '(...)), so perhaps we should add a one-time
- ;; warning about this, and wrap it in (pair? (mem...)) as an example.
- ;;
- ;; and another thing... the original might be broken: (eq? x #(1)) where equal?
- ;; is more sensible, but that also changes the behavior of the expression:
- ;; (memq x '(#(1))) may be #f (or #t!) when (member x '(#(1))) is '(#(1)).
- ;;
- ;; I think I'll try to turn out a more-or-less working expression, but warn about it.
-
- (case (car p)
- ((string=? equal?)
- (set! eqfnc (if (or (not eqfnc)
- (eq? eqfnc (car p)))
- (car p)
- 'equal?))
- (and (= (length p) 3)
- (constant-arg p)))
-
- ((char=?)
- (if (memq eqfnc '(#f char=?))
- (set! eqfnc 'char=?)
- (if (not (eq? eqfnc 'equal?))
- (set! eqfnc 'eqv?)))
- (and (= (length p) 3)
- (constant-arg p)))
-
- ((eq? eqv?)
- (let ((leqf (car (->eqf (->lint-type ((if (code-constant? (cadr p)) cadr caddr) p))))))
- (cond ((not eqfnc)
- (set! eqfnc leqf))
-
- ((or (memq leqf '(#t equal?))
- (not (eq? eqfnc leqf)))
- (set! eqfnc 'equal?))
-
- ((memq eqfnc '(#f eq?))
- (set! eqfnc leqf))))
- (and (= (length p) 3)
- (constant-arg p)))
-
- ((char-ci=? string-ci=? =)
- (and (or (not eqfnc)
- (eq? eqfnc (car p)))
- (set! eqfnc (car p))
- (= (length p) 3)
- (constant-arg p)))
+ (define collect-vals
+ (let ()
+ (define (constant-arg p)
+ (if (code-constant? (cadr p))
+ (set! vals (cons (cadr p) vals))
+ (and (code-constant? (caddr p))
+ (set! vals (cons (caddr p) vals)))))
- ((eof-object?)
- (upgrade-eqf)
- (set! vals (cons #<eof> vals)))
+ (define (upgrade-eqf)
+ (set! eqfnc (case eqfnc
+ ((string=? string-ci=? = equal?) 'equal?)
+ ((#f eq?) 'eq?)
+ (else 'eqv?))))
- ((not)
- (upgrade-eqf)
- (set! vals (cons #f vals)))
-
- ((boolean?)
- (upgrade-eqf)
- (set! vals (cons #f (cons #t vals))))
-
- ((zero?)
- (if (memq eqfnc '(#f eq?)) (set! eqfnc 'eqv?))
- (set! vals (cons 0 (cons 0.0 vals))))
-
- ((null?)
- (upgrade-eqf)
- (set! vals (cons () vals)))
-
- ((memq memv member)
- (cond ((eq? (car p) 'member)
- (set! eqfnc 'equal?))
-
- ((eq? (car p) 'memv)
- (set! eqfnc (if (eq? eqfnc 'string=?) 'equal? 'eqv?)))
-
- ((not eqfnc)
- (set! eqfnc 'eq?)))
- (and (= (length p) 3)
- (quoted-pair? (caddr p))
- (set! vals (append (cadr (caddr p)) vals))))
-
- (else #f)))
+ (lambda (p)
+ ;; = can't share: (equal? 1 1.0) -> #f, so (or (not x) (= x 1)) can't be simplified
+ ;; except via member+morally-equal? but that brings in float-epsilon and NaN differences.
+ ;; We could add both: 1 1.0 as in cond?
+ ;;
+ ;; another problem: using memx below means the returned value of the expression
+ ;; may not match the original (#t -> '(...)), so perhaps we should add a one-time
+ ;; warning about this, and wrap it in (pair? (mem...)) as an example.
+ ;;
+ ;; and another thing... the original might be broken: (eq? x #(1)) where equal?
+ ;; is more sensible, but that also changes the behavior of the expression:
+ ;; (memq x '(#(1))) may be #f (or #t!) when (member x '(#(1))) is '(#(1)).
+ ;;
+ ;; I think I'll try to turn out a more-or-less working expression, but warn about it.
+
+ (case (car p)
+ ((string=? equal?)
+ (set! eqfnc (if (or (not eqfnc)
+ (eq? eqfnc (car p)))
+ (car p)
+ 'equal?))
+ (and (= (length p) 3)
+ (constant-arg p)))
+
+ ((char=?)
+ (if (memq eqfnc '(#f char=?))
+ (set! eqfnc 'char=?)
+ (if (not (eq? eqfnc 'equal?))
+ (set! eqfnc 'eqv?)))
+ (and (= (length p) 3)
+ (constant-arg p)))
+
+ ((eq? eqv?)
+ (let ((leqf (car (->eqf (->lint-type ((if (code-constant? (cadr p)) cadr caddr) p))))))
+ (cond ((not eqfnc)
+ (set! eqfnc leqf))
+
+ ((or (memq leqf '(#t equal?))
+ (not (eq? eqfnc leqf)))
+ (set! eqfnc 'equal?))
+
+ ((memq eqfnc '(#f eq?))
+ (set! eqfnc leqf))))
+ (and (= (length p) 3)
+ (constant-arg p)))
+
+ ((char-ci=? string-ci=? =)
+ (and (or (not eqfnc)
+ (eq? eqfnc (car p)))
+ (set! eqfnc (car p))
+ (= (length p) 3)
+ (constant-arg p)))
+
+ ((eof-object?)
+ (upgrade-eqf)
+ (set! vals (cons #<eof> vals)))
+
+ ((not)
+ (upgrade-eqf)
+ (set! vals (cons #f vals)))
+
+ ((boolean?)
+ (upgrade-eqf)
+ (set! vals (cons #f (cons #t vals))))
+
+ ((zero?)
+ (if (memq eqfnc '(#f eq?)) (set! eqfnc 'eqv?))
+ (set! vals (cons 0 (cons 0.0 vals))))
+
+ ((null?)
+ (upgrade-eqf)
+ (set! vals (cons () vals)))
+
+ ((memq memv member)
+ (cond ((eq? (car p) 'member)
+ (set! eqfnc 'equal?))
+
+ ((eq? (car p) 'memv)
+ (set! eqfnc (if (eq? eqfnc 'string=?) 'equal? 'eqv?)))
+
+ ((not eqfnc)
+ (set! eqfnc 'eq?)))
+ (and (= (length p) 3)
+ (quoted-pair? (caddr p))
+ (set! vals (append (cadr (caddr p)) vals))))
+
+ (else #f)))))
(do ((fp (cdr form) (cdr fp)))
((not (pair? fp)))
@@ -3751,12 +3757,14 @@
(equal? (cadr arg1) (cadr arg2)))
(if (and (rational? (caddr arg1))
(rational? (caddr arg2)))
- (return `(,(car arg1)
- ,(cadr arg1)
- ,((if (memq (car arg1) '(< <=)) min max) (caddr arg1) (caddr arg2)))))
- (return `(,(car arg1)
- ,(cadr arg1)
- (,(if (memq (car arg1) '(< <=)) 'min 'max) ,(caddr arg1) ,(caddr arg2)))))
+ (return (list (car arg1)
+ (cadr arg1)
+ ((if (memq (car arg1) '(< <=)) min max) (caddr arg1) (caddr arg2)))))
+ (return (list (car arg1)
+ (cadr arg1)
+ (list (if (memq (car arg1) '(< <=)) 'min 'max)
+ (caddr arg1)
+ (caddr arg2)))))
(when (and (or (equal? (caddr arg1) (cadr arg2)) ; (and (op x y) (op y z))
(equal? (cadr arg1) (caddr arg2)) ; (and (op x y) (op z x))
@@ -3844,7 +3852,7 @@
(when (and (member (cadr arg1) arg2)
(memq (car arg2) '(string=? char=? eq? eqv? equal?))
- (null? (cdddr arg2))
+ (len=2? (cdr arg2))
(hash-table-ref bools (car arg1))
(or (and (code-constant? (cadr arg2))
(compatible? (car arg1) (->lint-type (cadr arg2))))
@@ -4115,7 +4123,7 @@
(and (len>1? val) ; and redundant tests
(hash-table-ref booleans (car val))
(any? (lambda (p)
- (and (pair? p)
+ (and (len>1? p)
(subsumes? (car val) (car p))
(equal? (cadr val) (cadr p))))
new-form)))))
@@ -4142,16 +4150,19 @@
(fix:<= . <=) (fx<= . <=) (flo:<= . <=) (fl<= . <=)
(fix:>= . >=) (fx>= . >=) (flo:>= . >=) (fl>= . >=)
(fxlogand . logand) (fxlogior . logior) (fxlogxor . logxor) (fxlognot . lognot)
+ (fxand . logand) (fxior . logior) (fxxor . logxor) (fxnot . lognot)
(fix:quotient . quotient) (fix:min . min) (fix:max . max) (fxquotient . quotient)
+ (flmax . max) (flmin . min)
(flo:abs . abs) (flabs . abs)
(flo:sin . sin) (flsin . sin)
(flo:cos . cos) (flcos . cos)
(flo:tan . tan) (fltan . tan)
+ (flo:asin . asin) (flasin . asin)
+ (flo:acos . acos) (flacos . acos)
(flo:atan . atan) (flatan . atan)
(flo:sqrt . sqrt) (flsqrt . sqrt)
- (flo:exp . exp) (flexp . exp)
+ (flo:exp . exp) (flexp . exp) (flexpt . expt)
(flo:log . log) (fllog . log))))
-
(lambda (tree)
(cond ((assq tree dumb-ops) => cdr)
((or (not (pair? tree))
@@ -4396,7 +4407,7 @@
(pair? (cddr arg1))
(pair? (cddr arg2))
(equal? (cddr arg1) (cddr arg2)))
- `(/ (+ ,(cadr arg1) ,(cadr arg2)) ,@(cddr arg1)))
+ (cons '/ (cons (list '+ (cadr arg1) (cadr arg2)) (cddr arg1))))
(else (cons '+ val)))))
(else
@@ -4509,18 +4520,16 @@
(eq? op2 'exp))
(list 'exp (list '+ (cadr arg1) (cadr arg2))))
- ((and (eq? op1 'sqrt) ; (* (sqrt x) (sqrt y)) -> (sqrt (* x y))
- (eq? op2 'sqrt))
- (list 'sqrt (list '* (cadr arg1) (cadr arg2))))
+ ;; (* (sqrt x) (sqrt y)) -> (sqrt (* x y)) if x and y not both negative?
((not (and (eq? op1 'expt) (eq? op2 'expt)))
(cons '* val))
((equal? (cadr arg1) (cadr arg2)) ; (* (expt x y) (expt x z)) -> (expt x (+ y z))
- `(expt ,(cadr arg1) (+ ,(caddr arg1) ,(caddr arg2))))
+ (list 'expt (cadr arg1) (list '+ (caddr arg1) (caddr arg2))))
((equal? (caddr arg1) (caddr arg2)) ; (* (expt x y) (expt z y)) -> (expt (* x z) y)
- `(expt (* ,(cadr arg1) ,(cadr arg2)) ,(caddr arg1)))
+ (list 'expt (list '* (cadr arg1) (cadr arg2)) (caddr arg1)))
(else (cons '* val)))))
@@ -4543,7 +4552,7 @@
0)
((memv -1 val)
- `(- (* ,@(remove -1 val)))) ; (* -1 x y) -> (- (* x y))
+ (list '- (cons '* (remove -1 val)))) ; (* -1 x y) -> (- (* x y))
((let search ((args val)) ; (* x (if y 0 z) w) -> (if y 0 (* x z w))
(and (pair? args)
@@ -4589,7 +4598,7 @@
(if (null? div)
(cons '* (reverse mul))
`(/ (* ,@(reverse mul)) ,@(reverse div))))))
- (if (equal? expr form)
+ (if (morally-equal? expr form) ; possible NaN
form
(simplify-numerics expr env)))))
@@ -4663,8 +4672,8 @@
(let ((true (caddr arg2))
(false (cadddr arg2)))
`(if ,(cadr arg2)
- ,(if (eqv? true 0) arg1 `(- ,arg1 ,true))
- ,(if (eqv? true 0) `(- ,arg1 ,false) arg1))))
+ ,(if (eqv? true 0) arg1 (list '- arg1 true))
+ ,(if (eqv? true 0) (list '- arg1 false) arg1))))
(else (cons '- args)))))
(else
@@ -5027,14 +5036,16 @@
((memq (caar args) '(* + / -)) ; maybe extend this list
`(,(car form) (,(caar args) ,@(map (lambda (p)
- (if (and (pair? p)
+ (if (and (len=2? p)
(memq (car p) '(inexact->exact exact)))
(cadr p)
p))
(cdar args)))))
((and (eq? (caar args) 'random)
(eq? (car form) 'floor)
+ (null? (cddar args))
(float? (cadar args))
+ (not (nan? (cadar args))) ; (floor (random nan.0))!
(= (floor (cadar args)) (cadar args)))
(list 'random (floor (cadar args))))
@@ -5069,6 +5080,8 @@
((and (eq? (caar args) '-) ; (abs (- x)) -> (abs x)
(len=1? (cdar args)))
(list (car form) (cadar args)))
+
+ ;; make-polar as arg never happens
(else (cons (car form) args))))
(hash-table-set! h 'abs numabs)
@@ -5262,7 +5275,7 @@
(integer-result? (caar args))
(and (eq? (caar args) 'random)
(pair? (cdar args))
- (rational? (cadar args))))))
+ (rational? (cadar args)))))) ; perhaps (exact (random 10.0)) -> (random 10)??
(car args))
((number? (car args))
(catch #t (lambda () (inexact->exact (car args))) (lambda any (cons (car form) args))))
@@ -5991,7 +6004,7 @@
(and (every? code-constant? elements)
elements)
(and (every? (lambda (e)
- (and (pair? e)
+ (and (len=2? e)
(eq? (car e) 'quote)))
elements)
(map caadr elements))))))
@@ -7293,7 +7306,7 @@
;; not string->number -- no point in copying a number and it's caught below
(when (pair? (cdr form))
- (if (code-constant? (cadr form))
+ (if (every? code-constant? (cdr form))
(let ((seq (checked-eval form)))
(if (not (eq? seq :checked-eval-error)) ; (symbol->string 'abs) -> "abs"
(lint-format "perhaps ~A -> ~A~A" caller
@@ -8034,7 +8047,7 @@
((string-append) ; (apply string-append (map ...))
(if (eq? (car cdr-args) 'symbol->string)
(lint-format "perhaps ~A" caller ; (apply string-append (map symbol->string ...))
- (lists->string form `(format #f "~{~A~}" ,(cadr cdr-args))))
+ (lists->string form (list 'format #f "~{~A~}" (cadr cdr-args))))
(if (simple-lambda? (car cdr-args))
(let ((body (caddar cdr-args)))
(if (and (len=3? body)
@@ -8105,7 +8118,8 @@
(= (car ary) (cdr ary)) ; else () as last, so can't suggest (car last)
(= (cdr ary) (- len 2)))
(lint-format "perhaps ~A" caller
- (lists->string form `(,@(copy (cdr form) (make-list (- len 2))) (car ,(list-ref form (- len 1))))))))))))
+ (lists->string form (append (copy (cdr form) (make-list (- len 2)))
+ (list (list 'car (list-ref form (- len 1)))))))))))))
(hash-special 'apply sp-apply))
@@ -8126,7 +8140,7 @@
(lint-format "format with one argument takes a string: ~A" caller (truncated-list->string form)))
((and (string? (cadr form)) ; (format "str") -> str
- (eq? head 'format) ; not snd-display
+ (eq? head 'format) ; not snd-display, error, etc
(not (char-position #\~ (cadr form))))
(lint-format "perhaps ~A" caller (lists->string form (cadr form)))))
env)
@@ -8237,15 +8251,14 @@
(lint-format "perhaps ~A" caller ; (format #f "~S" x) -> (object->string x)
(lists->string form (cons 'object->string
(cons (cadddr form)
- (if (string=? (caddr form) "~A") '(#f) ()))))))))
+ (if (string=? (caddr form) "~A") '(#f) ())))))))
+ (if (and (eq? (cadr form) 't) ; (format t " ")
+ (not (var-member 't env)))
+ (lint-format "'t in ~A should probably be #t" caller (truncated-list->string form))))
(if (any? all-caps-warning (cdr form))
(lint-format "There's no need to shout: ~A" caller (truncated-list->string form)))
- (if (and (eq? (cadr form) 't) ; (format t " ")
- (not (var-member 't env)))
- (lint-format "'t in ~A should probably be #t" caller (truncated-list->string form)))
-
(if (not (string? control-string))
(if (not (proper-list? args))
(lint-format "~S looks suspicious" caller form))
@@ -8261,7 +8274,8 @@
(if (> ndirs nargs) "too few" "too many")
(truncated-list->string form)))
- ((and (not (cadr form)) ; (format #f "123")
+ ((and (eq? head 'format)
+ (not (cadr form)) ; (format #f "123")
(zero? ndirs)
(not (char-position #\~ control-string)))
(lint-format "~A could be ~S, (format is a no-op here)" caller (truncated-list->string form) (caddr form)))
@@ -8276,22 +8290,22 @@
(case (car a)
((number->string)
(if (null? (cddr a)) ; (format #f "~A" (number->string x))
- (lint-format "format arg ~A could be ~A" caller a (cadr a))
+ (lint-format "~A arg ~A could be ~A" caller head a (cadr a))
(if (and (pair? (cddr a))
(integer? (caddr a))
(memv (caddr a) '(2 8 10 16)))
(if (= (caddr a) 10)
- (lint-format "format arg ~A could be ~A" caller a (cadr a))
- (lint-format "format arg ~A could use the format directive ~~~A and change the argument to ~A" caller a
+ (lint-format "~A arg ~A could be ~A" caller head a (cadr a))
+ (lint-format "~A arg ~A could use the format directive ~~~A and change the argument to ~A" caller head a
(case (caddr a) ((2) "B") ((8) "O") (else "X"))
(cadr a))))))
((symbol->string list->string object->string vector->string) ; (format #f "~A" (symbol->string 'x))
- (lint-format "format arg ~A could be ~A" caller a (cadr a)))
+ (lint-format "~A arg ~A could be ~A" caller head a (cadr a)))
((make-string) ; (format #f "~A" (make-string len c))
(if (pair? (cddr a))
- (lint-format "format arg ~A could use the format directive ~~NC and change the argument to ... ~A ~A ..." caller a
+ (lint-format "~A arg ~A could use the format directive ~~NC and change the argument to ... ~A ~A ..." caller head a
(cadr a) (if (char? (caddr a)) (format #f "~W" (caddr a)) (caddr a)))))
((apply)
@@ -8300,17 +8314,29 @@
(lint-format "use ~~{...~~} rather than ~A: ~A" caller (cadr a) a)))
((string-append) ; (format #f "~A" (string-append x y))
- (lint-format "format appends strings, so ~A seems wasteful" caller a)))))
+ (if (eq? head 'format)
+ (lint-format "format appends strings, so ~A seems wasteful" caller a))))))
args)))))
(hash-special 'format sp-format))
- ;; ---------------- error ----------------
+ ;; ---------------- error/throw ----------------
(let ()
(define (sp-error caller head form env)
- (if (any? all-caps-warning (cdr form))
- (lint-format "There's no need to shout: ~A" caller (truncated-list->string form))))
- (hash-special 'error sp-error))
-
+ (when (pair? (cdr form))
+ (let* ((tag (cadr form))
+ (eq (eqf tag env)))
+ (if (string? tag)
+ (lint-format "~A's first argument should be a catchable tag, not ~S" caller head tag)
+ (if (not (member eq '((eq? eq?) (#t #t))))
+ (lint-format "~A tag ~S is unreliable (catch uses eq? to match tags)" caller 'error tag)))
+ (if (and (pair? (cddr form))
+ (string? (caddr form))
+ (proper-list? (cdddr form)))
+ ((hash-table-ref special-case-functions 'format) caller head form env)))))
+
+ (hash-special 'error sp-error)
+ (hash-special 'throw sp-error))
+
;; ---------------- sort! ----------------
(let ()
(define (sp-sort caller head form env)
@@ -8362,10 +8388,11 @@
(null? (cdddr str)))
(lint-format "perhaps ~A" caller
(lists->string form
- (if (and (integer? (caddr form))
- (integer? (caddr str)))
- (list 'substring (cadr str) (+ (caddr str) (caddr form)))
- (list 'substring (cadr str) (list '+ (caddr str) (caddr form)))))))
+ (list 'substring (cadr str)
+ (if (and (integer? (caddr form))
+ (integer? (caddr str)))
+ (+ (caddr str) (caddr form))
+ (list '+ (caddr str) (caddr form)))))))
;; end indices are complicated -- since this rarely happens, not worth the trouble
(if (eqv? (caddr form) 0) ; (substring x 0) -> (copy x)
@@ -8465,10 +8492,11 @@
(eq? (caadr form) 'list-tail))
(lint-format "perhaps ~A" caller ; (list-tail (list-tail x 1) 2) -> (list-tail x 3)
(lists->string form
- (if (and (integer? (caddr form))
- (integer? (caddr (cadr form))))
- (list 'list-tail (cadadr form) (+ (caddr (cadr form)) (caddr form)))
- (list 'list-tail (cadadr form) (list '+ (caddr (cadr form)) (caddr form))))))))))
+ (list 'list-tail (cadadr form)
+ (if (and (integer? (caddr form))
+ (integer? (caddr (cadr form))))
+ (+ (caddr (cadr form)) (caddr form))
+ (list '+ (caddr (cadr form)) (caddr form))))))))))
(hash-special 'list-tail sp-list-tail))
;; ---------------- eq? ----------------
@@ -8572,7 +8600,7 @@
;; (equal? a (list b)) and equivalents happens a lot, but is the extra consing worse than
;; (and (pair? a) (equal? (car a) b) (null? (cdr a))) -- code readability seems more important here
-
+
(cond ((or (eq? (car eq1) 'equal?)
(eq? (car eq2) 'equal?))
(if (eq? head 'equal?)
@@ -8587,10 +8615,10 @@
(if (eq? head 'eqv?)
(if specific-op ; (eqv? (integer->char x) #\null)
(lint-format "~A could be ~A in ~S" caller head specific-op form))
- (lint-format "~A ~A be eqv?~A in ~S" caller head
- (if (eq? head 'eq?) "should" "could")
- (if specific-op (format #f " or ~A" specific-op) "")
- form)))
+ (lint-format "~A ~A be eqv?~A in ~S" caller head
+ (if (eq? head 'eq?) "should" "could")
+ (if specific-op (format #f " or ~A" specific-op) "")
+ form)))
((not (or (eq? (car eq1) 'eq?)
(eq? (car eq2) 'eq?))))
@@ -8610,6 +8638,17 @@
form))))))
(hash-special 'eqv? sp-eqv?)
(hash-special 'equal? sp-eqv?))
+
+ (let ()
+ (define (sp-morally-equal caller head form env)
+ (if (and (= (length form) 3)
+ (code-constant? (cadr form))
+ (code-constant? (caddr form)))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (apply morally-equal? (cdr form))))))
+ (hash-special 'morally-equal? sp-morally-equal))
+
;; ---------------- map for-each ----------------
(let ()
@@ -8656,7 +8695,7 @@
(cddr form))))
(if (eq? head 'for-each)
(cons (cadr form) args)
- `(list (,(cadr form) ,@args))))))))
+ (list 'list (cons (cadr form) args))))))))
;; 2 happens a lot, but introduces evaluation order quibbles
;; we used to check for values if list arg -- got 4 hits!
@@ -9307,21 +9346,12 @@
(lambda (caller head form env)
(if (len=2? form)
(let ((arg (cadr form)))
- (if (and (pair? arg)
+ (if (and (len>1? arg)
(eq? (car arg) 'quote)
(symbol? (cadr arg)) ; (*s7* 'vector-print-length)
(not (hash-table-ref s7-fields (cadr arg))))
(lint-format "unknown *s7* field: ~A" caller arg)))))))
- ;; ---------------- throw ----------------
- (hash-special 'throw
- (lambda (caller head form env)
- (if (pair? (cdr form))
- (let* ((tag (cadr form))
- (eq (eqf tag env)))
- (if (not (member eq '((eq? eq?) (#t #t))))
- (lint-format "~A tag ~S is unreliable (catch uses eq? to match tags)" caller 'throw tag))))))
-
;; ---------------- make-hash-table ----------------
(hash-special 'make-hash-table
(lambda (caller head form env)
@@ -9408,7 +9438,7 @@
(lists->string form ; (cons* (symbol->string v) " | " (w)) -> (cons (symbol->string v) (cons " | " (w)))
(if (any-null? (cadddr form))
(list 'list (cadr form) (caddr form))
- `(cons ,(cadr form) (cons ,@(cddr form))))))))))
+ (list 'cons (cadr form) (cons 'cons (cddr form))))))))))
(hash-special 'cons* sp-cons*))
;; ---------------- the-environment etc ----------------
@@ -9900,7 +9930,8 @@
((do)
(if (len>1? (cdr arg))
(let ((end+res (caddr arg)))
- (check-arg (if (len>1? end+res)
+ (check-arg (if (and (pair? end+res)
+ (> (length end+res) 1))
(list-ref end+res (- (length end+res) 1))
())))))
@@ -9908,7 +9939,8 @@
(if (len>1? (cdr arg))
(for-each
(lambda (clause)
- (if (and (len>1? clause)
+ (if (and (pair? clause)
+ (> (length clause) 1)
(not (eq? (cadr clause) '=>)))
(check-arg (list-ref clause (- (length clause) 1)))))
(cddr arg))))
@@ -10458,10 +10490,9 @@
(when (> (length hist) 2) ; an experiment -- if all refs are by list-ref (in effect) suggest a vector
(let ((init (var-initial-value local-var)))
;; (format *stderr* "hist: ~A~%init: ~A~%outer: ~A~%" hist init outer-form)
- (when (pair? init)
-
- ;; list->vector
- (if (and (or (memq (car init) '(list make-list string->list vector->list))
+ (when (and (pair? init)
+ ;; list->vector
+ (or (memq (car init) '(list make-list string->list vector->list))
(and (eq? (car init) 'quote)
(pair? (cdr init))
(pair? (cadr init))))
@@ -10473,10 +10504,10 @@
(memq (car p) '(list-ref list-set! length reverse map for-each
list->vector list->string list? pair? null? quote)))))
hist))
- (lint-format "~A could be a vector, rather than a list" caller vname))
+ (lint-format "~A could be a vector, rather than a list" caller vname))))
;; string->byte-vector got no hits (see tmp)
;; vector->int|float-vector is mostly test stuff
- )))
+ ;; there are only a few a-lists>20 in len
;; --------
(let ((first (car hist))) ; all but the initial binding have to match this
@@ -10524,7 +10555,7 @@
(+ lint-left-margin 4) #\space
;; "probably" here because the accesses could have hidden protective assumptions
;; i.e. full accessor is not valid at point of let binding
- `(,vname (,new-op ,@(tree-subst (var-initial-value local-var) vname (cdr first))))
+ (list vname (cons new-op (tree-subst (var-initial-value local-var) vname (cdr first))))
(truncated-list->string outer-form))))))))))))
;; translate to dilambda fixing arg if necessary and mention generic set!
@@ -10739,7 +10770,7 @@
vname (truncated-list->string (var-initial-value local-var)) (var-definer local-var))))
;; not ref'd or set
- (if (not (memq vname '(documentation signature iterator? defanimal)))
+ (if (not (memq vname '(documentation signature iterator? define-animal)))
(let ((val (if (pair? (var-history local-var)) (car (var-history local-var)) (var-initial-value local-var)))
(def (var-definer local-var)))
(let-temporarily ((line-number (if (eq? caller top-level:) -1 line-number)))
@@ -11063,7 +11094,7 @@
(and (pair? new-unused)
(set! unused new-unused)))))
(cddr p))))
- (lint-format "~A parameter ~A is a function whose parameter~P ~{~A~^, ~} ~A never used~%" caller
+ (lint-format "~A parameter ~A is a function whose parameter~P ~{~A~^, ~} ~A never used" caller
vname (car p)
(length unused)
(map (lambda (p) (+ p 1)) (reverse unused))
@@ -11442,7 +11473,7 @@
;; (... (define f14 (lambda (x y) (if (positive? x) (+ x y) y))) (+ (f11 1 2) (f14 1 2))) ->
;; (... (let ((f14 (lambda (x y) (if (positive? x) (+ x y) y)))) (+ (f11 1 2) (f14 1 2))))
(lint-format "the scope of ~A could be reduced: ~A" caller name
- (truncated-lists->string `(... ,expr ,use-expr ,@end-dots)
+ (truncated-lists->string (cons '... (cons expr (cons use-expr end-dots)))
`(... (,letx ((,name ,(caddr expr)))
,use-expr)
,@end-dots)))))
@@ -11451,7 +11482,7 @@
;; (... (set! x (+ x y)) ...)
(lint-format "use set! to redefine ~A: ~A" caller name
(lists->string (cons '... (cons use-expr end-dots))
- `(... (set! ,name ,(caddr use-expr)) ,@end-dots))))
+ (cons '... (cons (list 'set! name (caddr use-expr)) end-dots)))))
((pair? (cadr use-expr))
(if (symbol? (caadr use-expr))
(let-temporarily ((target-line-length 120))
@@ -11877,7 +11908,7 @@
(lint-format "assuming ~A is not a macro, perhaps ~A" caller
func-name
(lists->string (list '... (car start-repeats) '...)
- `(for-each ,func (vector ,@(reverse args)))))))))))))
+ (list 'for-each func (cons 'vector (reverse args)))))))))))))
(set! repeats 0)
(set! repeat-arg 0)
(set! start-repeats fs)))
@@ -12641,16 +12672,18 @@
(let ((cc1 (simplify-boolean (list 'not (car c1)) () () env)))
(lint-format "perhaps ~A" caller
(lists->string form
- (if (null? (cddr c2))
- (list 'and cc1 (cadr c2))
- `(and ,cc1 (begin ,@(cdr c2))))))))
+ (list 'and cc1
+ (if (null? (cddr c2))
+ (cadr c2)
+ (cons 'begin (cdr c2))))))))
(and (pair? (car c1)) ; (cond ((null? x) #t) (else y)) -> (or (null? x) y)
(eq? (return-type (caar c1) env) 'boolean?)
(lint-format "perhaps ~A" caller
(lists->string form
- (if (null? (cddr c2))
- (list 'or (car c1) (cadr c2))
- (list 'or (car c1) (cons 'begin (cdr c2)))))))))
+ (list 'or (car c1)
+ (if (null? (cddr c2))
+ (cadr c2)
+ (cons 'begin (cdr c2)))))))))
(and (boolean? (cadr c2))
(null? (cddr c2))
(not (equal? (cadr c1) (cadr c2)))
@@ -12710,7 +12743,7 @@
(if (equal? eqv-select (cadr p))
(values (caddr p) (other-case (caddr p)))
(values (cadr p) (other-case (cadr p)))))
- (else (error "oops"))))
+ (else (error 'wrong-type-arg "oops"))))
(cdr test))
exprs))))
@@ -12911,30 +12944,34 @@
(let ((inner-name (cadr inner))
(inner-args (caddr inner))
(inner-body (cdddr inner)))
+ (when (pair? inner-body)
(do ((p outer-args (cdr p))
(a inner-args (cdr a)))
((or (null? p)
(not (pair? a))
(not (pair? (car a)))
+ (pair? (caar a))
(and (not (eq? (car p) (caar a)))
(tree-memq (car p) inner-body)))
;; args can be reversed, but rarely match as symbols
(when (and (null? p)
(or (null? a)
(and (null? (cdr a))
+ (pair? (cdar a))
(code-constant? (cadar a)))))
- (let* ((args-match (do ((p outer-args (cdr p))
- (a inner-args (cdr a)))
- ((or (null? p)
- (not (eq? (car p) (caar a)))
- (not (eq? (caar a) (cadar a))))
- (null? p))))
+ (let* ((args-match (do ((p1 outer-args (cdr p1))
+ (a1 inner-args (cdr a1)))
+ ((or (null? p1)
+ (null? (cdar a1))
+ (not (eq? (car p1) (caar a1)))
+ (not (eq? (caar a1) (cadar a1))))
+ (null? p1))))
(args-aligned (and (not args-match)
- (do ((p outer-args (cdr p))
- (a inner-args (cdr a)))
- ((or (null? p)
- (not (eq? (car p) (cadar a))))
- (null? p))))))
+ (do ((p1 outer-args (cdr p1))
+ (a1 inner-args (cdr a1)))
+ ((or (null? p1)
+ (not (eq? (car p1) (cadar a1))))
+ (null? p1))))))
(when (or args-match args-aligned)
(let ((definer (if (null? a) 'define 'define*))
(extras (if (and (pair? a)
@@ -12955,7 +12992,7 @@
(reverse result))
(set! result (cons (caar a) result))))
,@extras)
- ,@(tree-subst outer-name inner-name inner-body)))))))))))))
+ ,@(tree-subst outer-name inner-name inner-body))))))))))))))
(define (set!? form env)
(and *report-any-!-as-setter* ; (inc! x) when inc! is unknown, assume it sets x
@@ -12982,42 +13019,43 @@
(define (check-definee caller sym form env)
- (cond ((keyword? sym) ; (define :x 1)
- (lint-format "keywords are constants ~A" caller sym))
-
- ((and (eq? sym 'pi) ; (define pi (atan 0 -1))
- (member (caddr form) '((atan 0 -1)
- (acos -1)
- (* 2 (acos 0))
- (* 4 (atan 1))
- (* 4 (atan 1 1)))))
- (lint-format "~A is one of its many names, but pi is a predefined constant in s7" caller (caddr form)))
-
- ((constant? sym) ; (define most-positive-fixnum 432)
- (lint-format "~A is a constant in s7: ~A" caller sym form))
-
- ((eq? sym 'quote)
- (lint-format "either a stray quote, or a real bad idea: ~A" caller (truncated-list->string form)))
-
- ((pair? sym)
- (check-definee caller (car sym) form env))
-
- ((let ((v (var-member sym env)))
- (and (var? v)
- (eq? (var-definer v) 'define-constant)
- (len>2? form)
- (not (equal? (caddr form) (var-initial-value v)))
- v))
- => (lambda (v)
- (let ((line (if (and (pair? (var-initial-value v))
- (positive? (pair-line-number (var-initial-value v))))
- (format #f "(line ~D): " (pair-line-number (var-initial-value v)))
- "")))
- (lint-format "~A in ~A is already a constant, defined ~A~A" caller sym
- (truncated-list->string form)
- line
- (truncated-list->string (var-initial-value v))))))))
-
+ (when (pair? (cddr form))
+ (cond ((keyword? sym) ; (define :x 1)
+ (lint-format "keywords are constants ~A" caller sym))
+
+ ((and (eq? sym 'pi) ; (define pi (atan 0 -1))
+ (member (caddr form) '((atan 0 -1)
+ (acos -1)
+ (* 2 (acos 0))
+ (* 4 (atan 1))
+ (* 4 (atan 1 1)))))
+ (lint-format "~A is one of its many names, but pi is a predefined constant in s7" caller (caddr form)))
+
+ ((constant? sym) ; (define most-positive-fixnum 432)
+ (lint-format "~A is a constant in s7: ~A" caller sym form))
+
+ ((eq? sym 'quote)
+ (lint-format "either a stray quote, or a real bad idea: ~A" caller (truncated-list->string form)))
+
+ ((pair? sym)
+ (check-definee caller (car sym) form env))
+
+ ((let ((v (var-member sym env)))
+ (and (var? v)
+ (eq? (var-definer v) 'define-constant)
+ (len>2? form)
+ (not (equal? (caddr form) (var-initial-value v)))
+ v))
+ => (lambda (v)
+ (let ((line (if (and (pair? (var-initial-value v))
+ (positive? (pair-line-number (var-initial-value v))))
+ (format #f "(line ~D): " (pair-line-number (var-initial-value v)))
+ "")))
+ (lint-format "~A in ~A is already a constant, defined ~A~A" caller sym
+ (truncated-list->string form)
+ line
+ (truncated-list->string (var-initial-value v)))))))))
+
(define binders (let ((h (make-hash-table)))
(for-each
(lambda (op)
@@ -13417,7 +13455,7 @@
(hash-walker op define-walker))
'(define define* define-constant
define-macro define-macro* define-bacro define-bacro* define-expansion
- definstrument defanimal define-envelope ; for clm
+ definstrument define-animal define-envelope ; for clm
define-public define*-public defmacro-public define-inlinable
define-integrable define^))) ; these give more informative names in Guile and scmutils (MIT-scheme))
@@ -13566,7 +13604,13 @@
(begin
(if (memq (car settee) '(vector-ref list-ref string-ref hash-table-ref))
;; (set! (vector-ref v 0) 3)
- (lint-format "~A as target of set!~A" caller (car settee) (truncated-list->string form)))
+ (lint-format "~A as target of set!~A" caller (car settee) (truncated-list->string form))
+ (if (and (eq? (car settee) 'symbol-access)
+ (len>1? setval)
+ (eq? (car setval) 'lambda)
+ (list? (cadr setval))
+ (not (= (length (cadr setval)) 2)))
+ (lint-format "symbol-access function should take 2 arguments: ~A" caller (truncated-list->string form))))
(lint-walk caller settee env) ; this counts as a reference since it's by reference so to speak
;; try type check (dilambda signatures)
@@ -13614,6 +13658,7 @@
((cond) ; (set! x (cond (z w) (else x))) -> (if z (set! x w)) -- this never happens
(if (and (= (length setval) 3)
+ (pair? (caddr setval))
(memq (caaddr setval) '(#t else))
(null? (cddr (caddr setval)))
(null? (cddadr setval)))
@@ -13786,9 +13831,10 @@
;; (if x (f y) (g y)) -> ((if x f g) y)
;; but f and g can't be or/and unless there are no expressions
;; I now like all of these -- originally found them odd: CL influence!
- (if (equal? true-op test)
- `((or ,test ,false-op) ,@true-rest)
- `((if ,test ,true-op ,false-op) ,@true-rest)))
+ (cons (if (equal? true-op test)
+ (list 'or test false-op)
+ (list 'if test true-op false-op))
+ true-rest))
((and (eq? (caadr diff) #t)
(not (cadadr diff)))
@@ -13882,9 +13928,9 @@
;; (if A (+ B B E C) (+ D D E C)) -> (+ (if A (+ B B) (+ D D)) E C)
(lint-format "perhaps ~A" caller
(lists->string form
- `(,true-op
- (if ,expr ,tp ,tq)
- ,@(car headdiff)))))))))))))))
+ (cons true-op
+ (cons (list 'if expr tp tq)
+ (car headdiff))))))))))))))))
;; (when (and (pair? true)...)
;; end tree-subst section
@@ -13966,7 +14012,7 @@
(if (pair? (car false))
(list (list (caar false) '...))
(list (car false) '...)))))))
- (lists->string form `(cond (,nexpr ,@nfalse) ,@true-rest)))))
+ (lists->string form (cons 'cond (cons (cons nexpr nfalse) true-rest))))))
;; true-op = case happens a lot, but never in a way that (not expr)->false can be combined in the case
@@ -14000,8 +14046,8 @@
(lists->string form
(simplify-boolean
(if (not false)
- `(and ,expr (not ,true-test) ,true-false)
- `(if (and ,expr (not ,true-test)) ,true-false ,false))
+ (list 'and expr (list 'not true-test) true-false)
+ (list 'if (list 'and expr (list 'not true-test)) true-false false))
() () env)))))
;; (if a (if b d e) (if c d e)) -> (if (if a b c) d e)? reversed does not happen.
@@ -14052,7 +14098,7 @@
(case false-op
((cond) ; (if a A (cond...)) -> (cond (a A) ...)
(when (proper-list? false-rest)
- (lint-format "perhaps ~A" caller (lists->string form `(cond (,expr ,true) ,@false-rest)))))
+ (lint-format "perhaps ~A" caller (lists->string form (cons 'cond (cons (list expr true) false-rest))))))
((if)
@@ -14153,7 +14199,7 @@
(if (pair? false)
(let ((false-test (and (pair? false-rest) (car false-rest))))
(if (and (eq? false-op 'if) ; (if x 3 (if (not x) 4)) -> (if x 3 4)
- (len>1? false-rest)
+ (> (or (length false-rest) 0) 1) ; proper-list and len>1?
(not (side-effect? test env)))
(if (or (equal? test false-test)
(equal? expr false-test))
@@ -14192,7 +14238,7 @@
(member setval test)) ; that's all there's room for
(let ((f (if (equal? settee (if (memq test-op '(< <=)) rel-arg1 rel-arg2)) 'max 'min)))
(lint-format "perhaps ~A" caller
- (lists->string form `(set! ,settee (,f ,@true-rest)))))))))
+ (lists->string form (list 'set! settee (cons f true-rest)))))))))
;; (if (<= (list-ref ind i) 32) (list-set! ind i 32)) -> (list-set! ind i (max (list-ref ind i) 32))
((list-set! vector-set!)
@@ -14212,7 +14258,7 @@
(if (memq test-op '(< <=)) 'max 'min)))))
(if mx-op
(lint-format "perhaps ~A" caller
- (lists->string form `(,true-op ,settee ,index (,mx-op ,@(cdr test)))))))))))))))
+ (lists->string form (list true-op settee index (cons mx-op (cdr test)))))))))))))))
(cond ((not (pair? true-rest)))
((not (eq? (car true) 'if)) ; (if test0 (if test1 expr)) -> (if (and test0 test1) expr)
@@ -14248,6 +14294,7 @@
(let ((f (if (equal? (cadr test) (if (memq (car test) '(< <=)) true false))
'min 'max)))
(lint-format "perhaps ~A" caller (lists->string form (list f true false))))))
+ ;; no hits for negative?/positive? and 0/0.0 here
(cond ((eq? expr #t) ; (if #t #f) -> #f
(lint-format "perhaps ~A" caller (lists->string form true)))
@@ -14284,10 +14331,11 @@
;; (if x y #t) -> (or (not x) y)
(lint-format "perhaps ~A" caller
(let ((nexpr (if false
- (if (and (len>1? expr)
- (eq? (car expr) 'not))
- (list 'or (cadr expr) true)
- (list 'or (list 'not expr) true))
+ (list 'or (if (and (len>1? expr)
+ (eq? (car expr) 'not))
+ (cadr expr)
+ (list 'not expr))
+ true)
(list 'and expr true))))
(lists->string form (simplify-boolean nexpr () () env)))))))
((= len 4)
@@ -14570,7 +14618,7 @@
(lists->string form
(if (not (or (side-effect? expr env)
(tree-set-member (map car sv) expr)))
- `(let ,(reverse sv) (if ,expr ,ntv ,nfv))
+ (list 'let (reverse sv) (list 'if expr ntv nfv))
(let ((uniq (find-unique-name form)))
`(let ((,uniq ,expr))
(let ,(reverse sv)
@@ -14594,7 +14642,7 @@
(eq? (car expr) 'not))
(cons 'unless (cons (cadr expr) (unbegin true)))
(cons 'when (cons expr (unbegin true)))))))
-
+
(if (symbol? expr)
(set-ref expr caller form env)
(lint-walk caller expr env))
@@ -14624,9 +14672,9 @@
(lint-format "perhaps ~A"
caller
(truncated-lists->string form
- `(,(if (eq? head 'when) 'unless 'when)
- ,(cadr test)
- ,@(cddr form)))))
+ (cons (if (eq? head 'when) 'unless 'when)
+ (cons (cadr test)
+ (cddr form))))))
(if (never-false test)
(lint-format "~A test is never false: ~A" caller head (truncated-list->string form))
(if (never-true test) ; (unless #f...)
@@ -14679,10 +14727,10 @@
(cadr form))
#f)
,@(cdr body))))
- (when (or (and (memq (car body) '(when unless))
- (len>1? body))
- (and (eq? (car body) 'if)
- (len=3? body)))
+ (when (case (car body)
+ ((when unless) (len>1? body))
+ ((if) (len=3? body))
+ (else #f))
(let ((new-test (let ((inner-test (if (eq? (car body) 'unless)
(list 'not (cadr body))
(cadr body)))
@@ -14797,7 +14845,7 @@
(cdr form))))
;; (cond ((< x 1) (+ x 1)) ((< y 1) (+ x 3)) (else (+ x 2))) -> (+ x (cond ((< x 1) 1) ((< y 1) 3) (else 2)))
(lint-format "perhaps ~A" caller
- (lists->string form `(,@header (cond ,@middle) ,@trailer))))))))
+ (lists->string form (append header (list (cons 'cond middle)) trailer))))))))
(partition-form (cdr form) (if else-error (- len 1) len)))))
;; not escaping else here because the trailing args might be evaluated first
@@ -14814,20 +14862,20 @@
;; (cond (X (f y z)) (Y (f y z)) (Z (f y z))) -> (if (or X Y Z) (f y z))
(lint-format "perhaps ~A" caller
(lists->string form
- `(if (or ,@(map car (cdr form)))
- ,first-result)))
+ (list 'if (cons 'or (map car (cdr form))) first-result)))
;; here we need an else clause else (apply #<unspecified> args)
(if (memq (car else-clause) '(#t else))
;; (cond (X (f y z)) (else (g y z))) -> ((cond (X f) (else g)) y z)
(lint-format "perhaps ~A" caller
(lists->string form
- `((cond ,@(map (lambda (c)
- (list (car c) (caadr c)))
- (cdr form)))
- ,@(cdr first-result))))))))))))
+ (cons (cons 'cond (map (lambda (c)
+ (list (car c) (caadr c)))
+ (cdr form)))
+ (cdr first-result))))))))))))
;; ----------------
(let ((falses ())
- (trues ()))
+ (trues ())
+ (prev-bool #f))
(for-each
(lambda (clause)
(set! ctr (+ ctr 1))
@@ -14835,7 +14883,8 @@
(begin
(set! all-eqv #f)
(set! has-combinations #f)
- ;; ; (cond 1)
+ (set! prev-bool #f)
+ ;; (cond 1)
(lint-format "cond clause ~A in ~A is not a pair?" caller clause (truncated-list->string form)))
(begin
@@ -14846,6 +14895,25 @@
(not (and (pair? (cdr clause))
(eq? (cadr clause) '=>))) ; case sends selector, but cond sends test result
(cond-eqv? (car clause) eqv-select #t))))
+
+ ;; look for successive clause tests where the earlier includes the current (number? followed by integer? etc)
+ ;; slightly sloppy I guess -- the arg could be self-modifying!
+ (if (and (pair? clause)
+ (len>1? (car clause))
+ (hash-table-ref bools (caar clause)))
+ (begin
+ (if (and prev-bool
+ (equal? (cadar prev-clause) (cadar clause)) ; args match
+ (subsumes? prev-bool (caar clause))) ; previous test already included this case
+ (lint-format "~A makes ~A pointless in ~A~A~%" caller
+ (car prev-clause)
+ (car clause)
+ (truncated-list->string form)
+ (if (eq? prev-bool 'list?)
+ (format #f "~%~NC(r5rs list? is proper-list? in s7)" (+ lint-left-margin 4) #\space)
+ "")))
+ (set! prev-bool (caar clause)))
+ (set! prev-bool #f))
(if (and (pair? prev-clause)
(not has-combinations)
@@ -14919,7 +14987,7 @@
(else ,@(unbegin (cadddr first-sequel))))))))))
((when unless)
;; (cond (a A) (else (when b B)))
- (when (len>1? (cdr first-sequel))
+ (when (> (length first-sequel) 2)
(lint-format "else clause could be folded into the outer cond: ~A" caller
(lists->string form
(append (copy form (make-list ctr))
@@ -15090,7 +15158,7 @@
(cond ((equal? (simplify-boolean (car c1) () () env)
(simplify-boolean (list 'not (car c2)) () () env))
(lint-format "perhaps ~A" caller ; (cond ((x) y) ((not (x)) z)) -> (cond ((x) y) (else z))
- (lists->string form `(cond ,c1 (else ,@(cdr c2))))))
+ (lists->string form (list 'cond c1 (cons 'else (cdr c2))))))
((and (pair? (cdr c2))
(not (pair? (cadr c2)))
(not (memq (car c2) '(else #t)))
@@ -15365,9 +15433,9 @@
(lint-format "perhaps ~A" caller
(lists->string form
(let ((not-reps
- (simplify-boolean (if (null? (cdr reps))
- (list 'not (car reps))
- (list 'not (cons 'and reps)))
+ (simplify-boolean (list 'not (if (null? (cdr reps))
+ (car reps)
+ (cons 'and reps)))
() () env)))
`(,@(copy form (make-list head-len))
(,not-reps
@@ -15411,7 +15479,7 @@
(if (and (pair? (car clause))
(eq? (caar clause) 'not))
(cons 'unless (append (cdar clause) (cdr clause)))
- (cons 'when (cons (car clause) (cdr clause))))))))))
+ (cons 'when clause))))))))
(when has-else ; len > 1 here
(let ((last-clause (list-ref form (- len 1)))) ; not the else branch! -- just before it.
@@ -15534,10 +15602,10 @@
((eq? (car a) #t)
(if (not (car b))
nexpr
- (simplify-boolean `(or ,nexpr ,(car b)) () () env)))
+ (simplify-boolean (list 'or nexpr (car b)) () () env)))
((car a) ; i.e a is not #f
- `(if ,nexpr ,(car a) ,(car b)))
+ (list 'if nexpr (car a) (car b)))
((eq? (car b) #t)
(simplify-boolean (list 'not nexpr) () () env))
@@ -15570,11 +15638,13 @@
;; (cond ((and A B) c) (B d) (else e)) -> (cond (B (if A c d)) (else e))
(lint-format "perhaps ~A" caller
(lists->string form
- `(cond (,(car arg2)
- (if ,((if (equal? (car arg2) (cadar arg1)) caddar cadar) arg1)
- ,(cadr arg1)
- ,(cadr arg2)))
- ,@(cdddr form))))))
+ (cons 'cond
+ (cons (list (car arg2)
+ (list 'if
+ ((if (equal? (car arg2) (cadar arg1)) caddar cadar) arg1)
+ (cadr arg1)
+ (cadr arg2)))
+ (cdddr form)))))))
(if (and (len=1? last-clause) ; (cond ... ((or ...)) (else ...)) -> (cond ... (else (or ... ...)))
(pair? (car last-clause))
@@ -15665,6 +15735,9 @@
(selector (cadr form))
(suggest made-suggestion))
+ ;(let ((leaves (tree-leaves form)) (branches (length (cddr form))))
+ ; (if (> leaves 100) (format *stderr* "case: ~A in ~A: ~A~%" leaves branches (/ (* 1.0 leaves) branches))))
+
;; ----------------
;; if regular case + else -- just like cond above
(let ((len (- (length form) 2))) ; number of clauses
@@ -15750,7 +15823,7 @@
(middle (if (len=1? (car first-clause))
(list 'eqv? (cadr form) (caar first-clause))
`(memv ,(cadr form) ',(car first-clause)))))
- (lists->string form `(,@header (if ,middle ,fmid ,emid) ,@trailer)))))))
+ (lists->string form (append header (cons (list 'if middle fmid emid) trailer))))))))
;; len > 2 so use case in the revision
(let ((middle (map (lambda (c)
(if (and else-error
@@ -15966,13 +16039,28 @@
;; else-foldable as (((keys-from-test) true-branch) (else false-branch))
(set! else-foldable
(if (pair? (cdddr expr))
- `(,(case-branch (cadr expr) selector (list (caddr expr)))
- (else ,(cadddr expr)))
+ (list (case-branch (cadr expr) selector (list (caddr expr)))
+ (list 'else (cadddr expr)))
(list (case-branch (cadr expr) selector (cddr expr))))))))))))))
(lint-walk-open-body caller (car form) exprs env))))
(cddr form))
+ (let ((key-phrase
+ (let ((keylen (length all-keys)))
+ (cond ((< keylen 20))
+ ((every? char? all-keys)
+ "vector (indexed by char->integer)")
+ ((every? (lambda (k) (and (integer? k) (<= 0 k 1000))) all-keys)
+ "vector")
+ ((> keylen 40)
+ "hash-table")))))
+ (when (string? key-phrase)
+ (lint-format "perhaps use a ~A rather than a case statement:~%~NC~A" caller
+ key-phrase
+ (+ lint-left-margin 4) #\space
+ (truncated-list->string form))))
+
(if (and has-else
(pair? result)
(not else-foldable))
@@ -16005,8 +16093,8 @@
(when (len>1? clause) ; ignore clauses that are messed up
(let ((keys (car clause))
(exprs (cdr clause)))
- (when (and (not (eq? keys 'else))
- (not (equal? exprs else-exprs)))
+ (unless (or (eq? keys 'else)
+ (equal? exprs else-exprs))
(let ((prev (member exprs new-keys-and-exprs (lambda (a b) (equal? a (cdr b))))))
(if prev
(let* ((cur-clause (car prev))
@@ -16373,7 +16461,7 @@
;; do -> for-each
(when (len=1? step-vars)
(let ((var (car step-vars)))
- (when (and (len>1? (cdr var))
+ (when (and (len>2? var)
(len>1? (caddr var))
(len=1? (caddr form))
(pair? (caaddr form))
@@ -16660,16 +16748,17 @@
(lint-format "perhaps ~A" caller
(lists->string form
(if (eq? vname (cadadr p))
- (if (and (pair? (cddr p))
- (len>1? (caddr p))
- (memq (caaddr p) '(else #t t)))
- (if (null? (cddr (caddr p)))
- (list 'or vvalue (cadr (caddr p)))
- (list 'or vvalue (cons 'begin (cdaddr p))))
- (list 'or vvalue
- (cons 'cond (cddr p))))
- `(cond (,vvalue => ,(caadr (cadr p)))
- ,@(cddr p))))))
+ (list 'or vvalue
+ (if (and (pair? (cddr p))
+ (len>1? (caddr p))
+ (memq (caaddr p) '(else #t t)))
+ (if (null? (cddr (caddr p)))
+ (cadr (caddr p))
+ (cons 'begin (cdaddr p)))
+ (cons 'cond (cddr p))))
+ (cons 'cond
+ (cons (list vvalue '=> (caadr (cadr p)))
+ (cddr p)))))))
(when (and (null? (cddr p)) ; (let ((x (+ y 1))) (abs x)) -> (abs (+ y 1))
(eq? vname (cadr p))) ; not tree-subst or trailing (pair) args: the let might be forcing evaluation order
@@ -16702,13 +16791,15 @@
(len=2? if-false)
(eq? vname (cadr if-false)))
(let ((else-clause (if (eq? if-true vname)
- `((else #f))
+ (list (list 'else #f))
(if (and (pair? if-true)
(tree-unquoted-member vname if-true))
:oops! ; if the let var appears in the else portion, we can't do anything with =>
- `((else ,if-true))))))
+ (list (list 'else if-true))))))
(unless (eq? else-clause :oops!)
- (lint-format "perhaps ~A" caller (lists->string form `(cond (,vvalue => ,(car if-false)) ,@else-clause))))))))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (cons 'cond (cons (list vvalue '=> (car if-false)) else-clause)))))))))
(let ((crf #f))
;; all this stuff still misses (cond ((not x)...)) and (set! y (if x (cdr x)...)) i.e. need embedding in this case
@@ -16718,14 +16809,24 @@
(equal? (cadr p) (list 'not vname)))
(and (pair? vvalue)
(memq (car vvalue) '(assoc assv assq member memv memq))
- (pair? (cadr p))
+ (len>1? (cadr p)) ; (let ((x (memq z y))) (if (pair? x) (g x))) -> (cond ((memq z y) => g))
(or (eq? (caadr p) 'pair?)
+ (and (eq? (caadr p) 'list?)
+ (lint-format "in ~A, ~A can't be null so pair? might be better" caller p vname)
+ #t)
(and (eq? (caadr p) 'null?)
;; (let ((x (assoc y z))) (if (null? x) (g x)))
(lint-format "in ~A, ~A can't be null because ~A in ~A only returns #f or a pair"
caller p vname (car vvalue) (truncated-list->string (car varlist)))
#f))
- (eq? (cadadr p) vname)))
+ (eq? (cadadr p) vname))
+ (and (memq (car vvalue) '(char-position string-position string->number length arity)) ; length|arity only in s7
+ (or (eq? (cadr p) vname)
+ (and (len>1? (cadr p))
+ (or (memq (caadr p) '(number? complex?))
+ (and (not (eq? (car vvalue) 'string->number))
+ (eq? (caadr p) 'integer?)))
+ (eq? (cadadr p) vname)))))
(or (and (len=2? (caddr p)) ; one func arg
(or (eq? vname (cadr (caddr p)))
@@ -16751,11 +16852,11 @@
(null? (cdddr p))))
(let ((else-clause (if (pair? (cdddr p))
(if (eq? (cadddr p) vname)
- `((else #f)) ; this stands in for the local var
+ (list (list 'else #f)) ; this stands in for the local var
(if (and (pair? (cadddr p))
(tree-unquoted-member vname (cadddr p)))
:oops! ; if the let var appears in the else portion, we can't do anything with =>
- `((else ,(cadddr p)))))
+ (list (list 'else (cadddr p)))))
(case (car p)
((and) '((else #f)))
((or) '((else #t)))
@@ -16763,7 +16864,9 @@
(unless (eq? else-clause :oops!)
;; (let ((x (assoc y z))) (if x (cdr x))) -> (cond ((assoc y z) => cdr))
(lint-format "perhaps ~A" caller
- (lists->string form `(cond (,vvalue => ,(or crf (caaddr p))) ,@else-clause))))))))
+ (lists->string form (cons 'cond
+ (cons (list vvalue '=> (or crf (caaddr p)))
+ else-clause)))))))))
)) ; one var in varlist
@@ -16807,57 +16910,66 @@
((cond)
;; happens about a dozen times
(let ((vars (map car (cadr form))))
- (if (tree-set-member vars (cdar body))
- (call-with-exit
- (lambda (quit)
- (let ((branch-let #f))
- (for-each (lambda (c)
- (if (and (not branch-let)
- (pair? c)
- (side-effect? (car c) env))
- (quit))
- (when (and (pair? c)
- (tree-set-member vars c))
- (if branch-let (quit))
- (set! branch-let c)))
- (cdar body))
- (if (and branch-let
+ (when (tree-set-member vars (cdar body))
+ (call-with-exit
+ (lambda (quit)
+ (let ((branch-let #f))
+ (for-each (lambda (c)
+ (if (and (not branch-let)
+ (pair? c)
+ (side-effect? (car c) env))
+ (quit))
+ (when (and (pair? c)
+ (tree-set-member vars c))
+ (if branch-let (quit))
+ (set! branch-let c)))
+ (cdar body))
+ (when (and branch-let
(not (memq (car branch-let) vars))
(not (tree-set-member vars (car branch-let))))
- (lint-format "perhaps move the let into the '~A branch: ~A" caller
- (truncated-list->string branch-let)
- (lists->string form
+ (lint-format "perhaps move the let into the '~A branch: ~A" caller
+ (truncated-list->string branch-let)
+ (lists->string form
+ (if (eq? '=> (cadr branch-let))
+ (if (eq? branch-let (cadar body))
+ `(cond (,(car branch-let) => (let ,(cadr form) ,@(cddr branch-let))) ...)
+ `(cond ... (,(car branch-let) => (let ,(cadr form) ,@(cddr branch-let))) ...))
(if (eq? branch-let (cadar body))
`(cond (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...)
- `(cond ... (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...)))))))))))
+ `(cond ... (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...))))))))))))
((case)
(let ((vars (map car (cadr form)))
(test (cadar body)))
- (if (and (not (memq test vars))
- (not (tree-set-member vars test))
- (tree-set-member vars (cddar body)))
- (call-with-exit
- (lambda (quit)
- (let ((branch-let #f))
- (for-each (lambda (c)
- (when (and (pair? c)
- (tree-set-member vars (cdr c)))
- (if branch-let (quit))
- (set! branch-let c)))
- (cddar body))
- (if (proper-list? branch-let)
- (lint-format "perhaps move the let into the '~A branch: ~A" caller
- (truncated-list->string branch-let)
- (lists->string form
+ (when (and (not (memq test vars))
+ (not (tree-set-member vars test))
+ (tree-set-member vars (cddar body)))
+ (call-with-exit
+ (lambda (quit)
+ (let ((branch-let #f))
+ (for-each (lambda (c)
+ (when (and (pair? c)
+ (tree-set-member vars (cdr c)))
+ (if branch-let (quit))
+ (set! branch-let c)))
+ (cddar body))
+ (when (proper-list? branch-let)
+ (lint-format "perhaps move the let into the '~A branch: ~A" caller
+ (truncated-list->string branch-let)
+ (lists->string form
+ (if (eq? '=> (cadr branch-let))
+ (if (eq? branch-let (caddar body))
+ `(case ,test (,(car branch-let) => (let ,(cadr form) ,@(cddr branch-let))) ...)
+ `(case ,test ... (,(car branch-let) => (let ,(cadr form) ,@(cddr branch-let))) ...))
(if (eq? branch-let (caddar body))
`(case ,test (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...)
- `(case ,test ... (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...)))))))))))
+ `(case ,test ... (,(car branch-let) (let ,(cadr form) ,@(cdr branch-let))) ...))))))))))))
((when unless) ; no hits -- maybe someday?
(let ((test (cadar body))
(vars (map car (cadr form))))
(unless (or (memq test vars)
(tree-set-member vars test)
- (side-effect? test env))
+ (side-effect? test env)
+ (not (proper-list? (cddar body))))
(lint-format "perhaps move the let inside the ~A: ~A" caller
(caar body)
(truncated-lists->string form `(,(caar body) ,test (let ,(cadr form) ,@(cddar body))))))))))
@@ -16868,9 +16980,10 @@
(when (and (= suggest made-suggestion)
(not named-let)
(< (length varlist) 8)
+ (every? pair? varlist)
(not (memq (caar body) '(lambda lambda* define define* define-macro)))
(not (and (eq? (caar body) 'set!)
- (any? (lambda (v) (eq? (car v) (cadar body))) varlist)))
+ (any? (lambda (v) (and (eq? (car v) (cadar body)))) varlist)))
(not (any-macro? (caar body) env))
(not (any? (lambda (p)
(and (unquoted-pair? p)
@@ -16902,14 +17015,12 @@
caller (lists->string form new-body))))
) ; null cdr body etc
- (when (and (pair? (cadr form)) ; (let ((x x)) (+ x 1)) -> (+ x 1), (let ((x x))...) does not copy x if x is a sequence
- (= suggest made-suggestion)
+ (when (and (pair? (cadr form)) ; (let ((x x)) (+ x 1)) -> (+ x 1), (let ((x x))...) does not copy x if x is a sequence
+ (= suggest made-suggestion) ; used to check for returned lambda here, but that doesn't matter
(every? (lambda (c)
(and (len>1? c) ; the usual... (let binding might be messed up)
(eq? (car c) (cadr c))))
- (cadr form))
- (not (and (pair? (caddr form))
- (memq (caaddr form) '(lambda lambda*)))))
+ (cadr form)))
(let ((vs (map car (cadr form))))
(unless (any? (lambda (p)
(and (pair? p)
@@ -17022,17 +17133,18 @@
;; the pattern (set! x y) ... (set! y x) happens a few times (say 5 to 10)
(lint-format "perhaps use let-temporarily here: ~A" caller
(lists->string form
- (let ((new-let `(let-temporarily
- ((,saved-name ,(if (pair? first-pos)
- (caddar first-pos)
- saved-name)))
- ,@(map (lambda (expr)
- (if (or (and (pair? first-pos)
- (eq? expr (car first-pos)))
- (eq? expr (car last-pos)))
- (values)
- expr))
- body))))
+ (let ((new-let (cons 'let-temporarily
+ (cons (list (list saved-name
+ (if (pair? first-pos)
+ (caddar first-pos)
+ saved-name)))
+ (map (lambda (expr)
+ (if (or (and (pair? first-pos)
+ (eq? expr (car first-pos)))
+ (eq? expr (car last-pos)))
+ (values)
+ expr))
+ body)))))
(if (null? (cdr vars)) ; we know vars is a pair, want len=1
new-let
(list 'let (map (lambda (v)
@@ -17130,14 +17242,15 @@
setval
(list 'let (map (lambda (v) (if (eq? (car v) settee) (values) v)) varlist)
setval))
- `(let ,(map (lambda (v)
- (if (eq? (car v) settee) ; (let ((x 0)) (set! x 1)...) -> (let ((x 1)) ...)
- (list (car v) setval) ; replace initial with set! value
- v))
- varlist)
- ,@(if (null? (cddr body))
- (cdr body)
- (list (cadr body) '...)))))))
+ (cons 'let
+ (cons (map (lambda (v)
+ (if (eq? (car v) settee) ; (let ((x 0)) (set! x 1)...) -> (let ((x 1)) ...)
+ (list (car v) setval) ; replace initial with set! value
+ v))
+ varlist)
+ (if (null? (cddr body))
+ (cdr body)
+ (list (cadr body) '...))))))))
;; repetition for the moment
(when (and (pair? varlist)
(assq settee vars) ; settee is a local var
@@ -17300,17 +17413,18 @@
varlist))
;; (let ((xx 0)) (do ((x 1 (+ x 1)) (y x (- y 1))) ((= x 3) xx) (display y))) ->
;; (do ((xx 0) (x 1 (+ x 1)) (y x (- y 1))) ...)
- (lint-format "perhaps ~A" caller
- (lists->string form
- (let ((do-form (cdar body)))
- (if (null? (cdr body)) ; do is only expr in let
- (list 'do (append varlist (car do-form))
- '...)
- `(do ,(append varlist (car do-form))
- (,(and (pair? (cadr do-form)) (caadr do-form))
- ,@(if (side-effect? (cdadr do-form) env) (cdadr do-form) ())
- ,@(cdr body)) ; include rest of let as do return value
- ...)))))))))
+ (let ((do-form (cdar body)))
+ (if (pair? do-form)
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (if (null? (cdr body)) ; do is only expr in let
+ (list 'do (append varlist (car do-form))
+ '...)
+ `(do ,(append varlist (car do-form))
+ (,(and (pair? (cadr do-form)) (caadr do-form))
+ ,@(if (side-effect? (cdadr do-form) env) (cdadr do-form) ())
+ ,@(cdr body)) ; include rest of let as do return value
+ ...))))))))))
(when (and (> (length body) 3) ; setting this to 1 did not catch anything new
(every? pair? varlist)
@@ -17471,7 +17585,9 @@
;; (let ((x 1) (y (f g 2))) (let loop ((a (+ x 1)) (b y)) (loop a b))) -> (let loop ((a (+ 1 1)) (b (f g 2))) (loop a b))
(lint-format "perhaps ~A" caller
(lists->string form
- `(let ,inner-vars ,new-args ,@named-body)))))))
+ (cons 'let
+ (cons inner-vars
+ (cons new-args named-body)))))))))
;; maybe more code than this is worth -- combine lets
(when (and (memq (car inner) '(let let*))
@@ -17585,6 +17701,7 @@
(pair? body)
(pair? (car body))
(eq? (caar body) 'do)
+ (len>2? (car body))
(< (tree-leaves (cdr body)) *max-cdr-len*))
(let ((inits (if (pair? (cadar body))
(map cadr (cadar body))
@@ -17969,7 +18086,9 @@
(lint-format "perhaps ~A" caller
(case varlist-len
((1) (lists->string form
- `(cond (,(cadr last-var) => ,(caaddr p)) ,@else-clause)))
+ (cons 'cond
+ (cons (list (cadr last-var) '=> (caaddr p))
+ else-clause))))
((2) (lists->string form
`(let (,(car varlist))
(cond (,(cadr last-var) => ,(caaddr p)) ,@else-clause))))
@@ -18432,9 +18551,9 @@
;; (call-with-input-file "file" (lambda (p) (read-char p))) -> (call-with-input-file "file" read-char)
(lint-format "perhaps ~A" caller
(lists->string form
- (if (= len 2)
- (list head (caar body))
- (list head (cadr form) (caar body)))))
+ (list head (if (= len 2)
+ (caar body)
+ (values (cadr form) (caar body))))))
(let ((cc (make-var :name port
:initial-value (list (case head
((call-with-input-string) 'open-input-string)
@@ -18585,12 +18704,12 @@
(lint-walk-body caller (caadr form) (cddr form) new-env))))))
(hash-walker 'let-syntax (lambda (caller form env)
- (lint-walk-body caller 'define-method (cddr form) env)
- env))
+ (lint-walk-body caller 'define-method (cddr form) env)
+ env))
(hash-walker 'letrec-syntax (lambda (caller form env)
- (lint-walk-body caller 'define-method (cddr form) env)
- env))
+ (lint-walk-body caller 'define-method (cddr form) env)
+ env))
;; ---------------- case-lambda ----------------
(let ()
@@ -18627,9 +18746,9 @@
(lint-format "perhaps ~A" caller
(lists->string form
(if doc-string
- `(let ((documentation ,doc-string))
- (lambda ,(caar body) ,@(cdar body)))
- (cons 'lambda (cons (caar body) (cdar body)))))))
+ (list 'let (list (list 'documentation doc-string))
+ (cons 'lambda (car body)))
+ (cons 'lambda (car body))))))
((2)
(when (let arglists-equal? ((args1 (caar body))
(args2 (caadr body)))
@@ -18786,10 +18905,11 @@
(set! lvars (sort! lvars (lambda (a b) (< (caddr a) (caddr b)))))
(if named-let
- `(,(car tree) ,(cadr (assq (cadr tree) lvars))
+ `(,(car tree) ,(cadr (assq (cadr tree) lvars))
,(map (lambda (v) (list (cadr v) (cadddr v))) (cdr lvars))
,@new-body)
- `(,(car tree) ,(map (lambda (v) (list (cadr v) (cadddr v))) lvars)
+ `(,(car tree)
+ ,(map (lambda (v) (list (cadr v) (cadddr v))) lvars)
,@new-body)))))
((letrec letrec*)
@@ -18810,9 +18930,9 @@
(for-each (lambda (local lv)
(list-set! lv 3 (walker (cadr local) lvars)))
locals lvars)
- `(,(car tree)
- ,(map (lambda (v) (list (cadr v) (cadddr v))) lvars)
- ,@(walker body (append lvars vars)))))
+ (cons (car tree)
+ (cons (map (lambda (v) (list (cadr v) (cadddr v))) lvars)
+ (walker body (append lvars vars))))))
((do)
(if (not (and (len>1? (cdr tree))
@@ -18883,6 +19003,7 @@
((lambda*)
(if (not (and (pair? (cdr tree))
+ (proper-list? (cddr tree))
(or (symbol? (cadr tree))
(proper-list? (cadr tree)))))
(quit))
@@ -19178,7 +19299,8 @@
(format #f "(~A ... (~A ~A))"
(car arg) head
(truncated-list->string (list-ref body len)))))))))
- (when (eq? (car arg) 'or)
+ (when (and (eq? (car arg) 'or)
+ (proper-list? arg))
(let ((else-clause (let ((last-clause (list-ref arg (- (length arg) 1))))
(if (and (pair? last-clause)
(memq (car last-clause) '(error throw)))
@@ -19231,7 +19353,7 @@
(lint-format "perhaps~A~%~NC~A ->~%~NC~A" caller
disclaimer
(+ lint-left-margin 4) #\space
- (lint-pp `(,@header ,(one-call-and-dots (car p)) ,@trailer))
+ (lint-pp (append header (cons (one-call-and-dots (car p)) trailer)))
(+ lint-left-margin 4) #\space
(if (and (memq (caar p) '(let let*))
(list? (cadar p))
@@ -19241,7 +19363,7 @@
(if (< (tree-leaves last) 12)
(format #f "(~A ... ~A)"
(caar p)
- (lint-pp `(,@header ,last ,@trailer)))
+ (lint-pp (append header (cons last trailer))))
(lint-pp `(let ((_1_ ,(one-call-and-dots (car p))))
(,@header _1_ ,@trailer)))))
(lint-pp `(let ((_1_ ,(one-call-and-dots (car p))))
@@ -19283,19 +19405,19 @@
(hash-table-ref no-side-effect-functions head)
(not (memq head unsafe-makers)))
(for-each (lambda (p)
- (if (let constable? ((cp p))
- (and (len>1? cp)
- (memq (car cp) '(list vector))
- (every? (lambda (inp)
- (or (code-constant? inp)
- (constable? inp)))
- (cdr cp))))
- (let ((pval (eval/error caller p)))
- (if (not (eq? pval :error))
- (lint-format "perhaps ~A -> ~A~A" caller
- (truncated-list->string p)
- (if (eq? (car p) 'list) "'" "")
- (object->string pval))))))
+ (when (let constable? ((cp p))
+ (and (len>1? cp)
+ (memq (car cp) '(list vector))
+ (every? (lambda (inp)
+ (or (code-constant? inp)
+ (constable? inp)))
+ (cdr cp))))
+ (let ((pval (eval/error caller p)))
+ (if (not (eq? pval :error))
+ (lint-format "perhaps ~A -> ~A~A" caller
+ (truncated-list->string p)
+ (if (eq? (car p) 'list) "'" "")
+ (object->string pval))))))
(cdr form)))
(when (and (not (= line-number last-simplify-numeric-line-number))
@@ -19356,7 +19478,7 @@
(if (side-effect? test env)
(format #f " (ignoring ~S's possible side-effects)" test)
"")
- (lists->string form `(,@header ,middle ,@q))))))))))))
+ (lists->string form (append header (cons middle q)))))))))))))
((pair? head)
(cond ((not (and (pair? (cdr head))
(memq (car head) '(lambda lambda*)))))
@@ -19459,61 +19581,91 @@
(lint-format "perhaps ~A" caller ; `(,x) -> (list x)
(lists->string form (list 'list (cadr form)))))))
((3)
- (when (pair? (caddr form))
- (let ((arg1 (cadr form))
- (arg2 (caddr form)))
- (if (not (or (and (pair? arg1)
- (tree-set-member '(#_{apply_values} #_{list} #_{append} unquote) arg1))
- (tree-set-member '(#_{append} unquote) arg2)
- (tree-set-member '(#_{list} #_{apply_values}) (cdr arg2))))
+ (let ((arg1 (cadr form))
+ (arg2 (caddr form)))
+ (if (not (or (and (pair? arg1)
+ (tree-set-member '(#_{apply_values} #_{append} unquote) arg1))
+ (and (pair? arg2)
+ (or (tree-set-member '(#_{append} unquote) arg2)
+ (tree-set-member '(#_{list} #_{apply_values}) (cdr arg2))))))
(lint-format "perhaps ~A" caller ; `(f ,(map g x)) -> (list 'f (map g x))
(lists->string form ; `(f ,@(map g x)) -> (cons 'f (map g x))
- (case (car arg2)
- ((#_{apply_values})
- (list 'cons arg1 (cadr arg2)))
- ((#_{list})
- `(list ,arg1 (list ,@(cdr arg2))))
- (else
- (list 'list arg1 arg2)))))
- (if (and (eq? (car arg2) #_{apply_values})
- (not (qq-tree? (cadr arg2)))
- (pair? arg1) ; `(,@x ,@y) -> (append x y)
+ (if (pair? arg2)
+ (case (car arg2)
+ ((#_{apply_values})
+ (list 'cons (un_{list} arg1) (cadr arg2)))
+ ((#_{list})
+ (list 'list (un_{list} arg1) (cons 'list (cdr arg2))))
+ (else
+ (list 'list (un_{list} arg1) arg2)))
+ (list 'list (un_{list} arg1) arg2))))
+ (if (and (len=2? arg1)
(eq? (car arg1) #_{apply_values})
(not (qq-tree? (cadr arg1))))
- (lint-format "perhaps ~A" caller
- (lists->string form
- (list 'append
- (un_{list} (cadr arg1))
- (un_{list} (cadr arg2))))))))))
-
- ;; `(+ ,y ,@(map f x)) -> (cons '+ (cons y (map f x)))
- ;; `(+ ,y ,@x ,@z etc) -> (cons '+ (cons y (append x z ...)))
- ;; `(f ,@x ,@y etc) -> (cons 'f (append x y ...))
- ;; `(,@x ,@y etc) -> (append x y ...)
- (else ; checked already that form is a proper-list, so the length here is > 3
+ (if (and (len=2? arg2)
+ (not (qq-tree? (cadr arg2)))
+ (eq? (car arg2) #_{apply_values})) ; `(,@x ,@y) -> (append x y)
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (list 'append
+ (un_{list} (cadr arg1))
+ (un_{list} (cadr arg2)))))
+ (if (not (and (pair? arg2)
+ (tree-set-member '(#_{apply_values} #_{append} unquote) arg2)))
+ (lint-format "perhaps ~A" caller ; `(,@x ,y) -> (append x (list y))
+ (lists->string form
+ (list 'append
+ (un_{list} (cadr arg1))
+ (list 'list (un_{list} arg2)))))))))))
+
+ (else ; checked already that form is a proper-list, so the length here is > 3
(define (safe-av? p)
(and (pair? p)
(eq? (car p) #_{apply_values})
(not (tree-set-member '(#_{apply_values} #_{list} #_{append} unquote) (cdr p)))))
(let ((args (cdr form))) ; car is #_{list}
- (when (every? safe-av? (cddr args))
- (if (safe-av? (cadr args))
- (if (safe-av? (car args))
- (lint-format "perhaps ~A" caller
- (lists->string form
- (cons 'append (map cadr args))))
- (if (not (tree-set-member '(#_{apply_values} #_{list} #_{append} unquote) (car args)))
- (lint-format "perhaps ~A" caller
- (lists->string form
- `(cons ,(car args) (append ,@(map cadr (cdr args))))))))
- (if (not (or (tree-set-member '(#_{apply_values} #_{list} #_{append} unquote) (car args))
- (tree-set-member '(#_{apply_values} #_{list} #_{append} unquote) (cadr args))))
- (lint-format "perhaps ~A" caller
- (lists->string form
- (if (null? (cdddr args))
- `(cons ,(car args) (cons ,(cadr args) ,(cadr (caddr args))))
- `(cons ,(car args) (cons ,(cadr args) (append ,@(map cadr (cddr args)))))))))))))))))
+ (cond ((not (every? safe-av? (cddr args)))
+ (if (and (len=3? args)
+ (safe-av? (car args)) ; `(,@x ,@y ,z) -> (append x y (list z)) etc
+ (safe-av? (cadr args))
+ (not (and (pair? (caddr args))
+ (memq (caaddr args) '(#_{apply_values} #_{append} unquote)))))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (list 'append (cadar args) (cadadr args)
+ (list 'list (un_{list} (caddr args))))))))
+
+ ;; `(+ ,y ,@(map f x)) -> (cons '+ (cons y (map f x)))
+ ;; `(+ ,y ,@x ,@z etc) -> (cons '+ (cons y (append x z ...)))
+ ;; `(f ,@x ,@y etc) -> (cons 'f (append x y ...))
+ ;; `(,@x ,@y etc) -> (append x y ...)
+ ((safe-av? (cadr args))
+ (if (safe-av? (car args))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (cons 'append (map cadr args))))
+ (if (not (tree-set-member '(#_{apply_values} #_{append} unquote) (car args)))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ `(cons ,(un_{list} (car args)) (append ,@(map cadr (cdr args)))))))))
+
+ ((not (or (tree-set-member '(#_{apply_values} #_{append} unquote) (car args))
+ (tree-set-member '(#_{apply_values} #_{append} unquote) (cadr args))))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ `(cons ,(un_{list} (car args))
+ (cons ,(un_{list} (cadr args))
+ ,(if (null? (cdddr args))
+ (cadr (caddr args))
+ (cons 'append (map cadr (cddr args)))))))))
+ ((and (len=3? args)
+ (safe-av? (car args)) ; `(,@x ,y ,@z) -> (append x (cons y z))
+ (not (tree-set-member '(#_{apply_values} #_{append} unquote) (cadr args))))
+ (lint-format "perhaps ~A" caller
+ (lists->string form
+ (list 'append (cadar args)
+ (list 'cons (un_{list} (cadr args)) (cadr (caddr args))))))))))))))
(let ((vars env))
(for-each
(lambda (f)
@@ -19844,7 +19996,7 @@
(cons #\! (lambda (str)
(if (member str '("!optional" "!default" "!rest" "!key" "!aux" "!false" "!true" "!r6rs") string-ci=?) ; for MIT-scheme
(string->keyword (substring str 1))
- (if (string=? str "!eof") ; Bigloo?
+ (if (string=? str "!eof") ; Bigloo? or Chicken? Guile writes it as #<eof> but can't read it
(begin
(format outport "~NC#!eof is probably #<eof> in s7~%" lint-left-margin #\space)
#<eof>)
@@ -20198,26 +20350,4 @@
#f))
|#
-;;; list|vector->let? lst->ht if assoc
-;;; case->vector|hash named-let->call/exit?
-;;; it appears that case->vector is always a big win, case->hash less so, alist even less, but still a win
-;;; the data should be in the closure, not spelled out
-;;; make-list in recur or built-in?
-;;; if x `() `() -- lint could embed the if here and elsewhere
-;;; recur|do->assoc/member/*-position -- didn't I check this?
-;;;
-;;; 3472 3849 4619 12932 14923 16868 17303 18896
-;;;
-;;; "(let () (define (func x) (if (close-input-port ) (caaddr /) (with-input-from-file 0(let (make-dilambda (lambda () 1) (lambda (a) a)) (set! i01+))))) 16868
-;;; "(let () (define (func x) (if (or . 1+0/0i ) (caaddr (caaadr /)))) (define (hi) (func (make-hook '(0 0 #f)))) 3472
-;;; "(let () (define (func x) (cond ((byte-vector-ref ) (iterator? 12.)) (else (unless .+2 '((x 1) y . 2) 1 - or case quote . __asdf__ ))))" 14923
-;;; "(let () (define (func x) (lambda* .(lcm . do ))) (define (hi) (func (string #\\a #\\null #\\b))) (hi))" 18896
-;;; "(let () (define (func x) (let . `(((x 1))) )) (define (hi) (func =>)) (hi))" 12923
-;;; "(let () (define (func x) (do . 1 )) (define (hi) (func (cons 1 2))) (hi))" (list 'do (append varlist (car do-form)) '...) 17303
-;;;
-;;; repl complification
-;;; (let ((line-len (- (+ end prompt-length 1) start))) (if (>= line-len last-col) (set! end (- (+ end line-len) last-col))))
-;;; (let ((line-len (- (+ end prompt-length 1) start))) (if (>= line-len last-col) (set! end (- (+ start last-col) prompt-length 1))))
-
-
-;;; 169 28349 696530
+;;; 174 28550 727902