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

feat(grainfmt)!: Implement new formatter #1976

Merged
merged 48 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
2aea14d
chore(compiler): Add list AST node
ospencer Feb 11, 2023
0c4b1af
feat(grainfmt)!: Implement new formatter
ospencer Jan 21, 2024
83dcea1
Format stdlib
ospencer Jan 23, 2024
ce52938
Organizational PR feedback
ospencer Jan 23, 2024
0d05c90
Rework array brackets and print comments in empty arrays and lists
ospencer Jan 23, 2024
5ccbdd1
try faster bytes moving for windows
ospencer Jan 23, 2024
b0b143a
add issue reference
ospencer Jan 23, 2024
f0d1c06
Always have only 1 hardline between a doc comment and what it's comme…
ospencer Jan 25, 2024
5e95cdb
Try flushing stdout for windows
ospencer Jan 25, 2024
6201480
Merge branch 'main' into oscar/formatter
ospencer Jan 25, 2024
912bdc7
try exiting explicitly
ospencer Jan 26, 2024
9358b02
check timeout
ospencer Jan 26, 2024
f4a7fd9
use In_channel
ospencer Jan 26, 2024
5abe781
30 seconds
ospencer Jan 26, 2024
2d4179f
Allow formatter to write to stdout directly
ospencer Jan 27, 2024
b249ed2
Merge branch 'main' into oscar/formatter
ospencer Jan 27, 2024
eddad19
Merge branch 'main' into oscar/formatter
ospencer Jan 27, 2024
3be9dac
read stdout and stderr before waiting on the process
ospencer Jan 27, 2024
7758411
fix single branch if breaking
ospencer Feb 2, 2024
455e8e2
Merge branch 'main' into oscar/formatter
ospencer Feb 2, 2024
07a45da
Add flush_write_queue utility
ospencer Feb 4, 2024
99d549e
Make concat_map ~lead and ~trail parameters required
ospencer Feb 4, 2024
02b0633
Handle comments for punnable patterns
ospencer Feb 4, 2024
2ddb466
Simplify print_lambda_argument
ospencer Feb 4, 2024
450d116
Simplify print_ident_string
ospencer Feb 4, 2024
b67f21d
Pass print_attribute function directly
ospencer Feb 4, 2024
8f1526d
Nest print_application_argument calls
ospencer Feb 4, 2024
ac1d1d6
Don't indent binops more than necessary in more places
ospencer Feb 4, 2024
42ae64e
Remove fixed issue reference
ospencer Feb 4, 2024
e12046a
Add comment about Windows stuff
ospencer Feb 4, 2024
01bb054
fix off-by-one formatting
ospencer Feb 4, 2024
06d8623
add empty module formatter test
ospencer Feb 7, 2024
144d58f
Update non-pun comment
ospencer Feb 7, 2024
433a474
change type definition formatting to work like let bindings
ospencer Feb 7, 2024
915cdf2
Add example of how comments can make a block break
ospencer Feb 7, 2024
5873f39
Make comments stay on the opening of a brace
ospencer Feb 7, 2024
5fb6f39
fix windows empty module test
ospencer Feb 7, 2024
49ebddc
Rework match branch printing to ensure line length
ospencer Feb 11, 2024
355d53d
simplify indent api
ospencer Feb 11, 2024
5e7e895
rework parens construct
ospencer Feb 11, 2024
4ab9b02
rework braces construct
ospencer Feb 11, 2024
33ccc22
remove block_braces
ospencer Feb 11, 2024
45f672f
rework array_brackets
ospencer Feb 11, 2024
1be48e6
rework list_brackets
ospencer Feb 12, 2024
065ed19
rework angle_brackets
ospencer Feb 12, 2024
febccc3
Merge remote-tracking branch 'origin/main' into oscar/formatter
ospencer Feb 19, 2024
3811390
Print constants when we are able (#2009)
phated Feb 19, 2024
7107494
Implement record pattern for formatter (#2007)
phated Feb 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions compiler/grainformat/grainformat.re
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ let get_program_string = filename => {
let compile_parsed = filename => {
let filename = Filepath.to_string(filename);
let program_str = get_program_string(filename);
switch (Format.parse_source(program_str)) {
switch (Fmt.parse_source(program_str)) {
| Error(ParseError(exn)) =>
let bt =
if (Printexc.backtrace_status()) {
Expand Down Expand Up @@ -59,25 +59,30 @@ let format_code =
~original_source: array(string),
program: Parsetree.parsed_program,
) => {
let formatted_code =
Grain_formatting.Format.format_ast(~original_source, ~eol, program);

let buf = Buffer.create(0);
Buffer.add_string(buf, formatted_code);

let contents = Buffer.to_bytes(buf);
switch (output) {
| Some(outfile) =>
let outfile = Filepath.to_string(outfile);
// TODO: This crashes if you do something weird like `-o stdout/map.gr/foo`
// because `foo` doesn't exist so it tries to mkdir it and raises
Fs_access.ensure_parent_directory_exists(outfile);
let oc = Fs_access.open_file_for_writing(outfile);
output_bytes(oc, contents);
set_binary_mode_out(oc, true);
Grain_formatting.Fmt.format(
~write=output_string(oc),
~original_source,
~eol,
program,
);
close_out(oc);
| None =>
set_binary_mode_out(stdout, true);
print_bytes(contents);
Grain_formatting.Fmt.format(
~write=print_string,
~original_source,
~eol,
program,
);
flush(stdout);
};
};

Expand Down
72 changes: 72 additions & 0 deletions compiler/src/diagnostics/commenttree.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
open Grain_parsing;

// This structure isn't a tree at all, but we use a binary search algorithm to
// efficiently find comments, which is tree-like in spirit.

type t = {
comments: array(Parsetree.comment),
line_map: Hashtbl.t(int, Parsetree.comment),
};

let loc = cmt => {
switch (cmt) {
| Parsetree.Doc({cmt_loc})
| Block({cmt_loc})
| Line({cmt_loc})
| Shebang({cmt_loc}) => cmt_loc
};
};

let from_comments = x => {
// The array allows us to do a binary search for comments within a range.
let comments = Array.of_list(x);
// This map stores the last comment on a line, allowing us to quickly check
// for formatter-ignore comments.
let line_map = Hashtbl.create(Array.length(comments));
List.iter(
comment =>
Hashtbl.add(line_map, loc(comment).loc_start.pos_lnum, comment),
x,
);
{comments, line_map};
};

let rec find_start_index = (array, point, ans, left, right) =>
if (left <= right) {
let middle = (left + right) / 2;
if (loc(array[middle]).loc_start.pos_cnum >= point) {
find_start_index(array, point, Some(middle), left, middle - 1);
} else {
find_start_index(array, point, ans, middle + 1, right);
};
} else {
ans;
};

let rec collect_range = (array, start, stop) =>
if (start == Array.length(array)) {
[];
} else {
let elem = array[start];
if (loc(elem).loc_end.pos_cnum <= stop) {
[elem, ...collect_range(array, start + 1, stop)];
} else {
[];
};
};

let query =
(
tree,
{Location.loc_start: {pos_cnum: start}, loc_end: {pos_cnum: finish}},
) => {
let array = tree.comments;
let start_index =
find_start_index(array, start, None, 0, Array.length(array) - 1);
switch (start_index) {
| None => []
| Some(start_index) => collect_range(array, start_index, finish)
};
};

let query_line = (tree, line) => Hashtbl.find_opt(tree.line_map, line);
8 changes: 8 additions & 0 deletions compiler/src/diagnostics/commenttree.rei
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
open Grain_parsing;

type t;

let from_comments: list(Parsetree.comment) => t;

let query: (t, Location.t) => list(Parsetree.comment);
let query_line: (t, int) => option(Parsetree.comment);
Loading
Loading