annotate lisp/emacs-lisp/smie.el @ 112218:376148b31b5e

Add 2011 to FSF/AIST copyright years.
author Glenn Morris <rgm@gnu.org>
date Sun, 02 Jan 2011 15:50:46 -0800
parents 81cac26277b0
children 417b1e4d63cd
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1 ;;; smie.el --- Simple Minded Indentation Engine
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
2
112218
376148b31b5e Add 2011 to FSF/AIST copyright years.
Glenn Morris <rgm@gnu.org>
parents: 111775
diff changeset
3 ;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
4
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
5 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
6 ;; Keywords: languages, lisp, internal, parsing, indentation
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
7
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
8 ;; This file is part of GNU Emacs.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
9
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
11 ;; it under the terms of the GNU General Public License as published by
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
12 ;; the Free Software Foundation, either version 3 of the License, or
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
13 ;; (at your option) any later version.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
14
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
15 ;; GNU Emacs is distributed in the hope that it will be useful,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
18 ;; GNU General Public License for more details.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
19
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
20 ;; You should have received a copy of the GNU General Public License
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
21 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
22
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
23 ;;; Commentary:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
24
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
25 ;; While working on the SML indentation code, the idea grew that maybe
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
26 ;; I could write something generic to do the same thing, and at the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
27 ;; end of working on the SML code, I had a pretty good idea of what it
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
28 ;; could look like. That idea grew stronger after working on
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
29 ;; LaTeX indentation.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
30 ;;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
31 ;; So at some point I decided to try it out, by writing a new
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
32 ;; indentation code for Coq while trying to keep most of the code
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
33 ;; "table driven", where only the tables are Coq-specific. The result
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
34 ;; (which was used for Beluga-mode as well) turned out to be based on
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
35 ;; something pretty close to an operator precedence parser.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
36
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
37 ;; So here is another rewrite, this time following the actual principles of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
38 ;; operator precedence grammars. Why OPG? Even though they're among the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
39 ;; weakest kinds of parsers, these parsers have some very desirable properties
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
40 ;; for Emacs:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
41 ;; - most importantly for indentation, they work equally well in either
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
42 ;; direction, so you can use them to parse backward from the indentation
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
43 ;; point to learn the syntactic context;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
44 ;; - they work locally, so there's no need to keep a cache of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
45 ;; the parser's state;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
46 ;; - because of that locality, indentation also works just fine when earlier
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
47 ;; parts of the buffer are syntactically incorrect since the indentation
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
48 ;; looks at "as little as possible" of the buffer to make an indentation
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
49 ;; decision.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
50 ;; - they typically have no error handling and can't even detect a parsing
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
51 ;; error, so we don't have to worry about what to do in case of a syntax
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
52 ;; error because the parser just automatically does something. Better yet,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
53 ;; we can afford to use a sloppy grammar.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
54
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
55 ;; A good background to understand the development (especially the parts
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
56 ;; building the 2D precedence tables and then computing the precedence levels
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
57 ;; from it) can be found in pages 187-194 of "Parsing techniques" by Dick Grune
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
58 ;; and Ceriel Jacobs (BookBody.pdf available at
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
59 ;; http://www.cs.vu.nl/~dick/PTAPG.html).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
60 ;;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
61 ;; OTOH we had to kill many chickens, read many coffee grounds, and practice
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
62 ;; untold numbers of black magic spells, to come up with the indentation code.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
63 ;; Since then, some of that code has been beaten into submission, but the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
64 ;; smie-indent-keyword is still pretty obscure.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
65
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
66 ;; Conflict resolution:
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
67 ;;
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
68 ;; - One source of conflicts is when you have:
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
69 ;; (exp ("IF" exp "ELSE" exp "END") ("CASE" cases "END"))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
70 ;; (cases (cases "ELSE" insts) ...)
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
71 ;; The IF-rule implies ELSE=END and the CASE-rule implies ELSE>END.
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
72 ;; FIXME: we could try to resolve such conflicts automatically by changing
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
73 ;; the way BNF rules such as the IF-rule is handled. I.e. rather than
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
74 ;; IF=ELSE and ELSE=END, we could turn them into IF<ELSE and ELSE>END
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
75 ;; and IF=END,
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
76
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
77 ;; TODO & BUGS:
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
78 ;;
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
79 ;; - Using the structural information SMIE gives us, it should be possible to
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
80 ;; implement a `smie-align' command that would automatically figure out what
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
81 ;; there is to align and how to do it (something like: align the token of
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
82 ;; lowest precedence that appears the same number of times on all lines,
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
83 ;; and then do the same on each side of that token).
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
84 ;; - Maybe accept two juxtaposed non-terminals in the BNF under the condition
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
85 ;; that the first always ends with a terminal, or that the second always
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
86 ;; starts with a terminal.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
87
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
88 ;;; Code:
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
89
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
90 (eval-when-compile (require 'cl))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
91
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
92 (defgroup smie nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
93 "Simple Minded Indentation Engine."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
94 :group 'languages)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
95
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
96 (defvar comment-continue)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
97 (declare-function comment-string-strip "newcomment" (str beforep afterp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
98
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
99 ;;; Building precedence level tables from BNF specs.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
100
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
101 ;; We have 4 different representations of a "grammar":
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
102 ;; - a BNF table, which is a list of BNF rules of the form
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
103 ;; (NONTERM RHS1 ... RHSn) where each RHS is a list of terminals (tokens)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
104 ;; or nonterminals. Any element in these lists which does not appear as
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
105 ;; the `car' of a BNF rule is taken to be a terminal.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
106 ;; - A list of precedences (key word "precs"), is a list, sorted
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
107 ;; from lowest to highest precedence, of precedence classes that
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
108 ;; have the form (ASSOCIATIVITY TERMINAL1 .. TERMINALn), where
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
109 ;; ASSOCIATIVITY can be `assoc', `left', `right' or `nonassoc'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
110 ;; - a 2 dimensional precedence table (key word "prec2"), is a 2D
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
111 ;; table recording the precedence relation (can be `<', `=', `>', or
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
112 ;; nil) between each pair of tokens.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
113 ;; - a precedence-level table (key word "grammar"), which is a alist
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
114 ;; giving for each token its left and right precedence level (a
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
115 ;; number or nil). This is used in `smie-grammar'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
116 ;; The prec2 tables are only intermediate data structures: the source
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
117 ;; code normally provides a mix of BNF and precs tables, and then
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
118 ;; turns them into a levels table, which is what's used by the rest of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
119 ;; the SMIE code.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
120
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
121 (defun smie-set-prec2tab (table x y val &optional override)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
122 (assert (and x y))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
123 (let* ((key (cons x y))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
124 (old (gethash key table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
125 (if (and old (not (eq old val)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
126 (if (and override (gethash key override))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
127 ;; FIXME: The override is meant to resolve ambiguities,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
128 ;; but it also hides real conflicts. It would be great to
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
129 ;; be able to distinguish the two cases so that overrides
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
130 ;; don't hide real conflicts.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
131 (puthash key (gethash key override) table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
132 (display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
133 (puthash key val table))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
134
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
135 (put 'smie-precs->prec2 'pure t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
136 (defun smie-precs->prec2 (precs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
137 "Compute a 2D precedence table from a list of precedences.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
138 PRECS should be a list, sorted by precedence (e.g. \"+\" will
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
139 come before \"*\"), of elements of the form \(left OP ...)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
140 or (right OP ...) or (nonassoc OP ...) or (assoc OP ...). All operators in
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
141 one of those elements share the same precedence level and associativity."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
142 (let ((prec2-table (make-hash-table :test 'equal)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
143 (dolist (prec precs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
144 (dolist (op (cdr prec))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
145 (let ((selfrule (cdr (assq (car prec)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
146 '((left . >) (right . <) (assoc . =))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
147 (when selfrule
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
148 (dolist (other-op (cdr prec))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
149 (smie-set-prec2tab prec2-table op other-op selfrule))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
150 (let ((op1 '<) (op2 '>))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
151 (dolist (other-prec precs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
152 (if (eq prec other-prec)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
153 (setq op1 '> op2 '<)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
154 (dolist (other-op (cdr other-prec))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
155 (smie-set-prec2tab prec2-table op other-op op2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
156 (smie-set-prec2tab prec2-table other-op op op1)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
157 prec2-table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
158
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
159 (put 'smie-merge-prec2s 'pure t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
160 (defun smie-merge-prec2s (&rest tables)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
161 (if (null (cdr tables))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
162 (car tables)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
163 (let ((prec2 (make-hash-table :test 'equal)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
164 (dolist (table tables)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
165 (maphash (lambda (k v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
166 (if (consp k)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
167 (smie-set-prec2tab prec2 (car k) (cdr k) v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
168 (if (and (gethash k prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
169 (not (equal (gethash k prec2) v)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
170 (error "Conflicting values for %s property" k)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
171 (puthash k v prec2))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
172 table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
173 prec2)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
174
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
175 (put 'smie-bnf->prec2 'pure t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
176 (defun smie-bnf->prec2 (bnf &rest precs)
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
177 ;; FIXME: Add repetition operator like (repeat <separator> <elems>).
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
178 ;; Maybe also add (or <elem1> <elem2>...) for things like
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
179 ;; (exp (exp (or "+" "*" "=" ..) exp)).
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
180 ;; Basically, make it EBNF (except for the specification of a separator in
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
181 ;; the repetition).
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
182 (let ((nts (mapcar 'car bnf)) ;Non-terminals
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
183 (first-ops-table ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
184 (last-ops-table ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
185 (first-nts-table ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
186 (last-nts-table ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
187 (prec2 (make-hash-table :test 'equal))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
188 (override (apply 'smie-merge-prec2s
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
189 (mapcar 'smie-precs->prec2 precs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
190 again)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
191 (dolist (rules bnf)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
192 (let ((nt (car rules))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
193 (last-ops ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
194 (first-ops ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
195 (last-nts ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
196 (first-nts ()))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
197 (dolist (rhs (cdr rules))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
198 (unless (consp rhs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
199 (signal 'wrong-type-argument `(consp ,rhs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
200 (if (not (member (car rhs) nts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
201 (pushnew (car rhs) first-ops)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
202 (pushnew (car rhs) first-nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
203 (when (consp (cdr rhs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
204 ;; If the first is not an OP we add the second (which
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
205 ;; should be an OP if BNF is an "operator grammar").
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
206 ;; Strictly speaking, this should only be done if the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
207 ;; first is a non-terminal which can expand to a phrase
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
208 ;; without any OP in it, but checking doesn't seem worth
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
209 ;; the trouble, and it lets the writer of the BNF
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
210 ;; be a bit more sloppy by skipping uninteresting base
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
211 ;; cases which are terminals but not OPs.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
212 (assert (not (member (cadr rhs) nts)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
213 (pushnew (cadr rhs) first-ops)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
214 (let ((shr (reverse rhs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
215 (if (not (member (car shr) nts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
216 (pushnew (car shr) last-ops)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
217 (pushnew (car shr) last-nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
218 (when (consp (cdr shr))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
219 (assert (not (member (cadr shr) nts)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
220 (pushnew (cadr shr) last-ops)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
221 (push (cons nt first-ops) first-ops-table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
222 (push (cons nt last-ops) last-ops-table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
223 (push (cons nt first-nts) first-nts-table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
224 (push (cons nt last-nts) last-nts-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
225 ;; Compute all first-ops by propagating the initial ones we have
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
226 ;; now, according to first-nts.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
227 (setq again t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
228 (while (prog1 again (setq again nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
229 (dolist (first-nts first-nts-table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
230 (let* ((nt (pop first-nts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
231 (first-ops (assoc nt first-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
232 (dolist (first-nt first-nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
233 (dolist (op (cdr (assoc first-nt first-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
234 (unless (member op first-ops)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
235 (setq again t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
236 (push op (cdr first-ops))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
237 ;; Same thing for last-ops.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
238 (setq again t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
239 (while (prog1 again (setq again nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
240 (dolist (last-nts last-nts-table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
241 (let* ((nt (pop last-nts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
242 (last-ops (assoc nt last-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
243 (dolist (last-nt last-nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
244 (dolist (op (cdr (assoc last-nt last-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
245 (unless (member op last-ops)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
246 (setq again t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
247 (push op (cdr last-ops))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
248 ;; Now generate the 2D precedence table.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
249 (dolist (rules bnf)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
250 (dolist (rhs (cdr rules))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
251 (while (cdr rhs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
252 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
253 ((member (car rhs) nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
254 (dolist (last (cdr (assoc (car rhs) last-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
255 (smie-set-prec2tab prec2 last (cadr rhs) '> override)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
256 ((member (cadr rhs) nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
257 (dolist (first (cdr (assoc (cadr rhs) first-ops-table)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
258 (smie-set-prec2tab prec2 (car rhs) first '< override))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
259 (if (and (cddr rhs) (not (member (car (cddr rhs)) nts)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
260 (smie-set-prec2tab prec2 (car rhs) (car (cddr rhs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
261 '= override)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
262 (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
263 (setq rhs (cdr rhs)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
264 ;; Keep track of which tokens are openers/closer, so they can get a nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
265 ;; precedence in smie-prec2->grammar.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
266 (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
267 (puthash :smie-closer-alist (smie-bnf-closer-alist bnf) prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
268 prec2))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
269
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
270 ;; (defun smie-prec2-closer-alist (prec2 include-inners)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
271 ;; "Build a closer-alist from a PREC2 table.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
272 ;; The return value is in the same form as `smie-closer-alist'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
273 ;; INCLUDE-INNERS if non-nil means that inner keywords will be included
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
274 ;; in the table, e.g. the table will include things like (\"if\" . \"else\")."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
275 ;; (let* ((non-openers '())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
276 ;; (non-closers '())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
277 ;; ;; For each keyword, this gives the matching openers, if any.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
278 ;; (openers (make-hash-table :test 'equal))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
279 ;; (closers '())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
280 ;; (done nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
281 ;; ;; First, find the non-openers and non-closers.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
282 ;; (maphash (lambda (k v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
283 ;; (unless (or (eq v '<) (member (cdr k) non-openers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
284 ;; (push (cdr k) non-openers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
285 ;; (unless (or (eq v '>) (member (car k) non-closers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
286 ;; (push (car k) non-closers)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
287 ;; prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
288 ;; ;; Then find the openers and closers.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
289 ;; (maphash (lambda (k _)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
290 ;; (unless (member (car k) non-openers)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
291 ;; (puthash (car k) (list (car k)) openers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
292 ;; (unless (or (member (cdr k) non-closers)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
293 ;; (member (cdr k) closers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
294 ;; (push (cdr k) closers)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
295 ;; prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
296 ;; ;; Then collect the matching elements.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
297 ;; (while (not done)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
298 ;; (setq done t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
299 ;; (maphash (lambda (k v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
300 ;; (when (eq v '=)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
301 ;; (let ((aopeners (gethash (car k) openers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
302 ;; (dopeners (gethash (cdr k) openers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
303 ;; (new nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
304 ;; (dolist (o aopeners)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
305 ;; (unless (member o dopeners)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
306 ;; (setq new t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
307 ;; (push o dopeners)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
308 ;; (when new
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
309 ;; (setq done nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
310 ;; (puthash (cdr k) dopeners openers)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
311 ;; prec2))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
312 ;; ;; Finally, dump the resulting table.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
313 ;; (let ((alist '()))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
314 ;; (maphash (lambda (k v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
315 ;; (when (or include-inners (member k closers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
316 ;; (dolist (opener v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
317 ;; (unless (equal opener k)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
318 ;; (push (cons opener k) alist)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
319 ;; openers)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
320 ;; alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
321
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
322 (defun smie-bnf-closer-alist (bnf &optional no-inners)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
323 ;; We can also build this closer-alist table from a prec2 table,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
324 ;; but it takes more work, and the order is unpredictable, which
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
325 ;; is a problem for smie-close-block.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
326 ;; More convenient would be to build it from a levels table since we
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
327 ;; always have this table (contrary to the BNF), but it has all the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
328 ;; disadvantages of the prec2 case plus the disadvantage that the levels
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
329 ;; table has lost some info which would result in extra invalid pairs.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
330 "Build a closer-alist from a BNF table.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
331 The return value is in the same form as `smie-closer-alist'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
332 NO-INNERS if non-nil means that inner keywords will be excluded
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
333 from the table, e.g. the table will not include things like (\"if\" . \"else\")."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
334 (let ((nts (mapcar #'car bnf)) ;non terminals.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
335 (alist '()))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
336 (dolist (nt bnf)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
337 (dolist (rhs (cdr nt))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
338 (unless (or (< (length rhs) 2) (member (car rhs) nts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
339 (if no-inners
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
340 (let ((last (car (last rhs))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
341 (unless (member last nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
342 (pushnew (cons (car rhs) last) alist :test #'equal)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
343 ;; Reverse so that the "real" closer gets there first,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
344 ;; which is important for smie-close-block.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
345 (dolist (term (reverse (cdr rhs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
346 (unless (member term nts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
347 (pushnew (cons (car rhs) term) alist :test #'equal)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
348 (nreverse alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
349
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
350 (defun smie-bnf-classify (bnf)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
351 "Return a table classifying terminals.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
352 Each terminal can either be an `opener', a `closer', or neither."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
353 (let ((table (make-hash-table :test #'equal))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
354 (nts (mapcar #'car bnf))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
355 (alist '()))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
356 (dolist (category bnf)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
357 (puthash (car category) 'neither table) ;Remove non-terminals.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
358 (dolist (rhs (cdr category))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
359 (if (null (cdr rhs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
360 (puthash (pop rhs) 'neither table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
361 (let ((first (pop rhs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
362 (puthash first
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
363 (if (memq (gethash first table) '(nil opener))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
364 'opener
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
365 (unless (member first nts)
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
366 (error "SMIE: token %s is both opener and non-opener"
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
367 first))
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
368 'neither)
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
369 table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
370 (while (cdr rhs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
371 (puthash (pop rhs) 'neither table)) ;Remove internals.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
372 (let ((last (pop rhs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
373 (puthash last
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
374 (if (memq (gethash last table) '(nil closer))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
375 'closer
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
376 (unless (member last nts)
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
377 (error "SMIE: token %s is both closer and non-closer"
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
378 last))
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
379 'neither)
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
380 table)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
381 (maphash (lambda (tok v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
382 (when (memq v '(closer opener))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
383 (push (cons tok v) alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
384 table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
385 alist))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
386
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
387 (defun smie-debug--prec2-cycle (csts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
388 "Return a cycle in CSTS, assuming there's one.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
389 CSTS is a list of pairs representing arcs in a graph."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
390 ;; A PATH is of the form (START . REST) where REST is a reverse
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
391 ;; list of nodes through which the path goes.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
392 (let ((paths (mapcar (lambda (pair) (list (car pair) (cdr pair))) csts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
393 (cycle nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
394 (while (null cycle)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
395 (dolist (path (prog1 paths (setq paths nil)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
396 (dolist (cst csts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
397 (when (eq (car cst) (nth 1 path))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
398 (if (eq (cdr cst) (car path))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
399 (setq cycle path)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
400 (push (cons (car path) (cons (cdr cst) (cdr path)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
401 paths))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
402 (cons (car cycle) (nreverse (cdr cycle)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
403
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
404 (defun smie-debug--describe-cycle (table cycle)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
405 (let ((names
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
406 (mapcar (lambda (val)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
407 (let ((res nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
408 (dolist (elem table)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
409 (if (eq (cdr elem) val)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
410 (push (concat "." (car elem)) res))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
411 (if (eq (cddr elem) val)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
412 (push (concat (car elem) ".") res)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
413 (assert res)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
414 res))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
415 cycle)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
416 (mapconcat
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
417 (lambda (elems) (mapconcat 'identity elems "="))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
418 (append names (list (car names)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
419 " < ")))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
420
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
421 ;; (defun smie-check-grammar (grammar prec2 &optional dummy)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
422 ;; (maphash (lambda (k v)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
423 ;; (when (consp k)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
424 ;; (let ((left (nth 2 (assoc (car k) grammar)))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
425 ;; (right (nth 1 (assoc (cdr k) grammar))))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
426 ;; (when (and left right)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
427 ;; (cond
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
428 ;; ((< left right) (assert (eq v '<)))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
429 ;; ((> left right) (assert (eq v '>)))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
430 ;; (t (assert (eq v '=))))))))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
431 ;; prec2))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
432
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
433 (put 'smie-prec2->grammar 'pure t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
434 (defun smie-prec2->grammar (prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
435 "Take a 2D precedence table and turn it into an alist of precedence levels.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
436 PREC2 is a table as returned by `smie-precs->prec2' or
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
437 `smie-bnf->prec2'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
438 ;; For each operator, we create two "variables" (corresponding to
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
439 ;; the left and right precedence level), which are represented by
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
440 ;; cons cells. Those are the very cons cells that appear in the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
441 ;; final `table'. The value of each "variable" is kept in the `car'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
442 (let ((table ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
443 (csts ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
444 (eqs ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
445 tmp x y)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
446 ;; From `prec2' we construct a list of constraints between
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
447 ;; variables (aka "precedence levels"). These can be either
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
448 ;; equality constraints (in `eqs') or `<' constraints (in `csts').
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
449 (maphash (lambda (k v)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
450 (when (consp k)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
451 (if (setq tmp (assoc (car k) table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
452 (setq x (cddr tmp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
453 (setq x (cons nil nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
454 (push (cons (car k) (cons nil x)) table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
455 (if (setq tmp (assoc (cdr k) table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
456 (setq y (cdr tmp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
457 (setq y (cons nil (cons nil nil)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
458 (push (cons (cdr k) y) table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
459 (ecase v
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
460 (= (push (cons x y) eqs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
461 (< (push (cons x y) csts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
462 (> (push (cons y x) csts)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
463 prec2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
464 ;; First process the equality constraints.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
465 (let ((eqs eqs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
466 (while eqs
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
467 (let ((from (caar eqs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
468 (to (cdar eqs)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
469 (setq eqs (cdr eqs))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
470 (if (eq to from)
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
471 nil ;Nothing to do.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
472 (dolist (other-eq eqs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
473 (if (eq from (cdr other-eq)) (setcdr other-eq to))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
474 (when (eq from (car other-eq))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
475 ;; This can happen because of `assoc' settings in precs
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
476 ;; or because of a rhs like ("op" foo "op").
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
477 (setcar other-eq to)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
478 (dolist (cst csts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
479 (if (eq from (cdr cst)) (setcdr cst to))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
480 (if (eq from (car cst)) (setcar cst to)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
481 ;; Then eliminate trivial constraints iteratively.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
482 (let ((i 0))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
483 (while csts
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
484 (let ((rhvs (mapcar 'cdr csts))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
485 (progress nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
486 (dolist (cst csts)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
487 (unless (memq (car cst) rhvs)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
488 (setq progress t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
489 ;; We could give each var in a given iteration the same value,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
490 ;; but we can also give them arbitrarily different values.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
491 ;; Basically, these are vars between which there is no
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
492 ;; constraint (neither equality nor inequality), so
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
493 ;; anything will do.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
494 ;; We give them arbitrary values, which means that we
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
495 ;; replace the "no constraint" case with either > or <
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
496 ;; but not =. The reason we do that is so as to try and
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
497 ;; distinguish associative operators (which will have
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
498 ;; left = right).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
499 (unless (caar cst)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
500 (setcar (car cst) i)
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
501 ;; (smie-check-grammar table prec2 'step1)
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
502 (incf i))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
503 (setq csts (delq cst csts))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
504 (unless progress
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
505 (error "Can't resolve the precedence cycle: %s"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
506 (smie-debug--describe-cycle
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
507 table (smie-debug--prec2-cycle csts)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
508 (incf i 10))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
509 ;; Propagate equalities back to their source.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
510 (dolist (eq (nreverse eqs))
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
511 (when (null (cadr eq))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
512 ;; There's an equality constraint, but we still haven't given
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
513 ;; it a value: that means it binds tighter than anything else,
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
514 ;; and it can't be an opener/closer (those don't have equality
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
515 ;; constraints).
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
516 ;; So set it here rather than below since doing it below
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
517 ;; makes it more difficult to obey the equality constraints.
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
518 (setcar (cdr eq) i)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
519 (incf i))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
520 (assert (or (null (caar eq)) (eq (caar eq) (cadr eq))))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
521 (setcar (car eq) (cadr eq))
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
522 ;; (smie-check-grammar table prec2 'step2)
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
523 )
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
524 ;; Finally, fill in the remaining vars (which did not appear on the
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
525 ;; left side of any < constraint).
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
526 (dolist (x table)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
527 (unless (nth 1 x)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
528 (setf (nth 1 x) i)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
529 (incf i)) ;See other (incf i) above.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
530 (unless (nth 2 x)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
531 (setf (nth 2 x) i)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
532 (incf i)))) ;See other (incf i) above.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
533 ;; Mark closers and openers.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
534 (dolist (x (gethash :smie-open/close-alist prec2))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
535 (let* ((token (car x))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
536 (cons (case (cdr x)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
537 (closer (cddr (assoc token table)))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
538 (opener (cdr (assoc token table))))))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
539 (assert (numberp (car cons)))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
540 (setf (car cons) (list (car cons)))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
541 (let ((ca (gethash :smie-closer-alist prec2)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
542 (when ca (push (cons :smie-closer-alist ca) table)))
111605
ca8b605ca70f * lisp/emacs-lisp/smie.el (smie-prec2->grammar): Obey equality constraints
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111603
diff changeset
543 ;; (smie-check-grammar table prec2 'step3)
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
544 table))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
545
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
546 ;;; Parsing using a precedence level table.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
547
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
548 (defvar smie-grammar 'unset
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
549 "List of token parsing info.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
550 This list is normally built by `smie-prec2->grammar'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
551 Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
552 Parsing is done using an operator precedence parser.
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
553 LEFT-LEVEL and RIGHT-LEVEL can be either numbers or a list, where a list
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
554 means that this operator does not bind on the corresponding side,
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
555 e.g. a LEFT-LEVEL of nil means this is a token that behaves somewhat like
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
556 an open-paren, whereas a RIGHT-LEVEL of nil would correspond to something
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
557 like a close-paren.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
558
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
559 (defvar smie-forward-token-function 'smie-default-forward-token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
560 "Function to scan forward for the next token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
561 Called with no argument should return a token and move to its end.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
562 If no token is found, return nil or the empty string.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
563 It can return nil when bumping into a parenthesis, which lets SMIE
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
564 use syntax-tables to handle them in efficient C code.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
565
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
566 (defvar smie-backward-token-function 'smie-default-backward-token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
567 "Function to scan backward the previous token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
568 Same calling convention as `smie-forward-token-function' except
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
569 it should move backward to the beginning of the previous token.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
570
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
571 (defalias 'smie-op-left 'car)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
572 (defalias 'smie-op-right 'cadr)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
573
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
574 (defun smie-default-backward-token ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
575 (forward-comment (- (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
576 (buffer-substring-no-properties
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
577 (point)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
578 (progn (if (zerop (skip-syntax-backward "."))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
579 (skip-syntax-backward "w_'"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
580 (point))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
581
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
582 (defun smie-default-forward-token ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
583 (forward-comment (point-max))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
584 (buffer-substring-no-properties
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
585 (point)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
586 (progn (if (zerop (skip-syntax-forward "."))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
587 (skip-syntax-forward "w_'"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
588 (point))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
589
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
590 (defun smie--associative-p (toklevels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
591 ;; in "a + b + c" we want to stop at each +, but in
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
592 ;; "if a then b elsif c then d else c" we don't want to stop at each keyword.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
593 ;; To distinguish the two cases, we made smie-prec2->grammar choose
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
594 ;; different levels for each part of "if a then b else c", so that
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
595 ;; by checking if the left-level is equal to the right level, we can
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
596 ;; figure out that it's an associative operator.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
597 ;; This is not 100% foolproof, tho, since the "elsif" will have to have
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
598 ;; equal left and right levels (since it's optional), so smie-next-sexp
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
599 ;; has to be careful to distinguish those different cases.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
600 (eq (smie-op-left toklevels) (smie-op-right toklevels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
601
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
602 (defun smie-next-sexp (next-token next-sexp op-forw op-back halfsexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
603 "Skip over one sexp.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
604 NEXT-TOKEN is a function of no argument that moves forward by one
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
605 token (after skipping comments if needed) and returns it.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
606 NEXT-SEXP is a lower-level function to skip one sexp.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
607 OP-FORW is the accessor to the forward level of the level data.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
608 OP-BACK is the accessor to the backward level of the level data.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
609 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
610 first token we see is an operator, skip over its left-hand-side argument.
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
611 HALFSEXP can also be a token, in which case it means to parse as if
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
612 we had just successfully passed this token.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
613 Possible return values:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
614 (FORW-LEVEL POS TOKEN): we couldn't skip TOKEN because its back-level
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
615 is too high. FORW-LEVEL is the forw-level of TOKEN,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
616 POS is its start position in the buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
617 (t POS TOKEN): same thing when we bump on the wrong side of a paren.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
618 (nil POS TOKEN): we skipped over a paren-like pair.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
619 nil: we skipped over an identifier, matched parentheses, ..."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
620 (catch 'return
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
621 (let ((levels
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
622 (if (stringp halfsexp)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
623 (prog1 (list (cdr (assoc halfsexp smie-grammar)))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
624 (setq halfsexp nil)))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
625 (while
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
626 (let* ((pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
627 (token (funcall next-token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
628 (toklevels (cdr (assoc token smie-grammar))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
629 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
630 ((null toklevels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
631 (when (zerop (length token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
632 (condition-case err
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
633 (progn (goto-char pos) (funcall next-sexp 1) nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
634 (scan-error (throw 'return
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
635 (list t (caddr err)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
636 (buffer-substring-no-properties
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
637 (caddr err)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
638 (+ (caddr err)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
639 (if (< (point) (caddr err))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
640 -1 1)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
641 (if (eq pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
642 ;; We did not move, so let's abort the loop.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
643 (throw 'return (list t (point))))))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
644 ((not (numberp (funcall op-back toklevels)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
645 ;; A token like a paren-close.
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
646 (assert (numberp ; Otherwise, why mention it in smie-grammar.
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
647 (funcall op-forw toklevels)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
648 (push toklevels levels))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
649 (t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
650 (while (and levels (< (funcall op-back toklevels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
651 (funcall op-forw (car levels))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
652 (setq levels (cdr levels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
653 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
654 ((null levels)
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
655 (if (and halfsexp (numberp (funcall op-forw toklevels)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
656 (push toklevels levels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
657 (throw 'return
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
658 (prog1 (list (or (car toklevels) t) (point) token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
659 (goto-char pos)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
660 (t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
661 (let ((lastlevels levels))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
662 (if (and levels (= (funcall op-back toklevels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
663 (funcall op-forw (car levels))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
664 (setq levels (cdr levels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
665 ;; We may have found a match for the previously pending
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
666 ;; operator. Is this the end?
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
667 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
668 ;; Keep looking as long as we haven't matched the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
669 ;; topmost operator.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
670 (levels
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
671 (if (numberp (funcall op-forw toklevels))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
672 (push toklevels levels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
673 ;; We matched the topmost operator. If the new operator
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
674 ;; is the last in the corresponding BNF rule, we're done.
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
675 ((not (numberp (funcall op-forw toklevels)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
676 ;; It is the last element, let's stop here.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
677 (throw 'return (list nil (point) token)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
678 ;; If the new operator is not the last in the BNF rule,
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
679 ;; and is not associative, it's one of the inner operators
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
680 ;; (like the "in" in "let .. in .. end"), so keep looking.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
681 ((not (smie--associative-p toklevels))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
682 (push toklevels levels))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
683 ;; The new operator is associative. Two cases:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
684 ;; - it's really just an associative operator (like + or ;)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
685 ;; in which case we should have stopped right before.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
686 ((and lastlevels
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
687 (smie--associative-p (car lastlevels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
688 (throw 'return
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
689 (prog1 (list (or (car toklevels) t) (point) token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
690 (goto-char pos))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
691 ;; - it's an associative operator within a larger construct
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
692 ;; (e.g. an "elsif"), so we should just ignore it and keep
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
693 ;; looking for the closing element.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
694 (t (setq levels lastlevels))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
695 levels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
696 (setq halfsexp nil)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
697
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
698 (defun smie-backward-sexp (&optional halfsexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
699 "Skip over one sexp.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
700 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
701 first token we see is an operator, skip over its left-hand-side argument.
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
702 HALFSEXP can also be a token, in which case we should skip the text
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
703 assuming it is the left-hand-side argument of that token.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
704 Possible return values:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
705 (LEFT-LEVEL POS TOKEN): we couldn't skip TOKEN because its right-level
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
706 is too high. LEFT-LEVEL is the left-level of TOKEN,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
707 POS is its start position in the buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
708 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
709 (nil POS TOKEN): we skipped over a paren-like pair.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
710 nil: we skipped over an identifier, matched parentheses, ..."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
711 (smie-next-sexp
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
712 (indirect-function smie-backward-token-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
713 (indirect-function 'backward-sexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
714 (indirect-function 'smie-op-left)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
715 (indirect-function 'smie-op-right)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
716 halfsexp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
717
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
718 (defun smie-forward-sexp (&optional halfsexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
719 "Skip over one sexp.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
720 HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
721 first token we see is an operator, skip over its right-hand-side argument.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
722 HALFSEXP can also be a token, in which case we should skip the text
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
723 assuming it is the right-hand-side argument of that token.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
724 Possible return values:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
725 (RIGHT-LEVEL POS TOKEN): we couldn't skip TOKEN because its left-level
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
726 is too high. RIGHT-LEVEL is the right-level of TOKEN,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
727 POS is its end position in the buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
728 (t POS TOKEN): same thing but for an open-paren or the beginning of buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
729 (nil POS TOKEN): we skipped over a paren-like pair.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
730 nil: we skipped over an identifier, matched parentheses, ..."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
731 (smie-next-sexp
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
732 (indirect-function smie-forward-token-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
733 (indirect-function 'forward-sexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
734 (indirect-function 'smie-op-right)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
735 (indirect-function 'smie-op-left)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
736 halfsexp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
737
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
738 ;;; Miscellanous commands using the precedence parser.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
739
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
740 (defun smie-backward-sexp-command (&optional n)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
741 "Move backward through N logical elements."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
742 (interactive "^p")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
743 (smie-forward-sexp-command (- n)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
744
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
745 (defun smie-forward-sexp-command (&optional n)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
746 "Move forward through N logical elements."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
747 (interactive "^p")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
748 (let ((forw (> n 0))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
749 (forward-sexp-function nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
750 (while (/= n 0)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
751 (setq n (- n (if forw 1 -1)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
752 (let ((pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
753 (res (if forw
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
754 (smie-forward-sexp 'halfsexp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
755 (smie-backward-sexp 'halfsexp))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
756 (if (and (car res) (= pos (point)) (not (if forw (eobp) (bobp))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
757 (signal 'scan-error
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
758 (list "Containing expression ends prematurely"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
759 (cadr res) (cadr res)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
760 nil)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
761
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
762 (defvar smie-closer-alist nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
763 "Alist giving the closer corresponding to an opener.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
764
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
765 (defun smie-close-block ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
766 "Close the closest surrounding block."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
767 (interactive)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
768 (let ((closer
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
769 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
770 (backward-up-list 1)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
771 (if (looking-at "\\s(")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
772 (string (cdr (syntax-after (point))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
773 (let* ((open (funcall smie-forward-token-function))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
774 (closer (cdr (assoc open smie-closer-alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
775 (levels (list (assoc open smie-grammar)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
776 (seen '())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
777 (found '()))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
778 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
779 ;; Even if we improve the auto-computation of closers,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
780 ;; there are still cases where we need manual
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
781 ;; intervention, e.g. for Octave's use of `until'
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
782 ;; as a pseudo-closer of `do'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
783 (closer)
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
784 ((or (equal levels '(nil)) (numberp (nth 1 (car levels))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
785 (error "Doesn't look like a block"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
786 (t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
787 ;; Now that smie-setup automatically sets smie-closer-alist
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
788 ;; from the BNF, this is not really needed any more.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
789 (while levels
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
790 (let ((level (pop levels)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
791 (dolist (other smie-grammar)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
792 (when (and (eq (nth 2 level) (nth 1 other))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
793 (not (memq other seen)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
794 (push other seen)
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
795 (if (numberp (nth 2 other))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
796 (push other levels)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
797 (push (car other) found))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
798 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
799 ((null found) (error "No known closer for opener %s" open))
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
800 ;; What should we do if there are various closers?
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
801 (t (car found))))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
802 (unless (save-excursion (skip-chars-backward " \t") (bolp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
803 (newline))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
804 (insert closer)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
805 (if (save-excursion (skip-chars-forward " \t") (eolp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
806 (indent-according-to-mode)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
807 (reindent-then-newline-and-indent))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
808
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
809 (defun smie-down-list (&optional arg)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
810 "Move forward down one level paren-like blocks. Like `down-list'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
811 With argument ARG, do this that many times.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
812 A negative argument means move backward but still go down a level.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
813 This command assumes point is not in a string or comment."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
814 (interactive "p")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
815 (let ((start (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
816 (inc (if (< arg 0) -1 1))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
817 (offset (if (< arg 0) 1 0))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
818 (next-token (if (< arg 0)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
819 smie-backward-token-function
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
820 smie-forward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
821 (while (/= arg 0)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
822 (setq arg (- arg inc))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
823 (while
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
824 (let* ((pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
825 (token (funcall next-token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
826 (levels (assoc token smie-grammar)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
827 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
828 ((zerop (length token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
829 (if (if (< inc 0) (looking-back "\\s(\\|\\s)" (1- (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
830 (looking-at "\\s(\\|\\s)"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
831 ;; Go back to `start' in case of an error. This presumes
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
832 ;; none of the token we've found until now include a ( or ).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
833 (progn (goto-char start) (down-list inc) nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
834 (forward-sexp inc)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
835 (/= (point) pos)))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
836 ((and levels (not (numberp (nth (+ 1 offset) levels)))) nil)
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
837 ((and levels (not (numberp (nth (- 2 offset) levels))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
838 (let ((end (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
839 (goto-char start)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
840 (signal 'scan-error
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
841 (list "Containing expression ends prematurely"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
842 pos end))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
843 (t)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
844
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
845 (defvar smie-blink-matching-triggers '(?\s ?\n)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
846 "Chars which might trigger `blink-matching-open'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
847 These can include the final chars of end-tokens, or chars that are
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
848 typically inserted right after an end token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
849 I.e. a good choice can be:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
850 (delete-dups
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
851 (mapcar (lambda (kw) (aref (cdr kw) (1- (length (cdr kw)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
852 smie-closer-alist))")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
853
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
854 (defcustom smie-blink-matching-inners t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
855 "Whether SMIE should blink to matching opener for inner keywords.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
856 If non-nil, it will blink not only for \"begin..end\" but also for \"if...else\"."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
857 :type 'boolean
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
858 :group 'smie)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
859
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
860 (defun smie-blink-matching-check (start end)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
861 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
862 (goto-char end)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
863 (let ((ender (funcall smie-backward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
864 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
865 ((not (and ender (rassoc ender smie-closer-alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
866 ;; This not is one of the begin..end we know how to check.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
867 (blink-matching-check-mismatch start end))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
868 ((not start) t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
869 ((eq t (car (rassoc ender smie-closer-alist))) nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
870 (t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
871 (goto-char start)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
872 (let ((starter (funcall smie-forward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
873 (not (member (cons starter ender) smie-closer-alist))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
874
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
875 (defun smie-blink-matching-open ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
876 "Blink the matching opener when applicable.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
877 This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
878 (let ((pos (point)) ;Position after the close token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
879 token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
880 (when (and blink-matching-paren
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
881 smie-closer-alist ; Optimization.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
882 (or (eq (char-before) last-command-event) ;; Sanity check.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
883 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
884 (or (progn (skip-chars-backward " \t")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
885 (setq pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
886 (eq (char-before) last-command-event))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
887 (progn (skip-chars-backward " \n\t")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
888 (setq pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
889 (eq (char-before) last-command-event)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
890 (memq last-command-event smie-blink-matching-triggers)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
891 (not (nth 8 (syntax-ppss))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
892 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
893 (setq token (funcall smie-backward-token-function))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
894 (when (and (eq (point) (1- pos))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
895 (= 1 (length token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
896 (not (rassoc token smie-closer-alist)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
897 ;; The trigger char is itself a token but is not one of the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
898 ;; closers (e.g. ?\; in Octave mode), so go back to the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
899 ;; previous token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
900 (setq pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
901 (setq token (funcall smie-backward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
902 (when (rassoc token smie-closer-alist)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
903 ;; We're after a close token. Let's still make sure we
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
904 ;; didn't skip a comment to find that token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
905 (funcall smie-forward-token-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
906 (when (and (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
907 ;; Skip the trigger char, if applicable.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
908 (if (eq (char-after) last-command-event)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
909 (forward-char 1))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
910 (if (eq ?\n last-command-event)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
911 ;; Skip any auto-indentation, if applicable.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
912 (skip-chars-forward " \t"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
913 (>= (point) pos))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
914 ;; If token ends with a trigger char, don't blink for
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
915 ;; anything else than this trigger char, lest we'd blink
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
916 ;; both when inserting the trigger char and when
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
917 ;; inserting a subsequent trigger char like SPC.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
918 (or (eq (point) pos)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
919 (not (memq (char-before)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
920 smie-blink-matching-triggers)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
921 (or smie-blink-matching-inners
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
922 (not (numberp (nth 2 (assoc token smie-grammar))))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
923 ;; The major mode might set blink-matching-check-function
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
924 ;; buffer-locally so that interactive calls to
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
925 ;; blink-matching-open work right, but let's not presume
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
926 ;; that's the case.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
927 (let ((blink-matching-check-function #'smie-blink-matching-check))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
928 (blink-matching-open))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
929
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
930 ;;; The indentation engine.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
931
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
932 (defcustom smie-indent-basic 4
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
933 "Basic amount of indentation."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
934 :type 'integer
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
935 :group 'smie)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
936
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
937 (defvar smie-rules-function 'ignore
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
938 "Function providing the indentation rules.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
939 It takes two arguments METHOD and ARG where the meaning of ARG
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
940 and the expected return value depends on METHOD.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
941 METHOD can be:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
942 - :after, in which case ARG is a token and the function should return the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
943 OFFSET to use for indentation after ARG.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
944 - :before, in which case ARG is a token and the function should return the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
945 OFFSET to use to indent ARG itself.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
946 - :elem, in which case the function should return either:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
947 - the offset to use to indent function arguments (ARG = `arg')
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
948 - the basic indentation step (ARG = `basic').
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
949 - :list-intro, in which case ARG is a token and the function should return
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
950 non-nil if TOKEN is followed by a list of expressions (not separated by any
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
951 token) rather than an expression.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
952
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
953 When ARG is a token, the function is called with point just before that token.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
954 A return value of nil always means to fallback on the default behavior, so the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
955 function should return nil for arguments it does not expect.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
956
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
957 OFFSET can be:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
958 nil use the default indentation rule.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
959 `(column . COLUMN) indent to column COLUMN.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
960 NUMBER offset by NUMBER, relative to a base token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
961 which is the current token for :after and
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
962 its parent for :before.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
963
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
964 The functions whose name starts with \"smie-rule-\" are helper functions
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
965 designed specifically for use in this function.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
966
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
967 (defalias 'smie-rule-hanging-p 'smie-indent--hanging-p)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
968 (defun smie-indent--hanging-p ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
969 "Return non-nil if the current token is \"hanging\".
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
970 A hanging keyword is one that's at the end of a line except it's not at
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
971 the beginning of a line."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
972 (and (not (smie-indent--bolp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
973 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
974 (<= (line-end-position)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
975 (progn
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
976 (when (zerop (length (funcall smie-forward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
977 ;; Could be an open-paren.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
978 (forward-char 1))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
979 (skip-chars-forward " \t")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
980 (or (eolp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
981 (and (looking-at comment-start-skip)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
982 (forward-comment (point-max))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
983 (point))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
984
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
985 (defalias 'smie-rule-bolp 'smie-indent--bolp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
986 (defun smie-indent--bolp ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
987 "Return non-nil if the current token is the first on the line."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
988 (save-excursion (skip-chars-backward " \t") (bolp)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
989
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
990 ;; Dynamically scoped.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
991 (defvar smie--parent) (defvar smie--after) (defvar smie--token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
992
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
993 (defun smie-indent--parent ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
994 (or smie--parent
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
995 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
996 (let* ((pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
997 (tok (funcall smie-forward-token-function)))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
998 (unless (numberp (cadr (assoc tok smie-grammar)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
999 (goto-char pos))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1000 (setq smie--parent
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1001 (smie-backward-sexp 'halfsexp))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1002
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1003 (defun smie-rule-parent-p (&rest parents)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1004 "Return non-nil if the current token's parent is among PARENTS.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1005 Only meaningful when called from within `smie-rules-function'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1006 (member (nth 2 (smie-indent--parent)) parents))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1007
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1008 (defun smie-rule-next-p (&rest tokens)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1009 "Return non-nil if the next token is among TOKENS.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1010 Only meaningful when called from within `smie-rules-function'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1011 (let ((next
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1012 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1013 (unless smie--after
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1014 (smie-indent-forward-token) (setq smie--after (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1015 (goto-char smie--after)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1016 (smie-indent-forward-token))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1017 (member (car next) tokens)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1018
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1019 (defun smie-rule-prev-p (&rest tokens)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1020 "Return non-nil if the previous token is among TOKENS."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1021 (let ((prev (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1022 (smie-indent-backward-token))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1023 (member (car prev) tokens)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1024
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1025 (defun smie-rule-sibling-p ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1026 "Return non-nil if the parent is actually a sibling.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1027 Only meaningful when called from within `smie-rules-function'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1028 (eq (car (smie-indent--parent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1029 (cadr (assoc smie--token smie-grammar))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1030
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1031 (defun smie-rule-parent (&optional offset)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1032 "Align with parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1033 If non-nil, OFFSET should be an integer giving an additional offset to apply.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1034 Only meaningful when called from within `smie-rules-function'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1035 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1036 (goto-char (cadr (smie-indent--parent)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1037 (cons 'column
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1038 (+ (or offset 0)
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1039 ;; Use smie-indent-virtual when indenting relative to an opener:
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1040 ;; this will also by default use current-column unless
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1041 ;; that opener is hanging, but will additionally consult
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1042 ;; rules-function, so it gives it a chance to tweak
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1043 ;; indentation (e.g. by forcing indentation relative to
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1044 ;; its own parent, as in fn a => fn b => fn c =>).
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1045 (if (or (listp (car smie--parent)) (smie-indent--hanging-p))
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1046 (smie-indent-virtual) (current-column))))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1047
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1048 (defvar smie-rule-separator-outdent 2)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1049
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1050 (defun smie-indent--separator-outdent ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1051 ;; FIXME: Here we actually have several reasonable behaviors.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1052 ;; E.g. for a parent token of "FOO" and a separator ";" we may want to:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1053 ;; 1- left-align ; with FOO.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1054 ;; 2- right-align ; with FOO.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1055 ;; 3- align content after ; with content after FOO.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1056 ;; 4- align content plus add/remove spaces so as to align ; with FOO.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1057 ;; Currently, we try to align the contents (option 3) which actually behaves
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1058 ;; just like option 2 (if the number of spaces after FOO and ; is equal).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1059 (let ((afterpos (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1060 (let ((tok (funcall smie-forward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1061 (unless tok
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1062 (with-demoted-errors
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1063 (error "smie-rule-separator: can't skip token %s"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1064 smie--token))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1065 (skip-chars-forward " ")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1066 (unless (eolp) (point)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1067 (or (and afterpos
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1068 ;; This should always be true, unless
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1069 ;; smie-forward-token-function skipped a \n.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1070 (< afterpos (line-end-position))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1071 (- afterpos (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1072 smie-rule-separator-outdent)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1073
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1074 (defun smie-rule-separator (method)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1075 "Indent current token as a \"separator\".
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1076 By \"separator\", we mean here a token whose sole purpose is to separate
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1077 various elements within some enclosing syntactic construct, and which does
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1078 not have any semantic significance in itself (i.e. it would typically no exist
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1079 as a node in an abstract syntax tree).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1080 Such a token is expected to have an associative syntax and be closely tied
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1081 to its syntactic parent. Typical examples are \",\" in lists of arguments
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1082 \(enclosed inside parentheses), or \";\" in sequences of instructions (enclosed
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1083 in a {..} or begin..end block).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1084 METHOD should be the method name that was passed to `smie-rules-function'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1085 Only meaningful when called from within `smie-rules-function'."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1086 ;; FIXME: The code below works OK for cases where the separators
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1087 ;; are placed consistently always at beginning or always at the end,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1088 ;; but not if some are at the beginning and others are at the end.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1089 ;; I.e. it gets confused in cases such as:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1090 ;; ( a
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1091 ;; , a,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1092 ;; b
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1093 ;; , c,
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1094 ;; d
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1095 ;; )
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1096 ;;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1097 ;; Assuming token is associative, the default rule for associative
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1098 ;; tokens (which assumes an infix operator) works fine for many cases.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1099 ;; We mostly need to take care of the case where token is at beginning of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1100 ;; line, in which case we want to align it with its enclosing parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1101 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1102 ((and (eq method :before) (smie-rule-bolp) (not (smie-rule-sibling-p)))
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1103 (let ((parent-col (cdr (smie-rule-parent)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1104 (parent-pos-col ;FIXME: we knew this when computing smie--parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1105 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1106 (goto-char (cadr smie--parent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1107 (smie-indent-forward-token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1108 (forward-comment (point-max))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1109 (current-column))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1110 (cons 'column
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1111 (max parent-col
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1112 (min parent-pos-col
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1113 (- parent-pos-col (smie-indent--separator-outdent)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1114 ((and (eq method :after) (smie-indent--bolp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1115 (smie-indent--separator-outdent))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1116
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1117 (defun smie-indent--offset (elem)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1118 (or (funcall smie-rules-function :elem elem)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1119 (if (not (eq elem 'basic))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1120 (funcall smie-rules-function :elem 'basic))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1121 smie-indent-basic))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1122
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1123 (defun smie-indent--rule (method token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1124 ;; FIXME: Too many parameters.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1125 &optional after parent base-pos)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1126 "Compute indentation column according to `indent-rule-functions'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1127 METHOD and TOKEN are passed to `indent-rule-functions'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1128 AFTER is the position after TOKEN, if known.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1129 PARENT is the parent info returned by `smie-backward-sexp', if known.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1130 BASE-POS is the position relative to which offsets should be applied."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1131 ;; This is currently called in 3 cases:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1132 ;; - :before opener, where rest=nil but base-pos could as well be parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1133 ;; - :before other, where
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1134 ;; ; after=nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1135 ;; ; parent is set
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1136 ;; ; base-pos=parent
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1137 ;; - :after tok, where
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1138 ;; ; after is set; parent=nil; base-pos=point;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1139 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1140 (let ((offset
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1141 (let ((smie--parent parent)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1142 (smie--token token)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1143 (smie--after after))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1144 (funcall smie-rules-function method token))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1145 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1146 ((not offset) nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1147 ((eq (car-safe offset) 'column) (cdr offset))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1148 ((integerp offset)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1149 (+ offset
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1150 (if (null base-pos) 0
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1151 (goto-char base-pos)
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1152 ;; Use smie-indent-virtual when indenting relative to an opener:
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1153 ;; this will also by default use current-column unless
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1154 ;; that opener is hanging, but will additionally consult
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1155 ;; rules-function, so it gives it a chance to tweak indentation
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1156 ;; (e.g. by forcing indentation relative to its own parent, as in
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1157 ;; fn a => fn b => fn c =>).
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1158 ;; When parent==nil it doesn't matter because the only case
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1159 ;; where it's really used is when the base-pos is hanging anyway.
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1160 (if (or (and parent (null (car parent)))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1161 (smie-indent--hanging-p))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1162 (smie-indent-virtual) (current-column)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1163 (t (error "Unknown indentation offset %s" offset))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1164
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1165 (defun smie-indent-forward-token ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1166 "Skip token forward and return it, along with its levels."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1167 (let ((tok (funcall smie-forward-token-function)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1168 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1169 ((< 0 (length tok)) (assoc tok smie-grammar))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1170 ((looking-at "\\s(\\|\\s)\\(\\)")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1171 (forward-char 1)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1172 (cons (buffer-substring (1- (point)) (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1173 (if (match-end 1) '(0 nil) '(nil 0)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1174
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1175 (defun smie-indent-backward-token ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1176 "Skip token backward and return it, along with its levels."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1177 (let ((tok (funcall smie-backward-token-function))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1178 class)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1179 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1180 ((< 0 (length tok)) (assoc tok smie-grammar))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1181 ;; 4 == open paren syntax, 5 == close.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1182 ((memq (setq class (syntax-class (syntax-after (1- (point))))) '(4 5))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1183 (forward-char -1)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1184 (cons (buffer-substring (point) (1+ (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1185 (if (eq class 4) '(nil 0) '(0 nil)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1186
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1187 (defun smie-indent-virtual ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1188 ;; We used to take an optional arg (with value :not-hanging) to specify that
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1189 ;; we should only use (smie-indent-calculate) if we're looking at a hanging
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1190 ;; keyword. This was a bad idea, because the virtual indent of a position
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1191 ;; should not depend on the caller, since it leads to situations where two
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1192 ;; dependent indentations get indented differently.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1193 "Compute the virtual indentation to use for point.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1194 This is used when we're not trying to indent point but just
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1195 need to compute the column at which point should be indented
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1196 in order to figure out the indentation of some other (further down) point."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1197 ;; Trust pre-existing indentation on other lines.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1198 (if (smie-indent--bolp) (current-column) (smie-indent-calculate)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1199
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1200 (defun smie-indent-fixindent ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1201 ;; Obey the `fixindent' special comment.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1202 (and (smie-indent--bolp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1203 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1204 (comment-normalize-vars)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1205 (re-search-forward (concat comment-start-skip
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1206 "fixindent"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1207 comment-end-skip)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1208 ;; 1+ to account for the \n comment termination.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1209 (1+ (line-end-position)) t))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1210 (current-column)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1211
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1212 (defun smie-indent-bob ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1213 ;; Start the file at column 0.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1214 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1215 (forward-comment (- (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1216 (if (bobp) 0)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1217
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1218 (defun smie-indent-close ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1219 ;; Align close paren with opening paren.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1220 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1221 ;; (forward-comment (point-max))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1222 (when (looking-at "\\s)")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1223 (while (not (zerop (skip-syntax-forward ")")))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1224 (skip-chars-forward " \t"))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1225 (condition-case nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1226 (progn
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1227 (backward-sexp 1)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1228 (smie-indent-virtual)) ;:not-hanging
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1229 (scan-error nil)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1230
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1231 (defun smie-indent-keyword (&optional token)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1232 "Indent point based on the token that follows it immediately.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1233 If TOKEN is non-nil, assume that that is the token that follows point.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1234 Returns either a column number or nil if it considers that indentation
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1235 should not be computed on the basis of the following token."
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1236 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1237 (let* ((pos (point))
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1238 (toklevels
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1239 (if token
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1240 (assoc token smie-grammar)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1241 (let* ((res (smie-indent-forward-token)))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1242 ;; Ignore tokens on subsequent lines.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1243 (if (and (< pos (line-beginning-position))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1244 ;; Make sure `token' also *starts* on another line.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1245 (save-excursion
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1246 (smie-indent-backward-token)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1247 (< pos (line-beginning-position))))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1248 nil
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1249 (goto-char pos)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1250 res)))))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1251 (setq token (pop toklevels))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1252 (cond
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1253 ((null (cdr toklevels)) nil) ;Not a keyword.
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1254 ((not (numberp (car toklevels)))
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1255 ;; Different cases:
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1256 ;; - smie-indent--bolp: "indent according to others".
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1257 ;; - common hanging: "indent according to others".
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1258 ;; - SML-let hanging: "indent like parent".
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1259 ;; - if-after-else: "indent-like parent".
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1260 ;; - middle-of-line: "trust current position".
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1261 (cond
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1262 ((smie-indent--rule :before token))
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1263 ((smie-indent--bolp) ;I.e. non-virtual indent.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1264 ;; For an open-paren-like thingy at BOL, always indent only
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1265 ;; based on other rules (typically smie-indent-after-keyword).
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1266 nil)
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1267 (t
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1268 ;; By default use point unless we're hanging.
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1269 (unless (smie-indent--hanging-p) (current-column)))))
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1270 (t
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1271 ;; FIXME: This still looks too much like black magic!!
111775
81cac26277b0 * emacs-lisp/smie.el (smie-prec2->grammar): Simplify handling
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111622
diff changeset
1272 (let* ((parent (smie-backward-sexp token)))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1273 ;; Different behaviors:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1274 ;; - align with parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1275 ;; - parent + offset.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1276 ;; - after parent's column + offset (actually, after or before
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1277 ;; depending on where backward-sexp stopped).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1278 ;; ? let it drop to some other indentation function (almost never).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1279 ;; ? parent + offset + parent's own offset.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1280 ;; Different cases:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1281 ;; - bump into a same-level operator.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1282 ;; - bump into a specific known parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1283 ;; - find a matching open-paren thingy.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1284 ;; - bump into some random parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1285 ;; ? borderline case (almost never).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1286 ;; ? bump immediately into a parent.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1287 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1288 ((not (or (< (point) pos)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1289 (and (cadr parent) (< (cadr parent) pos))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1290 ;; If we didn't move at all, that means we didn't really skip
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1291 ;; what we wanted. Should almost never happen, other than
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1292 ;; maybe when an infix or close-paren is at the beginning
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1293 ;; of a buffer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1294 nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1295 ((save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1296 (goto-char pos)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1297 (smie-indent--rule :before token nil parent (cadr parent))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1298 ((eq (car parent) (car toklevels))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1299 ;; We bumped into a same-level operator; align with it.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1300 (if (and (smie-indent--bolp) (/= (point) pos)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1301 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1302 (goto-char (goto-char (cadr parent)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1303 (not (smie-indent--bolp))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1304 ;; If the parent is at EOL and its children are indented like
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1305 ;; itself, then we can just obey the indentation chosen for the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1306 ;; child.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1307 ;; This is important for operators like ";" which
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1308 ;; are usually at EOL (and have an offset of 0): otherwise we'd
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1309 ;; always go back over all the statements, which is
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1310 ;; a performance problem and would also mean that fixindents
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1311 ;; in the middle of such a sequence would be ignored.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1312 ;;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1313 ;; This is a delicate point!
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1314 ;; Even if the offset is not 0, we could follow the same logic
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1315 ;; and subtract the offset from the child's indentation.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1316 ;; But that would more often be a bad idea: OT1H we generally
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1317 ;; want to reuse the closest similar indentation point, so that
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1318 ;; the user's choice (or the fixindents) are obeyed. But OTOH
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1319 ;; we don't want this to affect "unrelated" parts of the code.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1320 ;; E.g. a fixindent in the body of a "begin..end" should not
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1321 ;; affect the indentation of the "end".
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1322 (current-column)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1323 (goto-char (cadr parent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1324 ;; Don't use (smie-indent-virtual :not-hanging) here, because we
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1325 ;; want to jump back over a sequence of same-level ops such as
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1326 ;; a -> b -> c
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1327 ;; -> d
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1328 ;; So as to align with the earliest appropriate place.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1329 (smie-indent-virtual)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1330 (t
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1331 (if (and (= (point) pos) (smie-indent--bolp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1332 ;; Since we started at BOL, we're not computing a virtual
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1333 ;; indentation, and we're still at the starting point, so
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1334 ;; we can't use `current-column' which would cause
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1335 ;; indentation to depend on itself and we can't use
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1336 ;; smie-indent-virtual since that would be an inf-loop.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1337 nil
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1338 ;; In indent-keyword, if we're indenting `then' wrt `if', we
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1339 ;; want to use indent-virtual rather than use just
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1340 ;; current-column, so that we can apply the (:before . "if")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1341 ;; rule which does the "else if" dance in SML. But in other
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1342 ;; cases, we do not want to use indent-virtual (e.g. indentation
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1343 ;; of "*" w.r.t "+", or ";" wrt "("). We could just always use
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1344 ;; indent-virtual and then have indent-rules say explicitly to
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1345 ;; use `point' after things like "(" or "+" when they're not at
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1346 ;; EOL, but you'd end up with lots of those rules.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1347 ;; So we use a heuristic here, which is that we only use virtual
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1348 ;; if the parent is tightly linked to the child token (they're
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1349 ;; part of the same BNF rule).
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1350 (if (car parent) (current-column) (smie-indent-virtual)))))))))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1351
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1352 (defun smie-indent-comment ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1353 "Compute indentation of a comment."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1354 ;; Don't do it for virtual indentations. We should normally never be "in
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1355 ;; front of a comment" when doing virtual-indentation anyway. And if we are
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1356 ;; (as can happen in octave-mode), moving forward can lead to inf-loops.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1357 (and (smie-indent--bolp)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1358 (let ((pos (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1359 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1360 (beginning-of-line)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1361 (and (re-search-forward comment-start-skip (line-end-position) t)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1362 (eq pos (or (match-end 1) (match-beginning 0))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1363 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1364 (forward-comment (point-max))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1365 (skip-chars-forward " \t\r\n")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1366 (smie-indent-calculate))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1367
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1368 (defun smie-indent-comment-continue ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1369 ;; indentation of comment-continue lines.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1370 (let ((continue (and comment-continue
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1371 (comment-string-strip comment-continue t t))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1372 (and (< 0 (length continue))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1373 (looking-at (regexp-quote continue)) (nth 4 (syntax-ppss))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1374 (let ((ppss (syntax-ppss)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1375 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1376 (forward-line -1)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1377 (if (<= (point) (nth 8 ppss))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1378 (progn (goto-char (1+ (nth 8 ppss))) (current-column))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1379 (skip-chars-forward " \t")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1380 (if (looking-at (regexp-quote continue))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1381 (current-column))))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1383 (defun smie-indent-comment-close ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1384 (and (boundp 'comment-end-skip)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1385 comment-end-skip
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1386 (not (looking-at " \t*$")) ;Not just a \n comment-closer.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1387 (looking-at comment-end-skip)
111603
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1388 (let ((end (match-string 0)))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1389 (and (nth 4 (syntax-ppss))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1390 (save-excursion
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1391 (goto-char (nth 8 (syntax-ppss)))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1392 (and (looking-at comment-start-skip)
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1393 (let ((start (match-string 0)))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1394 ;; Align the common substring between starter
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1395 ;; and ender, if possible.
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1396 (if (string-match "\\(.+\\).*\n\\(.*?\\)\\1"
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1397 (concat start "\n" end))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1398 (+ (current-column) (match-beginning 0)
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1399 (- (match-beginning 2) (match-end 2)))
c901fac3b428 * lisp/emacs-lisp/smie.el (smie-rule-parent, smie-indent--rule):
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111382
diff changeset
1400 (current-column)))))))))
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1401
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1402 (defun smie-indent-comment-inside ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1403 (and (nth 4 (syntax-ppss))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1404 'noindent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1405
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1406 (defun smie-indent-after-keyword ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1407 ;; Indentation right after a special keyword.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1408 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1409 (let* ((pos (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1410 (toklevel (smie-indent-backward-token))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1411 (tok (car toklevel)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1412 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1413 ((null toklevel) nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1414 ((smie-indent--rule :after tok pos nil (point)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1415 ;; The default indentation after a keyword/operator is
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1416 ;; 0 for infix, t for prefix, and use another rule
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1417 ;; for postfix.
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1418 ((not (numberp (nth 2 toklevel))) nil) ;A closer.
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1419 ((or (not (numberp (nth 1 toklevel))) ;An opener.
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1420 (rassoc tok smie-closer-alist)) ;An inner.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1421 (+ (smie-indent-virtual) (smie-indent--offset 'basic))) ;
111622
df422e3ae879 * emacs-lisp/smie.el (smie-bnf-classify): Signal errors for tokens
Stefan Monnier <monnier@iro.umontreal.ca>
parents: 111605
diff changeset
1422 (t (smie-indent-virtual)))))) ;An infix.
111382
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1423
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1424 (defun smie-indent-exps ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1425 ;; Indentation of sequences of simple expressions without
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1426 ;; intervening keywords or operators. E.g. "a b c" or "g (balbla) f".
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1427 ;; Can be a list of expressions or a function call.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1428 ;; If it's a function call, the first element is special (it's the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1429 ;; function). We distinguish function calls from mere lists of
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1430 ;; expressions based on whether the preceding token is listed in
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1431 ;; the `list-intro' entry of smie-indent-rules.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1432 ;;
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1433 ;; TODO: to indent Lisp code, we should add a way to specify
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1434 ;; particular indentation for particular args depending on the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1435 ;; function (which would require always skipping back until the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1436 ;; function).
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1437 ;; TODO: to indent C code, such as "if (...) {...}" we might need
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1438 ;; to add similar indentation hooks for particular positions, but
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1439 ;; based on the preceding token rather than based on the first exp.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1440 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1441 (let ((positions nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1442 arg)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1443 (while (and (null (car (smie-backward-sexp)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1444 (push (point) positions)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1445 (not (smie-indent--bolp))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1446 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1447 ;; Figure out if the atom we just skipped is an argument rather
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1448 ;; than a function.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1449 (setq arg
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1450 (or (null (car (smie-backward-sexp)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1451 (funcall smie-rules-function :list-intro
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1452 (funcall smie-backward-token-function)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1453 (cond
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1454 ((null positions)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1455 ;; We're the first expression of the list. In that case, the
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1456 ;; indentation should be (have been) determined by its context.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1457 nil)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1458 (arg
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1459 ;; There's a previous element, and it's not special (it's not
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1460 ;; the function), so let's just align with that one.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1461 (goto-char (car positions))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1462 (current-column))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1463 ((cdr positions)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1464 ;; We skipped some args plus the function and bumped into something.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1465 ;; Align with the first arg.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1466 (goto-char (cadr positions))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1467 (current-column))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1468 (positions
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1469 ;; We're the first arg.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1470 (goto-char (car positions))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1471 (+ (smie-indent--offset 'args)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1472 ;; We used to use (smie-indent-virtual), but that
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1473 ;; doesn't seem right since it might then indent args less than
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1474 ;; the function itself.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1475 (current-column)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1476
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1477 (defvar smie-indent-functions
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1478 '(smie-indent-fixindent smie-indent-bob smie-indent-close
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1479 smie-indent-comment smie-indent-comment-continue smie-indent-comment-close
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1480 smie-indent-comment-inside smie-indent-keyword smie-indent-after-keyword
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1481 smie-indent-exps)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1482 "Functions to compute the indentation.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1483 Each function is called with no argument, shouldn't move point, and should
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1484 return either nil if it has no opinion, or an integer representing the column
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1485 to which that point should be aligned, if we were to reindent it.")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1486
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1487 (defun smie-indent-calculate ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1488 "Compute the indentation to use for point."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1489 (run-hook-with-args-until-success 'smie-indent-functions))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1490
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1491 (defun smie-indent-line ()
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1492 "Indent current line using the SMIE indentation engine."
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1493 (interactive)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1494 (let* ((savep (point))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1495 (indent (or (with-demoted-errors
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1496 (save-excursion
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1497 (forward-line 0)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1498 (skip-chars-forward " \t")
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1499 (if (>= (point) savep) (setq savep nil))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1500 (or (smie-indent-calculate) 0)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1501 0)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1502 (if (not (numberp indent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1503 ;; If something funny is used (e.g. `noindent'), return it.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1504 indent
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1505 (if (< indent 0) (setq indent 0)) ;Just in case.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1506 (if savep
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1507 (save-excursion (indent-line-to indent))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1508 (indent-line-to indent)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1509
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1510 (defun smie-setup (grammar rules-function &rest keywords)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1511 "Setup SMIE navigation and indentation.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1512 GRAMMAR is a grammar table generated by `smie-prec2->grammar'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1513 RULES-FUNCTION is a set of indentation rules for use on `smie-rules-function'.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1514 KEYWORDS are additional arguments, which can use the following keywords:
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1515 - :forward-token FUN
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1516 - :backward-token FUN"
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1517 (set (make-local-variable 'smie-rules-function) rules-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1518 (set (make-local-variable 'smie-grammar) grammar)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1519 (set (make-local-variable 'indent-line-function) 'smie-indent-line)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1520 (set (make-local-variable 'forward-sexp-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1521 'smie-forward-sexp-command)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1522 (while keywords
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1523 (let ((k (pop keywords))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1524 (v (pop keywords)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1525 (case k
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1526 (:forward-token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1527 (set (make-local-variable 'smie-forward-token-function) v))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1528 (:backward-token
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1529 (set (make-local-variable 'smie-backward-token-function) v))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1530 (t (message "smie-setup: ignoring unknown keyword %s" k)))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1531 (let ((ca (cdr (assq :smie-closer-alist grammar))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1532 (when ca
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1533 (set (make-local-variable 'smie-closer-alist) ca)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1534 ;; Only needed for interactive calls to blink-matching-open.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1535 (set (make-local-variable 'blink-matching-check-function)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1536 #'smie-blink-matching-check)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1537 (add-hook 'post-self-insert-hook
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1538 #'smie-blink-matching-open 'append 'local)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1539 (set (make-local-variable 'smie-blink-matching-triggers)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1540 (append smie-blink-matching-triggers
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1541 ;; Rather than wait for SPC to blink, try to blink as
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1542 ;; soon as we type the last char of a block ender.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1543 (let ((closers (sort (mapcar #'cdr smie-closer-alist)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1544 #'string-lessp))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1545 (triggers ())
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1546 closer)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1547 (while (setq closer (pop closers))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1548 (unless (and closers
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1549 ;; FIXME: this eliminates prefixes of other
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1550 ;; closers, but we should probably elimnate
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1551 ;; prefixes of other keywords as well.
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1552 (string-prefix-p closer (car closers)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1553 (push (aref closer (1- (length closer))) triggers)))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1554 (delete-dups triggers)))))))
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1555
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1556
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1557 (provide 'smie)
1aba3578b8d8 * lisp/emacs-lisp/smie.el: New package.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff changeset
1558 ;;; smie.el ends here