From c46d22d2fe3e60964da7a0d564af0be6c4311bcb Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 13 Aug 2025 19:05:09 +0200 Subject: [PATCH 001/113] a Rascal formatter setup --- .../lang/rascal/format/Declarations.rsc | 21 ++++++++++++++++ .../lang/rascal/format/Expressions.rsc | 21 ++++++++++++++++ .../library/lang/rascal/format/Grammar.rsc | 4 ++++ .../library/lang/rascal/format/Rascal.rsc | 24 +++++++++++++++++++ .../library/lang/rascal/format/Statements.rsc | 21 ++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc create mode 100644 src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc create mode 100644 src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc create mode 100644 src/org/rascalmpl/library/lang/rascal/format/Statements.rsc diff --git a/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc b/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc new file mode 100644 index 00000000000..e1133e641c7 --- /dev/null +++ b/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc @@ -0,0 +1,21 @@ +@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. +} +module lang::rascal::format::Declarations + +extend lang::box::util::Box2Text; \ No newline at end of file diff --git a/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc b/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc new file mode 100644 index 00000000000..ed7a17f389a --- /dev/null +++ b/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc @@ -0,0 +1,21 @@ +@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. +} +module lang::rascal::format::Expressions + +extend lang::box::util::Box2Text; diff --git a/src/org/rascalmpl/library/lang/rascal/format/Grammar.rsc b/src/org/rascalmpl/library/lang/rascal/format/Grammar.rsc index d29f1ad0e30..73e27142e60 100644 --- a/src/org/rascalmpl/library/lang/rascal/format/Grammar.rsc +++ b/src/org/rascalmpl/library/lang/rascal/format/Grammar.rsc @@ -10,6 +10,10 @@ @contributor{Arnold Lankamp - Arnold.Lankamp@cwi.nl} @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; diff --git a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc new file mode 100644 index 00000000000..e4396603c7d --- /dev/null +++ b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc @@ -0,0 +1,24 @@ +@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. +} +module lang::rascal::format::Rascal + +extend lang::rascal::format::Statements; +extend lang::rascal::format::Expressions; +extend lang::rascal::format::Modules; +extend lang::rascal::format::Declarations; diff --git a/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc b/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc new file mode 100644 index 00000000000..8b7a7cd351f --- /dev/null +++ b/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc @@ -0,0 +1,21 @@ +@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. +} +module lang::rascal::format::Expressions + +extend lang::box::util::Box2Text; \ No newline at end of file From d6d886eefb3495e905690d3438161e30b5b7d556 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 12:43:36 +0200 Subject: [PATCH 002/113] make sure around empty boxes no additional spacing is added --- src/org/rascalmpl/library/lang/box/util/Box2Text.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/rascalmpl/library/lang/box/util/Box2Text.rsc b/src/org/rascalmpl/library/lang/box/util/Box2Text.rsc index 1c4a64fe043..35a2651d024 100644 --- a/src/org/rascalmpl/library/lang/box/util/Box2Text.rsc +++ b/src/org/rascalmpl/library/lang/box/util/Box2Text.rsc @@ -125,9 +125,9 @@ 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]; + return [*((U(list[Box] nested) := b) ? u(nested) : [b]) | b <- boxes, b notin {H([]),V([]),HV([]),HOV([]),I([])}]; } @synopsis{simple vertical concatenation (every list element is a line)} From 6f038c0514b7c4614b0553b76b03f95c83eab357 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 12:44:42 +0200 Subject: [PATCH 003/113] removed dead var --- src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc b/src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc index 6aff94d64e0..d705528c6bf 100644 --- a/src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc +++ b/src/org/rascalmpl/library/lang/box/util/Tree2Box.rsc @@ -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 : + case : return NULL(); // if we are given a comment node, then we can format it here for use by layoutDiff From 2fcf830cb7caef5dd1750991bcad43cbe7254222 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 12:44:54 +0200 Subject: [PATCH 004/113] progress on a rascal formatter --- .../lang/rascal/format/Declarations.rsc | 21 --- .../lang/rascal/format/Expressions.rsc | 21 --- .../library/lang/rascal/format/Rascal.rsc | 124 +++++++++++++++++- .../library/lang/rascal/format/Statements.rsc | 21 --- 4 files changed, 120 insertions(+), 67 deletions(-) delete mode 100644 src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc delete mode 100644 src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc delete mode 100644 src/org/rascalmpl/library/lang/rascal/format/Statements.rsc diff --git a/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc b/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc deleted file mode 100644 index e1133e641c7..00000000000 --- a/src/org/rascalmpl/library/lang/rascal/format/Declarations.rsc +++ /dev/null @@ -1,21 +0,0 @@ -@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. -} -module lang::rascal::format::Declarations - -extend lang::box::util::Box2Text; \ No newline at end of file diff --git a/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc b/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc deleted file mode 100644 index ed7a17f389a..00000000000 --- a/src/org/rascalmpl/library/lang/rascal/format/Expressions.rsc +++ /dev/null @@ -1,21 +0,0 @@ -@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. -} -module lang::rascal::format::Expressions - -extend lang::box::util::Box2Text; diff --git a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc index e4396603c7d..7bf3452f029 100644 --- a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc +++ b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc @@ -16,9 +16,125 @@ 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; -extend lang::rascal::format::Statements; -extend lang::rascal::format::Expressions; -extend lang::rascal::format::Modules; -extend lang::rascal::format::Declarations; +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((Visibility) ``) = NULL(); + +/* Declarations */ + +Box toBox(FunctionModifier* modifiers) = H([toBox(b) | b <- modifiers]); + +Box toBox((Signature) ` 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) ` `) + = H([toBox(modifiers), toBox(typ), H([toBox(name), toBox(parameters)], hs=0)]); + +Box toBox((FunctionDeclaration) ` ;`) + = V([ + toBox(tags), + H([toBox(vis), toBox(sig), L(";")]) + ]); + +Box toBox((FunctionDeclaration) ` = ;`) + = V([ + toBox(tags), + H([toBox(vis), toBox(sig)]), + I([H([L("="), H([toBox(exp), L(";")], hs=0)])]) + ]); + +Box toBox((FunctionDeclaration) ` = 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) ` { }`) + = 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 `) + = H([ + L("@"), L("synopsis"), L("{"), + H([L("") | l <- split("\n", ""[1..-1])]), + L("}")] + , hs=0); + +Box toBox((Tag) `@ `) + = HOV([ + H([L("@"), L("")], hs=0), + toBox(c)] + , hs=0) + when "" != "synopsis"; + +// syntax Parameters +// = \default: "(" Formals formals KeywordFormals keywordFormals ")" +// | varArgs: "(" Formals formals "..." KeywordFormals keywordFormals ")" ; + +Box toBox((Parameters) `( )`) + = H([L("("), H([toBox(formals), toBox(keywordFormals)]), L(")")], hs=0); + +/* Statements */ + +Box toBox(Statement* stmts) + = V([toBox(s) | s <- stmts]); + +Box toBox((Statement) `return ;`) + = HV([L("return"), I([H([toBox(e), L(";")], hs=0)])]); + +/* Expressions */ + +Box toBox((Expression) ` ? : `) + = HOV([ + toBox(condition), + I([H([L("?"), toBox(thenExp)])]), + I([H([L(":"), toBox(elseExp)])]) + ]); \ No newline at end of file diff --git a/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc b/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc deleted file mode 100644 index 8b7a7cd351f..00000000000 --- a/src/org/rascalmpl/library/lang/rascal/format/Statements.rsc +++ /dev/null @@ -1,21 +0,0 @@ -@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. -} -module lang::rascal::format::Expressions - -extend lang::box::util::Box2Text; \ No newline at end of file From 2c616efc0e5d19f5aab0c1cba8fbaa72c32296fe Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 15:13:14 +0200 Subject: [PATCH 005/113] removed dead doc comment --- src/org/rascalmpl/library/lang/box/syntax/Box.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/rascalmpl/library/lang/box/syntax/Box.rsc b/src/org/rascalmpl/library/lang/box/syntax/Box.rsc index 9e43f84eda1..248bd5114f2 100644 --- a/src/org/rascalmpl/library/lang/box/syntax/Box.rsc +++ b/src/org/rascalmpl/library/lang/box/syntax/Box.rsc @@ -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{ From 6adec9fc2dd272c01051aad9911c3ad5b9dea1bf Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 15:13:21 +0200 Subject: [PATCH 006/113] minor progress on rascal formatter --- .../library/lang/rascal/format/Rascal.rsc | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc index 7bf3452f029..bc36d09284e 100644 --- a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc +++ b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc @@ -56,6 +56,19 @@ list[TextEdit] formatRascalModule(start[Module] \module) Box toBox(Toplevel* toplevels) = V([toBox(t) | t <- toplevels], vs=2); +Box toBox((Module) ` module `) + = 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 ;`) + = H([L("import"), H([toBox(m), L(";")], hs=0)]); + Box toBox((Visibility) ``) = NULL(); /* Declarations */ @@ -137,4 +150,19 @@ Box toBox((Expression) ` ? : (<{Expression ","}* arguments>)`) + = H([toBox(caller), L("("), toBox(arguments), L(")")], hs=0); + +// call with kwargs +Box toBox((Expression) `(<{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 ","}* arguments> <{KeywordArgument[Expression] ","}+ kwargs>)`) + = H([toBox(caller), L("("), V([toBox(arguments),toBox(kwargs)]), L(")")], hs=0); + +Box toBox({KeywordArgument[Expression] ","}+ args) + = HV([G([toBox(a), L(",") | a <- args][..-1], gs=2, op=H, hs=0)]); From afdc030cbabf3fcbedc75b0d45ad49a6f07aa996 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 14 Aug 2025 17:01:41 +0200 Subject: [PATCH 007/113] convenience for separated lists --- src/org/rascalmpl/library/lang/box/syntax/Box.rsc | 11 ++++++++++- .../rascalmpl/library/lang/rascal/format/Rascal.rsc | 12 +++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/org/rascalmpl/library/lang/box/syntax/Box.rsc b/src/org/rascalmpl/library/lang/box/syntax/Box.rsc index 248bd5114f2..18e562990a6 100644 --- a/src/org/rascalmpl/library/lang/box/syntax/Box.rsc +++ b/src/org/rascalmpl/library/lang/box/syntax/Box.rsc @@ -80,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([]); \ No newline at end of file +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); \ No newline at end of file diff --git a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc index bc36d09284e..40038101716 100644 --- a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc +++ b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc @@ -128,13 +128,12 @@ Box toBox((Tag) `@ `) , hs=0) when "" != "synopsis"; -// syntax Parameters -// = \default: "(" Formals formals KeywordFormals keywordFormals ")" -// | varArgs: "(" Formals formals "..." KeywordFormals keywordFormals ")" ; - Box toBox((Parameters) `( )`) = H([L("("), H([toBox(formals), toBox(keywordFormals)]), L(")")], hs=0); +Box toBox((Parameters) `( ... )`) + = H([L("("), H([H([toBox(formals), L("...")], hs=0), toBox(keywordFormals)]), L(")")], hs=0); + /* Statements */ Box toBox(Statement* stmts) @@ -165,4 +164,7 @@ Box toBox((Expression) `(<{Expression ","}* arguments> <{Keyw = H([toBox(caller), L("("), V([toBox(arguments),toBox(kwargs)]), L(")")], hs=0); Box toBox({KeywordArgument[Expression] ","}+ args) - = HV([G([toBox(a), L(",") | a <- args][..-1], gs=2, op=H, hs=0)]); + = SL([toBox(a) | a <- args], L(","), hs=0); + +// this should not be necessary +// Box HV([H([])]) = U([]); \ No newline at end of file From 7085bfa7b78f1181fcf52f40ce8c3292503b9aed Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sun, 17 Aug 2025 20:54:04 +0200 Subject: [PATCH 008/113] improving the formatter --- .../library/lang/rascal/format/Rascal.rsc | 84 ++++++++++++++----- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc index 40038101716..93c0aa163ba 100644 --- a/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc +++ b/src/org/rascalmpl/library/lang/rascal/format/Rascal.rsc @@ -36,20 +36,28 @@ import String; void formatRascalFile(loc \module) { start[Module] tree = parse(#start[Module], \module); edits = formatRascalModule(tree); - executeFileSystemChanges(changed(\module, edits)); + executeFileSystemChanges(changed(edits)); } @synopsis{Format a Rascal module string} str formatRascalString(str \module) - = executeTextEdits(\module, formatRascalModule(parse(#start[Module], \module, |unknown:///|))); + = executeTextEdits(\module, formatRascalModule(parse(#start[Module], \module, |tmp:///temporary.rsc|))); @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)); +list[TextEdit] formatRascalModule(start[Module] \module) { + try { + return layoutDiff(\module, parse(#start[Module], format(toBox(\module)), \module@\loc.top)); + } + catch e:ParseError(loc place): { + writeFile(|tmp:///temporary.rsc|, format(toBox(\module))); + println("Formatted module contains a parse error here: "); + throw e; + } +} /* Modules */ @@ -99,9 +107,11 @@ Box toBox((FunctionDeclaration) ` = Box toBox((FunctionDeclaration) ` = when <{Expression ","}+ conds>;`) = V([ toBox(tags), - H([toBox(vis), toBox(sig)]), - I([H([L("="), toBox(exp)])]), - I([L("when"), V([toBox(c) | c <- conds])]) + HOV([ + H([toBox(vis), toBox(sig)]), + I([H([L("="), toBox(exp)])]) + ]), + I([H([L("when"), HOV([toBox(conds)]), L(";")])]) ]); Box toBox((FunctionDeclaration) ` { }`) @@ -114,19 +124,19 @@ Box toBox((FunctionDeclaration) ` { Box toBox(Tag* tags) = V([toBox(t) | Tag t <- tags]); -Box toBox((Tag) `@synopsis `) - = H([ - L("@"), L("synopsis"), L("{"), - H([L("") | l <- split("\n", ""[1..-1])]), - L("}")] - , hs=0); +// Box toBox((Tag) `@synopsis `) +// = H([ +// L("@"), L("synopsis"), L("{"), +// H([L("") | l <- split("\n", ""[1..-1])]), +// L("}")] +// , hs=0); -Box toBox((Tag) `@ `) - = HOV([ - H([L("@"), L("")], hs=0), - toBox(c)] - , hs=0) - when "" != "synopsis"; +// Box toBox((Tag) `@ `) +// = HOV([ +// H([L("@"), L("")], hs=0), +// toBox(c)] +// , hs=0) +// when "" != "synopsis"; Box toBox((Parameters) `( )`) = H([L("("), H([toBox(formals), toBox(keywordFormals)]), L(")")], hs=0); @@ -142,6 +152,35 @@ Box toBox(Statement* stmts) Box toBox((Statement) `return ;`) = HV([L("return"), I([H([toBox(e), L(";")], hs=0)])]); +// | @breakable ifThen: Label label "if" "(" {Expression ","}+ conditions ")" Statement!variableDeclaration!functionDeclaration thenStatement () !>> "else" +// | @breakable ifThenElse: Label label "if" "(" {Expression ","}+ conditions ")" Statement thenStatement "else" Statement!variableDeclaration!functionDeclaration elseStatement + +// if with a block statement is formatted differently then without the block +Box toBox((Statement) `