I am on a fairly recent Emacs:

GNU Emacs 29.0.50 (build 3, x86_64-apple-darwin21.6.0, NS appkit-2113.60 Version 12.6.2 (Build 21G320)) of 2023-09-01

so I suspect that this problem is still on the HEAD master, but to be honest I have not tested it.

  V.

De : Vincent Belaïche <vincent.b.1@hotmail.fr>
Envoyé : jeudi 2 novembre 2023 12:27
À : emacs-devel <emacs-devel@gnu.org>; monnier@iro.umontreal.ca <monnier@iro.umontreal.ca>
Cc : boruch_baum@gmx.com <boruch_baum@gmx.com>; Andrés Ramírez <rrandresf@hotmail.com>
Objet : RE: a ses question
 
Dear Emacs experts,

Sorry for bothering, I am a bit at my end of wits. If I apply the patch attached to my previous email, load the patched ses.el and open an empty SES file toto.ses, and evaluate this expression in the *scratch* buffer, 

(let ((the-ses-buffer (get-buffer "toto.ses")))
  (with-current-buffer the-ses-buffer (insert (format "%S" (ses-range A1 A1)))))


then I get some error. It seems that the root cause is that the ses-sym-rowcol macro is evaluated (and not just expanded) in the *scratch* buffer instead of the toto.ses buffer, so symbol A1 has not 'ses-cell set to (0 . 0), and this makes it fail.

   Vincent.

De : Vincent Belaïche <vincent.b.1@hotmail.fr>
Envoyé : jeudi 2 novembre 2023 12:20
À : Andrés Ramírez <rrandresf@hotmail.com>
Cc : emacs-devel <emacs-devel@gnu.org>; boruch_baum@gmx.com <boruch_baum@gmx.com>
Objet : RE: a ses question
 
I think that the problem is that some macros in SES are written in a dirty way as they use interned symbols.

I tried to fix it in the attached patch ses.diff, but there is still a problem. If I open an empty SES file toto.ses and evaluate this form:

(let ((the-ses-buffer (get-buffer "toto.ses")))
  (with-current-buffer the-ses-buffer (insert (format "%S" (ses-range A1 A1)))))

