Skip to content

Commit

Permalink
feat(language): annotation formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
kris7t committed Dec 12, 2024
1 parent e549852 commit 6222ddf
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@

@SuppressWarnings("UnstableApiUsage")
public class ProblemFormatter extends AbstractJavaFormatter {
@Override
public void format(Object child, IFormattableDocument document) {
if (child instanceof AnnotatedElement annotatedElement) {
var annotationContainer = annotatedElement.getAnnotations();
if (annotationContainer != null) {
document.format(annotationContainer);
}
}
super.format(child, document);
}

protected void format(Problem problem, IFormattableDocument doc) {
doc.prepend(problem, this::noSpace);
var region = regionFor(problem);
Expand Down Expand Up @@ -72,10 +83,33 @@ protected void format(ClassDeclaration classDeclaration, IFormattableDocument do
doc.interior(region.keyword("{"), region.keyword("}"), IHiddenRegionFormatter::indent);
doc.prepend(region.keyword("."), this::noSpace);
for (var featureDeclaration : classDeclaration.getFeatureDeclarations()) {
doc.append(featureDeclaration, it -> it.setNewLines(1, 1, 2));
doc.format(featureDeclaration);
}
}

protected void format(ReferenceDeclaration referenceDeclaration, IFormattableDocument doc) {
var region = regionFor(referenceDeclaration);
doc.append(region.feature(ProblemPackage.Literals.REFERENCE_DECLARATION__KIND), this::oneSpace);
doc.prepend(region.feature(ProblemPackage.Literals.NAMED_ELEMENT__NAME), this::oneSpace);
formatList(region, ",", doc);
doc.surround(region.keyword("opposite"), this::oneSpace);
doc.surround(region.keyword("subsets"), this::oneSpace);
var multiplicity = referenceDeclaration.getMultiplicity();
if (multiplicity != null) {
doc.prepend(multiplicity, this::noSpace);
doc.append(multiplicity, this::oneSpace);
doc.format(multiplicity);
}
}

protected void format(Multiplicity multiplicity, IFormattableDocument doc) {
var region = regionFor(multiplicity);
doc.append(region.keyword("["), this::noSpace);
doc.prepend(region.keyword("]"), this::noSpace);
doc.surround(region.keyword(".."), this::noSpace);
}

protected void format(EnumDeclaration enumDeclaration, IFormattableDocument doc) {
surroundNewLines(doc, enumDeclaration, this::twoNewLines);
var region = regionFor(enumDeclaration);
Expand All @@ -85,6 +119,13 @@ protected void format(EnumDeclaration enumDeclaration, IFormattableDocument doc)
doc.prepend(region.keyword("}"), it -> it.setNewLines(1, 1, 2));
doc.interior(region.keyword("{"), region.keyword("}"), IHiddenRegionFormatter::indent);
doc.prepend(region.keyword("."), this::noSpace);
for (var comma : region.keywords(",")) {
doc.prepend(comma, this::noSpace);
doc.append(comma, it -> it.setNewLines(1, 1, 2));
}
for (var literal : enumDeclaration.getLiterals()) {
doc.format(literal);
}
}

protected void format(PredicateDefinition predicateDefinition, IFormattableDocument doc) {
Expand Down Expand Up @@ -139,6 +180,51 @@ protected void format(NodeDeclaration nodeDeclaration, IFormattableDocument doc)
doc.append(region.feature(ProblemPackage.Literals.NODE_DECLARATION__KIND), this::oneSpace);
formatList(region, ",", doc);
doc.prepend(region.keyword("."), this::noSpace);
for (var node : nodeDeclaration.getNodes()) {
doc.format(node);
}
}

protected void format(TopLevelAnnotation topLevelAnnotation, IFormattableDocument doc) {
surroundNewLines(doc, topLevelAnnotation, this::twoNewLines);
var region = regionFor(topLevelAnnotation);
doc.append(region.keyword("#"), this::noSpace);
doc.prepend(region.keyword("."), this::noSpace);
var annotation = topLevelAnnotation.getAnnotation();
if (annotation != null) {
doc.format(annotation);
}
}

protected void format(Annotation annotation, IFormattableDocument doc) {
var region = regionFor(annotation);
doc.prepend(region.keyword("("), this::noSpace);
formatParenthesizedList(region, doc);
for (var argument : annotation.getArguments()) {
doc.format(argument);
}
}

protected void format(AnnotationArgument annotationArgument, IFormattableDocument doc) {
var region = regionFor(annotationArgument);
doc.append(region.feature(ProblemPackage.Literals.ANNOTATION_ARGUMENT__PARAMETER), this::oneSpace);
doc.append(region.keyword("="), this::oneSpace);
doc.format(annotationArgument.getValue());
}

protected void format(AnnotationContainer annotationContainer, IFormattableDocument doc) {
var region = regionFor(annotationContainer);
for (var atSign : region.keywords("@")) {
doc.append(atSign, this::noSpace);
}
var annotatedElement = annotationContainer.eContainer();
boolean singleLine = annotatedElement instanceof Parameter ||
(annotatedElement instanceof Node && annotatedElement.eContainer() instanceof NodeDeclaration);
Procedure1<IHiddenRegionFormatter> initializer = singleLine ? this::oneSpace : this::newLine;
for (var annotation : annotationContainer.getAnnotations()) {
doc.format(annotation);
doc.append(annotation, initializer);
}
}

protected void formatParenthesizedList(ISemanticRegionsFinder region, IFormattableDocument doc) {
Expand Down Expand Up @@ -166,12 +252,12 @@ protected void twoNewLines(IHiddenRegionFormatter it) {
protected void surroundNewLines(IFormattableDocument doc, EObject eObject,
Procedure1<? super IHiddenRegionFormatter> init) {
var region = doc.getRequest().getTextRegionAccess().regionForEObject(eObject);
preprendNewLines(doc, region, init);
prependNewLines(doc, region, init);
appendNewLines(doc, region, init);
}

protected void preprendNewLines(IFormattableDocument doc, ISequentialRegion region,
Procedure1<? super IHiddenRegionFormatter> init) {
protected void prependNewLines(IFormattableDocument doc, ISequentialRegion region,
Procedure1<? super IHiddenRegionFormatter> init) {
if (region == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ void predicateWithoutBodyTest() {
@Test
void predicateWithBodyTest() {
testFormatter(
" pred foo ( node a , b ) <-> equal (a , _c ) , ! equal ( a , b ) ; equal+( a , b ) . ",
" pred foo ( node a , b ) <-> equal (a , _c ) , ! equal ( a , b ) ; equal+( a" +
" , b ) . ",
"pred foo(node a, b) <-> equal(a, _c), !equal(a, b); equal+(a, b).\n");
}

Expand Down Expand Up @@ -214,6 +215,154 @@ pred quux().
""");
}

@Test
void topLevelAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
# Example . # Example ( ) . # Example ( "foo" , 3 ) . # Example ( b = 2 , a = "bar" ) .
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
#Example.
#Example().
#Example("foo", 3).
#Example(b = 2, a = "bar").
""");
}

@Test
void annotationContainerTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
@ Example @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) class Foo.
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
@Example
@Example()
@Example("foo", 3)
@Example(b = 2, a = "bar")
class Foo.
""");
}

@Test
void enumLiteralAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
enum Foo { @ Example BAR , @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) BAZ }
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
enum Foo {
@Example
BAR,
@Example()
@Example("foo", 3)
@Example(b = 2, a = "bar")
BAZ
}
""");
}

@Test
void nodeAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
atom @ Example foo , @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) bar .
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
atom @Example foo, @Example() @Example("foo", 3) @Example(b = 2, a = "bar") bar.
""");
}

@Test
void nodeDeclarationAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
@ Example @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) atom foo .
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
@Example
@Example()
@Example("foo", 3)
@Example(b = 2, a = "bar")
atom foo.
""");
}

@Test
void parameterAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
pred foo ( @ Example node a , @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) b ).
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
pred foo(@Example node a, @Example() @Example("foo", 3) @Example(b = 2, a = "bar") b).
""");
}
@Test
void referenceDeclarationAnnotationTest() {
testFormatter("""
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
class Foo { @ Example contains Bar[ 1 .. * ] bar @ Example ( ) @ Example ( "foo" , 3 ) @ Example ( b = 2 , a = "bar" ) Foo foo } class Bar.
""", """
import builtin::annotations.
#pred Example(@optional string a, @optional int b).
class Foo {
@Example
contains Bar[1..*] bar
@Example()
@Example("foo", 3)
@Example(b = 2, a = "bar")
Foo foo
}
class Bar.
""");
}

private void testFormatter(String toFormat, String expected) {
Problem problem;
try {
Expand Down

0 comments on commit 6222ddf

Please sign in to comment.