comparison lisp/emacs-lisp/smie.el @ 110802:e544f6cc2447

SMIE: Reliably distinguish openers/closers in smie-prec2-levels * lisp/emacs-lisp/smie.el (smie-bnf-classify): New function. (smie-bnf-precedence-table): Use it to remember the closers/openers. (smie-merge-prec2s): Handle those new entries. (smie-prec2-levels): Only set precedence to nil for actual openers/closers. * lisp/progmodes/octave-mod.el (octave-smie-op-levels): Remove dummy entry that is now unnecessary.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Thu, 07 Oct 2010 13:27:19 +0200
parents 27917ce150c1
children a9904c1962db
comparison
equal deleted inserted replaced
110801:37b955157790 110802:e544f6cc2447
136 (if (null (cdr tables)) 136 (if (null (cdr tables))
137 (car tables) 137 (car tables)
138 (let ((prec2 (make-hash-table :test 'equal))) 138 (let ((prec2 (make-hash-table :test 'equal)))
139 (dolist (table tables) 139 (dolist (table tables)
140 (maphash (lambda (k v) 140 (maphash (lambda (k v)
141 (smie-set-prec2tab prec2 (car k) (cdr k) v)) 141 (if (consp k)
142 (smie-set-prec2tab prec2 (car k) (cdr k) v)
143 (if (and (gethash k prec2)
144 (not (equal (gethash k prec2) v)))
145 (error "Conflicting values for %s property" k)
146 (puthash k v prec2))))
142 table)) 147 table))
143 prec2))) 148 prec2)))
144 149
145 (defun smie-bnf-precedence-table (bnf &rest precs) 150 (defun smie-bnf-precedence-table (bnf &rest precs)
146 (let ((nts (mapcar 'car bnf)) ;Non-terminals 151 (let ((nts (mapcar 'car bnf)) ;Non-terminals
223 (if (and (cddr rhs) (not (member (car (cddr rhs)) nts))) 228 (if (and (cddr rhs) (not (member (car (cddr rhs)) nts)))
224 (smie-set-prec2tab prec2 (car rhs) (car (cddr rhs)) 229 (smie-set-prec2tab prec2 (car rhs) (car (cddr rhs))
225 '= override))) 230 '= override)))
226 (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override))) 231 (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override)))
227 (setq rhs (cdr rhs))))) 232 (setq rhs (cdr rhs)))))
233 ;; Keep track of which tokens are openers/closer, so they can get a nil
234 ;; precedence in smie-prec2-levels.
235 (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2)
228 prec2)) 236 prec2))
229 237
230 ;; (defun smie-prec2-closer-alist (prec2 include-inners) 238 ;; (defun smie-prec2-closer-alist (prec2 include-inners)
231 ;; "Build a closer-alist from a PREC2 table. 239 ;; "Build a closer-alist from a PREC2 table.
232 ;; The return value is in the same form as `smie-closer-alist'. 240 ;; The return value is in the same form as `smie-closer-alist'.
305 (dolist (term (reverse (cdr rhs))) 313 (dolist (term (reverse (cdr rhs)))
306 (unless (member term nts) 314 (unless (member term nts)
307 (pushnew (cons (car rhs) term) alist :test #'equal))))))) 315 (pushnew (cons (car rhs) term) alist :test #'equal)))))))
308 (nreverse alist))) 316 (nreverse alist)))
309 317
318 (defun smie-bnf-classify (bnf)
319 "Return a table classifying terminals.
320 Each terminal can either be an `opener', a `closer', or neither."
321 (let ((table (make-hash-table :test #'equal))
322 (alist '()))
323 (dolist (category bnf)
324 (puthash (car category) 'neither table) ;Remove non-terminals.
325 (dolist (rhs (cdr category))
326 (if (null (cdr rhs))
327 (puthash (pop rhs) 'neither table)
328 (let ((first (pop rhs)))
329 (puthash first
330 (if (memq (gethash first table) '(nil opener))
331 'opener 'neither)
332 table))
333 (while (cdr rhs)
334 (puthash (pop rhs) 'neither table)) ;Remove internals.
335 (let ((last (pop rhs)))
336 (puthash last
337 (if (memq (gethash last table) '(nil closer))
338 'closer 'neither)
339 table)))))
340 (maphash (lambda (tok v)
341 (when (memq v '(closer opener))
342 (push (cons tok v) alist)))
343 table)
344 alist))
310 345
311 (defun smie-debug--prec2-cycle (csts) 346 (defun smie-debug--prec2-cycle (csts)
312 "Return a cycle in CSTS, assuming there's one. 347 "Return a cycle in CSTS, assuming there's one.
313 CSTS is a list of pairs representing arcs in a graph." 348 CSTS is a list of pairs representing arcs in a graph."
314 ;; A PATH is of the form (START . REST) where REST is a reverse 349 ;; A PATH is of the form (START . REST) where REST is a reverse
343 " < "))) 378 " < ")))
344 379
345 (defun smie-prec2-levels (prec2) 380 (defun smie-prec2-levels (prec2)
346 ;; FIXME: Rather than only return an alist of precedence levels, we should 381 ;; FIXME: Rather than only return an alist of precedence levels, we should
347 ;; also extract other useful data from it: 382 ;; also extract other useful data from it:
348 ;; - matching sets of block openers&closers (which can otherwise become
349 ;; collapsed into a single equivalence class in smie-op-levels) for
350 ;; smie-close-block as well as to detect mismatches in smie-next-sexp
351 ;; or in blink-paren (as well as to do the blink-paren for inner
352 ;; keywords like the "in" of "let..in..end").
353 ;; - better default indentation rules (i.e. non-zero indentation after inner 383 ;; - better default indentation rules (i.e. non-zero indentation after inner
354 ;; keywords like the "in" of "let..in..end") for smie-indent-after-keyword. 384 ;; keywords like the "in" of "let..in..end") for smie-indent-after-keyword.
355 ;; Of course, maybe those things would be even better handled in the 385 ;; Of course, maybe those things would be even better handled in the
356 ;; bnf->prec function. 386 ;; bnf->prec function.
357 "Take a 2D precedence table and turn it into an alist of precedence levels. 387 "Take a 2D precedence table and turn it into an alist of precedence levels.
367 tmp x y) 397 tmp x y)
368 ;; From `prec2' we construct a list of constraints between 398 ;; From `prec2' we construct a list of constraints between
369 ;; variables (aka "precedence levels"). These can be either 399 ;; variables (aka "precedence levels"). These can be either
370 ;; equality constraints (in `eqs') or `<' constraints (in `csts'). 400 ;; equality constraints (in `eqs') or `<' constraints (in `csts').
371 (maphash (lambda (k v) 401 (maphash (lambda (k v)
372 (if (setq tmp (assoc (car k) table)) 402 (when (consp k)
373 (setq x (cddr tmp)) 403 (if (setq tmp (assoc (car k) table))
374 (setq x (cons nil nil)) 404 (setq x (cddr tmp))
375 (push (cons (car k) (cons nil x)) table)) 405 (setq x (cons nil nil))
376 (if (setq tmp (assoc (cdr k) table)) 406 (push (cons (car k) (cons nil x)) table))
377 (setq y (cdr tmp)) 407 (if (setq tmp (assoc (cdr k) table))
378 (setq y (cons nil (cons nil nil))) 408 (setq y (cdr tmp))
379 (push (cons (cdr k) y) table)) 409 (setq y (cons nil (cons nil nil)))
380 (ecase v 410 (push (cons (cdr k) y) table))
381 (= (push (cons x y) eqs)) 411 (ecase v
382 (< (push (cons x y) csts)) 412 (= (push (cons x y) eqs))
383 (> (push (cons y x) csts)))) 413 (< (push (cons x y) csts))
414 (> (push (cons y x) csts)))))
384 prec2) 415 prec2)
385 ;; First process the equality constraints. 416 ;; First process the equality constraints.
386 (let ((eqs eqs)) 417 (let ((eqs eqs))
387 (while eqs 418 (while eqs
388 (let ((from (caar eqs)) 419 (let ((from (caar eqs))
430 (dolist (eq (nreverse eqs)) 461 (dolist (eq (nreverse eqs))
431 (assert (or (null (caar eq)) (eq (car eq) (cdr eq)))) 462 (assert (or (null (caar eq)) (eq (car eq) (cdr eq))))
432 (setcar (car eq) (cadr eq))) 463 (setcar (car eq) (cadr eq)))
433 ;; Finally, fill in the remaining vars (which only appeared on the 464 ;; Finally, fill in the remaining vars (which only appeared on the
434 ;; right side of the < constraints). 465 ;; right side of the < constraints).
435 (dolist (x table) 466 (let ((classification-table (gethash :smie-open/close-alist prec2)))
436 ;; When both sides are nil, it means this operator binds very 467 (dolist (x table)
437 ;; very tight, but it's still just an operator, so we give it 468 ;; When both sides are nil, it means this operator binds very
438 ;; the highest precedence. 469 ;; very tight, but it's still just an operator, so we give it
439 ;; OTOH if only one side is nil, it usually means it's like an 470 ;; the highest precedence.
440 ;; open-paren, which is very important for indentation purposes, 471 ;; OTOH if only one side is nil, it usually means it's like an
441 ;; so we keep it nil, to make it easier to recognize. 472 ;; open-paren, which is very important for indentation purposes,
442 (unless (or (nth 1 x) (nth 2 x)) 473 ;; so we keep it nil if so, to make it easier to recognize.
443 (setf (nth 1 x) i) 474 (unless (or (nth 1 x)
444 (setf (nth 2 x) i)))) 475 (eq 'opener (cdr (assoc (car x) classification-table))))
476 (setf (nth 1 x) i)
477 (incf i)) ;See other (incf i) above.
478 (unless (or (nth 2 x)
479 (eq 'closer (cdr (assoc (car x) classification-table))))
480 (setf (nth 2 x) i)
481 (incf i))))) ;See other (incf i) above.
445 table)) 482 table))
446 483
447 ;;; Parsing using a precedence level table. 484 ;;; Parsing using a precedence level table.
448 485
449 (defvar smie-op-levels 'unset 486 (defvar smie-op-levels 'unset