Files
langkit/testsuite/tests/java_api/rewriting/common/RewritingTests.java
2025-08-22 09:26:09 +00:00

616 lines
27 KiB
Java

import com.adacore.libfoolang.Libfoolang.*;
import java.util.Arrays;
public class RewritingTests {
// ----- Utils -----
/** Functional interface representing a simple block of code. */
@FunctionalInterface
public interface Executable {
void execute();
}
/**
* Display the section header with the given name
*
* @param name The name of the section
*/
private static void header(String name) {
System.out.println("--- " + name + " ---");
}
/**
* Display the footer of a section
*
* @param name The name of the section
*/
private static void footer(String name) {
System.out.println("----" + "-".repeat(name.length()) + "----\n");
}
/**
* Util function for assertions
*/
private static void assertTrue(
String what,
boolean predicate
) throws RuntimeException {
System.out.println("Asserting: " + what);
if (!predicate) {
throw new RuntimeException("Assertion \"" + what + "\" failed");
}
}
private static void assertLangkitException(
String what,
Executable executable
) {
try {
System.out.println("Try: " + what);
executable.execute();
throw new RuntimeException("Assertion \"" + what + "\" failed");
} catch (LangkitException e) {
System.out.println(" Exception kind = " + e.kind);
System.out.println(" Exception message = " + e.getMessage());
}
}
// ----- Test methods -----
/** Test the rewriting context creation and properties */
private static void testRewritingContext() {
header("Rewriting context");
try (
AnalysisContext context = AnalysisContext.create();
) {
assertTrue(
"Rewriting context is None",
context.getRewritingContext() == RewritingContext.NONE
);
// Open a context and close it manually
System.out.println("Creating rewriting context");
RewritingContext rcontext1 = context.startRewriting();
assertTrue("Rewriting context reference to analysis context",
rcontext1.getAnalysisContext() == context);
assertLangkitException("Creating an other rewriting context",
() -> context.startRewriting());
assertTrue("Rewriting context is opened", !rcontext1.isClosed());
System.out.println("Closing the rewriting context");
rcontext1.close();
assertTrue("Rewriting context is closed", rcontext1.isClosed());
// Open a new context and apply it empty
System.out.println("\nCreating an other rewriting context");
RewritingContext rcontext2 = context.startRewriting();
System.out.println("Applying the new rewriting context");
RewritingApplyResult applyResult = rcontext2.apply();
assertTrue("Rewriting result is successful", applyResult.success);
assertTrue("Rewriting result has no diagnostics",
applyResult.getDiagnostics().length == 0);
assertTrue("Rewriting result unit is none",
applyResult.unit == AnalysisUnit.NONE);
assertTrue("Other rewriting context is closed",
rcontext2.isClosed());
System.out.println("Free the apply result");
applyResult.close();
}
footer("Rewriting context");
}
/** Test the rewriting unit creation and properties */
private static void testRewritingUnit() {
header("Rewriting unit");
try (
AnalysisContext context1 = AnalysisContext.create();
AnalysisContext context2 = AnalysisContext.create();
RewritingContext rcontext = context1.startRewriting();
) {
// Create valid rewriting units
System.out.println("Creating analysis and rewriting units");
AnalysisUnit unit1 = context1.getUnitFromFile("s1.txt");
AnalysisUnit unit2 = context1.getUnitFromFile("s2.txt");
AnalysisUnit unit3 = context1.getUnitFromFile("s3.txt");
AnalysisUnit nonRewritableUnit =
context2.getUnitFromFile("s1.txt");
RewritingUnit runit1 = unit1.getRewritingUnit();
RewritingUnit runit2 = unit2.getRewritingUnit();
assertTrue("Analysis unit reference to rewriting unit",
unit1.getRewritingUnit().equals(runit1));
assertTrue("Rewriting unit reference to analysis unit",
runit2.getAnalysisUnit().equals(unit2));
System.out.println("s2.txt rewriting unit unparsing:");
System.out.println("#####");
System.out.println(runit2.unparse());
System.out.println("#####");
assertTrue("Fetched rewriting units count is 2",
rcontext.rewritingUnits().length == 2);
assertLangkitException(
"Creating a rewriting unit from a non-rewritable context",
() -> nonRewritableUnit.getRewritingUnit()
);
}
footer("Rewriting unit");
}
/** Test the rewriting node fetching and properties */
private static void testRewritingNode() {
header("Rewriting node");
try (
AnalysisContext context1 = AnalysisContext.create();
AnalysisContext context2 = AnalysisContext.create();
RewritingContext rcontext = context1.startRewriting();
) {
// Create rewriting units
System.out.println("Creating analysis and rewriting units");
AnalysisUnit unit1 = context1.getUnitFromFile("s1.txt");
AnalysisUnit unit2 = context2.getUnitFromFile("s2.txt");
RewritingUnit runit1 = unit1.getRewritingUnit();
// Get the roots and verify them
System.out.println("\nGetting rewriting units root nodes");
FooNode node1 = unit1.getRoot();
FooNode node2 = unit2.getRoot();
RewritingNode rnode1 = runit1.getRoot();
assertTrue("Rewriting root is not None", !rnode1.isNone());
assertTrue("Rewriting node parsed node reference",
node1.equals(rnode1.getParsedNode()));
assertTrue("Parsed node rewriting reference",
rnode1.equals(node1.getRewritingNode()));
assertTrue("Rewriting root kind is the same as root",
rnode1.getKind() == node1.getKind());
assertTrue("Rewriting node context reference",
rcontext.equals(rnode1.getRewritingContext()));
assertTrue("Rewriting root is tied", rnode1.isTied());
assertLangkitException(
"Create a rewriting node from a non rewriting context",
() -> node2.getRewritingNode()
);
System.out.println("s1.txt rewriting root node image");
System.out.println(rnode1.image());
System.out.println("s1.txt rewriting root node unparsing");
System.out.println("#####");
System.out.println(rnode1.unparse());
System.out.println("#####");
assertTrue("Unit and root unparsing results are the same",
runit1.unparse().equals(rnode1.unparse()));
// Root children visiting
System.out.println("\nGetting the rewriting root children");
RewritingNode[] children = rnode1.children();
System.out.println(
"Root rewriting node children: " + Arrays.toString(children)
);
assertTrue("Children count is 3", children.length == 3);
assertTrue("Child parent is the root",
children[0].parent().equals(rnode1));
// Child navigation
System.out.println("\nNavigating the root node children");
RewritingNode rfirstChild = rnode1.firstChild();
RewritingNode rlastChild = rnode1.lastChild();
System.out.println("Root first child: " + rfirstChild);
System.out.println("Root last child: " + rlastChild);
assertTrue("Last child previous is the first child next",
rlastChild.previousChild()
.equals(rfirstChild.nextChild()));
assertTrue("Last child next is None",
rlastChild.nextChild().isNone());
assertTrue("First child previous is None",
rfirstChild.previousChild().isNone());
// First declaration visiting
System.out.println(
"\nGetting the name and expression of the first declaration"
);
RewritingNode rdecl1 = children[0];
RewritingNode rname1 = rdecl1.getChild(
MemberReference.FOO_DECL_F_NAME
);
RewritingNode rexpr1 = rdecl1.getChild(
MemberReference.FOO_DECL_F_EXPR
);
System.out.println(" name: " + rname1.toString());
System.out.println(" expr: " + rexpr1.toString());
assertLangkitException(
"Getting f_name child on the root list",
() -> rnode1.getChild(MemberReference.FOO_DECL_F_NAME)
);
assertLangkitException(
"Getting f_expr child on a name node",
() -> rname1.getChild(MemberReference.FOO_DECL_F_EXPR)
);
assertTrue("First child of the name is None",
rname1.firstChild().isNone());
assertTrue("Last child of the expr is None",
rexpr1.lastChild().isNone());
}
footer("Rewriting node");
}
/** Text the rewriting node text manipulation methods */
private static void testRewritingNodeTexts() {
header("Rewriting node text getting/setting");
try (
AnalysisContext context = AnalysisContext.create();
RewritingContext rcontext = context.startRewriting();
) {
// Create rewriting units
System.out.println("Creating analysis and rewriting units");
AnalysisUnit unit = context.getUnitFromFile("s1.txt");
RewritingUnit runit = unit.getRewritingUnit();
// Get the first decl stmt and get/set the name text
System.out.println("\nGetting the first declaration statement");
RewritingNode rroot = runit.getRoot();
RewritingNode rdecl1 = rroot.children()[0];
System.out.println("Original declaration statement: '" +
rdecl1.unparse().trim() +
"'");
RewritingNode rname1 = rdecl1.children()[0];
assertTrue("Variable name is 'orig_1'",
rname1.getText().equals("orig_1"));
System.out.println("Changing the variable name for 'hello'");
rname1.setText("hello");
assertTrue("Variable name has been changed",
rname1.getText().equals("hello"));
System.out.println("New declaration statement: '" +
rdecl1.unparse().trim() +
"'");
System.out.println("New rewriting unit:");
System.out.println("#####");
System.out.println(runit.unparse());
System.out.println("#####");
}
footer("Rewriting node text getting/setting");
}
/** Test the rewriting node creation methods */
private static void testRewritingNodeCreation() {
header("Rewriting node creation");
try (
AnalysisContext context = AnalysisContext.create();
RewritingContext rcontext = context.startRewriting();
) {
// Create rewriting units
System.out.println("Creating analysis and rewriting units");
AnalysisUnit unit = context.getUnitFromFile("s1.txt");
RewritingUnit runit = unit.getRewritingUnit();
RewritingNode rroot = runit.getRoot();
// Clone the first declaration statement
System.out.println("\nCloning the first declaration statement");
RewritingNode rdecl1 = rroot.firstChild();
RewritingNode rdecl1Clone = rdecl1.clone();
System.out.println("Source node: " + rdecl1);
System.out.println("Cloned node: " + rdecl1Clone);
assertTrue("Clone result is not tied", !rdecl1Clone.isTied());
assertTrue("Clone is different from the source",
!rdecl1Clone.equals(rdecl1));
// Create a declaration from scratch
System.out.println(
"\nCreating a declaration statement from scratch"
);
RewritingNode rdeclCreated1 = rcontext.createNode(NodeKind.VAR);
System.out.println("Created node: " + rdeclCreated1);
assertTrue("Created node is not tied", !rdeclCreated1.isTied());
assertTrue("Created node parsed node is None",
rdeclCreated1.getParsedNode().isNone());
assertTrue("Created declaration name is None",
rdeclCreated1.getChild(MemberReference.FOO_DECL_F_NAME)
.isNone());
// Create a name and an integer literal from scratch
System.out.println("\nCreating a name and an integer literal");
RewritingNode rname1 =
rcontext.createTokenNode(NodeKind.NAME, "first_name");
RewritingNode rlit1 =
rcontext.createTokenNode(NodeKind.LITERAL, "1");
assertTrue("Create name is not tied", !rname1.isTied());
assertTrue("Created name kind is NAME",
rname1.getKind() == NodeKind.NAME);
assertTrue("Create name text is 'first_name'",
rname1.getText().equals("first_name"));
assertLangkitException(
"Creating a token node with an non-token kind ",
() -> rcontext.createTokenNode(NodeKind.VAR, "impossible")
);
// Create another declaration directly with the name and value
System.out.println(
"\nCreating a declaration statement with its children"
);
RewritingNode rdeclCreated2 =
rcontext.createNode(NodeKind.VAR, rname1, rlit1);
System.out.println("Created node: " + rdeclCreated2);
assertTrue("Created node is not tied", !rdeclCreated2.isTied());
assertTrue("Created decl name is the previously created name",
rdeclCreated2.getChild(MemberReference.FOO_DECL_F_NAME)
.equals(rname1));
assertTrue(
"Created decl expression is the previously created one",
rdeclCreated2.getChild(MemberReference.FOO_DECL_F_EXPR)
.equals(rlit1)
);
assertLangkitException(
"Creating a node with already tied children",
() -> rcontext.createNode(NodeKind.VAR, rname1, rlit1)
);
RewritingNode rname2 =
rcontext.createTokenNode(NodeKind.NAME, "second_name");
RewritingNode rlit2 =
rcontext.createTokenNode(NodeKind.LITERAL, "2");
assertLangkitException(
"Creating a node with the invalid type",
() -> rcontext.createNode(NodeKind.NAME, rname2, rlit2)
);
// Create a declaration from a template
System.out.println(
"\nCreating a declaration statement from a template"
);
RewritingNode rdeclCreated3 = rcontext.createFromTemplate(
"var {} = {}",
GrammarRule.VAR_RULE_RULE,
rname2,
rlit2
);
System.out.println("Created node: " + rdeclCreated3);
assertTrue("Created node is a VAR",
rdeclCreated3.getKind() == NodeKind.VAR);
assertTrue("Created node is not tied", !rdeclCreated3.isTied());
assertTrue(
"Created declaration name text is 'second_name'",
rdeclCreated3.getChild(MemberReference.FOO_DECL_F_NAME)
.getText()
.equals("second_name")
);
assertTrue(
"Created declaration expression text is '2'",
rdeclCreated3.getChild(MemberReference.FOO_DECL_F_EXPR)
.getText()
.equals("2")
);
assertLangkitException(
"Creating from template with invalid argument count",
() -> rcontext.createFromTemplate(
"var {} = {}",
GrammarRule.VAR_RULE_RULE,
rname2
)
);
// Create the final declaration list with its children
System.out.println("\nCreating the declaration list");
RewritingNode rdeclList = rcontext.createNode(
NodeKind.DECL_LIST,
rdeclCreated2,
rdeclCreated3
);
System.out.println("Created declaration list: " + rdeclList);
RewritingNode[] children = rdeclList.children();
assertTrue("Created list child count is 2", children.length == 2);
System.out.println("Create declaration list unparse result:");
System.out.println("#####");
System.out.println(rdeclList.unparse());
System.out.println("#####");
}
footer("Rewriting node creation");
}
/**
* Test the rewriting node modification operations (replace, add, remove)
*/
private static void testRewritingNodeModifications() {
header("Rewriting node modifications");
try (
AnalysisContext context = AnalysisContext.create();
RewritingContext rcontext = context.startRewriting();
) {
// Create rewriting units
System.out.println("Creating analysis and rewriting units");
AnalysisUnit unit = context.getUnitFromFile("s1.txt");
RewritingUnit runit = unit.getRewritingUnit();
RewritingNode rroot = runit.getRoot();
RewritingNode[] children = rroot.children();
// Set the first declaration name
System.out.println("\nReplacing the first declaration name");
RewritingNode rdecl1 = children[0];
RewritingNode rname1 =
rdecl1.getChild(MemberReference.FOO_DECL_F_NAME);
RewritingNode rnameCreated1 =
rcontext.createTokenNode(NodeKind.NAME, "replaced");
assertTrue("First declaration name is 'orig_1'",
rname1.getText().equals("orig_1"));
assertTrue("First declaration name is tied", rname1.isTied());
rdecl1.setChild(MemberReference.FOO_DECL_F_NAME, rnameCreated1);
RewritingNode rname2 =
rdecl1.getChild(MemberReference.FOO_DECL_F_NAME);
assertTrue("Current name node is the created one",
rname2.equals(rnameCreated1));
assertTrue("First declaration name is now 'replaced'",
rname2.getText().equals("replaced"));
assertTrue("Created name is now tied", rnameCreated1.isTied());
assertTrue("Old name node is not tied anymore", !rname1.isTied());
assertLangkitException(
"Setting an already tied child",
() -> rdecl1.setChild(
MemberReference.FOO_DECL_F_NAME,
rnameCreated1
)
);
// Replace the first declaration name for the original one
System.out.println(
"\nReplacing the first delaration name for the original one"
);
rname2.replace(rname1);
assertTrue("Replacing name is now untied", !rname2.isTied());
assertTrue("Original name is now tied", rname1.isTied());
assertTrue(
"First declaration name is now 'orig_1'",
rdecl1.getChild(MemberReference.FOO_DECL_F_NAME)
.getText()
.equals("orig_1")
);
assertLangkitException(
"Replacing the name with an already tied node",
() -> rname1.replace(rname1)
);
assertLangkitException(
"Replacing an untied node",
() -> rname2.replace(rname2)
);
// Insert new declarations in the declaration list
System.out.println("\nDeclaration list original unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
RewritingNode rdeclCreated1 = rcontext.createFromTemplate(
"var c1 = 1",
GrammarRule.VAR_RULE_RULE
);
RewritingNode rdeclCreated2 = rcontext.createFromTemplate(
"var c2 = 2",
GrammarRule.VAR_RULE_RULE
);
RewritingNode rdeclCreated3 = rcontext.createFromTemplate(
"var c3 = 3",
GrammarRule.VAR_RULE_RULE
);
RewritingNode rdeclCreated4 = rcontext.createFromTemplate(
"var c4 = 4",
GrammarRule.VAR_RULE_RULE
);
// Insert a new declaration at the beginning
System.out.println("\nInserting a declaration at the beginning");
rroot.insertFirst(rdeclCreated1);
System.out.println("Declaration list unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
assertTrue("Inserted node is now tied", rdeclCreated1.isTied());
assertTrue("First declaration is the inserted one",
rroot.firstChild().equals(rdeclCreated1));
assertTrue("Children count is now 4",
rroot.children().length == 4);
assertLangkitException(
"Inserting a first child in a non list node",
() -> rdeclCreated1.insertFirst(rname2)
);
assertLangkitException(
"Inserting an already tied child node",
() -> rroot.insertFirst(rdeclCreated1)
);
// Insert a new declaration at the end
System.out.println("\nInserting a declartion at the end");
rroot.insertLast(rdeclCreated2);
System.out.println("Declaration list unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
assertTrue("Inserted node is now tied", rdeclCreated2.isTied());
assertTrue("Last declaration is the inserted one",
rroot.lastChild().equals(rdeclCreated2));
assertTrue("Children count is now 5",
rroot.children().length == 5);
assertLangkitException(
"Inserting a last child in a non list node",
() -> rdeclCreated2.insertLast(rname2)
);
assertLangkitException(
"Inserting an already tied child node",
() -> rroot.insertLast(rdeclCreated2)
);
// Insert a node before the 3rd node
System.out.println("\nInserting a declaration before the 3rd");
RewritingNode rthird = rroot.children()[2];
RewritingNode rthridName =
rthird.getChild(MemberReference.FOO_DECL_F_NAME);
rthird.insertBefore(rdeclCreated3);
System.out.println("Declaration list unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
assertTrue("Inserted node is now tied", rdeclCreated3.isTied());
assertTrue("3rd declaration is the inserted one",
rroot.children()[2].equals(rdeclCreated3));
assertTrue("Children count is now 6",
rroot.children().length == 6);
assertLangkitException(
"Inserting a node before a non-list-parent node",
() -> rthridName.insertBefore(rname2)
);
assertLangkitException(
"Inserting an already tied node",
() -> rthird.insertBefore(rdeclCreated3)
);
// Insert a node after the 4th one
System.out.println("\nInserting a declaration after the 4th");
rthird.insertAfter(rdeclCreated4);
System.out.println("Declaration list unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
assertTrue("Inserted node is now tied", rdeclCreated4.isTied());
assertTrue("5th declaration is the inserted one",
rroot.children()[4].equals(rdeclCreated4));
assertTrue("Children count is now 7",
rroot.children().length == 7);
assertLangkitException(
"Inserting a node before a non-list-parent node",
() -> rthridName.insertAfter(rname2)
);
assertLangkitException(
"Inserting an already tied node",
() -> rthird.insertAfter(rdeclCreated4)
);
// Remove the 2nd child from the declaration list
System.out.println("\nRemoving the 2nd child");
rroot.children()[1].removeFromParent();
System.out.println("Declaration list unparse:");
System.out.println("#####");
System.out.println(rroot.unparse());
System.out.println("#####");
assertTrue("Children count is now 6",
rroot.children().length == 6);
assertLangkitException(
"Removing a node which is not in a list node",
() -> rname1.removeFromParent()
);
assertLangkitException(
"Removing a node which is not tied",
() -> rname2.removeFromParent()
);
}
footer("Rewriting node modifications");
}
/** Run all Java rewriting tests */
public static void main(String[] args) {
System.out.println("===== Start the Java rewriting tests =====");
testRewritingContext();
testRewritingUnit();
testRewritingNode();
testRewritingNodeTexts();
testRewritingNodeCreation();
testRewritingNodeModifications();
System.out.println("===== End of the Java rewriting tests =====");
}
}