-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New indentation engine #591
Conversation
It still uses smie. The main design choice for this new version is
that the first word of a command is now a token "Com
start". Together with the "." token for ending
a command this makes the smie grammar parsing much more
"local".
;; Com1 .(1)
;; Definition foo := bar .(2)
;; ...
;; could easily lead to the grammar tree
;;
;; __.(2)
;; .(1) \
;; / \ ...
;; / \
;; Com1 :=
;; / \
;; Def foo bar
;;
;; which means that "(1)" is the parent of ":=", which is the parent
;; of "Def foo". This leads to hell. We need Def to be the parent. But
;; there are hundreds of commands in coq. so we adopt the policy below.
;;
;; 2. the lexer tries to always treat the first word of a command as a
;; dstinguished token "Com start". And a command is of the form ("Com
;; start" exp) in smie grammar. This way the top-node of a command is
;; always this token.
;;
;; This way the above script is parsed as:
;;
;; __.(2)
;; .(1) \
;; / \ ...
;; / \
;; Com1 Com start
;; |
;; :=
;; / \
;; foo bar
I haven't looked at the actual code, but the above sounds great to me.
Stefan
|
Awesome work. Thanks Pierre. I'm not qualified to look at the actual code, but the motivation looks 👍. A few examples / tests that were developed to indent "correctly" in the current system. How are the following indented with the new code? (what's below is how they are currently indented)
|
@cpitclaudel there is problem with the <{ }> thing. I will try to fix it before merging. @monnier I think that tweaking the lexer to parenthesize each command is a good way to go indeed. I should perhaps re-do the lexer(s) completely but for now it seems to work OK. |
(provided this is inside a real command) this is not indented as you want (see the shift of
|
Indeed, it's a hoare triple. The command being indented isn't too bad.
I suspected so :) I'm happy to change the syntax, too — but I was very happy when I found that trick, since it allowed me to indent very naturally:
So the really nice part is that the two halves of the triple line up ^^ It would be fine if the program part was indented further. |
I suspected so :) I'm happy to change the syntax, too — but I was very happy when I found that trick, since it allowed me to indent very naturally:
```
Definition … :=
<{ … }>
Some code here
and the continuation lines worked perfectly!
<{ and this magically aligned with the first part of the triple :) }>
```
Actually, if you take the analogy with `+` and treat both `<` and `>` as
having the same precedence, then the above would "naturally" indent to:
```
Definition … :=
<{ … }>
Some code here
and the continuation lines worked perfectly!
<{ and this magically aligned with the first part of the triple :) }>
```
Stefan
|
@monnier you are right but only if |
@cpitclaudel the |
Yes, that's even better than the current indentation actually :) |
@monnier you are right but only if `<` and `>` are declared left
associative.
Or just "associative" (i.e. have the same left and right precedence), as
is used for `;`, `,`, etc..
I think I will do this. It behaves the way @cpitclaudel wants.
It is still a hack that said.
Yup.
I wonder if there could be a better way. Maybe a special "three
parts" expression...
I think doing it right with Clément's current syntax requires either
changing the lexer (so it returns different tokens for the "<{" and the
"}>" of the preconditions than those of the post conditions) or extra
ad-hoc rules in the indentation rules: the grammar itself can't be made
to understand the structure because it is basically
assert ::= "<{" e "}>"
e ::= ... | assert e assert
but operator precedence grammars have as core constraint that you need
a terminal between every pair of non-terminals. You can turn the grammar
into:
e ::= ... | "<{" e "}>" e "<{" e "}>"
but this leads to unsolvable constraints, the closest solution to those
constraints is to make those tokens "associative" (i.e. same precedence
on both sides and same precedence for both tokens), so you lose the
original structure.
My guess is that if you want to indent the middle `e` deeper, the better
solution is to add an ad-hoc indenting rule (e.g. indent deeper if
you're right after a "}>" and the next token has higher left precedence).
Stefan
PS: This is also why you can't really have `.` as terminator but only
as separator:
terms ::= term
terms ::= term "." terms
is fine but
term1 ::= term "."
terms ::= term1
terms ::= term1 terms
isn't since there's no terminal between `term1` and `terms`.
|
Thanks both! I'm fine with changing the syntax if that helps, the current one was co-evolved with the previous parser specifically so that it would indent nicely :) |
That is not what I see. if I have
Maybe there is something wrong with my grammar? It says simply |
@erikmd can you tell me how to have the new indentation tests (currently in Not a blocker anyways. |
> > @monnier you are right but only if `<` and `>` are declared left associative.
> Or just "associative" (i.e. have the same left and right precedence), as
> is used for `;`, `,`, etc..
That is not what I see. if I have `(assoc "<" ">")` I have this indentation:
```
Definition foo :=
< fooo
bar >
rab
< foo
bar >.
```
Hmm... you might be right that the rule that does what I expected checks
that the token is equal rather than just checking the precedence.
|
Hi @Matafou, thanks for all this work on the indentation engine! Indeed, I guess it'd be very nice if this automation can be added before merging the PR (if you want we'll be able to discuss this briefly in the upcoming PG telco). |
Hi @Matafou, I've just run the
Attaching a zip of the folder with I'm using Emacs 26.1 on Debian 10 |
@erikmd I can't reproduce, not easy for me to install emacs-26. |
Your tests.sh assumes that "." is in $PATH. IMO this is usually not the case and I would suggest to change that. |
Main design choice for this new version: the first word of a command is now a token "Com start". Together with the "." token for ending a command this makes the parsing much more "local". Users may experience a few changes in the indentation. A few special cases where the old indentation would reduce shifting to the right have been removed. Non regression testing have been added. See comments in coq-smie.el at coq-smie-grammar for more details.
@erik @hendriktews I made my test directory CI ready. |
The tests run fine here with emacs 27.1, 26.3, 26.2, 26.1, 25.3 and 25.1.
your tests run without coq installed, therefore copy and adopt the
(keep the spaces at the front of all lines - it must be indented below the |
Many thanks @hendriktews! I just pushed the CI config. |
The new tests run fine, well done! |
I will merge today if noone objects. |
Let us wait for bug reports now :-). |
This PR proposes a new simplified indentation implementation.
It still uses smie. The main design choice for this new version is that the first word of a command is now a token "Com start". Together with the "." token for ending a command this makes the smie grammar parsing much more "local".
Users may experience a few changes in the indentation: a few special cases where the old indentation would avoid shifting to the right have been removed.
Non regression testing have been added. But:
ci
directory as I did, or should it go elsewhere? Ideally it would be nice (but not mandatory) to include this tests in the ci @erikmd