2023-03-20 20:10:30 +01:00
|
|
|
Format basic
|
|
|
|
|
$ refmt --print re ./input.re > ./formatted.re
|
|
|
|
|
|
2023-04-30 21:41:33 +02:00
|
|
|
Print the formatted file
|
|
|
|
|
$ cat ./formatted.re
|
|
|
|
|
type point = {
|
|
|
|
|
x: int,
|
|
|
|
|
y: int,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let id = x => x;
|
|
|
|
|
|
|
|
|
|
type myVariant =
|
|
|
|
|
| TwoCombos(inner, inner)
|
|
|
|
|
| Short
|
|
|
|
|
| AlsoHasARecord(int, int, point)
|
|
|
|
|
and inner =
|
|
|
|
|
| Unused
|
|
|
|
|
| HeresTwoConstructorArguments(int, int);
|
|
|
|
|
|
|
|
|
|
let computeTuple = (a, b, c, d, e, f, g, h) => (
|
|
|
|
|
a + b,
|
|
|
|
|
c + d,
|
|
|
|
|
e + f,
|
|
|
|
|
g + h,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let res =
|
|
|
|
|
switch (TwoCombos(Unused, Unused)) {
|
|
|
|
|
| TwoCombos(
|
|
|
|
|
HeresTwoConstructorArguments(x, y),
|
|
|
|
|
HeresTwoConstructorArguments(a, b),
|
|
|
|
|
) => (
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
a,
|
|
|
|
|
b,
|
|
|
|
|
)
|
|
|
|
|
| TwoCombos(_, _) => (0, 0, 0, 0)
|
|
|
|
|
| Short
|
|
|
|
|
| AlsoHasARecord(300, _, _) => (
|
|
|
|
|
100000,
|
|
|
|
|
100000,
|
|
|
|
|
100000,
|
|
|
|
|
100000,
|
|
|
|
|
)
|
2025-07-04 22:37:35 -07:00
|
|
|
| AlsoHasARecord(firstItem, two, { x, y }) =>
|
2023-04-30 21:41:33 +02:00
|
|
|
computeTuple(
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
two,
|
|
|
|
|
two,
|
|
|
|
|
two,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Match bodies may include sequence expressions, but without the `{}`
|
|
|
|
|
* braces required.
|
|
|
|
|
*/
|
|
|
|
|
let res =
|
|
|
|
|
switch (TwoCombos(Unused, Unused)) {
|
|
|
|
|
| TwoCombos(
|
|
|
|
|
HeresTwoConstructorArguments(x, y),
|
|
|
|
|
HeresTwoConstructorArguments(a, b),
|
|
|
|
|
) =>
|
|
|
|
|
let ret = (x, y, a, b);
|
|
|
|
|
ret;
|
|
|
|
|
| TwoCombos(_, _) =>
|
|
|
|
|
/**
|
|
|
|
|
* See, no braces required - saves indentation as well!
|
|
|
|
|
*/
|
|
|
|
|
let ret = (0, 0, 0, 0);
|
|
|
|
|
ret;
|
|
|
|
|
| Short
|
|
|
|
|
| AlsoHasARecord(300, _, _) =>
|
|
|
|
|
/**
|
|
|
|
|
* And no final semicolon is required.
|
|
|
|
|
*/
|
|
|
|
|
let ret = (100000, 100000, 100000, 100000);
|
|
|
|
|
ret;
|
2025-07-04 22:37:35 -07:00
|
|
|
| AlsoHasARecord(firstItem, two, { x, y }) =>
|
2023-04-30 21:41:33 +02:00
|
|
|
computeTuple(
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
firstItem,
|
|
|
|
|
two,
|
|
|
|
|
two,
|
|
|
|
|
two,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Ensure that nested Pexp_functions are correctly wrapped in parens.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
let res =
|
|
|
|
|
switch (TwoCombos(Unused, Unused)) {
|
|
|
|
|
| TwoCombos(
|
|
|
|
|
HeresTwoConstructorArguments(x, y),
|
|
|
|
|
HeresTwoConstructorArguments(a, b),
|
|
|
|
|
) => (
|
|
|
|
|
fun
|
|
|
|
|
| Some(x) => x + 1
|
|
|
|
|
| None => 0
|
|
|
|
|
)
|
|
|
|
|
| TwoCombos(_, _) =>
|
|
|
|
|
let x = (
|
|
|
|
|
fun
|
|
|
|
|
| Some(x) => x + 1
|
|
|
|
|
| None => 0
|
|
|
|
|
);
|
|
|
|
|
x;
|
|
|
|
|
| Short
|
|
|
|
|
| AlsoHasARecord(300, _, _) =>
|
|
|
|
|
id(
|
|
|
|
|
fun
|
|
|
|
|
| Some(x) => x + 1
|
|
|
|
|
| None => 0,
|
|
|
|
|
)
|
2025-07-04 22:37:35 -07:00
|
|
|
| AlsoHasARecord(firstItem, two, { x, y }) =>
|
2023-04-30 21:41:33 +02:00
|
|
|
id(
|
|
|
|
|
fun
|
|
|
|
|
| Some(x) => x + 1
|
|
|
|
|
| None => 0,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* test (), which is sugar for (()) */
|
|
|
|
|
switch (Some()) {
|
|
|
|
|
| Some () => 1
|
|
|
|
|
| _ => 2
|
|
|
|
|
};
|
|
|
|
|
switch (Some()) {
|
|
|
|
|
| Some () => 1
|
|
|
|
|
| _ => 2
|
|
|
|
|
};
|
|
|
|
|
switch (Some()) {
|
|
|
|
|
| Some () => 1
|
|
|
|
|
| _ => 2
|
|
|
|
|
};
|
|
|
|
|
switch (Some()) {
|
|
|
|
|
| Some () => 1
|
|
|
|
|
| _ => 2
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type foo =
|
|
|
|
|
| Foo(unit);
|
|
|
|
|
switch (Foo()) {
|
|
|
|
|
| Foo () => 1
|
|
|
|
|
};
|
|
|
|
|
switch (Foo()) {
|
|
|
|
|
| Foo () => 1
|
|
|
|
|
};
|
|
|
|
|
switch (Foo()) {
|
|
|
|
|
| Foo () => 1
|
|
|
|
|
};
|
|
|
|
|
switch (Foo()) {
|
|
|
|
|
| Foo () => 1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch () {
|
|
|
|
|
| () => 1
|
|
|
|
|
};
|
|
|
|
|
switch () {
|
|
|
|
|
| () => 1
|
|
|
|
|
};
|
|
|
|
|
switch () {
|
|
|
|
|
| () => 1
|
|
|
|
|
};
|
|
|
|
|
switch () {
|
|
|
|
|
| () => 1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (Some(1)) {
|
|
|
|
|
| Some(1) => 1
|
|
|
|
|
| None => 2
|
|
|
|
|
| _ => 3
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let myInt = 100;
|
|
|
|
|
/* Numeric ranges are rejected by the type checker, but validly parsed so drop
|
|
|
|
|
* this in an annotation to test the parsing. */
|
|
|
|
|
[@something? 1 .. 2]
|
|
|
|
|
let rangeInt = 0;
|
|
|
|
|
|
|
|
|
|
let myChar = 'x';
|
|
|
|
|
let rangeChar =
|
|
|
|
|
switch (myChar) {
|
|
|
|
|
| 'a' .. 'b' => "a to b"
|
|
|
|
|
| 'b' .. 'z' => "b to z"
|
|
|
|
|
| c => "something else"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* with parens around direct list pattern in constructor pattern */
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([]) => ()
|
|
|
|
|
| Some([_]) when true => ()
|
|
|
|
|
| Some([x]) => ()
|
|
|
|
|
| Some([x, ...xs]) when true => ()
|
|
|
|
|
| Some([x, y, z]) => ()
|
|
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* no parens around direct list pattern in constructor pattern (sugar) */
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([]) => ()
|
|
|
|
|
| Some([_]) when true => ()
|
|
|
|
|
| Some([x]) => ()
|
|
|
|
|
| Some([x, ...xs]) when true => ()
|
|
|
|
|
| Some([x, y, z]) => ()
|
|
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* with parens around direct array pattern in constructor pattern */
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([||]) => "empty"
|
|
|
|
|
| Some([|_|]) when true => "one any"
|
|
|
|
|
| Some([|a|]) => "one"
|
|
|
|
|
| Some([|a, b|]) => "two"
|
|
|
|
|
| _ => "many"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* no parens around direct array pattern in constructor pattern (sugar) */
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([||]) => "empty"
|
|
|
|
|
| Some([|_|]) when true => "one any"
|
|
|
|
|
| Some([|a|]) => "one"
|
|
|
|
|
| Some([|a, b|]) => "two"
|
|
|
|
|
| _ => "many"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* parens around direct record pattern in constructor pattern */
|
|
|
|
|
switch (None) {
|
2025-07-04 22:37:35 -07:00
|
|
|
| Some({ x }) when true => ()
|
|
|
|
|
| Some({ x, y }) => ()
|
2023-04-30 21:41:33 +02:00
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* no parens around direct record pattern in constructor pattern (sugar) */
|
|
|
|
|
switch (None) {
|
2025-07-04 22:37:35 -07:00
|
|
|
| Some({ x }) when true => ()
|
|
|
|
|
| Some({ x, y }) => ()
|
2023-04-30 21:41:33 +02:00
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([|
|
|
|
|
|
someSuperLongString,
|
|
|
|
|
thisShouldBreakTheLine,
|
|
|
|
|
|]) =>
|
|
|
|
|
()
|
|
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some((
|
|
|
|
|
someSuperLongString,
|
|
|
|
|
thisShouldBreakTheLine,
|
|
|
|
|
)) =>
|
|
|
|
|
()
|
|
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (None) {
|
|
|
|
|
| Some([
|
|
|
|
|
someSuperLongString,
|
|
|
|
|
thisShouldBreakTheLine,
|
|
|
|
|
]) =>
|
|
|
|
|
()
|
|
|
|
|
| Some([
|
|
|
|
|
someSuperLongString,
|
|
|
|
|
...es6ListSugarLikeSyntaxWhichIsSuperLong,
|
|
|
|
|
])
|
|
|
|
|
when true === true =>
|
|
|
|
|
()
|
|
|
|
|
| Some([
|
|
|
|
|
someSuperLongString,
|
|
|
|
|
...es6ListSugarLikeSyntaxWhichIsSuperLong,
|
|
|
|
|
]) =>
|
|
|
|
|
()
|
|
|
|
|
| _ => ()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type aOrB =
|
|
|
|
|
| A(int)
|
|
|
|
|
| B(int);
|
2025-10-18 19:10:04 -07:00
|
|
|
let ((nestedAnnotation: int): int) = 0;
|
|
|
|
|
let ((A(i) | B(i)): aOrB) = A(0);
|
2023-04-30 21:41:33 +02:00
|
|
|
|
|
|
|
|
type test_foo =
|
|
|
|
|
| VariantType1
|
|
|
|
|
| VariantType2;
|
|
|
|
|
|
|
|
|
|
let branch_with_variant_and_annotation =
|
|
|
|
|
fun
|
|
|
|
|
| (VariantType1: test_foo) => true
|
|
|
|
|
| VariantType2 => false;
|
|
|
|
|
|
|
|
|
|
type intRange = {
|
|
|
|
|
from: option(string),
|
|
|
|
|
to_: option(string),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type optIntRange = option(intRange);
|
|
|
|
|
|
|
|
|
|
let optIntRangeOfIntRange =
|
|
|
|
|
fun
|
2025-07-04 22:37:35 -07:00
|
|
|
| ({ from: None, to_: None }: intRange) => (
|
2023-04-30 21:41:33 +02:00
|
|
|
None: optIntRange
|
|
|
|
|
)
|
2025-07-04 22:37:35 -07:00
|
|
|
| { from, to_ } =>
|
2024-07-28 20:15:16 -07:00
|
|
|
Some({
|
|
|
|
|
from,
|
|
|
|
|
to_,
|
|
|
|
|
});
|
2023-04-30 21:41:33 +02:00
|
|
|
|
2023-03-20 20:10:30 +01:00
|
|
|
Type-check basics
|
|
|
|
|
$ ocamlc -c -pp 'refmt --print binary' -intf-suffix .rei -impl formatted.re
|
|
|
|
|
|
|
|
|
|
Format the formatted file back
|
|
|
|
|
$ refmt --print re ./formatted.re > ./formatted_back.re
|
|
|
|
|
|
|
|
|
|
Ensure idempotency: first format and second format are the same
|
|
|
|
|
$ diff formatted.re formatted_back.re
|