Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 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
2f1bbaa
added missing import
jurgenvinju Nov 12, 2025
d4ddf43
Merge branch 'main' into rascal-formatter
jurgenvinju Nov 27, 2025
06f3ded
Merge branch 'main' into rascal-formatter
jurgenvinju Dec 24, 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
33 changes: 27 additions & 6 deletions src/org/rascalmpl/library/List.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module List

import Exception;
import Map;

import String;

@synopsis{Concatenate a list of lists.}
@examples{
Expand Down Expand Up @@ -259,8 +259,7 @@ intercalate(", ", ["zebra", "elephant", "snake", "owl"]);
```
}
str intercalate(str sep, list[value] l) =
"<for(int i <- index(l)){><i == 0 ? "" : sep><l[i]><}>";

"<for (value e <- l) {><e><sep><}>"[..-size(sep)];

@synopsis{Intersperses a list of values with a separator.}
@examples{
Expand All @@ -272,9 +271,8 @@ intersperse(1, []);
intersperse([], [1]);
```
}
list[&T] intersperse(&T sep, list[&T] xs) =
(isEmpty(xs))? [] : ([head(xs)] | it + [sep,x] | x <- tail(xs));

list[&T] intersperse(&T sep, list[&T] xs) =
[x, sep | &T x <- xs][..-1];

@synopsis{Test whether a list is empty.}
@description{
Expand Down Expand Up @@ -655,6 +653,29 @@ tuple[list[&T],list[&T]] split(list[&T] l) {
return <take(half,l), drop(half,l)>;
}

@synopsis{Groups sublists for consecutive elements which are `similar`}
@description{
This function does not change the order of the elements. Only elements
which are similar end-up in a sub-list with more than one element. The
elements which are not similar to their siblings, end up in singleton
lists.
}
@examples{
```rascal-shell
import List;
bool bothEvenOrBothOdd(int a, int b) = (a % 2 == 0 && b % 2 == 0) || (a % 2 == 1 && b % 2 == 1);
group([1,7,3,6,2,9], bothEvenOrBothOdd);
```
}
public list[list[&T]] group(list[&T] input, bool (&T a, &T b) similar) {
lres = while ([hd, *tl] := input) {
sim = [hd, *takeWhile(tl, bool (&T a) { return similar(a, hd); })];
append sim;
input = drop(size(sim), input);
}

return lres;
}

@synopsis{Sum the elements of a list.}
@examples{
Expand Down
2 changes: 1 addition & 1 deletion src/org/rascalmpl/library/Type.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The ((subtype)) relation of Rascal has all the mathematical properties of a _fin
This is a core design principle of Rascal with the following benefits:
* Type inference has a guaranteed least or greatest solution, always. This means that constraints are always solvable in an unambigous manner.
* A _principal type_ can always be computed, which is a most precise and unique solution of a type inference problem. Without the lattice, solution candidates could become incomparable and thus ambiguous. Without
this principal type property, type inference is predictable for programmers.
this principal type property, type inference is unpredictable for programmers.
* Solving type inference constraints can be implemented efficiently. The algorithm, based on ((lub)) and ((glb)), makes progress _deterministically_ and does not require backtracking
to find better solutions. Since the lattice is not very deep, fixed-point solutions are always found quickly.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ void executeFileSystemChange(changed(loc file, list[TextEdit] edits)) {
}

str executeTextEdits(str content, list[TextEdit] edits) {
assert isSorted(edits, less=bool (TextEdit e1, TextEdit e2) {
return e1.range.offset < e2.range.offset;
});
// assert isSorted(edits, less=bool (TextEdit e1, TextEdit e2) {
// return e1.range.offset < e2.range.offset;
// });

for (replace(loc range, str repl) <- reverse(edits)) {
content = "<content[..range.offset]><repl><content[range.offset+range.length..]>";
}
int cursor = 0;

return content;
// linear-time streamed reconstruction of the entire text
return "<for (replace(loc range, str repl) <- edits) {><content[cursor..range.offset]><repl><
cursor = range.offset + range.length;}><content[cursor..]>";
}
79 changes: 58 additions & 21 deletions src/org/rascalmpl/library/analysis/diff/edits/HiFiLayoutDiff.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ module analysis::diff::edits::HiFiLayoutDiff
extend analysis::diff::edits::HiFiTreeDiff;
import ParseTree; // this should not be necessary because imported by HiFiTreeDiff
import String; // this should not be be necessary because imported by HiFiTreeDiff
import lang::rascal::grammar::definition::Characters;
import IO;

@synopsis{Normalization choices for case-insensitive literals.}
data CaseInsensitivity
Expand Down Expand Up @@ -106,22 +108,31 @@ list[TextEdit] layoutDiff(Tree original, Tree formatted, bool recoverComments =
default list[TextEdit] rec(
Tree t:appl(Production p, list[Tree] argsA),
appl(p /* must be the same by the above assert */, list[Tree] argsB))
= [*rec(a, b) | <a, b> <- zip2(argsA, argsB)];
= [*rec(argsA[i], argsB[i]) | i <- [0..size(argsA)]];

// first add required locations to layout nodes
original = reposition(original, markLit=true, markLayout=true, markSubLayout=true);
// TODO: check if indeed repositioning is never needed
// original = reposition(original, markLit=true, markLayout=true, markSubLayout=true);

return rec(original, formatted);
}

private Symbol newlineClass = \char-class([range(10,10)]);

@synopsis{Make sure the new layout still contains all the source code comments of the original layout}
@description{
This algorithm uses the @category("Comments") tag to detect source code comments inside layout substrings. If the original
This algorithm uses the `@category(/[cC]omments/)` tag to detect source code comments inside layout substrings. If the original
layout contains comments, we re-introduce the comments at the expected level of indentation. New comments present in the
replacement are kept and will overwrite any original comments.

This trick is complicated by the syntax of multiline comments and single line comments that have
to end with a newline.
There are corner cases with respect to the original comments:
* the single line comment that does not end with a newline itself, yet it must always end with a newline after it.
* multiple single line comments after each other

Then there are corner cases with respect to the replacement whitespace:
* the last line of the replacement whitespace is special. This is the indentation to use for all comments.
* but there could be no newlines in the replacement whitespace; and still there is a single line comment to be included.
Now we need to infer an indentation level for what follows the comment from "thin air".
}
@benefits{
* if comments are kepts and formatted by tools like Tree2Box, then this algorithm does not overwrite these.
Expand All @@ -132,7 +143,14 @@ to end with a newline.
* if comments are not marked with `@category("Comment")` in the original grammar, then this algorithm recovers nothing.
}
private str learnComments(Tree original, Tree replacement) {
originalComments = ["<c>" | /c:appl(prod(_,_,{\tag("category"(/^[Cc]omment$/)), *_}), _) := original];
bool mustEndWithNewline(lit("\n")) = true;
bool mustEndWithNewline(conditional(Symbol s, _)) = mustEndWithNewline(s);
// if a comment can not contain newline characters, but everything else, then it must be followed by one:
bool mustEndWithNewline(\iter(Symbol cc:\char-class(_))) = intersection(cc, newlineClass) != newlineClass;
bool mustEndWithNewline(\iter-star(Symbol cc:\char-class(_))) = intersection(cc, newlineClass) != newlineClass;
default bool mustEndWithNewline(_) = false;

originalComments = [<s, s[-1] == "\n" || mustEndWithNewline(lastSym)> | /c:appl(prod(_,[*_,Symbol lastSym],{\tag("category"(/^[Cc]omment$/)), *_}), _) := original, str s := "<c>"];

if (originalComments == []) {
// if the original did not contain comments, stick with the replacements
Expand All @@ -146,23 +164,42 @@ private str learnComments(Tree original, Tree replacement) {
return "<replacement>";
}

// At this point, we know that: (a) comments are not present in the replacement and (b) they used to be there in the original.
// So the old comments are going to be the new output. however, we want to learn indentation from the replacement.
// At this point, we know that:
// (a) comments are not present in the replacement and
// (b) they used to be there in the original.
// So the old comments are going to be copied to the new output.
// But, we want to indent them using the style of the replacement.

// The last line of the replacement string typically has the indentation for the construct that follows:
// | // a comment
// | if (true) {
// ^^^^
// newIndent
//
// However, if the replacement string is on a single line, then we don't have the indentation
// for the string on the next line readily available. In this case we indent the next line
// to the start column of the replacement layout, as a proxy.

str replString = "<replacement>";
str newIndent = split("\n", replString)[-1] ? "";

// Drop the last newline of single-line comments, because we don't want two newlines in the output for every comment:
str dropEndNl(str line:/^.*\n$/) = (line[..-1]);
default str dropEndNl(str line) = line;
if (/\n/ !:= replString) {
// no newline in the repl string, so no indentation available for what follows the comment...
newIndent = "<for (_ <- [0..replacement@\loc.begin.column]) {> <}>";
}

// the first line of the replacement ,is the indentation to use.
str replString = "<replacement>";
str replacementIndent = /^\n+$/ !:= replString
? split("\n", replString)[0]
: "";

// trimming each line makes sure we forget about the original indentation, and drop accidental spaces after comment lines
return replString + indent(replacementIndent,
"<for (c <- originalComments, str line <- split("\n", dropEndNl(c))) {><indent(replacementIndent, trim(line), indentFirstLine=true)>
'<}>"[..-1], indentFirstLine=false) + replString;
// we always place sequential comments vertically, because we don't know if we are dealing
// we a single line comment that has to end with newline by follow restriction or by a literal "\n".
// TODO: a deeper analysis of the comment rule that's in use could also be used to discover this.
str trimmedOriginals = "<for (<c, newLine> <- originalComments) {><trim(c)><if (newLine) {>
'<}><}>";

// we wrap the comment with the formatted whitespace to assure the proper indentation
// of its first line, and the proper indentation of what comes after this layout node
return replString
+ indent(newIndent, trimmedOriginals, indentFirstLine=false)
+ newIndent
;
}

private Symbol delabel(label(_, Symbol t)) = t;
Expand Down
29 changes: 11 additions & 18 deletions src/org/rascalmpl/library/analysis/formalconcepts/CXTIO.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,26 @@
http://www.eclipse.org/legal/epl-v10.html
}
module analysis::formalconcepts::CXTIO

import IO;
import String;
import List;
import Set;
import analysis::formalconcepts::FCA;

@synopsis{Read object attribute in .cxt format.}
public FormalContext[str, str] readCxt(loc input) {
@synopsis{Read object attribute in .cxt format.}
public FormalContext[str, str] readCxt(loc input) {
list[str] d = readFileLines(input);
int nRows = toInt(d[2]);
int nCols = toInt(d[3]);
int theStart = 5+nRows+nCols;
list[str] e = tail(d, size(d)-theStart);
int theStart = 5 + nRows + nCols;
list[str] e = tail(d, size(d) - theStart);
int idx = 5;
map [str, set[str]] vb = ();
map[str, set[str]] vb = ();
for (str f <- e) {
set[str] b = {d[5+nRows+i]|int i<-[0, 1..size(f)], charAt(f,i)==88};
vb[d[idx]] = b;
idx = idx+1;
}
return toFormalContext(vb);
set[str] b = {d[5 + nRows + i]| int i <- [0, 1..size(f)], charAt(f, i) == 88};
vb[d[idx]] = b;
idx = idx + 1;
}

loc input = |file:///ufs/bertl/cxt/digits.cxt|;

public void main() {
FormalContext[str, str] d = readCxt(input);
ConceptLattice[str, str] e = fca(d);
println(toDotString(e));
}
return toFormalContext(vb);
}
Loading
Loading