Skip to content
Snippets Groups Projects
Commit a3a28e6c authored by René Schöne's avatar René Schöne
Browse files

Change component resolving for inherited children of type-decls.

- also add simple passing tests
parent dcc63fc3
Branches
Tags
1 merge request!37Resolve "Inherited components of a type can not be chosen as port targets"
Pipeline #15482 failed
......@@ -7,6 +7,7 @@
### Development Changes
- Bugfix: "error: variable handler is already defined" when using multiple protocols [#58](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/58)
- Bugfix: Inherited components of a type can not be chosen as port targets [#59](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/59)
## 1.0.0
......
......@@ -91,7 +91,7 @@ aspect RagConnectNameResolution {
String childTypeName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(parentTypeName);
// iterate over components and find the matching typeComponent
for (Component comp : type.getComponentList()) {
for (Component comp : type.allComponentsAsOwnedByMe()) {
if (comp.isTypeComponent() && comp.getName().equals(childTypeName)) {
return comp.asTypeComponent();
}
......@@ -114,7 +114,7 @@ aspect RagConnectNameResolution {
String childTypeName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(parentTypeName);
// iterate over components and find the matching typeComponent
for (Component comp : type.getComponentList()) {
for (Component comp : type.allComponentsAsOwnedByMe()) {
if (comp.getName().equals(childTypeName)) {
return comp;
}
......@@ -138,7 +138,7 @@ aspect RagConnectNameResolution {
String tokenName = id.substring(dotIndex + 1);
TypeDecl type = program().resolveTypeDecl(typeName);
// iterate over components and find the matching tokenComponent
for (Component comp : type.getComponentList()) {
for (Component comp : type.allComponentsAsOwnedByMe()) {
if (comp.isTokenComponent() && comp.getName().equals(tokenName)) {
return comp.asTokenComponent();
}
......@@ -175,10 +175,60 @@ aspect RagConnectNameResolution {
}
return null;
}
}
aspect RelastNameResolution {
syn boolean Role.matches(String typeName, String roleName) = false;
eq NavigableRole.matches(String typeName, String roleName) {
return getType().getName().equals(typeName) && getName().equals(roleName);
}
/** Returns all components including inherited ones */
syn List<Component> TypeDecl.allComponents() {
List<Component> result = new ArrayList<>();
getComponentList().forEach(result::add);
if (hasSuperType()) {
mergeComponentLists(result, getSuperType().allComponents());
}
return result;
}
/** Returns same as allComponents() but for each component the containingTypeDecl will compute to this component */
syn nta JastAddList<Component> TypeDecl.allComponentsAsOwnedByMe() {
JastAddList<Component> result = new JastAddList<>();
for (Component comp : allComponents()) {
result.add(comp.treeCopy());
}
return result;
}
public static void TypeDecl.mergeComponentLists(List<Component> subTypeResult, List<Component> superTypeResult) {
for (int i = superTypeResult.size() - 1; i >= 0; i--) {
Component superTypeComponent = superTypeResult.get(i);
if (subTypeResult.stream().noneMatch(subTypeComponent -> subTypeComponent.matches(superTypeComponent))) {
subTypeResult.add(0, superTypeComponent);
}
}
}
syn boolean Component.matches(Component other) = false;
eq TokenComponent.matches(Component other) {
if (!other.isTokenComponent()) { return false; }
return getName().equals(other.getName()) && getJavaTypeUse().prettyPrint().equals(other.asTokenComponent().getJavaTypeUse().prettyPrint());
}
eq TypeComponent.matches(Component other) {
return getName().equals(other.getName()) && getTypeDecl().equals(other.asTypeComponent().getTypeDecl());
}
eq NormalComponent.matches(Component other) {
if (!other.isTypeComponent() || !other.asTypeComponent().isNormalComponent()) { return false; }
return super.matches(other);
}
eq ListComponent.matches(Component other) {
if (!other.isTypeComponent() || !other.asTypeComponent().isListComponent()) { return false; }
return super.matches(other);
}
eq OptComponent.matches(Component other) {
if (!other.isTypeComponent() || !other.asTypeComponent().isOptComponent()) { return false; }
return super.matches(other);
}
}
# Passing
This directory contains use case for RagConnect, that just need to pass compiling (no dedicated Java test).
// both directions for SpecialA1
send SpecialA1.Input ;
receive SpecialA1.Input ;
send SpecialA1.Many ;
receive SpecialA1.Many ;
send SpecialA1.Maybe ;
receive SpecialA1.Maybe ;
send SpecialA1.B ;
receive SpecialA1.B ;
// only one direction for SpecialA2
send SpecialA2.Input ;
send SpecialA2.Many ;
send SpecialA2.Maybe ;
send SpecialA2.B ;
Root ::= A ;
A ::= <Input:String> Many:B* [Maybe:B] B ;
SpecialA1 : A ;
SpecialA2 : A ;
B ::= ;
package org.jastadd.ragconnect.tests;
import org.jastadd.ragconnect.tests.utils.TestUtils;
import org.junit.jupiter.api.BeforeEach;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jastadd.ragconnect.tests.utils.TestUtils.readFile;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* TODO: Add description.
*
* @author rschoene - Initial contribution
*/
public abstract class AbstractCompilerTest extends RagConnectTest {
protected abstract String getDirectoryName();
protected String getOutputDirectory() {
return TestUtils.OUTPUT_DIRECTORY_PREFIX + getDirectoryName();
}
protected abstract String getDefaultGrammarName();
@BeforeEach
public void ensureOutputDirectory() {
File outputDirectory = new File(getOutputDirectory());
assertTrue((outputDirectory.exists() && outputDirectory.isDirectory()) || outputDirectory.mkdir());
}
protected Path test(String inputDirectoryName, int expectedReturnValue, String rootNode, String... connectNames) throws IOException {
String grammarFile = Paths.get(inputDirectoryName, getDefaultGrammarName() + ".relast").toString();
List<String> connectFiles = Arrays.stream(connectNames)
.map(connectName -> Paths.get(inputDirectoryName,connectName + ".connect").toString())
.collect(Collectors.toList());
return TestUtils.runCompiler(grammarFile, connectFiles, rootNode,
getDirectoryName(), expectedReturnValue);
}
protected void testAndCompare(String inputDirectoryName, String expectedName, String rootNode, String... connectNames) throws IOException {
Path outPath = test(inputDirectoryName, 1, rootNode, connectNames);
final String startOfErrorsPattern = "Errors:\n";
String out = readFile(outPath, Charset.defaultCharset());
assertThat(out).contains(startOfErrorsPattern);
out = out.substring(out.indexOf(startOfErrorsPattern) + startOfErrorsPattern.length());
TestUtils.assertLinesMatch(getDirectoryName(), expectedName, out);
logger.info("ragconnect for " + expectedName + " returned:\n{}", out);
}
}
package org.jastadd.ragconnect.tests;
import org.jastadd.ragconnect.tests.utils.TestUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jastadd.ragconnect.tests.utils.TestUtils.readFile;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Test error messages.
*
* @author rschoene - Initial contribution
*/
public class ErrorsTest extends RagConnectTest {
private static final String ERROR_DIRECTORY = "errors/";
private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY;
public class ErrorsTest extends AbstractCompilerTest {
private static final String DEFAULT_GRAMMAR_NAME = "Errors";
@Override
protected String getDirectoryName() {
return "errors";
}
@BeforeAll
public static void createOutputDirectory() {
File outputDirectory = new File(OUTPUT_DIRECTORY);
assertTrue((outputDirectory.exists() && outputDirectory.isDirectory()) || outputDirectory.mkdir());
@Override
protected String getDefaultGrammarName() {
return "Errors";
}
@Test
void testStandardErrors() throws IOException {
test("Standard", "A", "Standard");
testAndCompare(getDirectoryName(), "Standard", "A", "Standard");
}
@Test
void testTwoPartsErrors() throws IOException {
test("Part", "A", "Part1", "Part2");
testAndCompare(getDirectoryName(), "Part", "A", "Part1", "Part2");
}
@SuppressWarnings("SameParameterValue")
private void test(String expectedName, String rootNode, String... connectNames) throws IOException {
String grammarFile = ERROR_DIRECTORY + DEFAULT_GRAMMAR_NAME + ".relast";
List<String> connectFiles = Arrays.stream(connectNames)
.map(connectName -> ERROR_DIRECTORY + connectName + ".connect")
.collect(Collectors.toList());
Path outPath = TestUtils.runCompiler(grammarFile, connectFiles, rootNode, ERROR_DIRECTORY, 1);
final String startOfErrorsPattern = "Errors:\n";
String out = readFile(outPath, Charset.defaultCharset());
assertThat(out).contains(startOfErrorsPattern);
out = out.substring(out.indexOf(startOfErrorsPattern) + startOfErrorsPattern.length());
TestUtils.assertLinesMatch(ERROR_DIRECTORY, expectedName, out);
logger.info("ragconnect for " + expectedName + " returned:\n{}", out);
}
}
package org.jastadd.ragconnect.tests;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Paths;
/**
* Use cases that just need to compile.
*
* @author rschoene - Initial contribution
*/
public class PassingTest extends AbstractCompilerTest {
@Override
protected String getDirectoryName() {
return "passing";
}
@Override
protected String getDefaultGrammarName() {
return "Test";
}
protected void run(String inputDirectoryName, String rootNode) throws IOException {
super.test(Paths.get("passing", inputDirectoryName).toString(),
0, rootNode, getDefaultGrammarName());
}
@Test
public void testInheritance() throws IOException {
run("inheritance", "Root");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment