Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
c46d22d
a Rascal formatter setup
jurgenvinju Aug 13, 2025
d6d886e
make sure around empty boxes no additional spacing is added
jurgenvinju Aug 14, 2025
6f038c0
removed dead var
jurgenvinju Aug 14, 2025
2fcf830
progress on a rascal formatter
jurgenvinju Aug 14, 2025
3c20142
Merge branch 'hifi-tree-diff' into rascal-formatter
jurgenvinju Aug 14, 2025
b36df06
Merge branch 'main' into rascal-formatter
jurgenvinju Aug 14, 2025
f196ba9
Merge branch 'main' into rascal-formatter
jurgenvinju Aug 14, 2025
2c616ef
removed dead doc comment
jurgenvinju Aug 14, 2025
6adec9f
minor progress on rascal formatter
jurgenvinju Aug 14, 2025
afdc030
convenience for separated lists
jurgenvinju Aug 14, 2025
7085bfa
improving the formatter
jurgenvinju Aug 17, 2025
73356c3
Merge branch 'minor-fixes-for-formatters' into rascal-formatter
jurgenvinju Aug 17, 2025
d43ecf5
more additions to the formatter
jurgenvinju Aug 17, 2025
962b521
renamed test to a unique name
jurgenvinju Aug 18, 2025
bc33cb6
added lots of new formatting rules for Rascal
jurgenvinju Aug 18, 2025
bd5d40e
some deforestation makes the algorithm much faster
jurgenvinju Aug 18, 2025
a0cae59
added missing group function (ported from Set)
jurgenvinju Aug 18, 2025
5610e68
factored expensive constant to private global
jurgenvinju Aug 18, 2025
b5ca046
more constructs are formatted now and we group statements if they wer…
jurgenvinju Aug 18, 2025
be576a1
added lots of formatting rules
jurgenvinju Aug 18, 2025
2b7f7c3
prevent generation of empty literals, replace by NULL where neceessary
jurgenvinju Aug 18, 2025
7709572
fixed an issue and added some debug code
jurgenvinju Aug 19, 2025
9279533
added assert for empty literals
jurgenvinju Aug 21, 2025
2958ef0
Merge branch 'main' into rascal-formatter
jurgenvinju Aug 21, 2025
0993c59
minor fixes
jurgenvinju Aug 21, 2025
0a1d7ea
fixed unused warning
jurgenvinju Aug 21, 2025
850acdd
fixed some unused imports and removed unused function
jurgenvinju Aug 21, 2025
16dc9b7
replaced the complex and broken GG feature of Box2Text by an eager re…
jurgenvinju Aug 21, 2025
ff20d58
continued with adding more formatting rules
jurgenvinju Aug 21, 2025
bd75140
added rs for rowSeparator feature to Arrays, for when we want to disp…
jurgenvinju Aug 23, 2025
84213b4
tables fixed for the occurence of nested splices. This involves infer…
jurgenvinju Aug 25, 2025
a23e703
separated lists do not have space by default between the previous ele…
jurgenvinju Aug 25, 2025
5d08cf4
removed unused pattern variable
jurgenvinju Aug 25, 2025
dd6fc23
added more formatting rules. needed fixes in Box2Text
jurgenvinju Aug 25, 2025
43e23fe
streamlining
jurgenvinju Aug 25, 2025
e6c0b45
some progress with string termplate formatting
jurgenvinju Aug 25, 2025
a88b978
added todo
jurgenvinju Aug 26, 2025
95dc0f4
turned prefix of \' continuation into a layout node to make sure layo…
jurgenvinju Aug 26, 2025
c4badbe
re-introduced striprec which has disappeared from Type during a cleanup
jurgenvinju Aug 26, 2025
eb94796
gave constructor names to StringLiteral alternatives for easy API
jurgenvinju Aug 26, 2025
ace1460
added plausably correct formatting of string templates with left-alig…
jurgenvinju Aug 27, 2025
5ccca1d
slices
jurgenvinju Aug 27, 2025
d10dc4a
Merge branch 'main' into rascal-formatter
jurgenvinju Aug 27, 2025
d68abb3
better callOrTree indentation
jurgenvinju Aug 28, 2025
e0d7d25
Merge branch 'main' into rascal-formatter
jurgenvinju Oct 4, 2025
9786b06
inlined G semantics again to be able to deal with nested U boxes prop…
jurgenvinju Oct 6, 2025
75e0191
started formatting syntax definitions
jurgenvinju Oct 6, 2025
2679cea
fixes in G boxes with H contexts
jurgenvinju Oct 6, 2025
ba3128c
added todo
jurgenvinju Oct 6, 2025
a2da436
added and used toClusterBox function for retaining vertical clusters …
jurgenvinju Oct 7, 2025
e95a888
add clustering to function statements
jurgenvinju Oct 7, 2025
fc257f3
AG is now also inlined and lazily evaluated to allow for U and G grou…
jurgenvinju Oct 7, 2025
98dc007
improved relation tables
jurgenvinju Oct 7, 2025
791d6b9
added debUG function for debugging G U and AG groups
jurgenvinju Oct 7, 2025
eca370e
fixed Main again
jurgenvinju Oct 7, 2025
f2af14d
added more constructs to format
jurgenvinju Oct 7, 2025
7b6dd34
all binary expressions are now lists by tree2box
jurgenvinju Oct 8, 2025
52823cd
added backward grouping
jurgenvinju Oct 8, 2025
3cfe450
added backward option to G groups
jurgenvinju Oct 8, 2025
46736f0
added backwards grouping to debUG
jurgenvinju Oct 8, 2025
6f5658f
single line comments that have to end with a newline now end with a n…
jurgenvinju Oct 8, 2025
bf88448
expression elements wrapped in HV because they can become lists now d…
jurgenvinju Oct 8, 2025
f2527b3
single line comments fixed
jurgenvinju Oct 8, 2025
2070d2c
incremental additions to the Rascal formatter'
jurgenvinju Oct 8, 2025
e3e44aa
incremental additions to the Rascal formatter'
jurgenvinju Oct 8, 2025
a56918e
better empty sets
jurgenvinju Oct 8, 2025
a45661d
fixed tricky issues with single line comments in layoutDiff
jurgenvinju Oct 9, 2025
8cfe4c4
much better solution for single line comments that end up formatted i…
jurgenvinju Oct 9, 2025
f7e2f18
finetuning
jurgenvinju Oct 9, 2025
dcb6934
radical optimization due to caching symbol for newline character class
jurgenvinju Oct 9, 2025
280edda
conditional debug prints get special treatment
jurgenvinju Oct 9, 2025
d3565ca
added asserts to formatter
jurgenvinju Oct 9, 2025
c5b68b9
less leading space for indented data declaration variants
jurgenvinju Oct 10, 2025
082ab36
much better indentation for assignments and declarations with initial…
jurgenvinju Oct 10, 2025
d2ea2c5
fix for non-single-line comments that do not need forced newlines, bu…
jurgenvinju Oct 10, 2025
21531a7
removed test comments
jurgenvinju Oct 10, 2025
97393ec
inlined the hot width function (alias for string size)
jurgenvinju Oct 10, 2025
f153c9c
factored constant to a global for efficiency sake
jurgenvinju Oct 10, 2025
e5d3399
introduced varargs versions of all boxes and renamed the respective b…
jurgenvinju Oct 11, 2025
f72ba58
lot of finetuning and removing little issues
jurgenvinju Oct 12, 2025
13a3474
removed all superfluous brackets using the cleanMeUp function
jurgenvinju Oct 12, 2025
f8f6c47
fixed issues caused by rough cleanup
jurgenvinju Oct 12, 2025
1d70edf
more fixes
jurgenvinju Oct 12, 2025
2303b89
fixed multi-variable declarations
jurgenvinju Oct 13, 2025
ef55725
fixed additional statements in for loops inside string templates
jurgenvinju Oct 13, 2025
e5d03b5
fixed return of binary expressions
jurgenvinju Oct 13, 2025
883a798
added some more sanity checks, also for documentation purposes
jurgenvinju Oct 14, 2025
6427de1
removed the superfluous brackets from the Box2Text test cases, for do…
jurgenvinju Oct 14, 2025
54641d8
test renamings
jurgenvinju Oct 14, 2025
34e3cc2
removed more superfluous brackets
jurgenvinju Oct 14, 2025
5214fd3
Merge branch 'main' into rascal-formatter
jurgenvinju Oct 16, 2025
5e2b8f0
moving ahead with testing all files in the library automatically
jurgenvinju Oct 17, 2025
a7ad1a3
some bugs
jurgenvinju Oct 17, 2025
849a60a
fixed an 11-year-old search/replace bug in the C grammar
jurgenvinju Oct 19, 2025
bf82621
still fixing fall out of changin the default formatter for binary exp…
jurgenvinju Oct 19, 2025
f2b50f1
checker found another undeclared constructor
jurgenvinju Oct 19, 2025
a88df2c
restored relations-as-tables
jurgenvinju Oct 19, 2025
892e0de
single expressions end up in the first cell
jurgenvinju Oct 19, 2025
c648a6a
incremental improvements
jurgenvinju Oct 20, 2025
6d1060f
while and do-while in templates forgotten
jurgenvinju Oct 20, 2025
a3af4f0
formatted two files from the standard library
jurgenvinju Oct 27, 2025
e8893e7
Merge remote-tracking branch 'origin/main' into rascal-formatter
jurgenvinju Oct 27, 2025
ca2995f
spacing in signatures fixed
jurgenvinju Oct 27, 2025
2c215b1
optimized executeTextEdits from quadratic to linear algorithm
jurgenvinju Oct 27, 2025
727a604
fixed issues with reals that start with a dot
jurgenvinju Oct 27, 2025
c9f5175
Merge branch 'main' into rascal-formatter
jurgenvinju Nov 5, 2025
6ee64b6
fixed if-then-else formatter
jurgenvinju Nov 5, 2025
4f979f0
fixed rewrite-rule semi-colon attachment
jurgenvinju Nov 5, 2025
ead9233
fixed common keyword param spacing
jurgenvinju Nov 5, 2025
0af35cd
fixed default bracket syntax
jurgenvinju Nov 5, 2025
d37693f
not flatten the non-associative comparison operators
jurgenvinju Nov 5, 2025
b5cf64e
fixing details
jurgenvinju Nov 6, 2025
bf0bb8d
improved lists and sets of tuples
jurgenvinju Nov 6, 2025
e474a60
improved lists and sets of tuples also for patterns
jurgenvinju Nov 6, 2025
2dc71de
added pattern-replacement-with-when case
jurgenvinju Nov 6, 2025
cca1c89
rewrote core box constructors from _X to X_ to avoid issue with type …
jurgenvinju Nov 6, 2025
f320d0e
made intercalate and intersperse faster
jurgenvinju Nov 6, 2025
e0c8a3e
fixed typo in docs
jurgenvinju Nov 6, 2025
dcc531d
fixed function parameter layout
jurgenvinju Nov 6, 2025
1510755
radical optimization for large table layouts
jurgenvinju Nov 6, 2025
0fc3f9c
fixed #2512
jurgenvinju Nov 6, 2025
64e93b9
debugging
jurgenvinju Nov 6, 2025
a8399cb
variable becomes formatted
jurgenvinju Nov 6, 2025
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
12 changes: 10 additions & 2 deletions src/org/rascalmpl/library/lang/box/syntax/Box.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ module lang::box::\syntax::Box
* `L` produces A literal word. This word may only contain printable characters and no spaces; this is a required property that the formatting algorithm depends on for correctness.
* `U` splices its contents in the surrounding box, for automatic flattening of overly nested structures in syntax trees.
* `G` is an additional group-by feature that reduces tot the above core features
* `SL` is a convenience box for separated syntax lists based on `G`
* `NULL()` is the group that will dissappear from its context, useful for skipping content. It is based on the `U` box.
}
@benefits{
Expand Down Expand Up @@ -81,4 +80,13 @@ algorithm starts counting boxes and widths.
* Do not use `NULL` for empty Row cells, unless you do want your cells aligned to the left and filled up to the right with empty H boxes.
* NULL will be formatted as `H([])` if it's the outermost Box.
}
Box NULL() = U([]);
Box NULL() = U([]);

