Git Product home page Git Product logo

coqfmt's Introduction

Hi there!

I'm Hiroki Tokunaga, a worker in Japan.

Skills

These are the skills that either I have tried or I'm using daily and not something I can say I've understood a bit.

My Skills

My projects

Rust Projects

  • Ramen OS: A hobby OS supporting xHCI, USB storage reading and writing, and UEFI.
  • Antei OS: An experimental OS not using any Nightly Rust features.
  • xhci crate: A Rust library for writing xHCI drivers.
  • cpio_reader crate: A Rust library for reading CPIO files.
  • accessor crate: A Rust library for accessing MMIO.
  • qemu_print crate: A Rust library for printing strings to a console using QEMU's serial port support.
  • os_units crate: A Rust library providing memory size unit types, Bytes and NumOfPages.

Haskell Projects

TypeScript Projects

Coq Projects

  • Coqfmt: Coq code formatter (written in OCaml).

Krita plugins and programs

Other contributions

Translation into Japanese

Other accounts

My environment

  • OS: Gentoo Linux
  • Desktop environment: i3wm
  • Terminal: rxvt-unicode
  • Shell: Zsh
  • Editor: VSCode with Vim key-mapping
  • Tab size: 4 spaces
  • Keyboard layout: Programmer Dvorak (en), Kana Input (ja)

Anurag's GitHub stats

Top Langs

trophy

coqfmt's People

Contributors

bridgethemasterbuilder avatar dependabot[bot] avatar toku-sa-n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

coqfmt's Issues

Formatter can't handle proofs which omit `Proof.` command

I was testing out the formatter on some Coq files I had lying around and noticed that the indentation (Printer.t.indent_spaces) was becoming negative sometimes. That's because of stuff like:

Definition nandb (b1 : bool) (b2 : bool) : bool :=
  negb (andb b1 b2).

Example test_nandb1 : nandb true false = true.
reflexivity.
Qed.

This Example proof omits the optional Proof. command, so no indentation occurs, but Qed. then decreases the indentation level anyway. The naive solution is to simply check before deindenting but there is actually a bigger problem here, as you can see it doesn't indent the reflexivity tactic because of this bug.

The formatter should instead probably increase the indentation level after processing the proof statement. I must admit I didn't see an obvious way to do that with the way the code is architected at the moment, but as you are more familiar with the code maybe you know how. :) 

Pretty-print `VernacExtend`s without internal printers

coqfmt/lib/ppast.ml

Lines 68 to 73 in 3b59c3d