then I get this backtrace:

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
  >(nil nil)
  (or (> minrow maxrow) (> mincol maxcol))
  (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range"))
  (let ((minrow (car min)) (maxrow (car max)) (mincol (cdr min)) (maxcol (cdr max))) (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range")) (let ((--dotimes-limit-- (- maxrow minrow -1)) (r 0)) (while (< r --dotimes-limit--) (let ((row (+ r minrow))) (let ((--dotimes-limit-- (- maxcol mincol -1)) (c 0)) (while (< c --dotimes-limit--) (let ((col (+ c mincol))) (if (/= prev-row row) (progn (setq result (cons result-row result)) (setq result-row nil))) (setq result-row (cons (let ((cl-x (aref (aref ses--cells row) col))) (progn (progn (aref cl-x 0)))) result-row)) (setq prev-row row)) (setq c (1+ c))))) (setq r (1+ r)))))
  (let* ((cur (cons A1 A1)) (min (let ((rc (and (symbolp (if (consp cur) (car cur) cur)) (get (if (consp cur) (car cur) cur) 'ses-cell)))) (if (eq rc :ses-named) (and ses--named-cell-hashmap (gethash (if (consp cur) (car cur) cur) ses--named-cell-hashmap)) rc))) (max (let ((rc (and (symbolp (if (consp cur) (cdr cur) cur)) (get (if (consp cur) (cdr cur) cur) 'ses-cell)))) (if (eq rc :ses-named) (and ses--named-cell-hashmap (gethash (if (consp cur) (cdr cur) cur) ses--named-cell-hashmap)) rc)))) (message "min=%S max=%S" min max) (let ((minrow (car min)) (maxrow (car max)) (mincol (cdr min)) (maxcol (cdr max))) (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range")) (let ((--dotimes-limit-- (- maxrow minrow -1)) (r 0)) (while (< r --dotimes-limit--) (let ((row (+ r minrow))) (let ((--dotimes-limit-- (- maxcol mincol -1)) (c 0)) (while (< c --dotimes-limit--) (let ((col (+ c mincol))) (if (/= prev-row row) (progn (setq result (cons result-row result)) (setq result-row nil))) (setq result-row (cons (let ((cl-x (aref (aref ses--cells row) col))) (progn (progn (aref cl-x 0)))) result-row)) (setq prev-row row)) (setq c (1+ c))))) (setq r (1+ r))))))
  (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean 'list)) (let* ((cur (cons A1 A1)) (min (let ((rc (and (symbolp (if (consp cur) (car cur) cur)) (get (if (consp cur) (car cur) cur) 'ses-cell)))) (if (eq rc :ses-named) (and ses--named-cell-hashmap (gethash (if (consp cur) (car cur) cur) ses--named-cell-hashmap)) rc))) (max (let ((rc (and (symbolp (if (consp cur) (cdr cur) cur)) (get (if (consp cur) (cdr cur) cur) 'ses-cell)))) (if (eq rc :ses-named) (and ses--named-cell-hashmap (gethash (if (consp cur) (cdr cur) cur) ses--named-cell-hashmap)) rc)))) (message "min=%S max=%S" min max) (let ((minrow (car min)) (maxrow (car max)) (mincol (cdr min)) (maxcol (cdr max))) (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range")) (let ((--dotimes-limit-- (- maxrow minrow -1)) (r 0)) (while (< r --dotimes-limit--) (let ((row (+ r minrow))) (let ((--dotimes-limit-- (- maxcol mincol -1)) (c 0)) (while (< c --dotimes-limit--) (let ((col (+ c mincol))) (if (/= prev-row row) (progn (setq result (cons result-row result)) (setq result-row nil))) (setq result-row (cons (let ((cl-x (aref (aref ses--cells row) col))) (progn (progn (aref cl-x 0)))) result-row)) (setq prev-row row)) (setq c (1+ c))))) (setq r (1+ r)))))) (setq result (cons result-row result)) (while nil (let ((x (car-safe (prog1 nil (setq nil (cdr nil)))))) (cond ((eq x '>v) (let nil (setq transpose nil reorient-x nil reorient-y nil))) ((eq x '>^) (let nil (setq transpose nil reorient-x nil reorient-y t))) ((eq x '<^) (let nil (setq transpose nil reorient-x t reorient-y t))) ((eq x '<v) (let nil (setq transpose nil reorient-x t reorient-y nil))) ((eq x 'v>) (let nil (setq transpose t reorient-x nil reorient-y t))) ((eq x '^>) (let nil (setq transpose t reorient-x nil reorient-y nil))) ((eq x '^<) (let nil (setq transpose t reorient-x t reorient-y nil))) ((eq x 'v<) (let nil (setq transpose t reorient-x t reorient-y t))) ((memq x '(*1 *2 *)) (let nil (setq vectorize x))) ((eq x '!) (let nil (setq clean 'ses--clean-!))) ((eq x '_) (let nil (setq clean (list 'lambda '(&rest x) (list 'ses--clean-_ 'x (if nil (car-safe (prog1 nil (setq nil (cdr nil)))) 0)))))) (t (let nil (cond ((and (null (cdr (cdr result))) (memq x '(> <))) (setq nil (cons (intern (concat (symbol-name x) "v")) nil))) ((and (null (cdr (car result))) (memq x '(v ^))) (setq nil (cons (intern (concat (symbol-name x) ">")) nil))) (t (error "Unexpected flag `%S' in ses-range" x)))))))) (if reorient-y (setcdr (last result 2) nil) (setq result (cdr (nreverse result)))) (if reorient-x nil (setq result (mapcar #'nreverse result))) (if transpose (progn (let ((ret (mapcar #'(lambda (x) (list x)) (car-safe (prog1 result (setq result (cdr result)))))) iter) (while result (setq iter ret) (let ((--dolist-tail-- (car-safe (prog1 result (setq result (cdr result))))) elt) (while --dolist-tail-- (setq elt (car --dolist-tail--)) (setcar iter (cons elt (car iter))) (setq iter (cdr iter)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (setq result ret)))) (let* ((--cl-vectorize-*1-- #'(lambda (clean result) (cons clean (cons ''vec (apply #'append result))))) (--cl-vectorize-*2-- #'(lambda (clean result) (cons clean (cons ''vec (mapcar #'(lambda (x) (cons clean (cons ''vec x))) result)))))) (progn (cond ((null vectorize) (let nil (cons clean (apply #'append result)))) ((eq vectorize '*1) (let nil (funcall --cl-vectorize-*1-- clean result))) ((eq vectorize '*2) (let nil (funcall --cl-vectorize-*2-- clean result))) ((eq vectorize '*) (let nil (funcall (if (cdr result) --cl-vectorize-*2-- --cl-vectorize-*1--) clean result)))))))
  (format "%S" (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean 'list)) (let* ((cur (cons A1 A1)) (min (let ((rc (and (symbolp (if (consp cur) (car cur) cur)) (get (if (consp cur) (car cur) cur) 'ses-cell)))) (if (eq rc :ses-named) (and ses--named-cell-hashmap (gethash (if (consp cur) (car cur) cur) ses--named-cell-hashmap)) rc))) (max (let ((rc ...)) (if (eq rc :ses-named) (and ses--named-cell-hashmap ...) rc)))) (message "min=%S max=%S" min max) (let ((minrow (car min)) (maxrow (car max)) (mincol (cdr min)) (maxcol (cdr max))) (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range")) (let ((--dotimes-limit-- (- maxrow minrow -1)) (r 0)) (while (< r --dotimes-limit--) (let (...) (let ... ...)) (setq r (1+ r)))))) (setq result (cons result-row result)) (while nil (let ((x (car-safe (prog1 nil ...)))) (cond ((eq x '>v) (let nil (setq transpose nil reorient-x nil reorient-y nil))) ((eq x '>^) (let nil (setq transpose nil reorient-x nil reorient-y t))) ((eq x '<^) (let nil (setq transpose nil reorient-x t reorient-y t))) ((eq x '<v) (let nil (setq transpose nil reorient-x t reorient-y nil))) ((eq x 'v>) (let nil (setq transpose t reorient-x nil reorient-y t))) ((eq x '^>) (let nil (setq transpose t reorient-x nil reorient-y nil))) ((eq x '^<) (let nil (setq transpose t reorient-x t reorient-y nil))) ((eq x 'v<) (let nil (setq transpose t reorient-x t reorient-y t))) ((memq x '...) (let nil (setq vectorize x))) ((eq x '!) (let nil (setq clean ...))) ((eq x '_) (let nil (setq clean ...))) (t (let nil (cond ... ... ...)))))) (if reorient-y (setcdr (last result 2) nil) (setq result (cdr (nreverse result)))) (if reorient-x nil (setq result (mapcar #'nreverse result))) (if transpose (progn (let ((ret (mapcar ... ...)) iter) (while result (setq iter ret) (let (... elt) (while --dolist-tail-- ... ... ... ...))) (setq result ret)))) (let* ((--cl-vectorize-*1-- #'(lambda (clean result) (cons clean ...))) (--cl-vectorize-*2-- #'(lambda (clean result) (cons clean ...)))) (progn (cond ((null vectorize) (let nil (cons clean ...))) ((eq vectorize '*1) (let nil (funcall --cl-vectorize-*1-- clean result))) ((eq vectorize '*2) (let nil (funcall --cl-vectorize-*2-- clean result))) ((eq vectorize '*) (let nil (funcall ... clean result))))))))
  (insert (format "%S" (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean 'list)) (let* ((cur (cons A1 A1)) (min (let (...) (if ... ... rc))) (max (let (...) (if ... ... rc)))) (message "min=%S max=%S" min max) (let ((minrow (car min)) (maxrow (car max)) (mincol (cdr min)) (maxcol (cdr max))) (if (or (> minrow maxrow) (> mincol maxcol)) (error "Empty range")) (let ((--dotimes-limit-- ...) (r 0)) (while (< r --dotimes-limit--) (let ... ...) (setq r ...))))) (setq result (cons result-row result)) (while nil (let ((x (car-safe ...))) (cond ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((memq x ...) (let nil ...)) ((eq x ...) (let nil ...)) ((eq x ...) (let nil ...)) (t (let nil ...))))) (if reorient-y (setcdr (last result 2) nil) (setq result (cdr (nreverse result)))) (if reorient-x nil (setq result (mapcar #'nreverse result))) (if transpose (progn (let ((ret ...) iter) (while result (setq iter ret) (let ... ...)) (setq result ret)))) (let* ((--cl-vectorize-*1-- #'(lambda ... ...)) (--cl-vectorize-*2-- #'(lambda ... ...))) (progn (cond ((null vectorize) (let nil ...)) ((eq vectorize ...) (let nil ...)) ((eq vectorize ...) (let nil ...)) ((eq vectorize ...) (let nil ...))))))))
  (save-current-buffer (set-buffer the-ses-buffer) (insert (format "%S" (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean 'list)) (let* ((cur (cons A1 A1)) (min (let ... ...)) (max (let ... ...))) (message "min=%S max=%S" min max) (let ((minrow ...) (maxrow ...) (mincol ...) (maxcol ...)) (if (or ... ...) (error "Empty range")) (let (... ...) (while ... ... ...)))) (setq result (cons result-row result)) (while nil (let ((x ...)) (cond (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (... ...) (t ...)))) (if reorient-y (setcdr (last result 2) nil) (setq result (cdr (nreverse result)))) (if reorient-x nil (setq result (mapcar #'nreverse result))) (if transpose (progn (let (... iter) (while result ... ...) (setq result ret)))) (let* ((--cl-vectorize-*1-- #'...) (--cl-vectorize-*2-- #'...)) (progn (cond (... ...) (... ...) (... ...) (... ...))))))))
  (let ((the-ses-buffer (get-buffer "toto.ses"))) (save-current-buffer (set-buffer the-ses-buffer) (insert (format "%S" (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean 'list)) (let* ((cur ...) (min ...) (max ...)) (message "min=%S max=%S" min max) (let (... ... ... ...) (if ... ...) (let ... ...))) (setq result (cons result-row result)) (while nil (let (...) (cond ... ... ... ... ... ... ... ... ... ... ... ...))) (if reorient-y (setcdr (last result 2) nil) (setq result (cdr ...))) (if reorient-x nil (setq result (mapcar ... result))) (if transpose (progn (let ... ... ...))) (let* ((--cl-vectorize-*1-- ...) (--cl-vectorize-*2-- ...)) (progn (cond ... ... ... ...))))))))
  eval((let ((the-ses-buffer (get-buffer "toto.ses"))) (save-current-buffer (set-buffer the-ses-buffer) (insert (format "%S" (let (result-row result (prev-row -1) reorient-x reorient-y transpose vectorize (clean ...)) (let* (... ... ...) (message "min=%S max=%S" min max) (let ... ... ...)) (setq result (cons result-row result)) (while nil (let ... ...)) (if reorient-y (setcdr ... nil) (setq result ...)) (if reorient-x nil (setq result ...)) (if transpose (progn ...)) (let* (... ...) (progn ...))))))) nil)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  call-interactively(eval-last-sexp nil nil)
  command-execute(eval-last-sexp)
 




De : Vincent Belaïche <vincent.b.1@hotmail.fr>
Envoyé : mercredi 1 novembre 2023 20:23
À : Andrés Ramírez <rrandresf@hotmail.com>
Cc : emacs-devel <emacs-devel@gnu.org>; boruch_baum@gmx.com <boruch_baum@gmx.com>
Objet : RE: a ses question
 
I see, I usually use this kind of snippet with some eval-region and the code where ses-range is found is in some buffer region, and in this case the macro expansion is delayed as Emacs does need to slurp the buffer region in the first place. I do this through some preprocessor of mine that allows to embed some Elisp code in comments in a file with another language.

This is why I was not aware the snippet would fail, anyway, I should have tested it before sending.

   V.

De : Vincent Belaïche <vincent.b.1@hotmail.fr>
Envoyé : mercredi 1 novembre 2023 20:08
À : Andrés Ramírez <rrandresf@hotmail.com>
Cc : emacs-devel <emacs-devel@gnu.org>; boruch_baum@gmx.com <boruch_baum@gmx.com>
Objet : RE: a ses question
 
Hello,

Yes, I reproduced it, you can write the expression as follows :

   (eval '(ses-range A1 C3 *2 >v))

to delay the macro expansion. I think that this kind of snippet used to work, I need to investigate why it does not work any longer.

   V.





De : andrés ramírez <rrandresf@hotmail.com>
Envoyé : lundi 30 octobre 2023 20:03
À : Vincent Belaïche <vincent.b.1@hotmail.fr>
Cc : emacs-devel <emacs-devel@gnu.org>; boruch_baum@gmx.com <boruch_baum@gmx.com>
Objet : Re: a ses question
 
Hi. Vincent.

I just yanked the elisp snippet You shared (without any modification) I
just did M-x eval-defun, and It gave me this error:

--8<---------------cut here---------------start------------->8---
Debugger entered--Lisp error: (error "Eager macro-expansion failure: (void-variable ses-...")
  signal(error ("Eager macro-expansion failure: (void-variable ses-..."))
  error("Eager macro-expansion failure: %S" (void-variable ses--cells))
  internal-macroexpand-for-load((setq elisp--eval-defun-result (let ((print-level nil) (print-length nil)) (defalias 'smeter/further-processing #'(lambda nil "process input on as spreadsheet using ses formulae..." (interactive) (let (... ... ... ... ... ... myyyyymm mysesoutput chunk bigchunk) (goto-char ...) (setq beg ...) (setq workbook-filename ...) (forward-line 1) (setq beg ...) (forward-line 4) (setq prevmeasu ...) (setq beg ...) (setq waterbill ...) (forward-line 1) (setq beg ...) (forward-line 4) (setq measu ...) (setq beg ...) (setq myyyyymm ...) (if ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...)))))) t)
  eval-region(162 5110 t #f(compiled-function (ignore) #<bytecode -0x5bb31d1b5fed60e>))  ; Reading at buffer position 2635
  elisp--eval-defun()
  eval-defun(nil)
  funcall-interactively(eval-defun nil)
  call-interactively(eval-defun record nil)
  command-execute(eval-defun record)
  execute-extended-command(nil "eval-defun" "eval-defun")
  funcall-interactively(execute-extended-command nil "eval-defun" "eval-defun")
  call-interactively(execute-extended-command nil nil)
  command-execute(execute-extended-command)
--8<---------------cut here---------------end--------------->8---

Best Regards
Andrés Ramírez
>>>>> "Vincent" == Vincent Belaïche <vincent.b.1@hotmail.fr> writes:

    Vincent>  Just reading again the code which I sent in my
    Vincent> previous email, I found a problem, there would be one trailing column separator « & »
    Vincent> too many. Probably the following would be better:

    Vincent> (let ((range (with-current-buffer the-ses-buffer (ses-range A1 C3 ; adapt to your case
    Vincent>                                            *2 '>v ; use 'v> to read columnwsise
    Vincent>                                            )))) (dolist (row (cdr range)) ; cdr to
    Vincent> remove 'vec (pop row) ; remove 'vec (while (progn        (insert (format "%f" (pop
    Vincent> row))) ; assuming all cells are floating point numbers        (when row        (insert
    Vincent>        "&" ; if & is the column separator        ) t ; loop again              )))
    Vincent> (insert "\\\\\n"; if \\ is the row separator        )))