diff options
| author | Richard Stallman | 2024-08-02 12:03:45 -0400 |
|---|---|---|
| committer | Richard Stallman | 2024-08-02 12:03:45 -0400 |
| commit | 18491f48d973c9cbc453d9f742ec7f73e83df3bb (patch) | |
| tree | 44959170cca5b7818647952fdfbf52b61a96215b | |
| parent | 80108438e5e2e95ca75e59212fb1669a723241b5 (diff) | |
| download | emacs-18491f48d973c9cbc453d9f742ec7f73e83df3bb.tar.gz emacs-18491f48d973c9cbc453d9f742ec7f73e83df3bb.zip | |
Install cond*
* oond-star.el: New file.
| -rw-r--r-- | lisp/emacs-lisp/cond-star.el | 707 |
1 files changed, 707 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/cond-star.el b/lisp/emacs-lisp/cond-star.el new file mode 100644 index 00000000000..6309b0d1a15 --- /dev/null +++ b/lisp/emacs-lisp/cond-star.el | |||
| @@ -0,0 +1,707 @@ | |||
| 1 | ;;; -*-lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 1985-2024 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Maintainer: rms@gnu.org | ||
| 6 | ;; Package: emacs | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. It implements `cond*'. | ||
| 9 | |||
| 10 | ;; cond* is free software: you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 13 | ;; (at your option) any later version. | ||
| 14 | |||
| 15 | ;; cond* is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 22 | |||
| 23 | ;; Here is the list of functions the generated code is known to call: | ||
| 24 | ;; car, cdr, car-safe, cdr-safe, nth, nthcdr, null, eq, equal, eql, =, | ||
| 25 | ;; vectorp, length. | ||
| 26 | ;; It also uses these control and binding promitives: | ||
| 27 | ;; and, or, if, progn, let, let*, setq. | ||
| 28 | ;; For regexp matching only, it can call string-match and match-string. | ||
| 29 | |||
| 30 | ;;; ??? If a clause starts with a keyword, | ||
| 31 | ;;; should the element after the kwyword be treated in the usual way | ||
| 32 | ;;; as a pattern? Curently `cond*-non-exit-clause-substance' explicitly | ||
| 33 | ;;; prevents that by adding t at the front of its value. | ||
| 34 | |||
| 35 | (defmacro cond* (&rest clauses) | ||
| 36 | "Extended form of traditional Lisp `cond' construct. | ||
| 37 | A `cond*' construct is a series of clauses, and a clause | ||
| 38 | normally has the form (CONDITION BDOY...). | ||
| 39 | |||
| 40 | CONDITION can be a Lisp expression, as in `cond'. | ||
| 41 | Or it can be `(bind* BINDINGS...)' or `(match* PATTERN DATUM)'. | ||
| 42 | |||
| 43 | `(bind* BINDINGS...)' means to bind BINDINGS (as if they were in `let*') | ||
| 44 | for the body of the clause. As a condition, it counts as true | ||
| 45 | if the first binding's value is non-nil. All the bindings are made | ||
| 46 | unconditionally for whatever scope they cover. | ||
| 47 | |||
| 48 | `(match* PATTERN DATUM)' means to match DATUM against the pattern PATTERN | ||
| 49 | The condition counts as true if PATTERN matches DATUM. | ||
| 50 | |||
| 51 | When a clause's condition is true, and it exits the `cond*' | ||
| 52 | or is the last clause, the value of the last expression | ||
| 53 | in its body becomes the return value of the `cond*' construct. | ||
| 54 | |||
| 55 | Mon-exit clause: | ||
| 56 | |||
| 57 | If a clause has only one element, or if its first element is | ||
| 58 | t, or if it ends with the keyword :non-exit, then | ||
| 59 | this clause never exits the `cond*' construct. Instead, | ||
| 60 | control falls through to the next clause (if any). | ||
| 61 | The bindings made in CONDITION for the BODY of the non-exit clause | ||
| 62 | are passed along to the rest of the clauses in this `cond*' construct. | ||
| 63 | |||
| 64 | \\[match*\\] for documentation of the patterns for use in `match*'." | ||
| 65 | (cond*-convert clauses)) | ||
| 66 | |||
| 67 | (defmacro match* (pattern datum) | ||
| 68 | "This specifies matching DATUM against PATTERN. | ||
| 69 | It is not really a LIsp function, and it is meaningful | ||
| 70 | only in the CONDITION of a `cond*' clause. | ||
| 71 | |||
| 72 | `_' matches any value. | ||
| 73 | KEYWORD matches that keyword. | ||
| 74 | nil matches nil. | ||
| 75 | t matches t. | ||
| 76 | SYMBOL matches any value and binds SYMBOL to that value. | ||
| 77 | If SYMBOL has been matched and bound earlier in this pattern, | ||
| 78 | it matches here the same value that it matched before. | ||
| 79 | REGEXP matches a string if REGEXP matches it. | ||
| 80 | The match must cover the entire string from its first char to its last. | ||
| 81 | ATOM (meaning any other kind of non-list not described above) | ||
| 82 | matches anything `equal' to it. | ||
| 83 | (rx REGEXP) uses a regexp specified in s-expression form, | ||
| 84 | as in the function `rx', and matches the data that way. | ||
| 85 | (rx REGEXP SYM0 SYM1...) uses a regexp specified in s-expression form, | ||
| 86 | and binds the symbols SYM0, SYM1, and so on | ||
| 87 | to (match-string 0 DATUM), (match-string 1 DATUM), and so on. | ||
| 88 | You can use as many SYMs as regexp matching supports. | ||
| 89 | |||
| 90 | `OBJECT matches any value `equal' to OBJECT. | ||
| 91 | (cons CARPAT CDRPAT) | ||
| 92 | matches a cons cell if CARPAT matches its car and CDRPAT matches its cdr. | ||
| 93 | (list ELTPATS...) | ||
| 94 | matches a list if the ELTPATS match its elements. | ||
| 95 | The first ELTPAT should match the list's first element. | ||
| 96 | The second ELTPAT should match the list's second element. And so on. | ||
| 97 | (vector ELTPATS...) | ||
| 98 | matches a vector if the ELTPATS match its elements. | ||
| 99 | The first ELTPAT should match the vector's first element. | ||
| 100 | The second ELTPAT should match the vector's second element. And so on. | ||
| 101 | (cdr PATTERN) matches PATTERN with strict checking of cdrs. | ||
| 102 | That means that `list' patterns verify that the final cdr is nil. | ||
| 103 | Strict checking is the default. | ||
| 104 | (cdr-safe PATTERN) matches PATTERN with lax checking of cdrs. | ||
| 105 | That means that `list' patterns do not examine the final cdr. | ||
| 106 | (and CONJUNCTS...) matches each of the CONJUNCTS against the same data. | ||
| 107 | If all of them match, this pattern succeeds. | ||
| 108 | If one CONJUNCT fails, this pattern fails and does not try more CONJUNCTS. | ||
| 109 | (or DISJUNCTS...) matches each of te DISJUNCTS against the same data. | ||
| 110 | If one DISJUNCT succeeds, this pattern succeeds | ||
| 111 | and does not try more DISJUNCTs. | ||
| 112 | If all of them fail, this pattern fails. | ||
| 113 | (COND*-EXPANDER ...) | ||
| 114 | Here the car is a symbol that has a `cond*-expander' property | ||
| 115 | which defines how to handle it in a pattern. The property value | ||
| 116 | is a function. Trying to match such a pattern calls that | ||
| 117 | function with one argument, the pattern in question (including its car). | ||
| 118 | The function should return an equivalent pattern | ||
| 119 | to be matched inetead. | ||
| 120 | (PREDICATE SYMBOL) | ||
| 121 | matches datum if (PREDICATE DATUM) is true, | ||
| 122 | then binds SYMBOL to DATUM. | ||
| 123 | (PREDICATE SYMBOL MORE-ARGS...) | ||
| 124 | matches datum if (PREDICATE DATUM MORE-ARGS...) is true, | ||
| 125 | then binds SYMBOL to DATUM. | ||
| 126 | MORE-ARGS... can refer to symbols bound earlier in the pattern. | ||
| 127 | (constrain SYMBOL EXP) | ||
| 128 | matches datum if the form EXP is true. | ||
| 129 | EXP can refer to symbols bound earlier in the pattern." | ||
| 130 | (ignore datum) | ||
| 131 | (byte-compile-warn-x pattern "`match*' used other than as a `cond*' condition")) | ||
| 132 | |||
| 133 | (defun cond*-non-exit-clause-p (clause) | ||
| 134 | "If CLAUSE, a cond* clause, is a non-exit clause, return t." | ||
| 135 | (or (null (cdr-safe clause)) ;; clause has only one element. | ||
| 136 | (and (cdr-safe clause) | ||
| 137 | ;; Starts with t. | ||
| 138 | (or (eq (car clause) t) | ||
| 139 | ;; Begins with keyword. | ||
| 140 | (keywordp (car clause)))) | ||
| 141 | ;; Ends with keyword. | ||
| 142 | (keywordp (car (last clause))))) | ||
| 143 | |||
| 144 | (defun cond*-non-exit-clause-substance (clause) | ||
| 145 | "For a non-exit cond* clause CLAUSE, return its substance. | ||
| 146 | This removes a final keyword if that's what makes CLAUSE non-exit." | ||
| 147 | (cond ((null (cdr-safe clause)) ;; clause has only one element. | ||
| 148 | clause) | ||
| 149 | ;; Starts with t or a keyword. | ||
| 150 | ;; Include t as the first element of the substancea | ||
| 151 | ;; so that the following element is not treated as a pattern. | ||
| 152 | ((and (cdr-safe clause) | ||
| 153 | (or (eq (car clause) t) | ||
| 154 | (keywordp (car clause)))) | ||
| 155 | ;; Standardize on t as the first element. | ||
| 156 | (cons t (cdr clause))) | ||
| 157 | |||
| 158 | ;; Ends with keyword. | ||
| 159 | ((keywordp (car (last clause))) | ||
| 160 | ;; Do NOT include the final keyword. | ||
| 161 | (butlast clause)))) | ||
| 162 | |||
| 163 | (defun cond*-convert (clauses) | ||
| 164 | "Process a list of cond* clauses, CLAUSES. | ||
| 165 | Returns the equivalent Lisp expression." | ||
| 166 | (if clauses | ||
| 167 | (cond*-convert-clause (car-safe clauses) (cdr-safe clauses)))) | ||
| 168 | |||
| 169 | (defun cond*-convert-clause (clause rest) | ||
| 170 | "Process one `cond*' clause, CLAUSE. | ||
| 171 | REST is the rest of the clauses of this cond* expression." | ||
| 172 | (if (cond*-non-exit-clause-p clause) | ||
| 173 | ;; Handle a non-exit clause. Make its bindings active | ||
| 174 | ;; around the whole rest of this cond*, treating it as | ||
| 175 | ;; a condition whose value is always t, around the rest | ||
| 176 | ;; of this cond*. | ||
| 177 | (let ((substance (cond*-non-exit-clause-substance clause))) | ||
| 178 | (cond*-convert-condition | ||
| 179 | ;; Handle the first substantial element in the non-exit clause | ||
| 180 | ;; as a matching condition. | ||
| 181 | (car substance) | ||
| 182 | ;; Any following elements in the | ||
| 183 | ;; non-exit clause are just expressions. | ||
| 184 | (cdr substance) | ||
| 185 | ;; Remaining clauses will be UNCONDIT-CLAUSES: | ||
| 186 | ;; run unconditionally and handled as a cond* body. | ||
| 187 | rest | ||
| 188 | nil nil)) | ||
| 189 | ;; Handle a normal (conditional exit) clauss. | ||
| 190 | (cond*-convert-condition (car-safe clause) (cdr-safe clause) nil | ||
| 191 | rest (cond*-convert rest)))) | ||
| 192 | |||
| 193 | (defun cond*-convert-condition (condition true-exps uncondit-clauses rest iffalse) | ||
| 194 | "Process the condition part of one cond* clause. | ||
| 195 | TRUE-EXPS is a list of Lisp expressions to be executed if this | ||
| 196 | condition is true, and inside its bindings. | ||
| 197 | UNCONDIT-CLAUSES is a list of cond*-clauses to be executed if this | ||
| 198 | condition is true, and inside its bindings. | ||
| 199 | This is used for non-exit clauses; it is nil for conditional-exit clauses. | ||
| 200 | |||
| 201 | REST and IFFALSE are non-nil for conditional-exit clauses that are not final. | ||
| 202 | REST is a list of clauses to process after this one if | ||
| 203 | this one could have exited but does not exit. | ||
| 204 | This is used for conditional exit clauses. | ||
| 205 | IFFALSE is the value to compute after this one if | ||
| 206 | this one could have exited but does not exit. | ||
| 207 | This is used for conditional exit clauses." | ||
| 208 | (if (and uncondit-clauses rest) | ||
| 209 | (error "Clause is both exiting and non-exit")) | ||
| 210 | (let ((pat-type (car-safe condition))) | ||
| 211 | (cond ((eq pat-type 'bind*) | ||
| 212 | (let* ((bindings (cdr condition)) | ||
| 213 | (first-binding (car bindings)) | ||
| 214 | (first-variable (if (symbolp first-binding) first-binding | ||
| 215 | (car first-binding))) | ||
| 216 | (first-value (if (symbolp first-binding) nil | ||
| 217 | (cadr first-binding))) | ||
| 218 | (init-gensym (gensym "init")) | ||
| 219 | ;; BINDINGS with the initial value of the first binding | ||
| 220 | ;; replaced by INIT-GENSYM. | ||
| 221 | (mod-bindings | ||
| 222 | (cons (list first-variable init-gensym) (cdr bindings)))) | ||
| 223 | ;;; ??? Here pull out all nontrivial initial values | ||
| 224 | ;;; ??? to compute them earlier. | ||
| 225 | (if rest | ||
| 226 | ;; bind* starts an exiting clause which is not final. | ||
| 227 | ;; Therefore, must run IFFALSE. | ||
| 228 | `(let ((,init-gensym ,first-value)) | ||
| 229 | (if ,init-gensym | ||
| 230 | (let* ,mod-bindings | ||
| 231 | . ,true-exps) | ||
| 232 | ;; Always calculate all bindings' initial values, | ||
| 233 | ;; but the bindings must not cover IFFALSE. | ||
| 234 | (let* ,mod-bindings nil) | ||
| 235 | ,iffalse)) | ||
| 236 | (if uncondit-clauses | ||
| 237 | ;; bind* starts a non-exit clause which is not final. | ||
| 238 | ;; Run the TRUE-EXPS if condition value is true. | ||
| 239 | ;; Then always go on to run the UNCONDIT-CLAUSES. | ||
| 240 | (if true-exps | ||
| 241 | `(let ((,init-gensym ,first-value)) | ||
| 242 | ;;; ??? Should we make the bindings a second time for the UNCONDIT-CLAUSES. | ||
| 243 | ;;; as the doc string says, for uniformity with match*? | ||
| 244 | (let* ,mod-bindings | ||
| 245 | (when ,init-gensym | ||
| 246 | . ,true-exps) | ||
| 247 | ,(cond*-convert uncondit-clauses))) | ||
| 248 | `(let* ,bindings | ||
| 249 | ,(cond*-convert uncondit-clauses))) | ||
| 250 | ;; bind* starts a final clause. | ||
| 251 | ;; If there are TRUE-EXPS, run them if condition succeeded. | ||
| 252 | ;; Always make the bindings, in case the | ||
| 253 | ;; initial values have side effects. | ||
| 254 | `(let ((,init-gensym ,first-value)) | ||
| 255 | ;; Calculate all binding values unconditionally. | ||
| 256 | (let* ,mod-bindings | ||
| 257 | (when ,init-gensym | ||
| 258 | . ,true-exps))))))) | ||
| 259 | ((eq pat-type 'match*) | ||
| 260 | (cond*-match condition true-exps uncondit-clauses iffalse)) | ||
| 261 | (t | ||
| 262 | ;; Ordinary Lixp expression is the condition | ||
| 263 | (if rest | ||
| 264 | ;; A nonfinal exiting clause. | ||
| 265 | ;; If condition succeeds, run the TRUE-EXPS. | ||
| 266 | ;; There are following clauses, so run IFFALSE | ||
| 267 | ;; if the condition fails. | ||
| 268 | `(if ,condition | ||
| 269 | (progn . ,true-exps) | ||
| 270 | ,iffalse) | ||
| 271 | (if uncondit-clauses | ||
| 272 | ;; A non-exit clause. | ||
| 273 | ;; If condition succeeds, run the TRUE-EXPS. | ||
| 274 | ;; Then always go on to run the UNCONDIT-CLAUSES. | ||
| 275 | `(progn (if ,condition | ||
| 276 | (progn . ,true-exps)) | ||
| 277 | ,(cond*-convert uncondit-clauses)) | ||
| 278 | ;; An exiting clause which is also final. | ||
| 279 | ;; If there are TRUE-EXPS, run them if CONDITION succeeds. | ||
| 280 | (if true-exps | ||
| 281 | `(if ,condition (progn . ,true-exps)) | ||
| 282 | ;; Run and return CONDITION. | ||
| 283 | condition))))))) | ||
| 284 | |||
| 285 | (defun cond*-match (matchexp true-exps uncondit-clauses iffalse) | ||
| 286 | "Generate code to match a match* pattern PATTERN. | ||
| 287 | Match it against data represented by the expression DATA. | ||
| 288 | TRUE-EXPS, UNCONDIT-CLAUSES and IFFALSE have the same meanings | ||
| 289 | as in `cond*-condition'." | ||
| 290 | (when (or (null matchexp) (null (cdr-safe matchexp)) | ||
| 291 | (null (cdr-safe (cdr matchexp))) | ||
| 292 | (cdr-safe (cdr (cdr matchexp)))) | ||
| 293 | (byte-compile-warn-x matchexp "Malformed (match* ...) expression")) | ||
| 294 | (let* (raw-result | ||
| 295 | (pattern (nth 1 matchexp)) | ||
| 296 | (data (nth 2 matchexp)) | ||
| 297 | expression | ||
| 298 | (inner-data data) | ||
| 299 | ;; Add backtrack aliases for or-subpatterns to cdr of this. | ||
| 300 | (backtrack-aliases (list nil)) | ||
| 301 | run-true-exps | ||
| 302 | store-value-swap-outs retrieve-value-swap-outs | ||
| 303 | gensym) | ||
| 304 | ;; For now, always bind a gensym to the data to be matched. | ||
| 305 | (setq gensym (gensym "d") inner-data gensym) | ||
| 306 | ;; Process the whole pattern as a subpattern. | ||
| 307 | (setq raw-result (cond*-subpat pattern nil nil nil backtrack-aliases inner-data)) | ||
| 308 | (setq expression (cdr raw-result)) | ||
| 309 | ;; If there are conditional expressions and some | ||
| 310 | ;; unconditional clauses to follow, | ||
| 311 | ;; and the pattern bound some variables, | ||
| 312 | ;; copy their values into special aliases | ||
| 313 | ;; to be copied back at the start of the unonditional clauses. | ||
| 314 | (when (and uncondit-clauses true-exps | ||
| 315 | (car raw-result)) | ||
| 316 | (dolist (bound-var (car raw-result)) | ||
| 317 | (push `(setq ,(gensym "ua") ,(car bound-var)) store-value-swap-outs) | ||
| 318 | (push `(,(car bound-var) ,(gensym "ua")) retrieve-value-swap-outs))) | ||
| 319 | |||
| 320 | ;; Make an expression to run the TRUE-EXPS inside our bindings. | ||
| 321 | (if store-value-swap-outs | ||
| 322 | ;; If we have to store those bindings' values in aliases | ||
| 323 | ;; for the UNCONDIT-CLAUSES, ;; do so inside these bindigs. | ||
| 324 | (setq run-true-exps | ||
| 325 | (cond*-bind-pattern-syms | ||
| 326 | (car raw-result) | ||
| 327 | `(prog1 (progn . ,true-exps) . ,store-value-swap-outs))) | ||
| 328 | (setq run-true-exps | ||
| 329 | (cond*-bind-pattern-syms | ||
| 330 | (car raw-result) | ||
| 331 | `(progn . ,true-exps)))) | ||
| 332 | ;; Run TRUE-EXPS if match succeeded. Bind our bindings around it. | ||
| 333 | (setq expression | ||
| 334 | (if (and (null run-true-exps) (null iffalse)) | ||
| 335 | ;; We MUST compute the expression, even when no decision | ||
| 336 | ;; depends on its value, because it may call functions with | ||
| 337 | ;; side effects. | ||
| 338 | expression | ||
| 339 | `(if ,expression | ||
| 340 | ,run-true-exps | ||
| 341 | ;; For a non-final exiting clause, run IFFALSE if match failed. | ||
| 342 | ;; Don't bind the bindings around it, since | ||
| 343 | ;; an exiting clause's bindings don't affect later clauses. | ||
| 344 | ,iffalse))) | ||
| 345 | ;; For a non-final non-exiting clause, | ||
| 346 | ;; always run the UNCONDIT-CLAUSES. | ||
| 347 | (if uncondit-clauses | ||
| 348 | (setq expression | ||
| 349 | `(progn ,expression | ||
| 350 | (cond*-bind-pattern-syms | ||
| 351 | ,(if retrieve-value-swap-outs | ||
| 352 | ;; If we saved the bindings' values after the | ||
| 353 | ;; true-clauses, bind the same variables | ||
| 354 | ;; here to the values we saved then. | ||
| 355 | retrieve-value-swap-outs | ||
| 356 | ;; Otherwise bind them to the values | ||
| 357 | ;; they matched in the pattern. | ||
| 358 | (car raw-result)) | ||
| 359 | (cond*-convert uncondit-clauses))))) | ||
| 360 | ;; Bind the backtrack-aliases if any. | ||
| 361 | ;; We need them bound for the TRUE-EXPS. | ||
| 362 | ;; It is harmless to bind them around IFFALSE | ||
| 363 | ;; because they are all gensyms anyway. | ||
| 364 | (if (cdr backtrack-aliases) | ||
| 365 | (setq expression | ||
| 366 | `(let ,(mapcar 'cdr (cdr backtrack-aliases)) | ||
| 367 | ,expression))) | ||
| 368 | (if retrieve-value-swap-outs | ||
| 369 | (setq expression | ||
| 370 | `(let ,(mapcar 'cadr retrieve-value-swap-outs) | ||
| 371 | ,expression))) | ||
| 372 | ;; If we used a gensym, wrap on code to bind it. | ||
| 373 | (if gensym | ||
| 374 | (if (and (listp expression) (eq (car expression) 'progn)) | ||
| 375 | `(let ((,gensym ,data)) . ,(cdr expression)) | ||
| 376 | `(let ((,gensym ,data)) ,expression)) | ||
| 377 | expression))) | ||
| 378 | |||
| 379 | (defun cond*-bind-pattern-syms (bindings expr) | ||
| 380 | "Wrap EXPR in code to bind the BINDINGS. | ||
| 381 | This is used for the bindings specified explicitly in match* patterns." | ||
| 382 | ;; They can't have side effects. Skip them | ||
| 383 | ;; if we don't actually need them. | ||
| 384 | (if (equal expr '(progn)) | ||
| 385 | nil | ||
| 386 | (if bindings | ||
| 387 | (if (eq (car expr) 'progn) | ||
| 388 | `(let* ,bindings . ,(cdr expr)) | ||
| 389 | `(let* ,bindings ,expr)) | ||
| 390 | expr))) | ||
| 391 | |||
| 392 | (defvar cond*-debug-pattern nil) | ||
| 393 | |||
| 394 | ;;; ??? Structure type patterns not implemented yet. | ||
| 395 | ;;; ??? Probably should optimize the `nth' calls in handling `list'. | ||
| 396 | |||
| 397 | (defun cond*-subpat (subpat cdr-ignore bindings inside-or backtrack-aliases data) | ||
| 398 | "Generate code to match the subpattern within `match*'. | ||
| 399 | SUBPAT is the subpattern to handle. | ||
| 400 | CDR-IGNORE if true means don't verify there are no extra elts in a list. | ||
| 401 | BINDINGS is the list of bindings made by | ||
| 402 | the containing and previous subpatterns of this pattern. | ||
| 403 | Each element of BINDINGS must have the form (VAR VALUE). | ||
| 404 | BACKTRACK-ALIASES is used to pass data upward. Initial call should | ||
| 405 | pass (list). The cdr of this collects backtracking aliases made for | ||
| 406 | variables bound within (or...) patterns so that the caller | ||
| 407 | can bind them etc. Each of them has the form (USER-SYMBOL . GENSYM). | ||
| 408 | DATA is the expression for the data that this subpattern is | ||
| 409 | supposed to match against. | ||
| 410 | |||
| 411 | Return Value has the form (BINDINGS . CONDITION), where | ||
| 412 | BINDINGS is the list of bindings to be made for SUBPAT | ||
| 413 | plus the subpatterns that contain/precede it. | ||
| 414 | Each element of BINDINGS has the form (VAR VALUE). | ||
| 415 | CONDITION is the condition to be tested to decide | ||
| 416 | whether SUBPAT (as well as the subpatterns that contain/precede it) matches," | ||
| 417 | (if (equal cond*-debug-pattern subpat) | ||
| 418 | (debug)) | ||
| 419 | ;;; (push subpat subpat-log) | ||
| 420 | (cond ((eq subpat '_) | ||
| 421 | ;; _ as pattern makes no bindings and matches any data. | ||
| 422 | (cons bindings t)) | ||
| 423 | ((memq subpat '(nil t)) | ||
| 424 | (cons bindings `(eq ,subpat ,data))) | ||
| 425 | ((keywordp subpat) | ||
| 426 | (cons bindings `(eq ,subpat ,data))) | ||
| 427 | ((symbolp subpat) | ||
| 428 | (let ((this-binding (assq subpat bindings)) | ||
| 429 | (this-alias (assq subpat (cdr backtrack-aliases)))) | ||
| 430 | (if this-binding | ||
| 431 | ;; Variable already bound. | ||
| 432 | ;; Compare what this variable should be bound to | ||
| 433 | ;; to the data it is supposed to match. | ||
| 434 | ;; That is because we don't actually bind these bindings | ||
| 435 | ;; around the condition-testing expression. | ||
| 436 | (cons bindings `(equal ,(cadr this-binding) ,data)) | ||
| 437 | (if inside-or | ||
| 438 | (let (alias-gensym) | ||
| 439 | (if this-alias | ||
| 440 | ;; Inside `or' subpattern, if this symbol already | ||
| 441 | ;; has an alias for backtracking, just use that. | ||
| 442 | ;; This means the symbol was matched | ||
| 443 | ;; in a previous arm of the `or'. | ||
| 444 | (setq alias-gensym (cdr this-alias)) | ||
| 445 | ;; Inside `or' subpattern but this symbol has no alias, | ||
| 446 | ;; make an alias for it. | ||
| 447 | (setq alias-gensym (gensym "ba")) | ||
| 448 | (push (cons subpat alias-gensym) (cdr backtrack-aliases))) | ||
| 449 | ;; Make a binding for the symbol, to its backtrack-alias, | ||
| 450 | ;; and set the alias (a gensym) to nil. | ||
| 451 | (cons `((,subpat ,alias-gensym) . ,bindings) | ||
| 452 | `(setq ,alias-gensym ,data))) | ||
| 453 | ;; Not inside `or' subpattern: ask for a binding for this symbol | ||
| 454 | ;; and say it does match whatever datum. | ||
| 455 | (cons `((,subpat ,data) . ,bindings) | ||
| 456 | t))))) | ||
| 457 | ;; Various constants. | ||
| 458 | ((numberp subpat) | ||
| 459 | (cons bindings `(eql ,subpat ,data))) | ||
| 460 | ;; Regular expressions as strings. | ||
| 461 | ((stringp subpat) | ||
| 462 | (cons bindings `(string-match ,(concat subpat "\\'") ,data))) | ||
| 463 | ;; All other atoms match with `equal'. | ||
| 464 | ((not (consp subpat)) | ||
| 465 | (cons bindings `(equal ,subpat ,data))) | ||
| 466 | ((not (consp (cdr subpat))) | ||
| 467 | (byte-compile-warn-x subpat "%s subpattern with malformed or missing arguments" (car subpat))) | ||
| 468 | ;; Regular expressions specified as list structure. | ||
| 469 | ;; (rx REGEXP VARS...) | ||
| 470 | ((eq (car subpat) 'rx) | ||
| 471 | (let* ((rxpat (concat (rx-to-string (cadr subpat) t) "\\'")) | ||
| 472 | (vars (cddr subpat)) setqs (varnum 0) | ||
| 473 | (match-exp `(string-match ,rxpat ,data))) | ||
| 474 | (if (null vars) | ||
| 475 | (cons bindings match-exp) | ||
| 476 | ;; There are variables to bind to the matched substrings. | ||
| 477 | (if (> (length vars) 10) | ||
| 478 | (byte-compile-warn-x vars "Too many variables specified for matched substrings")) | ||
| 479 | (dolist (elt vars) | ||
| 480 | (unless (symbolp elt) | ||
| 481 | (byte-compile-warn-x vars "Non-symbol %s given as name for matched substring" elt))) | ||
| 482 | ;; Bind these variables to nil, before the pattern. | ||
| 483 | (setq bindings (nconc (mapcar 'list vars) bindings)) | ||
| 484 | ;; Make the expressions to set the variables. | ||
| 485 | (setq setqs (mapcar | ||
| 486 | (lambda (var) | ||
| 487 | (prog1 `(setq ,var (match-string ,varnum ,data)) | ||
| 488 | (setq varnum (1+ varnum)))) | ||
| 489 | vars)) | ||
| 490 | (cons bindings `(if ,match-exp | ||
| 491 | (progn ,@setqs t)))))) | ||
| 492 | ;; Quoted object as constant to match with `eq' or `equal'. | ||
| 493 | ((eq (car subpat) 'quote) | ||
| 494 | (if (symbolp (car-safe (cdr-safe subpat))) | ||
| 495 | (cons bindings `(eq ,subpat ,data)) | ||
| 496 | (cons bindings `(equal ,subpat ,data)))) | ||
| 497 | ;; Match a call to `cons' by destructuring. | ||
| 498 | ((eq (car subpat) 'cons) | ||
| 499 | (let (car-result cdr-result car-exp cdr-exp) | ||
| 500 | (setq car-result | ||
| 501 | (cond*-subpat (nth 1 subpat) cdr-ignore bindings inside-or backtrack-aliases `(car ,data))) | ||
| 502 | (setq bindings (car car-result) | ||
| 503 | car-exp (cdr car-result)) | ||
| 504 | (setq cdr-result | ||
| 505 | (cond*-subpat (nth 2 subpat) cdr-ignore bindings inside-or backtrack-aliases `(cdr ,data))) | ||
| 506 | (setq bindings (car cdr-result) | ||
| 507 | cdr-exp (cdr cdr-result)) | ||
| 508 | (cons bindings | ||
| 509 | (cond*-and `((consp ,data) ,car-exp ,cdr-exp))))) | ||
| 510 | ;; Match a call to `list' by destructuring. | ||
| 511 | ((eq (car subpat) 'list) | ||
| 512 | (let ((i 0) expressions) | ||
| 513 | ;; Check for bad structure of SUBPAT here? | ||
| 514 | (dolist (this-elt (cdr subpat)) | ||
| 515 | (let ((result | ||
| 516 | (cond*-subpat this-elt cdr-ignore bindings inside-or backtrack-aliases `(nth ,i ,data)))) | ||
| 517 | (setq bindings (car result)) | ||
| 518 | (push `(consp ,(if (zerop i) data `(nthcdr ,i ,data))) | ||
| 519 | expressions) | ||
| 520 | (setq i (1+ i)) | ||
| 521 | (push (cdr result) expressions))) | ||
| 522 | ;; Verify that list ends here, if we are supposed to check that. | ||
| 523 | (unless cdr-ignore | ||
| 524 | (push `(null (nthcdr ,i ,data)) expressions)) | ||
| 525 | (cons bindings (cond*-and (nreverse expressions))))) | ||
| 526 | ;; Match (apply 'vector (backquote-list* LIST...)), destructuring. | ||
| 527 | ((eq (car subpat) 'apply) | ||
| 528 | ;; We only try to handle the case generated by backquote. | ||
| 529 | ;; Convert it to a call to `vector' and handle that. | ||
| 530 | (let ((cleaned-up | ||
| 531 | `(vector . ,(cond*-un-backquote-list* (cdr (nth 2 subpat)))))) | ||
| 532 | ;; (cdr (nth 2 subpat)) gets LIST as above. | ||
| 533 | (cond*-subpat cleaned-up | ||
| 534 | cdr-ignore bindings inside-or backtrack-aliases data))) | ||
| 535 | ;; Match a call to `vector' by destructuring. | ||
| 536 | ((eq (car subpat) 'vector) | ||
| 537 | (let* ((elts (cdr subpat)) | ||
| 538 | (length (length elts)) | ||
| 539 | expressions (i 0)) | ||
| 540 | (dolist (elt elts) | ||
| 541 | (let* ((result | ||
| 542 | (cond*-subpat elt cdr-ignore | ||
| 543 | bindings inside-or backtrack-aliases `(aref ,i ,data)))) | ||
| 544 | (setq i (1+ i)) | ||
| 545 | (setq bindings (car result)) | ||
| 546 | (push (cdr result) expressions))) | ||
| 547 | (cons bindings | ||
| 548 | (cond*-and `((vectorp ,data) (= (length ,data) ,length) | ||
| 549 | . ,(nreverse expressions)))))) | ||
| 550 | ;; Subpattern to set the cdr-ignore flag | ||
| 551 | ((eq (car subpat) 'cdr-ignore) | ||
| 552 | (cond*-subpat (cadr subpat) t bindings inside-or backtrack-aliases data)) | ||
| 553 | ;; Subpattern to clear the cdr-ignore flag | ||
| 554 | ((eq (car subpat) 'cdr) | ||
| 555 | (cond*-subpat (cadr subpat) nil bindings inside-or backtrack-aliases data)) | ||
| 556 | ;; Handle conjunction subpatterns. | ||
| 557 | ((eq (car subpat) 'and) | ||
| 558 | (let (expressions) | ||
| 559 | ;; Check for bad structure of SUBPAT here? | ||
| 560 | (dolist (this-elt (cdr subpat)) | ||
| 561 | (let ((result | ||
| 562 | (cond*-subpat this-elt cdr-ignore bindings inside-or backtrack-aliases data))) | ||
| 563 | (setq bindings (car result)) | ||
| 564 | (push (cdr result) expressions))) | ||
| 565 | (cons bindings (cond*-and (nreverse expressions))))) | ||
| 566 | ;; Handle disjunction subpatterns. | ||
| 567 | ((eq (car subpat) 'or) | ||
| 568 | ;; The main complexity is unsetting the pattern variables | ||
| 569 | ;; that tentatively matche in an or-branch that later failed. | ||
| 570 | (let (expressions | ||
| 571 | (bindings-before-or bindings) | ||
| 572 | (aliases-before-or (cdr backtrack-aliases))) | ||
| 573 | ;; Check for bad structure of SUBPAT here? | ||
| 574 | (dolist (this-elt (cdr subpat)) | ||
| 575 | (let* ((bindings bindings-before-or) | ||
| 576 | bindings-to-clear expression | ||
| 577 | result) | ||
| 578 | (setq result | ||
| 579 | (cond*-subpat this-elt cdr-ignore bindings t backtrack-aliases data)) | ||
| 580 | (setq bindings (car result)) | ||
| 581 | (setq expression (cdr result)) | ||
| 582 | ;; Were any bindings made by this arm of the disjunction? | ||
| 583 | (when (not (eq bindings bindings-before-or)) | ||
| 584 | ;; Ok, arrange to clear their backtrack aliases | ||
| 585 | ;; if this arm does not match. | ||
| 586 | (setq bindings-to-clear bindings) | ||
| 587 | (let (clearing) | ||
| 588 | ;; For each of those bindings, | ||
| 589 | (while (not (eq bindings-to-clear bindings-before-or)) | ||
| 590 | ;; Make an expression to set it to nil, in CLEARING. | ||
| 591 | (let* ((this-variable (caar bindings-to-clear)) | ||
| 592 | (this-backtrack (assq this-variable | ||
| 593 | (cdr backtrack-aliases)))) | ||
| 594 | (push `(setq ,(cdr this-backtrack) nil) clearing)) | ||
| 595 | (setq bindings-to-clear (cdr bindings-to-clear))) | ||
| 596 | ;; Wrap EXPRESSION to clear those backtrack aliases | ||
| 597 | ;; if EXPRESSION is false. | ||
| 598 | (setq expression | ||
| 599 | (if (null clearing) | ||
| 600 | expression | ||
| 601 | (if (null (cdr clearing)) | ||
| 602 | `(or ,expression | ||
| 603 | ,(car clearing)) | ||
| 604 | `(progn ,@clearing)))))) | ||
| 605 | (push expression expressions))) | ||
| 606 | ;; At end of (or...), EACH variable bound by any arm | ||
| 607 | ;; has a backtrack alias gensym. At run time, that gensym's value | ||
| 608 | ;; will be what was bound in the successful arm, or nil. | ||
| 609 | ;; Now make a binding for each variable from its alias gensym. | ||
| 610 | (let ((aliases (cdr backtrack-aliases))) | ||
| 611 | (while (not (eq aliases aliases-before-or)) | ||
| 612 | (push `(,(caar aliases) ,(cdar aliases)) bindings) | ||
| 613 | (pop aliases))) | ||
| 614 | (cons bindings `(or . ,(nreverse expressions))))) | ||
| 615 | ;; Expand cond*-macro call, treat result as a subpattern. | ||
| 616 | ((get (car subpat) 'cond*-expander) | ||
| 617 | ;; Treat result as a subpattern. | ||
| 618 | (cond*-subpat (funcall (get (car subpat) 'cond*-expander) subpat) | ||
| 619 | cdr-ignore bindings inside-or backtrack-aliases data)) | ||
| 620 | ((macrop (car subpat)) | ||
| 621 | (cond*-subpat (macroexpand subpat) cdr-ignore bindings inside-or backtrack-aliases data)) | ||
| 622 | ;; Simple constrained variable, as in (symbolp x). | ||
| 623 | ((functionp (car subpat)) | ||
| 624 | ;; Without this, nested constrained variables just work. | ||
| 625 | (unless (symbolp (cadr subpat)) | ||
| 626 | (byte-compile-warn-x subpat "Complex pattern nested in constrained variable pattern")) | ||
| 627 | (let* ((rest-args (cddr subpat)) | ||
| 628 | ;; Process VAR to get a binding for it. | ||
| 629 | (result (cond*-subpat (cadr subpat) cdr-ignore bindings inside-or backtrack-aliases data)) | ||
| 630 | (new-bindings (car result)) | ||
| 631 | (expression (cdr result)) | ||
| 632 | (combined-exp | ||
| 633 | (cond*-and (list `(,(car subpat) ,data . ,rest-args) expression)))) | ||
| 634 | |||
| 635 | (cons new-bindings | ||
| 636 | (cond*-bind-around new-bindings combined-exp)))) | ||
| 637 | ;; Generalized constrained variable: (constrain VAR EXP) | ||
| 638 | ((eq (car subpat) 'constrain) | ||
| 639 | ;; Without this, nested constrained variables just work. | ||
| 640 | (unless (symbolp (cadr subpat)) | ||
| 641 | (byte-compile-warn-x subpat "Complex pattern nested in constrained variable pattern")) | ||
| 642 | ;; Process VAR to get a binding for it. | ||
| 643 | (let ((result (cond*-subpat (cadr subpat) cdr-ignore bindings inside-or backtrack-aliases data))) | ||
| 644 | (cons (car result) | ||
| 645 | ;; This is the test condition. | ||
| 646 | (cond*-bind-around (car result) (nth 2 subpat))))) | ||
| 647 | (t | ||
| 648 | (byte-compile-warn-x subpat "Undefined pattern type `%s' in `cond*'" (car subpat))))) | ||
| 649 | |||
| 650 | ;;; Subroutines of cond*-subpat. | ||
| 651 | |||
| 652 | (defun cond*-bind-around (bindings exp) | ||
| 653 | "Wrap a `let*' around EXP, to bind those of BINDINGS used in EXP." | ||
| 654 | (let ((what-to-bind (cond*-used-within bindings exp))) | ||
| 655 | (if what-to-bind | ||
| 656 | `(let* ,(nreverse what-to-bind) ,exp) | ||
| 657 | exp))) | ||
| 658 | |||
| 659 | (defun cond*-used-within (bindings exp) | ||
| 660 | "Return the list of those bindings in BINDINGS which EXP refers to. | ||
| 661 | This operates naively and errs on the side of overinclusion, | ||
| 662 | and does not distinguish function names from variable names. | ||
| 663 | That is safe for the purpose this is used for." | ||
| 664 | (cond ((symbolp exp) | ||
| 665 | (let ((which (assq exp bindings))) | ||
| 666 | (if which (list which)))) | ||
| 667 | ((listp exp) | ||
| 668 | (let (combined (rest exp)) | ||
| 669 | ;; Find the bindings used in each element of EXP | ||
| 670 | ;; and merge them together in COMBINED. | ||
| 671 | ;; It would be simpler to use dolist at each level, | ||
| 672 | ;; but this avoids errors from improper lists. | ||
| 673 | (while rest | ||
| 674 | (let ((in-this-elt (cond*-used-within bindings (car rest)))) | ||
| 675 | (while in-this-elt | ||
| 676 | ;; Don't insert the same binding twice. | ||
| 677 | (unless (memq (car-safe in-this-elt) combined) | ||
| 678 | (push (car-safe in-this-elt) combined)) | ||
| 679 | (pop in-this-elt))) | ||
| 680 | (pop rest)) | ||
| 681 | combined)))) | ||
| 682 | |||
| 683 | ;; Construct a simplified equivalent to `(and . ,CONJUNCTS), | ||
| 684 | ;; assuming that it will be used only as a truth value. | ||
| 685 | ;; We don't bother checking for nil in CONJUNCTS | ||
| 686 | ;; because that would not normally happen. | ||
| 687 | (defun cond*-and (conjuncts) | ||
| 688 | (setq conjuncts (remq t conjuncts)) | ||
| 689 | (if (null conjuncts) | ||
| 690 | t | ||
| 691 | (if (null (cdr conjuncts)) | ||
| 692 | (car conjuncts) | ||
| 693 | `(and . ,conjuncts)))) | ||
| 694 | |||
| 695 | ;; Convert the arguments in a form that calls `backquote-list*' | ||
| 696 | ;; into equivalent args to pass to `list'. | ||
| 697 | ;; We assume the last argument has the form 'LIST. | ||
| 698 | ;; That means quotify each of that list's elements, | ||
| 699 | ;; and preserve the other arguments in front of them. | ||
| 700 | (defun cond*-un-backquote-list* (args) | ||
| 701 | (if (cdr args) | ||
| 702 | (cons (car args) | ||
| 703 | (cond*-un-backquote-list* (cdr args))) | ||
| 704 | (mapcar (lambda (x) (list 'quote x)) (cadr (car args))))) | ||
| 705 | |||
| 706 | |||
| 707 | |||