(* FIXME: I have no idea how to extract the complete information of a `VernacExtend`.
See https://stackoverflow.com/questions/76792174/how-to-extract-the-exact-information-of-genarg. *)
| VernacExtend _ ->
Ppvernac.pr_vernac_expr expr
|> Pp.string_of_ppcmds |> Printer.write printer;
Printer.write printer "."

Using internal printers should be avoided because we cannot control line widths, indentations, etc.

Pp consecutive `Proof.`s

Input:

Theorem foo:1=1. Proof. Proof. reflexivity. Qed.

Expected output:

Theorem foo : 1 = 1.
Proof.
  reflexivity.
Qed.

or

Theorem foo : 1 = 1.
Proof.
Proof.
  reflexivity.
Qed.

Actual output:

Theorem foo : 1 = 1.
Proof.
  Proof.
    reflexivity.
  Qed.

Cannot format a simple Coq file.

input: lecture01.v

Require Import Arith.

Compute 1 + 1.
Compute 1 + 2 * 3.

(* how to write a function *)
Definition add (x:nat) (y:nat) : nat := x + y.

Compute add 3 4.

Compute (add 3 4).

Compute add (1*9) (1*9).

(* Gives me type signature *)
Check add.

Definition hypotenuse (x:nat) (y:nat) : nat :=
  (* how to write scoped variables *)
  let xsquared := x * x in
  let ysquared := y * y in
  let sum := xsquared + ysquared in
  sum.

Check hypotenuse.
Compute hypotenuse 3 4.

Compute 3 * 4.
Compute Nat.mul 3 4.
(* This tells me what "*" is! *)
Print "*".
Print add.
Print "+".

(* remember that the comparison operators of Coq have "?" *)
Compute 3 <=? 4.
Compute true.
Compute false.
Compute 4 <=? 3.
Compute leb 4 3.
(* Then, what does "<=" mean? *)
Print "<=".
Print "<=?".

(* ternary operator *)
Compute if (leb 3 4) then (add 1 2) else (4 - 3). (* => 3 *)
Compute if (leb 4 3) then (add 1 2) else (4 - 3). (* => 1 *)

Compute andb true false.
Compute orb false false.

(* Now, you can use more boolean operators *)
Open Scope bool_scope.
Compute true && false.
Compute false || true.

(* Require Import imports a library *)
(* The library contains a scoped library *)
(* Require Import String.
Open Scope string_scope.

Compute "foo".
Compute "foo" ++ "bar".

(* tuple type: bool * nat *)
Compute (true, 3).
(* we can nest it bool * nat * nat *)
Compute ((false, 3), add 3 4).
(* we can nest it nat * (bool * nat) *)
Compute (add 3 4, (false, 3)).
(* thus, this is left-associative *)

(* you can take either one of them *)
Compute fst (true, 3).
Compute fst (true, false, "aaa").
Compute fst (true, (false, "aaa")).
Compute snd (true, (false, "aaa")).
Compute snd (snd (true, (false, "aaa"))). "aaa" *)

(* Inductive is like a function *)
Inductive color : Type :=
  | Red : color
  | Blue : color
  | Dark (c:color) : color
  | Light (c:color) : color
.

Compute Red.
(* left-associative *)
Compute Dark (Light (Dark Blue)).
Compute Dark Blue.

(* You cannot define a type that already exists *)
(* Inductive color : Type :=
  | Yello : color. *)

Definition isdark (c:color) : bool :=
  (* you can use pattern-match *)
  match c with
  | Dark _ => true
  | _ => false (* without this clause, the compiler errs *)
  end.

Compute isdark (Dark Red).
Compute isdark (Light Red).
Compute isdark Red.

(* we use Fixpoint to write a recursive function *)
(* Definition is for a normal function *)
Fixpoint isred (c:color) : bool :=
  match c with
  | Red => true
  | Blue => false
  (* x is a value, contructor, and not an expression *)
  | Dark x => isred x
  | Light x => isred x
  end.

Compute isred Red.
Compute isred Blue.
Compute isred (Dark Red).
Compute isred (Light (Dark (Dark Red))).
Compute isred (Light (Dark (Dark Blue))).

Fixpoint factorial (n:nat) : nat :=
  match n with
  | O => 1
  | S n' => n * factorial n'
  end.

Compute factorial 10.
Compute factorial 6.

coqfmt cannot format this code.

$ cat lecture01.v | coqfmt
Fatal error: exception Coqfmt__Ppast.NotImplemented("Require Import Arith.\n\nCompute (1 + 1).\nCompute (1 + 2 * 3).\n\nDefinition add (x : nat) (y : nat) : nat := x + y.\n\nCompute (add 3 4).\nCompute (add 3 4).\nCompute (add (1 * 9) (1 * 9)).\n\nCheck add.\n\nDefinition hypotenuse (x : nat) (y : nat) : nat := ")

Support `Require Export` for local files

Foo.v

(* empty *)

Bar.v

From X Require Export Foo.

coqc -Q . X Foo.v && coqc -Q . X Bar.v succeeds, but cat Bar.v|coqfmt fails.

%cat Bar.v|coqfmt 
coqfmt: internal error, uncaught exception:
        Vernacentries.UnmappedLibrary(_, _)

Formatter inserts type annotations in Definitions even for inferred types

I'm sure you probably know about this already but just in case:

The formatter turns e.g.

Definition negb b := match b with
  | true => false
  | false => true
  end.

into

Definition negb (b : ) :=
  match b with
  | true => false
  | false => true
  end.

Also, for Fixpoint it adds a type annotation for the return type as well.

e.g.:

Fixpoint count n :=
  match n with
  | 0 => 0
  | S n => 1 + count n
  end.

to

Fixpoint count (n : ) :  :=
  match n with
  | 0 => 0
  | S n => 1 + count n
  end.

Formatter can't handle proofs consisting only of `Admitted.` or (I think) proofs which don't start with a tactic

#121 does not fully fix the issue raised by #119. E.g. proofs which are only Admitted. (to be implemented with PR #124)

Generally speaking, I feel like the current heuristic of VernacStartTheoremProof followed by a tactic is not good. After all, a proof may very well start with something other than a tactic. However, removing the is_tactic guard from the match arm makes a bunch of tests fail so I left it alone.

Adding another heuristic such as is_admitted (which I have already done in my local fork) on top of that is a hack at best, I think a more robust solution to this problem is required.

Add spaces on both sides of a colon

Given that ocamlformat adds spaces on both sides of a colon of a type annotation like below, coqfmt also should add them, not only after it.

val pp_ast : Ast.t -> string
Inductive foo : Type := (* not foo: Type *)
  | bar (x y : nat). (* not (x y: nat) *)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.