Skip to content
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

Merged
merged 4 commits into from
Sep 10, 2021
Merged

New indentation engine #591

merged 4 commits into from
Sep 10, 2021

Conversation

Matafou
Copy link
Contributor

@Matafou Matafou commented Jul 13, 2021

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:

  • Should the test go in the 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

@monnier
Copy link
Contributor

monnier commented Jul 13, 2021 via email

@cpitclaudel
Copy link
Member

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)

  Instance spec_of_vect_memcpy : spec_of "vect_memcpy" :=
    fnspec! "vect_memcpy" (len: word) (a1_ptr a2_ptr : address) /
          {n1} (a1: VectorArray.t word n1)
          {n2} (a2: VectorArray.t word n2)
          (pr1: word.unsigned len < Z.of_nat n1)
          (pr2: word.unsigned len < Z.of_nat n2)
          R,
    { requires tr mem :=
        (vectorarray_value AccessWord a1_ptr a1 ⋆
                           vectorarray_value AccessWord a2_ptr a2 ⋆ R) mem;
      ensures tr' mem' :=
        tr' = tr /\
        let res := vect_memcpy len a1 a2 pr1 pr2 in
        (vectorarray_value AccessWord a1_ptr (fst res) ⋆
                           vectorarray_value AccessWord a2_ptr (snd res) ⋆ R) mem' }.
  Instance spec_of_crc32 : spec_of "crc32" :=
    fnspec! "crc32" data_ptr len / (data : list byte) R ~> r,
    { requires tr mem :=
        (word.unsigned len = Z.of_nat (length data) /\
         (listarray_value AccessByte data_ptr data * R)%sep mem);
      ensures tr' mem' :=
        tr' = tr /\
        r = crc32' data /\
        (listarray_value AccessByte  data_ptr data * R)%sep mem' }.
        <{ Trace := tr;
           Memory := mem;
           Locals := locals;
           Functions := functions }>
        cmd.seq
          (cmd.while
             (expr.op (if signed then bopname.lts else bopname.ltu)
                      (expr.var from_var)
                      (expr.var to_var))
             body_impl)
          k_impl
        <{ pred (nlet_eq vars v k) }>

@Matafou
Copy link
Contributor Author

Matafou commented Jul 14, 2021

@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.

@Matafou
Copy link
Contributor Author

Matafou commented Jul 14, 2021

    <{ Trace := tr;
       Memory := mem;
       Locals := locals;
       Functions := functions }>
      cmd.seq
        (cmd.while
           (expr.op (if signed then bopname.lts else bopname.ltu)
                    (expr.var from_var)
                    (expr.var to_var))
           body_impl)
        k_impl
      <{ pred (nlet_eq vars v k) }>

(provided this is inside a real command) this is not indented as you want (see the shift of cmd.seq). I understand this is a hoare-like triple?
I will try to give a solution, but you were relying on a bug :-): basically you exploited the fact that this was indented badly (think that < as +):

  Definition foo :=
    + 3 +
    5. (* this should be (and is now) shifted to the right*)

@cpitclaudel
Copy link
Member

Indeed, it's a hoare triple. The command being indented isn't too bad.

I will try to give a solution, but you were relying on a bug :-)

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 :) }>

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.

@monnier
Copy link
Contributor

monnier commented Jul 14, 2021 via email

@Matafou
Copy link
Contributor Author

Matafou commented Jul 15, 2021

@monnier you are right but only if < and > are declared left associative. I think I will do this. It behaves the way @cpitclaudel wants. It is still a hack that said. I wonder if there could be a better way. Maybe a special "three parts" expression...

@Matafou
Copy link
Contributor Author

Matafou commented Jul 15, 2021

@cpitclaudel the !fnspec ... / ... , ... gets a shift to the right after the ,. Is it ok?

@cpitclaudel
Copy link
Member

@cpitclaudel the !fnspec ... / ... , ... gets a shift to the right after the ,. Is it ok?

Yes, that's even better than the current indentation actually :)

@monnier
Copy link
Contributor

monnier commented Jul 15, 2021 via email

@cpitclaudel
Copy link
Member

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 :)

@Matafou
Copy link
Contributor Author

Matafou commented Jul 15, 2021

@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 >.

Maybe there is something wrong with my grammar? It says simply (exp "<" exp) (exp ">" exp).
Only with "left" do I have the two "<" at the same column.

@Matafou
Copy link
Contributor Author

Matafou commented Jul 15, 2021

@erikmd can you tell me how to have the new indentation tests (currently in ci/test-indentation) should be made part of the CI?

Not a blocker anyways.

@monnier
Copy link
Contributor

monnier commented Jul 15, 2021 via email

@erikmd
Copy link
Member

erikmd commented Jul 20, 2021

@erikmd can you tell me how to have the new indentation tests (currently in ci/test-indentation) should be made part of the CI?

Not a blocker anyways.