@synopsis{Convenience box for adding separators to an existing box list}
@description{
Each element is wrapped by the `op` operator together with the next separator.
The resulting list is wrapped by a G box, of which the elements will be spliced
into their context.
}
Box SL(list[Box] boxes, Box sep, Box(list[Box]) op = H, int hs=1, int vs=0, int is=4)
= G([b, sep | b <- boxes][..-1], op=op, hs=hs, vs=vs, is=is);
2 changes: 1 addition & 1 deletion src/org/rascalmpl/library/lang/box/util/Box2Text.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ data Options = options(
int wrapAfter = 70
);

@synopsis{Quickly splice in any nested U boxes}
@synopsis{Quickly splice in any nested U boxes, and empty H, V, HV, I or HOV boxes}
list[Box] u(list[Box] boxes) {
return [*((U(list[Box] nested) := b) ? u(nested) : [b]) | b <- boxes, !isDegenerate(b)];
}
Expand Down
2 changes: 1 addition & 1 deletion src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ default Box toBox(t:appl(Production p, list[Tree] args), FO opts = fo()) {
// We remove all layout node positions to make the number of children predictable
// Comments can be recovered by `layoutDiff`. By not recursing into layout
// positions `toBox` becomes more than twice as fast.
case <prod(layouts(_), _, _), list[Tree] content>:
case <prod(layouts(_), _, _), list[Tree] _>:
return NULL();

// if we are given a comment node, then we can format it here for use by layoutDiff
Expand Down
4 changes: 4 additions & 0 deletions src/org/rascalmpl/library/lang/rascal/format/Grammar.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
@contributor{Arnold Lankamp - [email protected]}
@synopsis{Convert the Rascal internal grammar representation format (Grammar) to
a syntax definition in Rascal source code.}
@pitfalls{
This function does not use advanced formatting feature because it is a part of
components early in Rascal's bootstrapping and standard library construction cycle.
}
module lang::rascal::format::Grammar

import ParseTree;
Expand Down
170 changes: 170 additions & 0 deletions src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
@license{
Copyright (c) 2022, NWO-I Centrum Wiskunde & Informatica (CWI)
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
@synopsis{Composes a default formatter for Rascal modules}
@description{
This module composes and describes a "standard" formatting style for Rascal.
There could be other styles of course. Other styles can be build by
writing different `toBox` rules.
}
@bootstrapParser
module lang::rascal::format::Rascal

// by extending these modules we compose a `toBox` function
// which handles all relevant constructs of Rascal
extend lang::box::util::Tree2Box;
extend lang::rascal::\syntax::Rascal;

import ParseTree;
import analysis::diff::edits::ExecuteTextEdits;
import analysis::diff::edits::HiFiLayoutDiff;
import analysis::diff::edits::TextEdits;
import lang::box::\syntax::Box;
import lang::box::util::Box2Text;
import String;

@synopsis{Format an entire Rascal file, in-place.}
void formatRascalFile(loc \module) {
start[Module] tree = parse(#start[Module], \module);
edits = formatRascalModule(tree);
executeFileSystemChanges(changed(\module, edits));
}

@synopsis{Format a Rascal module string}
str formatRascalString(str \module)
= executeTextEdits(\module, formatRascalModule(parse(#start[Module], \module, |unknown:///|)));

@synopsis{Top-level work-horse for formatting Rascal modules}
@benefits{
* retains source code comments
* uses Box for adaptive nested formatting
}
list[TextEdit] formatRascalModule(start[Module] \module)
= layoutDiff(\module, parse(#start[Module], format(toBox(\module)), \module@\loc.top));


/* Modules */

Box toBox(Toplevel* toplevels) = V([toBox(t) | t <- toplevels], vs=2);

Box toBox((Module) `<Tags tags> module <QualifiedName name> <Import* imports> <Body body>`)
= V([
toBox(tags),
H([L("module"), toBox(name)]),
toBox(imports),
toBox(body)
], vs=1);

Box toBox(Import* imports) = V([toBox(i) | i <- imports]);

Box toBox((Import) `import <ImportedModule m> ;`)
= H([L("import"), H([toBox(m), L(";")], hs=0)]);

Box toBox((Visibility) ``) = NULL();

/* Declarations */

Box toBox(FunctionModifier* modifiers) = H([toBox(b) | b <- modifiers]);

Box toBox((Signature) `<FunctionModifiers modifiers> <Type typ> <Name name> <Parameters parameters> throws <{Type ","}+ exs>`)
= HOV([
H([toBox(modifiers), toBox(typ), H([toBox(name), toBox(parameters)], hs=0)]),
H([L("throws"), HV([toBox(e) | e <- exs])])], hs=1);

Box toBox((Signature) `<FunctionModifiers modifiers> <Type typ> <Name name> <Parameters parameters>`)
= H([toBox(modifiers), toBox(typ), H([toBox(name), toBox(parameters)], hs=0)]);

Box toBox((FunctionDeclaration) `<Tags tags> <Visibility vis> <Signature sig> ;`)
= V([
toBox(tags),
H([toBox(vis), toBox(sig), L(";")])
]);

Box toBox((FunctionDeclaration) `<Tags tags> <Visibility vis> <Signature sig> = <Expression exp>;`)
= V([
toBox(tags),
H([toBox(vis), toBox(sig)]),
I([H([L("="), H([toBox(exp), L(";")], hs=0)])])
]);

Box toBox((FunctionDeclaration) `<Tags tags> <Visibility vis> <Signature sig> = <Expression exp> when <{Expression ","}+ conds>;`)
= V([
toBox(tags),
H([toBox(vis), toBox(sig)]),
I([H([L("="), toBox(exp)])]),
I([L("when"), V([toBox(c) | c <- conds])])
]);

Box toBox((FunctionDeclaration) `<Tags tags> <Visibility vis> <Signature sig> { <Statement* stats> }`)
= V([
toBox(tags),
H([toBox(vis), toBox(sig), L("{")]),
I([toBox(stats)]),
L("}")
]);

Box toBox(Tag* tags) = V([toBox(t) | Tag t <- tags]);

Box toBox((Tag) `@synopsis <TagString c>`)
= H([
L("@"), L("synopsis"), L("{"),
H([L("<l>") | l <- split("\n", "<c>"[1..-1])]),
L("}")]
, hs=0);

Box toBox((Tag) `@<Name n> <TagString c>`)
= HOV([
H([L("@"), L("<n>")], hs=0),
toBox(c)]
, hs=0)
when "<n>" != "synopsis";

Box toBox((Parameters) `( <Formals formals> <KeywordFormals keywordFormals>)`)
= H([L("("), H([toBox(formals), toBox(keywordFormals)]), L(")")], hs=0);

Box toBox((Parameters) `( <Formals formals> ... <KeywordFormals keywordFormals>)`)
= H([L("("), H([H([toBox(formals), L("...")], hs=0), toBox(keywordFormals)]), L(")")], hs=0);

/* Statements */

Box toBox(Statement* stmts)
= V([toBox(s) | s <- stmts]);

Box toBox((Statement) `return <Expression e>;`)
= HV([L("return"), I([H([toBox(e), L(";")], hs=0)])]);

/* Expressions */

Box toBox((Expression) `<Expression condition> ? <Expression thenExp> : <Expression elseExp>`)
= HOV([
toBox(condition),
I([H([L("?"), toBox(thenExp)])]),
I([H([L(":"), toBox(elseExp)])])
]);

// call without kwargs
Box toBox((Expression) `<Expression caller>(<{Expression ","}* arguments>)`)
= H([toBox(caller), L("("), toBox(arguments), L(")")], hs=0);

// call with kwargs
Box toBox((Expression) `<Expression caller>(<{Expression ","}* arguments>, <{KeywordArgument[Expression] ","}+ kwargs>)`)
= H([toBox(caller), L("("), toBox(arguments), H([L(","), toBox(kwargs)], hs=1), L(")")], hs=0);

// call with kwargs no-comma
Box toBox((Expression) `<Expression caller>(<{Expression ","}* arguments> <{KeywordArgument[Expression] ","}+ kwargs>)`)
= H([toBox(caller), L("("), V([toBox(arguments),toBox(kwargs)]), L(")")], hs=0);

Box toBox({KeywordArgument[Expression] ","}+ args)
= SL([toBox(a) | a <- args], L(","), hs=0);

// this should not be necessary
// Box HV([H([])]) = U([]);
Loading