Skip to content

Commit

Permalink
Capture source information for class generalizations (#2883)
Browse files Browse the repository at this point in the history
* Capture source information for class generalizations

* Fix variable name typo

* Fix test case
  • Loading branch information
rafaelbey authored Jun 4, 2024
1 parent 4c2bea3 commit d5e332d
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.finos.legend.engine.language.pure.compiler.toPureGraph.handlers.Handlers;
import org.finos.legend.engine.language.pure.compiler.toPureGraph.test.TestBuilderHelper;
import org.finos.legend.engine.protocol.pure.v1.model.context.EngineErrorType;
import org.finos.legend.engine.protocol.pure.v1.model.context.PackageableElementPointer;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.Multiplicity;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.mapping.AssociationMapping;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.mapping.ClassMapping;
Expand Down Expand Up @@ -367,8 +368,9 @@ public static Root_meta_pure_mapping_MappingClass_Impl processMappingClass(org.f
{
Root_meta_pure_mapping_MappingClass_Impl mappingClass = new Root_meta_pure_mapping_MappingClass_Impl<>(" ", SourceInformationHelper.toM3SourceInformation(mappingclass.sourceInformation), null);
mappingClass._name(mappingclass.name);
MutableList<Generalization> generalizations = ListIterate.collect(mappingclass.superTypes, (superType) ->
MutableList<Generalization> generalizations = ListIterate.collect(mappingclass.superTypes, (superTypePtr) ->
{
String superType = superTypePtr.path;
Generalization generalization = new Root_meta_pure_metamodel_relationship_Generalization_Impl("", null, context.pureModel.getClass("meta::pure::metamodel::relationship::Generalization"))._general(context.resolveGenericType(superType))._specific(mappingClass);
context.resolveType(superType)._specializationsAdd(generalization);
return generalization;
Expand All @@ -392,7 +394,7 @@ public static org.finos.legend.pure.m3.coreinstance.meta.pure.mapping.aggregatio
Class _class = context.resolveClass(aggregateSetImplementationContainer.setImplementation._class, aggregateSetImplementationContainer.setImplementation.classSourceInformation);
aggregateSetImplementationContainer.setImplementation.mappingClass = new org.finos.legend.engine.protocol.pure.v1.model.packageableElement.mapping.MappingClass();
aggregateSetImplementationContainer.setImplementation.mappingClass.name = _class.getName() + "_" + parent.getName() + "_" + aggregateSetImplementationContainer.setImplementation.id;
aggregateSetImplementationContainer.setImplementation.mappingClass.superTypes = Lists.mutable.with(getElementFullPath(_class, context.pureModel.getExecutionSupport()));
aggregateSetImplementationContainer.setImplementation.mappingClass.superTypes = Lists.mutable.with(new PackageableElementPointer(getElementFullPath(_class, context.pureModel.getExecutionSupport())));
}
org.finos.legend.pure.m3.coreinstance.meta.pure.mapping.aggregationAware.AggregateSetImplementationContainer container = new Root_meta_pure_mapping_aggregationAware_AggregateSetImplementationContainer_Impl("", null, context.pureModel.getClass("meta::pure::mapping::aggregationAware::AggregateSetImplementationContainer"));
container._setImplementation((InstanceSetImplementation) aggregateSetImplementationContainer.setImplementation.accept(new ClassMappingFirstPassBuilder(context, parent)).getOne());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,19 @@ public PackageableElement visit(Class srcClass)
org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class _class = this.context.pureModel.getClass(fullPath, srcClass.sourceInformation);
GenericType _classGenericType = this.context.resolveGenericType(fullPath, srcClass.sourceInformation);
Set<String> uniqueSuperTypes = Sets.mutable.empty();
MutableList<Generalization> generalization = ListIterate.collect(srcClass.superTypes, superType ->
MutableList<Generalization> generalization = ListIterate.collect(srcClass.superTypes, superTypePtr ->
{
String superType = superTypePtr.path;
// validate no duplicated class supertype
if (!uniqueSuperTypes.add(superType))
{
throw new EngineException("Duplicated super type '" + superType + "' in class '" + this.context.pureModel.buildPackageString(srcClass._package, srcClass.name) + "'", srcClass.sourceInformation, EngineErrorType.COMPILATION);
}
Generalization g = new Root_meta_pure_metamodel_relationship_Generalization_Impl("", null, this.context.pureModel.getClass("meta::pure::metamodel::relationship::Generalization"))._general(this.context.resolveGenericType(superType, srcClass.sourceInformation))._specific(_class);
Generalization g = new Root_meta_pure_metamodel_relationship_Generalization_Impl("", SourceInformationHelper.toM3SourceInformation(superTypePtr.sourceInformation), this.context.pureModel.getClass("meta::pure::metamodel::relationship::Generalization"))._general(this.context.resolveGenericType(superType, superTypePtr.sourceInformation))._specific(_class);
if (!this.context.pureModel.isImmutable(superType))
{
org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class<?> superTypeClass;
Type type = this.context.resolveType(superType, srcClass.sourceInformation);
Type type = this.context.resolveType(superType, superTypePtr.sourceInformation);
try
{
superTypeClass = (org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class<?>) type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ private void validateProperties(PureModel pureModel, Map<String, Class> classes)
private void visitClassSuperType(Class _class, PureModel pureModel, Map<String, Class> classes, Set<Class> visitedClasses, Set<Class> discoveredClasses)
{
discoveredClasses.add(_class);
_class.superTypes.forEach(superTypePath ->
_class.superTypes.forEach(superTypePtr ->
{
String superTypePath = superTypePtr.path;
Class superType = classes.get(superTypePath);
if (superType != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ public void testMissingSuperType()
"\n" +
"Class test::B extends NotHere\n" +
"{\n" +
"}\n", "COMPILATION error at [6:1-8:1]: Can't find type 'NotHere'"
"}\n", "COMPILATION error at [6:1-8:1]: Error in 'test::B': Can't find type 'NotHere'"
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

package org.finos.legend.engine.language.pure.grammar.from.domain;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RuleContext;
Expand Down Expand Up @@ -91,12 +96,6 @@
import org.finos.legend.engine.protocol.pure.v1.model.valueSpecification.raw.classInstance.relation.ColSpecArray;
import org.finos.legend.engine.shared.core.operational.errorManagement.EngineException;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

public class DomainParseTreeWalker
{
private static final String TILDE = "~";
Expand Down Expand Up @@ -295,8 +294,11 @@ private Class visitClass(DomainParserGrammar.ClassDefinitionContext ctx)
_class.name = PureGrammarParserUtility.fromIdentifier(ctx.qualifiedName().identifier());
_class.stereotypes = ctx.stereotypes() == null ? Lists.mutable.empty() : this.visitStereotypes(ctx.stereotypes());
_class.constraints = ctx.constraints() == null ? Lists.mutable.empty() : ListIterate.collect(ctx.constraints().constraint(), c -> this.visitConstraint(ctx.constraints().constraint(), c));
// TODO ? add source info specific to each superType
_class.superTypes = ctx.EXTENDS() == null ? Lists.mutable.empty() : ListIterate.collect(ctx.type(), t -> PureGrammarParserUtility.fromQualifiedName(t.qualifiedName().packagePath() == null ? Collections.emptyList() : t.qualifiedName().packagePath().identifier(), t.qualifiedName().identifier()));
_class.superTypes = ctx.EXTENDS() == null ? Lists.mutable.empty() : ListIterate.collect(ctx.type(), t ->
{
String path = PureGrammarParserUtility.fromQualifiedName(t.qualifiedName().packagePath() == null ? Collections.emptyList() : t.qualifiedName().packagePath().identifier(), t.qualifiedName().identifier());
return new PackageableElementPointer(PackageableElementType.CLASS, path, this.walkerSourceInformation.getSourceInformation(t));
});
_class.taggedValues = ctx.taggedValues() == null ? Lists.mutable.empty() : this.visitTaggedValues(ctx.taggedValues());
_class.properties = ctx.classBody().properties().property() == null ? new ArrayList<>() : ListIterate.collect(ctx.classBody().properties().property(), this::visitSimpleProperty);
_class.qualifiedProperties = ctx.classBody().properties().qualifiedProperty() == null ? new ArrayList<>() : ListIterate.collect(ctx.classBody().properties().qualifiedProperty(), this::visitDerivedProperty);
Expand Down Expand Up @@ -448,37 +450,37 @@ private org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain
functionTestSuite.sourceInformation = this.walkerSourceInformation.getSourceInformation(functionTestSuiteDefContext);
if (functionTestSuiteDefContext.simpleFunctionTest() != null)
{
for (DomainParserGrammar.SimpleFunctionTestContext simpleFunctionTestContext: functionTestSuiteDefContext.simpleFunctionTest())
for (DomainParserGrammar.SimpleFunctionTestContext simpleFunctionTestContext : functionTestSuiteDefContext.simpleFunctionTest())
{
this.processFuncTest(ctx, functionTestSuite,func.parameters, simpleFunctionTestContext);
this.processFuncTest(ctx, functionTestSuite, func.parameters, simpleFunctionTestContext);
}
}
if (functionTestSuiteDefContext.functionData() != null)
{
functionTestSuite.testData = Lists.mutable.empty();
for (DomainParserGrammar.FunctionDataContext functionDataContext: functionTestSuiteDefContext.functionData())
for (DomainParserGrammar.FunctionDataContext functionDataContext : functionTestSuiteDefContext.functionData())
{
functionTestSuite.testData.add(this.processStoreTestData(functionDataContext));
functionTestSuite.testData.add(this.processStoreTestData(functionDataContext));
}
}
suites.add(functionTestSuite);
}
if (functionTestSuiteDefContext.simpleFunctionSuite() != null)
{
for (DomainParserGrammar.SimpleFunctionSuiteContext simpleFunctionSuiteContext: ctx.functionTestSuiteDef().simpleFunctionSuite())
for (DomainParserGrammar.SimpleFunctionSuiteContext simpleFunctionSuiteContext : ctx.functionTestSuiteDef().simpleFunctionSuite())
{
org.finos.legend.engine.protocol.pure.v1.model.packageableElement.function.FunctionTestSuite functionTestSuite = new org.finos.legend.engine.protocol.pure.v1.model.packageableElement.function.FunctionTestSuite();
functionTestSuite.id = PureGrammarParserUtility.fromIdentifier(simpleFunctionSuiteContext.identifier());
functionTestSuite.tests = Lists.mutable.empty();
functionTestSuite.sourceInformation = this.walkerSourceInformation.getSourceInformation(simpleFunctionSuiteContext);
for (DomainParserGrammar.SimpleFunctionTestContext simpleFunctionTestContext: simpleFunctionSuiteContext.simpleFunctionTest())
for (DomainParserGrammar.SimpleFunctionTestContext simpleFunctionTestContext : simpleFunctionSuiteContext.simpleFunctionTest())
{
this.processFuncTest(ctx, functionTestSuite,func.parameters, simpleFunctionTestContext);
this.processFuncTest(ctx, functionTestSuite, func.parameters, simpleFunctionTestContext);
}
if (simpleFunctionSuiteContext.functionData() != null)
{
functionTestSuite.testData = Lists.mutable.empty();
for (DomainParserGrammar.FunctionDataContext functionDataContext: simpleFunctionSuiteContext.functionData())
for (DomainParserGrammar.FunctionDataContext functionDataContext : simpleFunctionSuiteContext.functionData())
{
functionTestSuite.testData.add(this.processStoreTestData(functionDataContext));
}
Expand Down Expand Up @@ -509,7 +511,7 @@ private void processFuncTest(DomainParserGrammar.FunctionDefinitionContext funct
functionTest.id = PureGrammarParserUtility.fromIdentifier(simpleFunctionTestContext.identifier(0));
if (simpleFunctionTestContext.STRING() != null)
{
functionTest.doc = PureGrammarParserUtility.fromGrammarString(simpleFunctionTestContext.STRING().getText(), true);
functionTest.doc = PureGrammarParserUtility.fromGrammarString(simpleFunctionTestContext.STRING().getText(), true);
}
functionTest.sourceInformation = this.walkerSourceInformation.getSourceInformation(simpleFunctionTestContext);
DomainParserGrammar.FunctionParamsContext functionParamsContext = simpleFunctionTestContext.functionParams();
Expand Down Expand Up @@ -606,7 +608,7 @@ else if (contentType.equals(KNOWN_XML_CONTENT_TYPE))
{
externalFormatData.contentType = contentType;
}
return externalFormatData;
return externalFormatData;
}

private org.finos.legend.engine.protocol.pure.v1.model.packageableElement.function.StoreTestData processStoreTestData(DomainParserGrammar.FunctionDataContext functionDataContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public String visit(Class _class)
builder.append("Class ").append(HelperDomainGrammarComposer.renderAnnotations(_class.stereotypes, _class.taggedValues)).append(PureGrammarComposerUtility.convertPath(_class.getPath()));
if (!_class.superTypes.isEmpty())
{
builder.append(" extends ").append(Lists.mutable.withAll(_class.superTypes).makeString(", "));
builder.append(" extends ").append(_class.superTypes.stream().map(x -> x.path).collect(Collectors.joining(", ")));
}
builder.append("\n");
if (!_class.constraints.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@

package org.finos.legend.engine.language.pure.grammar.test.parser;

import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.Vocabulary;
import org.eclipse.collections.impl.list.mutable.ListAdapter;
import org.finos.legend.engine.language.pure.grammar.from.antlr4.domain.DomainParserGrammar;
import org.finos.legend.engine.language.pure.grammar.test.TestGrammarParser;
import org.finos.legend.engine.protocol.pure.v1.model.context.PackageableElementPointer;
import org.finos.legend.engine.protocol.pure.v1.model.context.PackageableElementType;
import org.finos.legend.engine.protocol.pure.v1.model.context.PureModelContextData;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.PackageableElement;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.Class;
import org.junit.Assert;
import org.junit.Test;

import java.util.List;
Expand Down Expand Up @@ -78,4 +87,31 @@ public void testGraphFetchTreeWithSubtypeTreeAtPropertyLevel()
String code4 = "function my::test(): Any[*]\n{\n " + emptySubTypeTreesAtRootLevel.replace("\n", "").replace(" ", "") + "\n}\n";
test(code4, "PARSER error at [3:53]: Unexpected token '}'");
}

@Test
public void testClass()
{
PureModelContextData pureModelContextData = test("Class <<temporal.businesstemporal>> {doc.doc = 'something'} A extends B\n" +
"{\n" +
" <<equality.Key>> {doc.doc = 'bla'} name: e::R[*];\n" +
" {doc.doc = 'bla'} ok: Integer[1..2];\n" +
" <<devStatus.inProgress>> q(s: String[1]) {$s + 'ok'}: c::d::R[1];\n" +
" {doc.doc = 'bla'} xza(s: z::k::B[1]) {$s + 'ok'}: String[1];\n" +
"}\n" +
"\n" +
"Class z::k::B\n" +
"{\n" +
" z: String[1];\n" +
"}\n");

Map<String, PackageableElement> elementMap = pureModelContextData.getElements().stream().collect(Collectors.toMap(x -> x.getPath(), Function.identity()));

Class aClass = (Class) elementMap.get("A");
Assert.assertEquals(1, aClass.superTypes.size());
Assert.assertEquals("B", aClass.superTypes.get(0).path);
Assert.assertEquals(PackageableElementType.CLASS, aClass.superTypes.get(0).type);
Assert.assertNotNull(aClass.superTypes.get(0).sourceInformation);
Assert.assertEquals(1, aClass.superTypes.get(0).sourceInformation.startLine);
Assert.assertEquals(71, aClass.superTypes.get(0).sourceInformation.startColumn);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.finos.legend.engine.protocol.pure.v1.model.SourceInformation;

import com.fasterxml.jackson.databind.util.StdConverter;
import java.util.Objects;
import org.finos.legend.engine.protocol.pure.v1.model.SourceInformation;

public class PackageableElementPointer
{
Expand Down Expand Up @@ -81,6 +81,15 @@ public int hashCode()
{
return Objects.hash(type, path);
}

public static class ToPathSerializerConverter extends StdConverter<PackageableElementPointer, String>
{
@Override
public String convert(PackageableElementPointer value)
{
return value.path;
}
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.finos.legend.engine.protocol.pure.v1.model.context.PackageableElementPointer;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.PackageableElement;
import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.PackageableElementVisitor;

Expand All @@ -22,7 +24,8 @@

public class Class extends PackageableElement
{
public List<String> superTypes = Collections.emptyList();
@JsonSerialize(contentConverter = PackageableElementPointer.ToPathSerializerConverter.class)
public List<PackageableElementPointer> superTypes = Collections.emptyList();
public List<Property> originalMilestonedProperties = Collections.emptyList();
public List<Property> properties = Collections.emptyList();
public List<QualifiedProperty> qualifiedProperties = Collections.emptyList();
Expand Down
Loading

0 comments on commit d5e332d

Please sign in to comment.