comparison lisp/emacs-lisp/smie.el @ 108649:c9e786f54683

Fix handling of non-associative equal levels. * emacs-lisp/smie.el (smie-prec2-levels): Choose distinct levels even when it's not needed. (smie-op-left, smie-op-right): New functions. (smie-next-sexp): New function, extracted from smie-backward-sexp. Better handle equal levels to distinguish the associative case from the "multi-keyword construct" case. (smie-backward-sexp, smie-forward-sexp): Use it.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Tue, 18 May 2010 12:03:51 -0400
parents 66f3c521df14
children 79ce86edba9f
comparison
equal deleted inserted replaced
108648:6d142dd06f97 108649:c9e786f54683
250 (let ((rhvs (mapcar 'cdr csts)) 250 (let ((rhvs (mapcar 'cdr csts))
251 (progress nil)) 251 (progress nil))
252 (dolist (cst csts) 252 (dolist (cst csts)
253 (unless (memq (car cst) rhvs) 253 (unless (memq (car cst) rhvs)
254 (setq progress t) 254 (setq progress t)
255 ;; We could give each var in a given iteration the same value,
256 ;; but we can also give them arbitrarily different values.
257 ;; Basically, these are vars between which there is no
258 ;; constraint (neither equality nor inequality), so
259 ;; anything will do.
260 ;; We give them arbitrary values, which means that we
261 ;; replace the "no constraint" case with either > or <
262 ;; but not =. The reason we do that is so as to try and
263 ;; distinguish associative operators (which will have
264 ;; left = right).
265 (unless (caar cst)
255 (setcar (car cst) i) 266 (setcar (car cst) i)
267 (incf i))
256 (setq csts (delq cst csts)))) 268 (setq csts (delq cst csts))))
257 (unless progress 269 (unless progress
258 (error "Can't resolve the precedence table to precedence levels"))) 270 (error "Can't resolve the precedence table to precedence levels")))
259 (incf i)) 271 (incf i 10))
260 ;; Propagate equalities back to their source. 272 ;; Propagate equalities back to their source.
261 (dolist (eq (nreverse eqs)) 273 (dolist (eq (nreverse eqs))
262 (assert (null (caar eq))) 274 (assert (null (caar eq)))
263 (setcar (car eq) (cadr eq))) 275 (setcar (car eq) (cadr eq)))
264 ;; Finally, fill in the remaining vars (which only appeared on the 276 ;; Finally, fill in the remaining vars (which only appeared on the
276 (defvar smie-op-levels 'unset 288 (defvar smie-op-levels 'unset
277 "List of token parsing info. 289 "List of token parsing info.
278 Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL). 290 Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL).
279 Parsing is done using an operator precedence parser.") 291 Parsing is done using an operator precedence parser.")
280 292
293 (defalias 'smie-op-left 'car)
294 (defalias 'smie-op-right 'cadr)
295
281 (defun smie-backward-token () 296 (defun smie-backward-token ()
282 ;; FIXME: This may be an OK default but probably needs a hook. 297 ;; FIXME: This may be an OK default but probably needs a hook.
283 (buffer-substring (point) 298 (buffer-substring (point)
284 (progn (if (zerop (skip-syntax-backward ".")) 299 (progn (if (zerop (skip-syntax-backward "."))
285 (skip-syntax-backward "w_'")) 300 (skip-syntax-backward "w_'"))
289 ;; FIXME: This may be an OK default but probably needs a hook. 304 ;; FIXME: This may be an OK default but probably needs a hook.
290 (buffer-substring (point) 305 (buffer-substring (point)
291 (progn (if (zerop (skip-syntax-forward ".")) 306 (progn (if (zerop (skip-syntax-forward "."))
292 (skip-syntax-forward "w_'")) 307 (skip-syntax-forward "w_'"))
293 (point)))) 308 (point))))
309
310 (defun smie-associative-p (toklevels)
311 ;; in "a + b + c" we want to stop at each +, but in
312 ;; "if a then b else c" we don't want to stop at each keyword.
313 ;; To distinguish the two cases, we made smie-prec2-levels choose
314 ;; different levels for each part of "if a then b else c", so that
315 ;; by checking if the left-level is equal to the right level, we can
316 ;; figure out that it's an associative operator.
317 ;; This is not 100% foolproof, tho, since a grammar like
318 ;; (exp ("A" exp "C") ("A" exp "B" exp "C"))
319 ;; will cause "B" to have equal left and right levels, even though
320 ;; it is not an associative operator.
321 ;; A better check would be the check the actual previous operator
322 ;; against this one to see if it's the same, but we'd have to change
323 ;; `levels' to keep a stack of operators rather than only levels.
324 (eq (smie-op-left toklevels) (smie-op-right toklevels)))
325
326 (defun smie-next-sexp (next-token next-sexp op-forw op-back halfsexp)
327 "Skip over one sexp.
328 NEXT-TOKEN is a function of no argument that moves forward by one
329 token (after skipping comments if needed) and returns it.
330 NEXT-SEXP is a lower-level function to skip one sexp.
331 OP-FORW is the accessor to the forward level of the level data.
332 OP-BACK is the accessor to the backward level of the level data.
333 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
334 first token we see is an operator, skip over its left-hand-side argument.
335 Possible return values:
336 (FORW-LEVEL POS TOKEN): we couldn't skip TOKEN because its back-level
337 is too high. FORW-LEVEL is the forw-level of TOKEN,
338 POS is its start position in the buffer.
339 (t POS TOKEN): same thing when we bump on the wrong side of a paren.
340 (nil POS TOKEN): we skipped over a paren-like pair.
341 nil: we skipped over an identifier, matched parentheses, ..."
342 (catch 'return
343 (let ((levels ()))
344 (while
345 (let* ((pos (point))
346 (token (funcall next-token))
347 (toklevels (cdr (assoc token smie-op-levels))))
348
349 (cond
350 ((null toklevels)
351 (if (equal token "")
352 (condition-case err
353 (progn (goto-char pos) (funcall next-sexp 1) nil)
354 (scan-error (throw 'return (list t (caddr err)))))))
355 ((null (funcall op-back toklevels))
356 ;; A token like a paren-close.
357 (assert (funcall op-forw toklevels)) ;Otherwise, why mention it?
358 (push (funcall op-forw toklevels) levels))
359 (t
360 (while (and levels (< (funcall op-back toklevels) (car levels)))
361 (setq levels (cdr levels)))
362 (cond
363 ((null levels)
364 (if (and halfsexp (funcall op-forw toklevels))
365 (push (funcall op-forw toklevels) levels)
366 (throw 'return
367 (prog1 (list (or (car toklevels) t) (point) token)
368 (goto-char pos)))))
369 (t
370 (if (and levels (= (funcall op-back toklevels) (car levels)))
371 (setq levels (cdr levels)))
372 (cond
373 ((null levels)
374 (cond
375 ((null (funcall op-forw toklevels))
376 (throw 'return (list nil (point) token)))
377 ((smie-associative-p toklevels)
378 (throw 'return
379 (prog1 (list (or (car toklevels) t) (point) token)
380 (goto-char pos))))
381 ;; We just found a match to the previously pending operator
382 ;; but this new operator is still part of a larger RHS.
383 ;; E.g. we're now looking at the "then" in
384 ;; "if a then b else c". So we have to keep parsing the
385 ;; rest of the construct.
386 (t (push (funcall op-forw toklevels) levels))))
387 (t
388 (if (funcall op-forw toklevels)
389 (push (funcall op-forw toklevels) levels))))))))
390 levels)
391 (setq halfsexp nil)))))
294 392
295 (defun smie-backward-sexp (&optional halfsexp) 393 (defun smie-backward-sexp (&optional halfsexp)
296 "Skip over one sexp. 394 "Skip over one sexp.
297 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the 395 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
298 first token we see is an operator, skip over its left-hand-side argument. 396 first token we see is an operator, skip over its left-hand-side argument.
302 POS is its start position in the buffer. 400 POS is its start position in the buffer.
303 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer. 401 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer.
304 (nil POS TOKEN): we skipped over a paren-like pair. 402 (nil POS TOKEN): we skipped over a paren-like pair.
305 nil: we skipped over an identifier, matched parentheses, ..." 403 nil: we skipped over an identifier, matched parentheses, ..."
306 (if (bobp) (list t (point)) 404 (if (bobp) (list t (point))
307 (catch 'return 405 (smie-next-sexp
308 (let ((levels ())) 406 (lambda () (forward-comment (- (point-max))) (smie-backward-token))
309 (while 407 (indirect-function 'backward-sexp)
310 (let* ((pos (point)) 408 (indirect-function 'smie-op-left)
311 (token (progn (forward-comment (- (point-max))) 409 (indirect-function 'smie-op-right)
312 (smie-backward-token))) 410 halfsexp)))
313 (toklevels (cdr (assoc token smie-op-levels))))
314
315 (cond
316 ((null toklevels)
317 (if (equal token "")
318 (condition-case err
319 (progn (goto-char pos) (backward-sexp 1) nil)
320 (scan-error (throw 'return (list t (caddr err)))))))
321 ((null (nth 1 toklevels))
322 ;; A token like a paren-close.
323 (assert (nth 0 toklevels)) ;Otherwise, why mention it?
324 (push (nth 0 toklevels) levels))
325 (t
326 (while (and levels (< (nth 1 toklevels) (car levels)))
327 (setq levels (cdr levels)))
328 (cond
329 ((null levels)
330 (if (and halfsexp (nth 0 toklevels))
331 (push (nth 0 toklevels) levels)
332 (throw 'return
333 (prog1 (list (or (car toklevels) t) (point) token)
334 (goto-char pos)))))
335 (t
336 (while (and levels (= (nth 1 toklevels) (car levels)))
337 (setq levels (cdr levels)))
338 (cond
339 ((null levels)
340 (cond
341 ((null (nth 0 toklevels))
342 (throw 'return (list nil (point) token)))
343 ((eq (nth 0 toklevels) (nth 1 toklevels))
344 (throw 'return
345 (prog1 (list (or (car toklevels) t) (point) token)
346 (goto-char pos))))
347 (t (debug)))) ;Not sure yet what to do here.
348 (t
349 (if (nth 0 toklevels)
350 (push (nth 0 toklevels) levels))))))))
351 levels)
352 (setq halfsexp nil))))))
353 411
354 ;; Mirror image, not used for indentation. 412 ;; Mirror image, not used for indentation.
355 (defun smie-forward-sexp (&optional halfsexp) 413 (defun smie-forward-sexp (&optional halfsexp)
356 "Skip over one sexp. 414 "Skip over one sexp.
357 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the 415 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
362 POS is its end position in the buffer. 420 POS is its end position in the buffer.
363 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer. 421 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer.
364 (nil POS TOKEN): we skipped over a paren-like pair. 422 (nil POS TOKEN): we skipped over a paren-like pair.
365 nil: we skipped over an identifier, matched parentheses, ..." 423 nil: we skipped over an identifier, matched parentheses, ..."
366 (if (eobp) (list t (point)) 424 (if (eobp) (list t (point))
367 (catch 'return 425 (smie-next-sexp
368 (let ((levels ())) 426 (lambda () (forward-comment (point-max)) (smie-forward-token))
369 (while 427 (indirect-function 'forward-sexp)
370 (let* ((pos (point)) 428 (indirect-function 'smie-op-right)
371 (token (progn (forward-comment (point-max)) 429 (indirect-function 'smie-op-left)
372 (smie-forward-token))) 430 halfsexp)))
373 (toklevels (cdr (assoc token smie-op-levels))))
374
375 (cond
376 ((null toklevels)
377 (if (equal token "")
378 (condition-case err
379 (progn (goto-char pos) (forward-sexp 1) nil)
380 (scan-error (throw 'return (list t (caddr err)))))))
381 ((null (nth 0 toklevels))
382 ;; A token like a paren-close.
383 (assert (nth 1 toklevels)) ;Otherwise, why mention it?
384 (push (nth 1 toklevels) levels))
385 (t
386 (while (and levels (< (nth 0 toklevels) (car levels)))
387 (setq levels (cdr levels)))
388 (cond
389 ((null levels)
390 (if (and halfsexp (nth 1 toklevels))
391 (push (nth 1 toklevels) levels)
392 (throw 'return
393 (prog1 (list (or (nth 1 toklevels) t) (point) token)
394 (goto-char pos)))))
395 (t
396 (while (and levels (= (nth 0 toklevels) (car levels)))
397 (setq levels (cdr levels)))
398 (cond
399 ((null levels)
400 (cond
401 ((null (nth 1 toklevels))
402 (throw 'return (list nil (point) token)))
403 ((eq (nth 1 toklevels) (nth 0 toklevels))
404 (throw 'return
405 (prog1 (list (or (nth 1 toklevels) t) (point) token)
406 (goto-char pos))))
407 (t (debug)))) ;Not sure yet what to do here.
408 (t
409 (if (nth 1 toklevels)
410 (push (nth 1 toklevels) levels))))))))
411 levels)
412 (setq halfsexp nil))))))
413 431
414 (defun smie-backward-sexp-command (&optional n) 432 (defun smie-backward-sexp-command (&optional n)
415 "Move backward through N logical elements." 433 "Move backward through N logical elements."
416 (interactive "p") 434 (interactive "p")
417 (if (< n 0) 435 (if (< n 0)