Hi @Matafou, thanks for all this work on the indentation engine!
I've just seen your mention about CI, basically the place where you committed the indentation test-suite is very fine (in ci/), and we'll just need to add some "GitHub Actions job" + some shell commands in file .github/workflows/test.yml to launch the tests themselves automatically (and fail if an error has been detected).

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).

@erikmd
Copy link
Member

erikmd commented Jul 20, 2021

Hi @Matafou, I've just run the tests.sh and I got this:

Testing indent-tac-boxed.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-tac-boxed.v indented_indent-tac-boxed.v
  *** or graphically: 
  ***  meld indent-tac-boxed.v indented_indent-tac-boxed.v
Testing indent-inside-command-boxed.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-inside-command-boxed.v indented_indent-inside-command-boxed.v
  *** or graphically: 
  ***  meld indent-inside-command-boxed.v indented_indent-inside-command-boxed.v
Testing indent_monadic.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent_monadic.v indented_indent_monadic.v
  *** or graphically: 
  ***  meld indent_monadic.v indented_indent_monadic.v
Testing indent-inside-command.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-inside-command.v indented_indent-inside-command.v
  *** or graphically: 
  ***  meld indent-inside-command.v indented_indent-inside-command.v
Testing indent-tac.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-tac.v indented_indent-tac.v
  *** or graphically: 
  ***  meld indent-tac.v indented_indent-tac.v
Testing indent-commands-boxed.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-commands-boxed.v indented_indent-commands-boxed.v
  *** or graphically: 
  ***  meld indent-commands-boxed.v indented_indent-commands-boxed.v
Testing indent-commands.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent-commands.v indented_indent-commands.v
  *** or graphically: 
  ***  meld indent-commands.v indented_indent-commands.v
Testing indent_equations.v... TEST FAILURE ***
  *** details can be seen with:
  ***  diff --side-by-side --suppress-common-lines indent_equations.v indented_indent_equations.v
  *** or graphically: 
  ***  meld indent_equations.v indented_indent_equations.v

Attaching a zip of the folder with *.log files.

test-indent.zip

I'm using Emacs 26.1 on Debian 10

@Matafou
Copy link
Contributor Author

Matafou commented Aug 15, 2021

@erikmd I can't reproduce, not easy for me to install emacs-26.
@hendriktews can you check that with 27 it works and 26 it does not please?

@hendriktews
Copy link
Collaborator

Your tests.sh assumes that "." is in $PATH. IMO this is usually not the case and I would suggest to change that.
All the following is with ./ prepended to coq-test-indent.sh in tests.sh.
When I run tests.sh I don't see a difference between emacs 27 and 26, see the attached output from running cd ci/test-indent; echo; emacs --version; echo; ./tests.sh in all containers with different emacs versions that I have. new-indend-log.log
To investigate a bit further, I also attach the output of cd ci/test-indent; echo; emacs --version; echo; ./tests.sh; echo; ls -l .*log; echo; cat .*log for 27.1 new-indend-cat-log-27.log and 26.1 new-indend-cat-log-26.log for a changed coq-test-inden.sh. The change removes -q from the diff invocation and puts set-x and set +x around the diff and the preceding echo line.

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.
@Matafou
Copy link
Contributor Author

Matafou commented Aug 26, 2021

@erik @hendriktews I made my test directory CI ready.
The PG/ci/test-indent contains a makefile, you just need to launch make and if some test fails it exits with code 1.
I don't know what needs to be done to trigger the test now but I think I can merge now (if the checks are OK).

@hendriktews
Copy link
Collaborator

The tests run fine here with emacs 27.1, 26.3, 26.2, 26.1, 25.3 and 25.1.

I don't know what needs to be done to trigger the test now but I think I can merge now (if the checks are OK).

your tests run without coq installed, therefore copy and adopt the
build recipe in .github/workflows/test.yml, ie. insert the
following at the end of that file:


  # Run indentation tests in ci/test-indent on all supported emacs
  # versions without coq installed.
  test-indent:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        emacs_version:
          - 25.1
          - 25.2
          - 25.3
          - 26.1
          - 26.2
          - 26.3
          - 27.1
      max-parallel: 4
      # don't cancel all in-progress jobs if one matrix job fails:
      fail-fast: false

    steps:
    - uses: actions/checkout@v2

    - uses: purcell/setup-emacs@master
      with:
        version: ${{ matrix.emacs_version }}

    - run: emacs --version
    - run: make -C ci/test-indent

(keep the spaces at the front of all lines - it must be indented below the jobs tag on line 13!)

@Matafou
Copy link
Contributor Author

Matafou commented Aug 27, 2021

Many thanks @hendriktews! I just pushed the CI config.

@hendriktews
Copy link
Collaborator

The new tests run fine, well done!

@Matafou
Copy link
Contributor Author

Matafou commented Sep 9, 2021

I will merge today if noone objects.

@Matafou Matafou merged commit 32b15ff into ProofGeneral:master Sep 10, 2021
@Matafou
Copy link
Contributor Author

Matafou commented Sep 10, 2021

Let us wait for bug reports now :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants