summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/autoload.el4
-rw-r--r--lisp/emacs-lisp/bytecomp.el17
-rw-r--r--lisp/emacs-lisp/smie.el202
3 files changed, 149 insertions, 74 deletions
diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el
index 532d68245d8..4dd1a118ebd 100644
--- a/lisp/emacs-lisp/autoload.el
+++ b/lisp/emacs-lisp/autoload.el
@@ -575,8 +575,8 @@ removes any prior now out-of-date autoload entries."
(autoload-ensure-default-file (autoload-generated-file)))
;; This is to make generated-autoload-file have Unix EOLs, so
;; that it is portable to all platforms.
- (unless (zerop (coding-system-eol-type buffer-file-coding-system))
- (set-buffer-file-coding-system 'unix))
+ (or (eq 0 (coding-system-eol-type buffer-file-coding-system))
+ (set-buffer-file-coding-system 'unix))
(or (> (buffer-size) 0)
(error "Autoloads file %s lacks boilerplate" buffer-file-name))
(or (file-writable-p buffer-file-name)
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index f1adc5b496c..f04aad994f3 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -301,21 +301,12 @@ suppress. For example, (not mapcar) will suppress warnings about mapcar."
(set :menu-tag "Some"
,@(mapcar (lambda (x) `(const ,x))
byte-compile-warning-types))))
-;;;###autoload(put 'byte-compile-warnings 'safe-local-variable 'byte-compile-warnings-safe-p)
;;;###autoload
-(defun byte-compile-warnings-safe-p (x)
- "Return non-nil if X is valid as a value of `byte-compile-warnings'."
- (or (booleanp x)
- (and (listp x)
- (if (eq (car x) 'not) (setq x (cdr x))
- t)
- (equal (mapcar
- (lambda (e)
- (when (memq e byte-compile-warning-types)
- e))
- x)
- x))))
+(put 'byte-compile-warnings 'safe-local-variable
+ (lambda (v)
+ (or (symbolp v)
+ (null (delq nil (mapcar (lambda (x) (not (symbolp x))) v))))))
(defun byte-compile-warning-enabled-p (warning)
"Return non-nil if WARNING is enabled, according to `byte-compile-warnings'."
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index 03c03126d2f..179e0a9f094 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -63,10 +63,31 @@
;; Since then, some of that code has been beaten into submission, but the
;; smie-indent-keyword is still pretty obscure.
-;;; Code:
+;; Conflict resolution:
+;;
+;; - One source of conflicts is when you have:
+;; (exp ("IF" exp "ELSE" exp "END") ("CASE" cases "END"))
+;; (cases (cases "ELSE" insts) ...)
+;; The IF-rule implies ELSE=END and the CASE-rule implies ELSE>END.
+;; FIXME: we could try to resolve such conflicts automatically by changing
+;; the way BNF rules such as the IF-rule is handled. I.e. rather than
+;; IF=ELSE and ELSE=END, we could turn them into IF<ELSE and ELSE>END
+;; and IF=END,
+
+;; TODO & BUGS:
+;;
+;; - FIXME: I think the behavior on empty lines is wrong. It shouldn't
+;; look at the next token on subsequent lines.
+;; - Using the structural information SMIE gives us, it should be possible to
+;; implement a `smie-align' command that would automatically figure out what
+;; there is to align and how to do it (something like: align the token of
+;; lowest precedence that appears the same number of times on all lines,
+;; and then do the same on each side of that token).
+;; - Maybe accept two juxtaposed non-terminals in the BNF under the condition
+;; that the first always ends with a terminal, or that the second always
+;; starts with a terminal.
-;; FIXME: I think the behavior on empty lines is wrong. It shouldn't
-;; look at the next token on subsequent lines.
+;;; Code:
(eval-when-compile (require 'cl))
@@ -155,6 +176,11 @@ one of those elements share the same precedence level and associativity."
(put 'smie-bnf->prec2 'pure t)
(defun smie-bnf->prec2 (bnf &rest precs)
+ ;; FIXME: Add repetition operator like (repeat <separator> <elems>).
+ ;; Maybe also add (or <elem1> <elem2>...) for things like
+ ;; (exp (exp (or "+" "*" "=" ..) exp)).
+ ;; Basically, make it EBNF (except for the specification of a separator in
+ ;; the repetition).
(let ((nts (mapcar 'car bnf)) ;Non-terminals
(first-ops-table ())
(last-ops-table ())
@@ -327,6 +353,7 @@ from the table, e.g. the table will not include things like (\"if\" . \"else\").
"Return a table classifying terminals.
Each terminal can either be an `opener', a `closer', or neither."
(let ((table (make-hash-table :test #'equal))
+ (nts (mapcar #'car bnf))
(alist '()))
(dolist (category bnf)
(puthash (car category) 'neither table) ;Remove non-terminals.
@@ -336,14 +363,22 @@ Each terminal can either be an `opener', a `closer', or neither."
(let ((first (pop rhs)))
(puthash first
(if (memq (gethash first table) '(nil opener))
- 'opener 'neither)
+ 'opener
+ (unless (member first nts)
+ (error "SMIE: token %s is both opener and non-opener"
+ first))
+ '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)
+ 'closer
+ (unless (member last nts)
+ (error "SMIE: token %s is both closer and non-closer"
+ last))
+ 'neither)
table)))))
(maphash (lambda (tok v)
(when (memq v '(closer opener))
@@ -385,6 +420,18 @@ CSTS is a list of pairs representing arcs in a graph."
(append names (list (car names)))
" < ")))
+;; (defun smie-check-grammar (grammar prec2 &optional dummy)
+;; (maphash (lambda (k v)
+;; (when (consp k)
+;; (let ((left (nth 2 (assoc (car k) grammar)))
+;; (right (nth 1 (assoc (cdr k) grammar))))
+;; (when (and left right)
+;; (cond
+;; ((< left right) (assert (eq v '<)))
+;; ((> left right) (assert (eq v '>)))
+;; (t (assert (eq v '=))))))))
+;; prec2))
+
(put 'smie-prec2->grammar 'pure t)
(defun smie-prec2->grammar (prec2)
"Take a 2D precedence table and turn it into an alist of precedence levels.
@@ -453,6 +500,7 @@ PREC2 is a table as returned by `smie-precs->prec2' or
;; left = right).
(unless (caar cst)
(setcar (car cst) i)
+ ;; (smie-check-grammar table prec2 'step1)
(incf i))
(setq csts (delq cst csts))))
(unless progress
@@ -462,8 +510,19 @@ PREC2 is a table as returned by `smie-precs->prec2' or
(incf i 10))
;; Propagate equalities back to their source.
(dolist (eq (nreverse eqs))
- (assert (or (null (caar eq)) (eq (car eq) (cdr eq))))
- (setcar (car eq) (cadr eq)))
+ (when (null (cadr eq))
+ ;; There's an equality constraint, but we still haven't given
+ ;; it a value: that means it binds tighter than anything else,
+ ;; and it can't be an opener/closer (those don't have equality
+ ;; constraints).
+ ;; So set it here rather than below since doing it below
+ ;; makes it more difficult to obey the equality constraints.
+ (setcar (cdr eq) i)
+ (incf i))
+ (assert (or (null (caar eq)) (eq (caar eq) (cadr eq))))
+ (setcar (car eq) (cadr eq))
+ ;; (smie-check-grammar table prec2 'step2)
+ )
;; Finally, fill in the remaining vars (which only appeared on the
;; right side of the < constraints).
(let ((classification-table (gethash :smie-open/close-alist prec2)))
@@ -484,6 +543,7 @@ PREC2 is a table as returned by `smie-precs->prec2' or
(incf i))))) ;See other (incf i) above.
(let ((ca (gethash :smie-closer-alist prec2)))
(when ca (push (cons :smie-closer-alist ca) table)))
+ ;; (smie-check-grammar table prec2 'step3)
table))
;;; Parsing using a precedence level table.
@@ -493,9 +553,9 @@ PREC2 is a table as returned by `smie-precs->prec2' or
This list is normally built by `smie-prec2->grammar'.
Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL).
Parsing is done using an operator precedence parser.
-LEFT-LEVEL and RIGHT-LEVEL can be either numbers or nil, where nil
+LEFT-LEVEL and RIGHT-LEVEL can be either numbers or a list, where a list
means that this operator does not bind on the corresponding side,
-i.e. a LEFT-LEVEL of nil means this is a token that behaves somewhat like
+e.g. a LEFT-LEVEL of nil means this is a token that behaves somewhat like
an open-paren, whereas a RIGHT-LEVEL of nil would correspond to something
like a close-paren.")
@@ -579,9 +639,10 @@ Possible return values:
(if (eq pos (point))
;; We did not move, so let's abort the loop.
(throw 'return (list t (point))))))
- ((null (funcall op-back toklevels))
+ ((not (numberp (funcall op-back toklevels)))
;; A token like a paren-close.
- (assert (funcall op-forw toklevels)) ;Otherwise, why mention it?
+ (assert (numberp ; Otherwise, why mention it in smie-grammar.
+ (funcall op-forw toklevels)))
(push toklevels levels))
(t
(while (and levels (< (funcall op-back toklevels)
@@ -589,7 +650,7 @@ Possible return values:
(setq levels (cdr levels)))
(cond
((null levels)
- (if (and halfsexp (funcall op-forw toklevels))
+ (if (and halfsexp (numberp (funcall op-forw toklevels)))
(push toklevels levels)
(throw 'return
(prog1 (list (or (car toklevels) t) (point) token)
@@ -605,15 +666,15 @@ Possible return values:
;; Keep looking as long as we haven't matched the
;; topmost operator.
(levels
- (if (funcall op-forw toklevels)
+ (if (numberp (funcall op-forw toklevels))
(push toklevels levels)))
;; We matched the topmost operator. If the new operator
;; is the last in the corresponding BNF rule, we're done.
- ((null (funcall op-forw toklevels))
+ ((not (numberp (funcall op-forw toklevels)))
;; It is the last element, let's stop here.
(throw 'return (list nil (point) token)))
;; If the new operator is not the last in the BNF rule,
- ;; ans is not associative, it's one of the inner operators
+ ;; and is not associative, it's one of the inner operators
;; (like the "in" in "let .. in .. end"), so keep looking.
((not (smie--associative-p toklevels))
(push toklevels levels))
@@ -714,7 +775,7 @@ Possible return values:
;; intervention, e.g. for Octave's use of `until'
;; as a pseudo-closer of `do'.
(closer)
- ((or (equal levels '(nil)) (nth 1 (car levels)))
+ ((or (equal levels '(nil)) (numberp (nth 1 (car levels))))
(error "Doesn't look like a block"))
(t
;; Now that smie-setup automatically sets smie-closer-alist
@@ -725,7 +786,7 @@ Possible return values:
(when (and (eq (nth 2 level) (nth 1 other))
(not (memq other seen)))
(push other seen)
- (if (nth 2 other)
+ (if (numberp (nth 2 other))
(push other levels)
(push (car other) found))))))
(cond
@@ -766,8 +827,8 @@ This command assumes point is not in a string or comment."
(progn (goto-char start) (down-list inc) nil)
(forward-sexp inc)
(/= (point) pos)))
- ((and levels (null (nth (+ 1 offset) levels))) nil)
- ((and levels (null (nth (- 2 offset) levels)))
+ ((and levels (not (numberp (nth (+ 1 offset) levels)))) nil)
+ ((and levels (not (numberp (nth (- 2 offset) levels))))
(let ((end (point)))
(goto-char start)
(signal 'scan-error
@@ -852,7 +913,7 @@ This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'.
(not (memq (char-before)
smie-blink-matching-triggers)))
(or smie-blink-matching-inners
- (null (nth 2 (assoc token smie-grammar)))))
+ (not (numberp (nth 2 (assoc token smie-grammar))))))
;; The major mode might set blink-matching-check-function
;; buffer-locally so that interactive calls to
;; blink-matching-open work right, but let's not presume
@@ -928,7 +989,7 @@ the beginning of a line."
(save-excursion
(let* ((pos (point))
(tok (funcall smie-forward-token-function)))
- (unless (cadr (assoc tok smie-grammar))
+ (unless (numberp (cadr (assoc tok smie-grammar)))
(goto-char pos))
(setq smie--parent
(smie-backward-sexp 'halfsexp))))))
@@ -969,8 +1030,14 @@ Only meaningful when called from within `smie-rules-function'."
(goto-char (cadr (smie-indent--parent)))
(cons 'column
(+ (or offset 0)
- (if (smie-indent--hanging-p)
- (smie-indent-virtual) (current-column))))))
+ ;; Use smie-indent-virtual when indenting relative to an opener:
+ ;; this will also by default use current-column unless
+ ;; that opener is hanging, but will additionally consult
+ ;; rules-function, so it gives it a chance to tweak
+ ;; indentation (e.g. by forcing indentation relative to
+ ;; its own parent, as in fn a => fn b => fn c =>).
+ (if (or (listp (car smie--parent)) (smie-indent--hanging-p))
+ (smie-indent-virtual) (current-column))))))
(defvar smie-rule-separator-outdent 2)
@@ -1030,11 +1097,7 @@ Only meaningful when called from within `smie-rules-function'."
;; FIXME: Rather than consult the number of spaces, we could *set* the
;; number of spaces so as to align the separator with the close-paren
;; while aligning the content with the rest.
- (let ((parent-col
- (save-excursion
- (goto-char (cadr smie--parent))
- (if (smie-indent--hanging-p)
- (smie-indent-virtual) (current-column))))
+ (let ((parent-col (cdr (smie-rule-parent)))
(parent-pos-col ;FIXME: we knew this when computing smie--parent.
(save-excursion
(goto-char (cadr smie--parent))
@@ -1083,7 +1146,16 @@ BASE-POS is the position relative to which offsets should be applied."
(+ offset
(if (null base-pos) 0
(goto-char base-pos)
- (if (smie-indent--hanging-p)
+ ;; Use smie-indent-virtual when indenting relative to an opener:
+ ;; this will also by default use current-column unless
+ ;; that opener is hanging, but will additionally consult
+ ;; rules-function, so it gives it a chance to tweak indentation
+ ;; (e.g. by forcing indentation relative to its own parent, as in
+ ;; fn a => fn b => fn c =>).
+ ;; When parent==nil it doesn't matter because the only case
+ ;; where it's really used is when the base-pos is hanging anyway.
+ (if (or (and parent (null (car parent)))
+ (smie-indent--hanging-p))
(smie-indent-virtual) (current-column)))))
(t (error "Unknown indentation offset %s" offset))))))
@@ -1160,27 +1232,30 @@ in order to figure out the indentation of some other (further down) point."
(let* ((pos (point))
(toklevels (smie-indent-forward-token))
(token (pop toklevels)))
- (if (null (car toklevels))
- (save-excursion
- (goto-char pos)
- ;; Different cases:
- ;; - smie-indent--bolp: "indent according to others".
- ;; - common hanging: "indent according to others".
- ;; - SML-let hanging: "indent like parent".
- ;; - if-after-else: "indent-like parent".
- ;; - middle-of-line: "trust current position".
- (cond
- ((null (cdr toklevels)) nil) ;Not a keyword.
- ((smie-indent--bolp)
- ;; For an open-paren-like thingy at BOL, always indent only
- ;; based on other rules (typically smie-indent-after-keyword).
- nil)
- ;; We're only ever here for virtual-indent.
- ((smie-indent--rule :before token))
- (t
- ;; By default use point unless we're hanging.
- (unless (smie-indent--hanging-p) (current-column)))))
-
+ (cond
+ ((< pos (line-beginning-position))
+ ;; The token we just read is actually not on the line where we started.
+ nil)
+ ((not (numberp (car toklevels)))
+ (save-excursion
+ (goto-char pos)
+ ;; Different cases:
+ ;; - smie-indent--bolp: "indent according to others".
+ ;; - common hanging: "indent according to others".
+ ;; - SML-let hanging: "indent like parent".
+ ;; - if-after-else: "indent-like parent".
+ ;; - middle-of-line: "trust current position".
+ (cond
+ ((null (cdr toklevels)) nil) ;Not a keyword.
+ ((smie-indent--rule :before token))
+ ((smie-indent--bolp) ;I.e. non-virtual indent.
+ ;; For an open-paren-like thingy at BOL, always indent only
+ ;; based on other rules (typically smie-indent-after-keyword).
+ nil)
+ (t
+ ;; By default use point unless we're hanging.
+ (unless (smie-indent--hanging-p) (current-column))))))
+ (t
;; FIXME: This still looks too much like black magic!!
(let* ((parent (smie-backward-sexp 'halfsexp)))
;; Different behaviors:
@@ -1260,7 +1335,7 @@ in order to figure out the indentation of some other (further down) point."
;; So we use a heuristic here, which is that we only use virtual
;; if the parent is tightly linked to the child token (they're
;; part of the same BNF rule).
- (if (car parent) (current-column) (smie-indent-virtual))))))))))
+ (if (car parent) (current-column) (smie-indent-virtual)))))))))))
(defun smie-indent-comment ()
"Compute indentation of a comment."
@@ -1298,10 +1373,19 @@ in order to figure out the indentation of some other (further down) point."
comment-end-skip
(not (looking-at " \t*$")) ;Not just a \n comment-closer.
(looking-at comment-end-skip)
- (nth 4 (syntax-ppss))
- (save-excursion
- (goto-char (nth 8 (syntax-ppss)))
- (current-column))))
+ (let ((end (match-string 0)))
+ (and (nth 4 (syntax-ppss))
+ (save-excursion
+ (goto-char (nth 8 (syntax-ppss)))
+ (and (looking-at comment-start-skip)
+ (let ((start (match-string 0)))
+ ;; Align the common substring between starter
+ ;; and ender, if possible.
+ (if (string-match "\\(.+\\).*\n\\(.*?\\)\\1"
+ (concat start "\n" end))
+ (+ (current-column) (match-beginning 0)
+ (- (match-beginning 2) (match-end 2)))
+ (current-column)))))))))
(defun smie-indent-comment-inside ()
(and (nth 4 (syntax-ppss))
@@ -1319,11 +1403,11 @@ in order to figure out the indentation of some other (further down) point."
;; The default indentation after a keyword/operator is
;; 0 for infix, t for prefix, and use another rule
;; for postfix.
- ((null (nth 2 toklevel)) nil) ;A closer.
- ((or (null (nth 1 toklevel)) ;An opener.
- (rassoc tok smie-closer-alist)) ;An inner.
+ ((not (numberp (nth 2 toklevel))) nil) ;A closer.
+ ((or (not (numberp (nth 1 toklevel))) ;An opener.
+ (rassoc tok smie-closer-alist)) ;An inner.
(+ (smie-indent-virtual) (smie-indent--offset 'basic))) ;
- (t (smie-indent-virtual)))))) ;An infix.
+ (t (smie-indent-virtual)))))) ;An infix.
(defun smie-indent-exps ()
;; Indentation of sequences of simple expressions without