diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2010-10-15 17:55:33 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2010-10-15 17:55:33 -0400 |
commit | 0c747cb143fa227e78f350ac353d703f489209df (patch) | |
tree | 5b434055c797bd75eaa1e3d9d0773e586d44daee /lisp/emacs-lisp/smie.el | |
parent | a01a7932080e8a6e7bc8472c58cefabcc2c37df3 (diff) | |
parent | aa095b2db98ae149737f8de00ee733b1d257ed33 (diff) | |
download | emacs-0c747cb143fa227e78f350ac353d703f489209df.tar.gz emacs-0c747cb143fa227e78f350ac353d703f489209df.tar.bz2 emacs-0c747cb143fa227e78f350ac353d703f489209df.zip |
Merge from trunk
Diffstat (limited to 'lisp/emacs-lisp/smie.el')
-rw-r--r-- | lisp/emacs-lisp/smie.el | 93 |
1 files changed, 65 insertions, 28 deletions
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el index 55516d276da..4f5b2046150 100644 --- a/lisp/emacs-lisp/smie.el +++ b/lisp/emacs-lisp/smie.el @@ -138,7 +138,12 @@ one of those elements share the same precedence level and associativity." (let ((prec2 (make-hash-table :test 'equal))) (dolist (table tables) (maphash (lambda (k v) - (smie-set-prec2tab prec2 (car k) (cdr k) v)) + (if (consp k) + (smie-set-prec2tab prec2 (car k) (cdr k) v) + (if (and (gethash k prec2) + (not (equal (gethash k prec2) v))) + (error "Conflicting values for %s property" k) + (puthash k v prec2)))) table)) prec2))) @@ -225,6 +230,9 @@ one of those elements share the same precedence level and associativity." '= override))) (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override))) (setq rhs (cdr rhs))))) + ;; Keep track of which tokens are openers/closer, so they can get a nil + ;; precedence in smie-prec2-levels. + (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2) prec2)) ;; (defun smie-prec2-closer-alist (prec2 include-inners) @@ -307,6 +315,33 @@ from the table, e.g. the table will not include things like (\"if\" . \"else\"). (pushnew (cons (car rhs) term) alist :test #'equal))))))) (nreverse alist))) +(defun smie-bnf-classify (bnf) + "Return a table classifying terminals. +Each terminal can either be an `opener', a `closer', or neither." + (let ((table (make-hash-table :test #'equal)) + (alist '())) + (dolist (category bnf) + (puthash (car category) 'neither table) ;Remove non-terminals. + (dolist (rhs (cdr category)) + (if (null (cdr rhs)) + (puthash (pop rhs) 'neither table) + (let ((first (pop rhs))) + (puthash first + (if (memq (gethash first table) '(nil opener)) + 'opener 'neither) + table)) + (while (cdr rhs) + (puthash (pop rhs) 'neither table)) ;Remove internals. + (let ((last (pop rhs))) + (puthash last + (if (memq (gethash last table) '(nil closer)) + 'closer 'neither) + table))))) + (maphash (lambda (tok v) + (when (memq v '(closer opener)) + (push (cons tok v) alist))) + table) + alist)) (defun smie-debug--prec2-cycle (csts) "Return a cycle in CSTS, assuming there's one. @@ -345,11 +380,6 @@ CSTS is a list of pairs representing arcs in a graph." (defun smie-prec2-levels (prec2) ;; FIXME: Rather than only return an alist of precedence levels, we should ;; also extract other useful data from it: - ;; - matching sets of block openers&closers (which can otherwise become - ;; collapsed into a single equivalence class in smie-op-levels) for - ;; smie-close-block as well as to detect mismatches in smie-next-sexp - ;; or in blink-paren (as well as to do the blink-paren for inner - ;; keywords like the "in" of "let..in..end"). ;; - better default indentation rules (i.e. non-zero indentation after inner ;; keywords like the "in" of "let..in..end") for smie-indent-after-keyword. ;; Of course, maybe those things would be even better handled in the @@ -369,18 +399,19 @@ PREC2 is a table as returned by `smie-precs-precedence-table' or ;; variables (aka "precedence levels"). These can be either ;; equality constraints (in `eqs') or `<' constraints (in `csts'). (maphash (lambda (k v) - (if (setq tmp (assoc (car k) table)) - (setq x (cddr tmp)) - (setq x (cons nil nil)) - (push (cons (car k) (cons nil x)) table)) - (if (setq tmp (assoc (cdr k) table)) - (setq y (cdr tmp)) - (setq y (cons nil (cons nil nil))) - (push (cons (cdr k) y) table)) - (ecase v - (= (push (cons x y) eqs)) - (< (push (cons x y) csts)) - (> (push (cons y x) csts)))) + (when (consp k) + (if (setq tmp (assoc (car k) table)) + (setq x (cddr tmp)) + (setq x (cons nil nil)) + (push (cons (car k) (cons nil x)) table)) + (if (setq tmp (assoc (cdr k) table)) + (setq y (cdr tmp)) + (setq y (cons nil (cons nil nil))) + (push (cons (cdr k) y) table)) + (ecase v + (= (push (cons x y) eqs)) + (< (push (cons x y) csts)) + (> (push (cons y x) csts))))) prec2) ;; First process the equality constraints. (let ((eqs eqs)) @@ -432,16 +463,22 @@ PREC2 is a table as returned by `smie-precs-precedence-table' or (setcar (car eq) (cadr eq))) ;; Finally, fill in the remaining vars (which only appeared on the ;; right side of the < constraints). - (dolist (x table) - ;; When both sides are nil, it means this operator binds very - ;; very tight, but it's still just an operator, so we give it - ;; the highest precedence. - ;; OTOH if only one side is nil, it usually means it's like an - ;; open-paren, which is very important for indentation purposes, - ;; so we keep it nil, to make it easier to recognize. - (unless (or (nth 1 x) (nth 2 x)) - (setf (nth 1 x) i) - (setf (nth 2 x) i)))) + (let ((classification-table (gethash :smie-open/close-alist prec2))) + (dolist (x table) + ;; When both sides are nil, it means this operator binds very + ;; very tight, but it's still just an operator, so we give it + ;; the highest precedence. + ;; OTOH if only one side is nil, it usually means it's like an + ;; open-paren, which is very important for indentation purposes, + ;; so we keep it nil if so, to make it easier to recognize. + (unless (or (nth 1 x) + (eq 'opener (cdr (assoc (car x) classification-table)))) + (setf (nth 1 x) i) + (incf i)) ;See other (incf i) above. + (unless (or (nth 2 x) + (eq 'closer (cdr (assoc (car x) classification-table)))) + (setf (nth 2 x) i) + (incf i))))) ;See other (incf i) above. table)) ;;; Parsing using a precedence level table. |