diff --git a/documents/RCL.md b/documents/RCL.md index 03898dcb4..8568f5552 100644 --- a/documents/RCL.md +++ b/documents/RCL.md @@ -380,7 +380,7 @@ model factory SWIM yields org.sa.rainbow.^model.^acme.swim.commands.SwimCommandF for org.sa.rainbow.^model.^acme.AcmeModelInstance command load is org.sa.rainbow.^model.^acme.swim.commands.SwimLoadModelCommand - command setDimmer(acme::SwimFam.LoadBalancerT target, int dimmer) + command setDimmer(SwimFam.LoadBalancerT target, int dimmer) is org.sa.rainbow.^model.^acme.swim.commands.SetDimmerCmd; ... } @@ -401,7 +401,7 @@ It is also possible to specify an operation to save a model when Rainbow is fini After this comes the list of operations that the model can produce, e.g.: ``` - command setDimmer(acme::SwimFam.LoadBalancerT target, int dimmer) + command setDimmer(SwimFam.LoadBalancerT target, int dimmer) is org.sa.rainbow.^model.^acme.swim.commands.SetDimmerCmd; ``` @@ -409,8 +409,8 @@ The first part is the name of the operation (which may be referred to by gauges effectors), e.g., _setDimmer_. Following this are the parameters for the operation. The first argument may be a **target** which specifies the kind of model element that the operation is defined on. The following list of arguments specify the operation paramters. -Operation argument types can refer to Acme types (by prefixing the type name with **acme::*, -Java types, or builtin types like **int**, **String**, etc.). Finally, the operation +Operation argument types can refer to Acme types, +Java types, or builtin types like **int**, **String**, etc. Finally, the operation specifies the implementing class for the operation. ## Probe Specifications diff --git a/ide/org.acme.xtext.parent/org.acme.xtext.tests/META-INF/MANIFEST.MF b/ide/org.acme.xtext.parent/org.acme.xtext.tests/META-INF/MANIFEST.MF new file mode 100644 index 000000000..160ad9eea --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext.tests/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.acme.xtext.tests +Bundle-ManifestVersion: 2 +Bundle-Name: org.acme.xtext.tests +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: org.acme.xtext.tests;singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: org.acme.xtext;bundle-version="1.0.0", + org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)", + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/ide/org.acme.xtext.parent/org.acme.xtext.tests/build.properties b/ide/org.acme.xtext.parent/org.acme.xtext.tests/build.properties new file mode 100644 index 000000000..5c6bbf99f --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext.tests/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/ide/org.acme.xtext.parent/org.acme.xtext.tests/pom.xml b/ide/org.acme.xtext.parent/org.acme.xtext.tests/pom.xml new file mode 100644 index 000000000..1af446cd7 --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext.tests/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + org.acme.xtext + org.acme.xtext.parent + 1.0.0-SNAPSHOT + + org.acme.xtext.tests + eclipse-test-plugin + + + + + org.eclipse.xtend + xtend-maven-plugin + + + + + \ No newline at end of file diff --git a/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeCompoundPropertyTest.xtend b/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeCompoundPropertyTest.xtend new file mode 100644 index 000000000..fbf75d63d --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeCompoundPropertyTest.xtend @@ -0,0 +1,176 @@ +package org.acme.xtext.tests + +import com.google.inject.Inject +import org.acme.acme.AcmeCompUnit +import org.acme.acme.AcmePackage +import org.acme.validation.Diagnostics +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.XtextRunner +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.Test +import org.junit.runner.RunWith + +import static org.junit.Assert.assertNotNull + +@RunWith(XtextRunner) +@InjectWith(AcmeInjectorProvider) +class AcmeCompoundPropertyTest { + @Inject extension ParseHelper parserHelper + + @Inject extension ValidationTestHelper + + @Test + def void testSetWrongType() { + ''' + system s = { + property prop : set{string} = {"hello", 1}; + } + '''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testSetOK() { + ''' + system s = { + property prop : set{string} = {"hello", "there"}; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testSetOfSetWrongType() { + ''' + system s = { + property prop : set{set{double}} = {{"hello", 1}, {1.2, 3.4, 5.6, 7.8}}; + } + '''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testSetOfSetOK() { + ''' + system s = { + property prop : set{set{double}} = {{1,2,3}, {1.2, 3.4, 5.6, 7.8}}; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testSeqWrongType() { + ''' + system s = { + property prop : seq = <"hello", 1>; + } + '''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testSeqOK() { + ''' + system s = { + property prop : seq = <"hello", "there">; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testRecordSameOrderOK() { + ''' + system s = { + property prop : record[field1 : int; field2 : string;] = [field1=1; field2="hello";]; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testRecordDifferentOrderOK() { + ''' + system s = { + property prop : record[field1 : int; field2 : string;] = [field2="hello";field1=1;]; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testRecordDifferentOrderFailType() { + ''' + system s = { + property prop : record[field1 : int; field2 : string;] = [field2="hello";field1=1.2;]; + } + '''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testRecordDifferentOrderSubFeldTypeOK() { + ''' + system s = { + property prop : record[field1 : float; field2 : string;] = [field2="hello";field1=1;]; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void textRecordInRecordDifferentOrderSubFieldTypeOK() { + ''' + system s = { + property prop : record[ + a:record[a : float; + b : string; + ]; + b: any;] = + [a = [a = 1; b = "me";]; b = false;]; + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void textRecordInRecordDifferentOrderSubFieldTypeFail() { + ''' + system s = { + property prop : record[ + a:record[a : float; + b : string; + ]; + b: any;] = + [a = [a = 1; b = false;]; b = false;]; + } + '''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } +} diff --git a/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeSimpleInstancePropertyTest.xtend b/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeSimpleInstancePropertyTest.xtend new file mode 100644 index 000000000..5f589ea82 --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext.tests/src/org/acme/xtext/tests/AcmeSimpleInstancePropertyTest.xtend @@ -0,0 +1,296 @@ +package org.acme.xtext.tests + +import com.google.inject.Inject +import org.acme.acme.AcmeCompUnit +import org.acme.acme.AcmePackage +import org.acme.acme.AcmePropertyDeclaration +import org.acme.validation.Diagnostics +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.XtextRunner +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.Test +import org.junit.runner.RunWith + +import static org.junit.Assert.assertNotNull + +@RunWith(XtextRunner) +@InjectWith(AcmeInjectorProvider) +class AcmeSimpleInstancePropertyTest { + + @Inject extension ParseHelper parserHelper + + @Inject extension ValidationTestHelper + + @Test + def void testPropertyIntInInstance() { + ''' + system sys = { + property prop : int = 2; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyStringInInstance() { + ''' + system sys = { + property prop : String = "foo"; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyBooleanInInstance() { + ''' + system sys = { + property prop : boolean = true; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyFloatWFloatInInstance() { + ''' + system sys = { + property prop : float = 1.23; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyFloatWIntInInstance() { + ''' + system sys = { + property prop : float = 1; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyDoubleWFloatInInstance() { + ''' + system sys = { + property prop : double = 1.23; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyDoubleWIntInInstance() { + ''' + system sys = { + property prop : double = 1; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyAnyInInstance() { + ''' + system sys = { + property prop : any = 1; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyIntInSuperType() { + ''' + family fam = { + property prop : int; + } + + system sys : fam = new fam extended with { + property prop = 2; + }'''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + @Test + def void testPropertyWrongValue() { + ''' + system sys = { + property prop : string = 1; + }'''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testPropertyWrongValueST() { + ''' + family fam = { + property prop : string; + } + + system sys : fam = new fam extended with { + property prop = 1; + }'''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.TYPES_INCOMPATIBLE) + ] + } + + @Test + def void testUnificationError() { + ''' + family fam = { + property prop : string; + } + + system sys : fam = new fam extended with { + property prop : int = 1; + }'''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.UNIFICATION_ERROR) + ] + } + + @Test + def void testUnificationErrorTyping() { + ''' + family fam1 = { + property prop : string; + } + + family fam2 extends fam1 with { + property prop : int; + }'''.parse => [ + assertNotNull(it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.UNIFICATION_ERROR) + ] + } + + @Test + def void testNoProblemWithPropertyInComponent() { + ''' + system sys = { + property prop : string = "foo"; + component comp = { + property prop : int = 1; + } + } + '''.parse => [ + assertNotNull(it) + assertNoErrors + ] + } + + def generateElementPropertyUnificationTest(boolean ok, boolean portOrRole, String... element) ''' + family fam = { + «element.get(portOrRole?1:0)» type compt = { + property prop : int = 1; + } + } + system sys : fam = new fam extended with { + «IF portOrRole» + «element.get(0)» comp = { + «element.get(1)» sub : compt = new compt extended with { + «IF ok» + property prop : int = 1; + «ELSE» + property prop : string = "hello"; + «ENDIF» + } + } + + «ELSE» + «element.get(0)» comp : compt = new compt extended with { + «IF ok» + property prop : int = 1; + «ELSE» + property prop : string="hello"; + «ENDIF» + } + «ENDIF» + } + ''' + + @Test + def void testComponentUnificationError() { + val submap = #{'component' -> 'port', 'connector' -> 'role'} + + for (element : #{'component', 'connector', 'group'}) { + var toParse = generateElementPropertyUnificationTest(true, false, element) + toParse.parse => [ + assertNotNull('''«element» test failed to parse''', it) + assertNoErrors() + ] + toParse = generateElementPropertyUnificationTest(false, false, element) + toParse.parse => [ + assertNotNull('''«element» test failed to parse''', it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.UNIFICATION_ERROR) + + ] + if (submap.containsKey(element)) { + val sub = submap.get(element) + toParse = generateElementPropertyUnificationTest(true, true, element, sub) + toParse.parse => [ + assertNotNull('''«sub» test failed to parse''', it) + assertNoErrors() + ] + toParse = generateElementPropertyUnificationTest(false, true, element, sub) + toParse.parse => [ + assertNotNull('''«sub» test failed to parse''', it) + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.UNIFICATION_ERROR) + ] + } + } + } + + @Test + def testUnificationErrorsOfAllTypes() { + val types =#{'int'->'20', 'boolean' -> 'false', 'string' -> '"foobar"', 'float'->'1.23', 'double' -> '4.56'} + + for (e1 : types.entrySet) { + for (e2 : types.entrySet) { + ''' + family fam = { + component type compt = { + property prop : «e1.key» = «e1.value»; + } + + component comp : compt = new compt extended with { + property prop : «e2.key» = «e2.value»; + } + }'''.parse => [ + try { + assertNotNull('''«e1.key»X«e2.key»''') + if (e1.key != e2.key) { + assertError(AcmePackage::eINSTANCE.acmePropertyDeclaration, Diagnostics.UNIFICATION_ERROR) + } + else { + assertNoErrors + } + } + catch (Exception e) { + System.out.println('''Failed «e1.key»X«e2.key»''') + throw e; + } + ] + } + } + } + +} diff --git a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/AcmeRuntimeModule.xtend b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/AcmeRuntimeModule.xtend index 67545e689..033d1306c 100644 --- a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/AcmeRuntimeModule.xtend +++ b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/AcmeRuntimeModule.xtend @@ -5,6 +5,8 @@ package org.acme import org.acme.scoping.QualifiedNameProvider import org.acme.scoping.AcmeScopeProvider +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.linking.lazy.LazyLinkingResource /** * Use this class to register components to be used at runtime / without the Equinox extension registry. @@ -19,4 +21,8 @@ class AcmeRuntimeModule extends AbstractAcmeRuntimeModule { AcmeScopeProvider } +// override bindXtextResource() { +// return AcmeLazyLinkingResource; +// } + } diff --git a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/scoping/AcmeScopeProvider.xtend b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/scoping/AcmeScopeProvider.xtend index 7ea4b99d0..225ba2d5a 100644 --- a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/scoping/AcmeScopeProvider.xtend +++ b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/scoping/AcmeScopeProvider.xtend @@ -44,7 +44,7 @@ class AcmeScopeProvider extends AbstractAcmeScopeProvider { eGet as String } catch (IllegalArgumentException e) { - target.eGet(AcmePackage.Literals.ACME_ELEMENT_TYPE_DECLARATION__NAME) as String + target.eGet(AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME) as String } } @@ -59,42 +59,42 @@ class AcmeScopeProvider extends AbstractAcmeScopeProvider { context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.portTypes + f.body.elementTypes], - [EObject p|getNameWithElementTypes(p, AcmePackage.Literals.ACME_PORT_TYPE_DECLARATION__NAME)] + [EObject p|getNameWithElementTypes(p, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeRoleTypeDeclaration: addFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.roleTypes + f.body.elementTypes], - [EObject r|getNameWithElementTypes(r, AcmePackage.Literals.ACME_ROLE_TYPE_DECLARATION__NAME)] + [EObject r|getNameWithElementTypes(r, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeComponentTypeDeclaration: addFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.componentTypes + f.body.elementTypes], - [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_COMPONENT_TYPE_DECLARATION__NAME)] + [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeConnectorTypeDeclaration: addFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.connectorTypes + f.body.elementTypes], - [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_CONNECTOR_TYPE_DECLARATION__NAME)] + [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeGroupTypeDeclaration: addFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.groupTypes + f.body.elementTypes], - [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_GROUP_TYPE_DECLARATION__NAME)] + [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeElementTypeDeclaration: addFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.elementTypes], - [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_ELEMENT_TYPE_DECLARATION__NAME)] + [EObject c|getNameWithElementTypes(c, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmePropertyTypeDeclaration: addFamiliesToScope( @@ -108,35 +108,35 @@ class AcmeScopeProvider extends AbstractAcmeScopeProvider { context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.portTypes + f.body.elementTypes], - [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_PORT_TYPE_DECLARATION__NAME)] + [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeRoleDeclaration: addSystemFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.roleTypes + f.body.elementTypes], - [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ROLE_TYPE_DECLARATION__NAME)] + [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeComponentDeclaration: addSystemFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.componentTypes + f.body.elementTypes], - [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_COMPONENT_TYPE_DECLARATION__NAME)] + [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeConnectorDeclaration: addSystemFamiliesToScope( context, super.getScope(context, reference), [AcmeFamilyDeclaration f|f.body.connectorTypes + f.body.elementTypes], - [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_CONNECTOR_TYPE_DECLARATION__NAME)] + [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmeGroupDeclaration: addSystemFamiliesToScope( context, super.getScope(context, reference), - [AcmeFamilyDeclaration f|f.body.portTypes + f.body.elementTypes], - [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_GROUP_DECLARATION__NAME)] + [AcmeFamilyDeclaration f|f.body.groupTypes + f.body.elementTypes], + [EObject e|getNameWithElementTypes(e, AcmePackage.Literals.ACME_ELEMENT_TYPE__NAME)] ) AcmePropertyDeclaration: addSystemFamiliesToScope( @@ -248,5 +248,7 @@ class AcmeScopeProvider extends AbstractAcmeScopeProvider { } } + + } diff --git a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/AcmeValidator.xtend b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/AcmeValidator.xtend index 5784bb518..512a4306d 100644 --- a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/AcmeValidator.xtend +++ b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/AcmeValidator.xtend @@ -3,14 +3,57 @@ */ package org.acme.validation +import java.util.Collection +import java.util.Collections +import java.util.Comparator +import java.util.LinkedHashSet +import java.util.List +import java.util.regex.Pattern +import org.acme.acme.AcmeComponentDeclaration +import org.acme.acme.AcmeComponentTypeDeclaration +import org.acme.acme.AcmeConnectorDeclaration +import org.acme.acme.AcmeConnectorTypeDeclaration +import org.acme.acme.AcmeElementInstance +import org.acme.acme.AcmeElementType +import org.acme.acme.AcmeElementTypeDeclaration +import org.acme.acme.AcmeFactory +import org.acme.acme.AcmeFamilyDeclaration +import org.acme.acme.AcmeGroupDeclaration +import org.acme.acme.AcmeGroupTypeDeclaration +import org.acme.acme.AcmePackage +import org.acme.acme.AcmePortDeclaration +import org.acme.acme.AcmePortTypeDeclaration +import org.acme.acme.AcmePropertyDeclaration +import org.acme.acme.AcmePropertyRecord +import org.acme.acme.AcmePropertyRecordEntry +import org.acme.acme.AcmePropertyRecordFieldDescription +import org.acme.acme.AcmePropertySequence +import org.acme.acme.AcmePropertySet +import org.acme.acme.AcmePropertyTypeRecord +import org.acme.acme.AcmePropertyTypeRef +import org.acme.acme.AcmePropertyTypeSequence +import org.acme.acme.AcmePropertyTypeSet +import org.acme.acme.AcmePropertyValueDeclaration +import org.acme.acme.AcmeRoleDeclaration +import org.acme.acme.AcmeRoleTypeDeclaration +import org.acme.acme.AcmeSystemDeclaration +import org.acme.acme.BooleanLiteral +import org.acme.acme.FloatLiteral +import org.acme.acme.IntegerLiteral +import org.acme.acme.PrimitivePropertyType +import org.acme.acme.PropertyBearer +import org.acme.acme.StringLiteral +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.validation.Check /** * This class contains custom validation rules. - * + * * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation */ class AcmeValidator extends AbstractAcmeValidator { - + // public static val INVALID_NAME = 'invalidName' // // @Check @@ -21,5 +64,466 @@ class AcmeValidator extends AbstractAcmeValidator { // INVALID_NAME) // } // } + @Check + def propertyValueMatchesType(AcmePropertyDeclaration decl) { + val unifiedProperty = unifyPropertyDeclarationWithSuperTypes(decl) + if (unifiedProperty.type !== null) { + if (unifiedProperty.^val !== null) { + val t = unifiedProperty.type.rootType + val checks = switch t { + case PrimitivePropertyType.INT.name(): + unifiedProperty.^val.value instanceof IntegerLiteral + case PrimitivePropertyType.FLOAT.name(): + unifiedProperty.^val.value instanceof FloatLiteral || + unifiedProperty.^val.value instanceof IntegerLiteral + case PrimitivePropertyType.ANY.name(): + true + case PrimitivePropertyType.DOUBLE.name(): + unifiedProperty.^val.value instanceof FloatLiteral || + unifiedProperty.^val.value instanceof IntegerLiteral + case PrimitivePropertyType.STRING.name(): + unifiedProperty.^val.value instanceof StringLiteral + case PrimitivePropertyType.BOOLEAN.name(): + unifiedProperty.^val.value instanceof BooleanLiteral + case t.startsWith("set"): { + val value = unifiedProperty.^val.value; + value instanceof AcmePropertySet && + setTypesCompatible((value as AcmePropertySet).inferredTypeString, t) + + } + case t.startsWith("seq"): { + val value = unifiedProperty.^val.value; + value instanceof AcmePropertySequence && + seqTypesCompatible((value as AcmePropertySequence).inferredTypeString, t) + } + case t.startsWith('record'): { + val value = unifiedProperty.^val.value; + value instanceof AcmePropertyRecord && + recordTypesCompatible((value as AcmePropertyRecord).inferredTypeString, t) + } + default: + false + } + if (!checks) { + error( + '''The value of «decl.name» does not typecheck''', + decl, + AcmePackage.Literals.ACME_PROPERTY_DECLARATION__VAL, + Diagnostics.TYPES_INCOMPATIBLE + ) + } + } else if (EcoreUtil2.getContainerOfType(decl, AcmeElementInstance) !== null) { + error('''The property «decl.name» must have a value''', decl, + AcmePackage.Literals.ACME_PROPERTY_DECLARATION__NAME, Diagnostics.NO_PROPERTY_VALUE) + } + } + + } + + def boolean typesCompatibleByString(String check, String against) { + switch against { + case PrimitivePropertyType.INT.name(): + check == PrimitivePropertyType.INT.name() + case PrimitivePropertyType.FLOAT.name(): + check == PrimitivePropertyType.INT.name() || check == PrimitivePropertyType.FLOAT.name() + case PrimitivePropertyType.DOUBLE.name(): + check == PrimitivePropertyType.INT.name() || check == PrimitivePropertyType.FLOAT.name() || + check == PrimitivePropertyType.DOUBLE.name() + case PrimitivePropertyType.BOOLEAN.name(): + check == PrimitivePropertyType.BOOLEAN.name() + case PrimitivePropertyType.STRING.name(): + check == PrimitivePropertyType.STRING.name() + case PrimitivePropertyType.ANY.name(): true + case against.startsWith('set'): + check.startsWith('set') && setTypesCompatible(check, against) + case against.startsWith('seq'): + check.startsWith('seq') && seqTypesCompatible(check, against) + case against.startsWith('record'): + check.startsWith('record') && recordTypesCompatible(check, against) + default: + throw new UnsupportedOperationException("unknown type") + } + } + static val RECORD_PATTERN = Pattern.compile("record\\[(.*)\\]"); + + def boolean recordTypesCompatible(String check, String against) { + var checkPart = check + var againstPart = against + if (check == against) return true; + if (check.startsWith('record') && against.startsWith('record')) { + checkPart = check.substring(0, check.length - 1).substring('record['.length) + var matcher = RECORD_PATTERN.matcher(checkPart) + var cp = "" + while (matcher.find) { + cp = Pattern.quote(matcher.group(1)) + checkPart = checkPart.replaceAll(cp, matcher.group(1).replaceAll("\\|", "&")); + } + val checkFields = checkPart.split("\\|") + + againstPart = against.substring(0, against.length - 1).substring('record['.length) + matcher = RECORD_PATTERN.matcher(againstPart) + while (matcher.find) { + cp = Pattern.quote(matcher.group(1)) + againstPart = againstPart.replaceAll(cp, matcher.group(1).replaceAll("\\|", "&")); } + val againstFields = againstPart.split("\\|") + + if (againstFields.length != checkFields.length) return false; + + for (var i = 0; i < againstFields.length; i++) { + var af = againstFields.get(i) + var cf = checkFields.get(i) + var ai = af.indexOf(':') + var ci = cf.indexOf(':') + val an = af.substring(0, ai) + val cn = cf.substring(0, ci) + if (an != cn) return false; + + if (!typesCompatibleByString(cf.substring(ci+1).replaceAll("&","|"), af.substring(ai+1).replaceAll("&","|"))) { + return false; + } + + } + return true; + + } + return false; + } + + def boolean seqTypesCompatible(String check, String against) { + var checkPart = check + var againstPart = against + if (check.startsWith('seq') && against.startsWith('seq')) { + checkPart = check.substring(0, check.length - 1).substring('seq<'.length) + againstPart = against.substring(0, against.length - 1).substring('seq<'.length) + return typesCompatibleByString(checkPart, againstPart) + } + return false + } + + def boolean setTypesCompatible(String check, String against) { + var checkPart = check + var againstPart = against + if (check.startsWith('set') && against.startsWith('set')) { + checkPart = check.substring(0, check.length - 1).substring('set{'.length) + againstPart = against.substring(0, against.length - 1).substring('set{'.length) + return typesCompatibleByString(checkPart, againstPart) + } + return false + } + + + + def inferMostCommonPropertyType(Collection list) { + var String type = null + for (v : list) { + val typeofV = getTypeOf(v) + if (type === null) + type = typeofV + else if (type != typeofV) { + type = inferMostCommonPropertyTypeFromString(type, typeofV) + } + } + type + } + + protected def String inferMostCommonPropertyTypeFromString(String type, String typeofV) { + var ret = type; + if (type == PrimitivePropertyType.INT.name() && typeofV == PrimitivePropertyType.FLOAT.name()) { + ret = PrimitivePropertyType.FLOAT.name() + } else if (type == PrimitivePropertyType.INT.name() && typeofV == PrimitivePropertyType.DOUBLE.name()) { + ret = PrimitivePropertyType.DOUBLE.name() + } else if (type == PrimitivePropertyType.FLOAT.name() && typeofV == PrimitivePropertyType.DOUBLE.name()) { + ret == typeofV == PrimitivePropertyType.DOUBLE.name() + } else if (type.startsWith('set') && typeofV.startsWith('set')) { + val tContents = type.substring(0, type.length - 1).substring('set{'.length) + val vContents = typeofV.substring(0, typeofV.length - 1).substring('set{'.length) + ret = "set{" + inferMostCommonPropertyTypeFromString(tContents, vContents) + "}" + } else if (type.startsWith('seq') && typeofV.startsWith('seq')) { + val tContents = type.substring(0, type.length - 1).substring('seq<'.length) + val vContents = typeofV.substring(0, typeofV.length - 1).substring('seq<'.length) + ret = "seq<" + inferMostCommonPropertyTypeFromString(tContents, vContents) + ">" + } else if (type.startsWith('record') && typeofV.startsWith('record')) { + throw new UnsupportedOperationException("Records not supported") + } else { + ret = PrimitivePropertyType.ANY.name() + } + ret + } + + def getTypeOf(AcmePropertyValueDeclaration declaration) { + val value = declaration.value + switch value { + IntegerLiteral: PrimitivePropertyType.INT.name() + FloatLiteral: PrimitivePropertyType.FLOAT.name() + BooleanLiteral: PrimitivePropertyType.BOOLEAN.name() + StringLiteral: PrimitivePropertyType.STRING.name() + AcmePropertySet: value.getInferredTypeString + AcmePropertySequence: value.getInferredTypeString + AcmePropertyRecord: value.getInferredTypeString + default: throw new UnsupportedOperationException("Unknown property value") + } + } + + def void collectSuperTypes(AcmeElementType type, LinkedHashSet types, boolean reversed) { + switch type { + AcmeComponentTypeDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + collectSuperTypes(it, types, reversed) + if(reversed) types.add(it) + ] + AcmeConnectorTypeDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + ] + AcmeGroupTypeDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + ] + AcmeRoleTypeDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + ] + AcmePortTypeDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + ] + AcmeFamilyDeclaration: + type.refs.forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + ] + } + } + + def getAllInstantiated(AcmeElementInstance e, boolean reversed) { + val LinkedHashSet types = new LinkedHashSet() + switch e { + AcmeComponentDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it as AcmeElementType) + collectSuperTypes(it as AcmeElementType, types, reversed) + if(reversed) types.add(it as AcmeElementType) + + ] + AcmeSystemDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it) + it.collectSuperTypes(types, reversed) + if(reversed) types.add(it) + + ] + AcmeConnectorDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it as AcmeElementType) + (it as AcmeElementType).collectSuperTypes(types, reversed) + if(reversed) types.add(it as AcmeElementType) + + ] + AcmeGroupDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it as AcmeElementType) + (it as AcmeElementType).collectSuperTypes(types, reversed) + if(reversed) types.add(it as AcmeElementType) + + ] + AcmePortDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it as AcmeElementType) + (it as AcmeElementType).collectSuperTypes(types, reversed) + if(reversed) types.add(it as AcmeElementType) + + ] + AcmeRoleDeclaration: + e.instantiated.filter[it instanceof AcmeElementType].forEach [ + if(!reversed) types.add(it as AcmeElementType) + (it as AcmeElementType).collectSuperTypes(types, reversed) + if(reversed) types.add(it as AcmeElementType) + + ] + } + types + } + + def unifyPropertyDeclarationWithSuperTypes(AcmePropertyDeclaration declaration) { + val prop = AcmeFactory.eINSTANCE.createAcmePropertyDeclaration() + prop.name = declaration.name + var e = EcoreUtil2.getContainerOfType(declaration, AcmeElementInstance) + + var LinkedHashSet superTypes = new LinkedHashSet() + + if (e !== null) { + superTypes = getAllInstantiated(e, true) + + } else { + val t = EcoreUtil2.getContainerOfType(declaration, AcmeElementType) + if (t !== null) { + collectSuperTypes(t, superTypes, true) + + } + } + + superTypes.map[it.body?.properties]?.flatten.filter[it.name == declaration.name].forEach [ + checkUnifiableProperty(prop, it, declaration) + ] + checkUnifiableProperty(prop, declaration, declaration) + prop + } + + def getTypeName(AcmePropertyTypeRef type) { + if (type.ref !== null) + type.ref.name + else if (type.structure != null) { + if (type.structure.primitive !== null) + type.structure.primitive.name() + else if (type.structure.num !== null) + "enum" + else if (type.structure.structure !== null) { + switch type.structure.structure { + AcmePropertyTypeRecord: "record [...]" + AcmePropertyTypeSet: "set {...}" + AcmePropertyTypeSequence: "seq <...>" + default: "???" + } + } + + } else { + "???" + } + } + +// def copy(AcmePropertyTypeRef ref) { +// val type = AcmeFactory.eINSTANCE.createAcmePropertyTypeRef +// if (ref.ref != null) type.ref = ref.ref +// else if (ref.structure !== null) { +// type.structure = AcmeFactory.eINSTANCE.createAcmePropertyTypeStructure +// if (ref.structure.primitive !== null) { +// type.structure.primitive = ref.structure.primitive +// } +// else if (ref.structure.structure != null) { +// val struct = ref.structure.structure +// switch struct { +// AcmePropertyTypeRecord: +// } +// } +// } +// type +// } + protected def void checkUnifiableProperty(AcmePropertyDeclaration prop, AcmePropertyDeclaration candidate, + AcmePropertyDeclaration declaration) { + if (prop.type === null) + prop.type = EcoreUtil2.copy(candidate.type) + else if (candidate.type !== null && prop.type?.rootType != candidate.type?.rootType) { + error( + '''The type «candidate.name» cannot be unified with «declaration.name» because «candidate.type.typeName» is not compatible wth «prop.type.typeName»''', + declaration, + declaration.type === null ? AcmePackage.Literals.ACME_PROPERTY_DECLARATION__NAME : AcmePackage.Literals. + ACME_PROPERTY_DECLARATION__TYPE, + Diagnostics.UNIFICATION_ERROR + ) + } + + if (prop.^val === null) + prop.^val = EcoreUtil2.copy(candidate.^val) + else if (!EcoreUtil.equals(prop.^val.value, candidate.^val.value)) { + error( + '''The value for «declaration.name» cannot be unified because it is given a different value in a supertype''', + declaration, + declaration.^val === null ? AcmePackage.Literals.ACME_PROPERTY_DECLARATION__NAME : AcmePackage.Literals. + ACME_PROPERTY_DECLARATION__VAL, + Diagnostics.UNIFICATION_ERROR + ) + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + // Extension Methods + + def String getInferredTypeString(AcmePropertySet set) { + '''set{«inferMostCommonPropertyType(set.values)»}''' + } + + def String getInferredTypeString(AcmePropertySequence seq) { + '''seq<«inferMostCommonPropertyType(seq.values)»>''' + } + + def String getInferredTypeString(AcmePropertyRecord req) { + val List fields = newLinkedList + for (f : req.fields) { + fields.add(f) + } + Collections.sort(fields, new Comparator () { + + override compare(AcmePropertyRecordEntry o1, AcmePropertyRecordEntry o2) { + return o1.name.compareTo(o2.name) + } + + }) + val sortedFieldsInferred = fields.map [ + '''«it.name»:«IF it.ref===null»«getTypeOf(it.value)»«ELSE»«it.ref.rootType»«ENDIF»''' + ].join("|") + + '''record[«sortedFieldsInferred»]''' + } + + def String getRootType(AcmePropertyTypeRef ref) { + if (ref.structure === null) + ref.ref.type.rootType + else if (ref.structure.primitive !== null && (ref.structure.primitive != PrimitivePropertyType.NOT_PRIMITIVE)) + ref.structure.primitive.name() + else if (ref.structure.structure !== null) { + val structure = ref.structure.structure + switch structure { + AcmePropertyTypeRecord: { + val List sortedFields = newLinkedList + for (f : structure.fields) { + sortedFields.add(f) + } + Collections.sort(sortedFields, new Comparator () { + + override compare(AcmePropertyRecordFieldDescription o1, AcmePropertyRecordFieldDescription o2) { + return o1.name.compareTo(o2.name) + } + + }) + '''record[«sortedFields.map[it.name + ":" + it.type.rootType].join("|")»]''' + } + + AcmePropertyTypeSet: '''set{«structure.type.rootType»}''' + AcmePropertyTypeSequence: '''seq<«structure.type.rootType»>''' + } + } else if (ref.structure.num !== null) { + '''enum{«ref.structure.num.values.join(",")»}''' + } else { + throw new UnsupportedOperationException("Unknown property type referenced") + } + } + + def void getRootName(AcmePropertyTypeRef ref) { + ref.ref.type === null ? ref.ref.name : ref.ref.type.rootName + } + + def PropertyBearer getBody(AcmeElementType type) { + switch type { + AcmeElementTypeDeclaration: type.body + AcmeFamilyDeclaration: type.body + AcmeComponentTypeDeclaration: type.body + AcmeConnectorTypeDeclaration: type.body + AcmeGroupTypeDeclaration: type.body + AcmePortTypeDeclaration: type.body + AcmeRoleTypeDeclaration: type.body + default: null + } + } + } diff --git a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/Diagnostics.java b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/Diagnostics.java new file mode 100644 index 000000000..059bf6d50 --- /dev/null +++ b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/validation/Diagnostics.java @@ -0,0 +1,8 @@ +package org.acme.validation; + +public interface Diagnostics { + public static final String TYPES_INCOMPATIBLE = "Incompatible Types"; + public static final String NO_PROPERTY_VALUE = "No Property Value"; + public static final String UNIFICATION_ERROR = "Unification error"; + +} diff --git a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/xtext/Acme.xtext b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/xtext/Acme.xtext index e10311cec..2c05971b6 100644 --- a/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/xtext/Acme.xtext +++ b/ide/org.acme.xtext.parent/org.acme.xtext/src/org/acme/xtext/Acme.xtext @@ -55,7 +55,21 @@ AcmeFamilyBody: )* '}' ; +PropertyBearer: + AcmeFamilyBody | AcmeSystemBody | AcmeComponentBody | AcmeConnectorBody | AcmePortBody | AcmeRoleBody | AcmeGroupBody | AcmeGenericElementBody +; + +AcmeElementInstance: + AcmeSystemDeclaration | AcmeComponentDeclaration | AcmeConnectorDeclaration | + AcmePortDeclaration | AcmeRoleDeclaration | AcmeGroupDeclaration +; +AcmeElementType: + AcmeElementTypeDeclaration | AcmeFamilyDeclaration | AcmeComponentTypeDeclaration | + AcmeConnectorTypeDeclaration | + AcmePortTypeDeclaration | AcmeRoleTypeDeclaration | + AcmeGroupTypeDeclaration +; AcmeSystemDeclaration: 'system' name=ID (':' declared+=[AcmeFamilyDeclaration] (',' declared+=[AcmeFamilyDeclaration])*)? @@ -166,7 +180,7 @@ MembersBlock: ; ElementsRef: - AcmeComponentDeclaration | AcmePortDeclaration | AcmeConnectorDeclaration | AcmeRoleDeclaration + AcmeComponentDeclaration | AcmePortDeclaration | AcmeConnectorDeclaration | AcmeRoleDeclaration ; QualifiedIdentifier returns ecore::EString: @@ -344,7 +358,7 @@ AcmeConnectorDeclaration: ; ConnectorOrGenericRef: - AcmeElementTypeDeclaration|AcmeConnectorTypeDeclaration + (AcmeElementTypeDeclaration|AcmeConnectorTypeDeclaration) ; AcmeConnectorBody: @@ -376,7 +390,7 @@ AcmeBindingDeclaration: ; PortOrRoleRef: - AcmePortDeclaration | AcmeRoleDeclaration + (AcmePortDeclaration | AcmeRoleDeclaration) ; AcmeAttachmentDeclaration: @@ -389,7 +403,7 @@ AcmeAttachmentDeclaration: AcmePropertyDeclaration: 'property' name=ID - (':' type+=AcmePropertyTypeRef)? + (':' type=AcmePropertyTypeRef)? ( '=' val=AcmePropertyValueDeclaration | 'U=' val=AcmePropertyValueDeclaration @@ -445,11 +459,11 @@ AcmePropertySet: ; AcmePropertySequence: - {AcmePropertySet} '<' (values+=AcmePropertyValueDeclaration (',' values+=AcmePropertyValueDeclaration)*)? '>' + {AcmePropertySequence} '<' (values+=AcmePropertyValueDeclaration (',' values+=AcmePropertyValueDeclaration)*)? '>' ; AcmePropertyRecordEntry: - name=ID (':' ref=AcmePropertyTypeDeclaration)? '=' value=AcmePropertyValueDeclaration + name=ID (':' ref=AcmePropertyTypeRef)? '=' value=AcmePropertyValueDeclaration ; AcmePropertyRecord: @@ -465,11 +479,11 @@ AcmePropertyTypeSet: ; AcmePropertyTypeSequence: - {AcmePropertyTypeSequence} ('seq' | 'sequence') '<' type=AcmePropertyTypeRef? '}' + {AcmePropertyTypeSequence} ('seq' | 'sequence') '<' type=AcmePropertyTypeRef? '>' ; AcmePropertyTypeEnum: - 'enum' '{' ID (',' ID)* '}' + 'enum' '{' values+=ID (',' values+=ID)* '}' ; AcmePropertyRecordFieldDescription: @@ -483,6 +497,7 @@ AcmePropertyTypeRef: enum PrimitivePropertyType: + NOT_PRIMITIVE="$__NotPrimitive__$" | INT='int' | FLOAT='float' | ANY='any' | DOUBLE='double' | STRING='string' | BOOLEAN='boolean' ; diff --git a/ide/org.acme.xtext.parent/pom.xml b/ide/org.acme.xtext.parent/pom.xml index f7c76fc81..39bf63c84 100644 --- a/ide/org.acme.xtext.parent/pom.xml +++ b/ide/org.acme.xtext.parent/pom.xml @@ -25,6 +25,7 @@ org.acme.xtext.ui org.acme.xtext.target org.acme.xtext.feature + org.acme.xtext.tests org.acme.xtext.repository diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/ModelUtil.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/ModelUtil.xtend index 7f58c3cd2..ac1aab086 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/ModelUtil.xtend +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/ModelUtil.xtend @@ -2,6 +2,7 @@ package org.sa.rainbow.configuration import java.util.Collection import java.util.List +import org.eclipse.xtext.common.types.JvmType import org.sa.rainbow.configuration.rcl.Component import org.sa.rainbow.configuration.rcl.ComponentType import org.sa.rainbow.configuration.rcl.DeclaredProperty @@ -9,6 +10,7 @@ import org.sa.rainbow.configuration.rcl.Factory import org.sa.rainbow.configuration.rcl.FormalParam import org.sa.rainbow.configuration.rcl.PropertyReference import org.sa.rainbow.configuration.rcl.Reference +import org.acme.acme.AnyTypeRef class ModelUtil { @@ -54,13 +56,19 @@ class ModelUtil { } static def getTypeName(FormalParam param) { - if (param.type.acme !== null) { - val ar = param.type.acme.referable - return XtendUtils.getAcmeTypeName(ar) + if (param.type.ref instanceof JvmType) { + return (param.type.ref as JvmType).simpleName } - if (param.type.java != null) { - return param.type.java.referable.simpleName + if (param.type.ref instanceof AnyTypeRef) { + return XtendUtils.getAcmeTypeName((param.type.ref as AnyTypeRef)) } +// if (param.type.acme !== null) { +// val ar = param.type.acme.referable +// return XtendUtils.getAcmeTypeName(ar) +// } +// if (param.type.java != null) { +// return param.type.java.referable.simpleName +// } if (param.type.base !== null) { return param.type.base.getName() } diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/RclRuntimeStandaloneModule.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/RclRuntimeStandaloneModule.xtend index 1c8c1a5a3..9229a3c24 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/RclRuntimeStandaloneModule.xtend +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/RclRuntimeStandaloneModule.xtend @@ -31,7 +31,7 @@ class RclRuntimeStandaloneModule extends RclRuntimeModule { override configure(Binder binder) { super.configure(binder) configureJvmTypeProvider(binder) - if (!EPackage.Registry.INSTANCE.containsKey("http://www.sa.org/rainbow/stitch/Stitch")) { + if (!EPackage.Registry.INSTANCE.containsKey("http://www.sa.org/rainbow/stitch/Stitch")) { EPackage.Registry.INSTANCE.put("http://www.sa.org/rainbow/stitch/Stitch", StitchPackage.eINSTANCE) } diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/XtendUtils.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/XtendUtils.xtend index 62af07d8f..0b507baba 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/XtendUtils.xtend +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/XtendUtils.xtend @@ -1,22 +1,23 @@ package org.sa.rainbow.configuration + /* -Copyright 2020 Carnegie Mellon University + * Copyright 2020 Carnegie Mellon University -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, and to permit - persons to whom the Software is furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ import java.util.Map @@ -33,6 +34,7 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.common.types.JvmDeclaredType import org.eclipse.xtext.common.types.JvmPrimitiveType +import org.eclipse.xtext.common.types.JvmType import org.sa.rainbow.configuration.rcl.Assignment import org.sa.rainbow.configuration.rcl.BooleanLiteral import org.sa.rainbow.configuration.rcl.DeclaredProperty @@ -49,23 +51,38 @@ import org.sa.rainbow.configuration.rcl.RichStringPart import org.sa.rainbow.configuration.rcl.StringLiteral class XtendUtils { - static def formalTypeName(FormalParam fp, boolean keepSimple) { - if (fp.type.java !== null) - keepSimple?fp.type.java.referable.simpleName:fp.type.java.referable.qualifiedName - else if (fp.type.acme !== null) { - switch fp.type.acme.referable { - AcmeComponentTypeDeclaration: return keepSimple?"IAcmeComponent":"org.acmestudio.acme.element.IAcmeComponent" - AcmeConnectorTypeDeclaration: return keepSimple?"IAcmeConnector":"org.acmestudio.acme.element.IAcmeConnector" - AcmePortTypeDeclaration: return keepSimple?"IAcmePort":"org.acmestudio.acme.element.IAcmePort" - AcmeRoleTypeDeclaration: return keepSimple?"IAcmeRole":"org.acmestudio.acme.element.IAcmeRole" - AcmeElementTypeDeclaration: return keepSimple?"IAcmeElement":"org.acmestudio.acme.element.IAcmeElement" - AcmeGroupTypeDeclaration: return keepSimple?"IAcmeGroup":"org.acmestudio.acme.element.IAcmeGroup" - default: return keepSimple?"IAcmeElement":"org.acmestudio.acme.element.IAcmeElement" + static def formalTypeName(FormalParam fp, boolean keepSimple) { + if (fp.type.ref instanceof JvmType) { + keepSimple ? (fp.type.ref as JvmType).simpleName:(fp.type.ref as JvmType).qualifiedName + } + else if (fp.type.ref instanceof AnyTypeRef) { + switch fp.type.ref as AnyTypeRef { + AcmeComponentTypeDeclaration: return keepSimple ? "IAcmeComponent" : "org.acmestudio.acme.element.IAcmeComponent" + AcmeConnectorTypeDeclaration: return keepSimple ? "IAcmeConnector" : "org.acmestudio.acme.element.IAcmeConnector" + AcmePortTypeDeclaration: return keepSimple ? "IAcmePort" : "org.acmestudio.acme.element.IAcmePort" + AcmeRoleTypeDeclaration: return keepSimple ? "IAcmeRole" : "org.acmestudio.acme.element.IAcmeRole" + AcmeElementTypeDeclaration: return keepSimple ? "IAcmeElement" : "org.acmestudio.acme.element.IAcmeElement" + AcmeGroupTypeDeclaration: return keepSimple ? "IAcmeGroup" : "org.acmestudio.acme.element.IAcmeGroup" + default: return keepSimple ? "IAcmeElement" : "org.acmestudio.acme.element.IAcmeElement" } - } - else if(fp.type.base !== null) fp.type.base.name() +// } +// +// +// if (fp.type.java !== null) +// keepSimple ? fp.type.java.referable.simpleName : fp.type.java.referable.qualifiedName +// else if (fp.type.acme !== null) { +// switch fp.type.acme.referable { +// AcmeComponentTypeDeclaration: return keepSimple ? "IAcmeComponent" : "org.acmestudio.acme.element.IAcmeComponent" +// AcmeConnectorTypeDeclaration: return keepSimple ? "IAcmeConnector" : "org.acmestudio.acme.element.IAcmeConnector" +// AcmePortTypeDeclaration: return keepSimple ? "IAcmePort" : "org.acmestudio.acme.element.IAcmePort" +// AcmeRoleTypeDeclaration: return keepSimple ? "IAcmeRole" : "org.acmestudio.acme.element.IAcmeRole" +// AcmeElementTypeDeclaration: return keepSimple ? "IAcmeElement" : "org.acmestudio.acme.element.IAcmeElement" +// AcmeGroupTypeDeclaration: return keepSimple ? "IAcmeGroup" : "org.acmestudio.acme.element.IAcmeGroup" +// default: return keepSimple ? "IAcmeElement" : "org.acmestudio.acme.element.IAcmeElement" +// } + } else if(fp.type.base !== null) fp.type.base.name() } - + def static getAcmeTypeName(AnyTypeRef ref) { switch ref { AcmeElementTypeDeclaration: ref.name @@ -76,54 +93,53 @@ class XtendUtils { AcmeGroupTypeDeclaration: ref.name } } - + def static convertToString(FormalParam p) { - - if (p.type.acme !== null) { + + if (p.type.ref instanceof AnyTypeRef) { '''«p.name».getQualifiedName()''' - } - else if (p.type.java !== null) { - val type = p.type.java.referable + } else if (p.type.ref instanceof JvmType) { + val type = (p.type.ref as JvmType) switch type { - JvmPrimitiveType: + JvmPrimitiveType: switch type.simpleName { - case "double", - case "Double": '''Double.toString(«p.name»)''' - case "int", - case "Integer": '''Integer.toString(«p.name»)''' - case "String": p.name - case "boolean", - case "Boolean" : '''Boolean.toString(«p.name»)''' - case "char" : '''Character.toString(«p.name»)''' + case "double", + case "Double": '''Double.toString(«p.name»)''' + case "int", + case "Integer": '''Integer.toString(«p.name»)''' + case "String": + p.name + case "boolean", + case "Boolean": '''Boolean.toString(«p.name»)''' + case "char": '''Character.toString(«p.name»)''' } JvmDeclaredType: '''«p.name».toString()''' } - } - else { - throw new IllegalArgumentException ("Don't know how to convert parameter " + p.name) + } else { + throw new IllegalArgumentException("Don't know how to convert parameter " + p.name) } } - - + static def boolean isSimpleDeclaredProperty(DeclaredProperty p) { val value = p?.value?.value val simple = switch value { - Reference | StringLiteral | BooleanLiteral | IntegerLiteral | DoubleLiteral | IPLiteral | LogLiteral : true - PropertyReference case value.referable instanceof DeclaredProperty: isSimpleDeclaredProperty(value.referable as DeclaredProperty) + Reference | StringLiteral | BooleanLiteral | IntegerLiteral | DoubleLiteral | IPLiteral | LogLiteral: true + PropertyReference case value.referable instanceof DeclaredProperty: isSimpleDeclaredProperty( + value.referable as DeclaredProperty) default: false } simple } - - + static def String valueOfSimpleDeclaredProperty(DeclaredProperty p) { val value = p?.value?.value val sv = switch value { - StringLiteral : unpackString(value, false, true) - BooleanLiteral : Boolean.toString(value.isTrue) - IntegerLiteral : Integer.toString(value.value) - DoubleLiteral : Double.toString(value.value) - PropertyReference case value.referable instanceof DeclaredProperty: valueOfSimpleDeclaredProperty(value.referable as DeclaredProperty) + StringLiteral: unpackString(value, false, true) + BooleanLiteral: Boolean.toString(value.isTrue) + IntegerLiteral: Integer.toString(value.value) + DoubleLiteral: Double.toString(value.value) + PropertyReference case value.referable instanceof DeclaredProperty: valueOfSimpleDeclaredProperty( + value.referable as DeclaredProperty) IPLiteral: value.value LogLiteral: value.value.getName Reference: value.referable.qualifiedName @@ -131,30 +147,29 @@ class XtendUtils { } sv } + static def String unpackString(StringLiteral literal, boolean strip, boolean completeProperties) { if (!completeProperties) { unpackString(literal, strip) - } - else { + } else { val rich = literal as RichString var str = new StringBuilder() for (expr : rich.expressions) { if (expr instanceof RichStringLiteral) { val s = (expr as RichStringLiteral)?.value?.replaceAll("«", "")?.replaceAll("»", "") - - if (s !== null) str.append(s) + + if(s !== null) str.append(s) } else if (expr instanceof RichStringPart) { val value = (expr as RichStringPart)?.referable?.value?.value val sv = switch value { - StringLiteral : unpackString(value, true, true) - BooleanLiteral: Boolean.toString(value.isTrue) - IntegerLiteral : Integer.toString(value.value) + StringLiteral: unpackString(value, true, true) + BooleanLiteral: Boolean.toString(value.isTrue) + IntegerLiteral: Integer.toString(value.value) DoubleLiteral: Double.toString(value.value) IPLiteral: value.value LogLiteral: value.value.getName Reference: value.referable.qualifiedName default: '''${«(expr as RichStringPart).referable.name»}''' - } str.append(sv) } @@ -170,7 +185,7 @@ class XtendUtils { return str.toString } } - + static def unpackString(StringLiteral literal, boolean strip) { // if (literal instanceof SimpleStringLiteral) { // val value=(literal as SimpleStringLiteral).value @@ -196,7 +211,7 @@ class XtendUtils { } return str.toString } - + static def fillNamedGroups(String regexp, Set namedGroups) { var m = Pattern.compile("\\(\\?<([a-zA-Z][a-zA-Z0-9]*)>").matcher(regexp); while (m.find()) { @@ -207,12 +222,12 @@ class XtendUtils { while (m.find()) { namedGroups.add(Integer.toString(i++)) } - + } - + static def getComponentName(EObject a) { val st = new StringBuilder(); - if (a instanceof Assignment) st.append((a as Assignment).name) + if(a instanceof Assignment) st.append((a as Assignment).name) var parent = EcoreUtil2.getContainerOfType(a.eContainer, Assignment) while (parent !== null) { st.insert(0, ':') @@ -221,10 +236,10 @@ class XtendUtils { } st.toString() } - + static var COMPOUND_NAME_STORE = newHashMap - - static def updateStore(Map knownCompoundNames) { + + static def updateStore(Map knownCompoundNames) { // Form all component names var compoundNames = COMPOUND_NAME_STORE.get(knownCompoundNames) as Set if (compoundNames === null) { @@ -232,8 +247,8 @@ class XtendUtils { for (n : knownCompoundNames.keySet()) { val split = n.split(":") var st = new StringBuilder() - for (var i = 0; i < split.length-1; i++) { - if (i != 0) st.append(":") + for (var i = 0; i < split.length - 1; i++) { + if(i != 0) st.append(":") st.append(split.get(i)) compoundNames.add(st.toString) } @@ -243,32 +258,31 @@ class XtendUtils { } compoundNames } - - static def isKeyProperty(Map knownCompoundNames, Assignment a) { + + static def isKeyProperty(Map knownCompoundNames, Assignment a) { val compoundNames = updateStore(knownCompoundNames) // Check if name is there val cn = getComponentName(a) return compoundNames.contains(cn) } - + static def getPropertySuggestions(Map knownCompoundNames, EObject a) { val compoundNames = updateStore(knownCompoundNames) val names = newHashSet val cn = getComponentName(a) - compoundNames.forEach[ + compoundNames.forEach [ if (it.startsWith(cn)) { val split2 = it.split(":") if (it.endsWith(":")) { - names.add((split2).get(split2.length-2)) - - } - else { - names.add((split2).get(split2.length-1)) + names.add((split2).get(split2.length - 2)) + + } else { + names.add((split2).get(split2.length - 1)) } - + } ] names } - -} \ No newline at end of file + +} diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/generator/RclGenerator.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/generator/RclGenerator.xtend index 076e723f7..2aa42f129 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/generator/RclGenerator.xtend +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/generator/RclGenerator.xtend @@ -21,7 +21,9 @@ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + import java.util.HashMap +import org.acme.acme.AnyTypeRef import org.eclipse.emf.common.util.EList import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.EObject @@ -282,8 +284,8 @@ class RclGenerator extends AbstractGenerator { public «cmd.cmd.simpleName» «cmd.name»Cmd «FOR p : cmd.formal BEFORE '(' SEPARATOR ',' AFTER ')'»«XtendUtils.formalTypeName(p, false)» «p.name» «ENDFOR» { «FOR p : cmd.formal» - «IF p.type.acme !== null» - Ensure.is_true(«p.name».declaresType("«XtendUtils.getAcmeTypeName(p.type.acme.referable)»")); + «IF p.type instanceof AnyTypeRef» + Ensure.is_true(«p.name».declaresType("«XtendUtils.getAcmeTypeName(p.type as AnyTypeRef)»")); «ENDIF» «ENDFOR» return new «cmd.cmd.simpleName» («constantName(cmd.name)», («factory.defn.modelClass.simpleName» )m_modelInstance, «IF cmd.formal.get(0).name != "target"»"", «ENDIF»«FOR p : cmd.formal SEPARATOR ', '»«XtendUtils.convertToString(p)»«ENDFOR»); diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/rcl.xtext b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/rcl.xtext index af587d7d4..08d9d8931 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/rcl.xtext +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/rcl.xtext @@ -78,12 +78,13 @@ FormalParam: Type: - /*{Type} 'int' | {Type} 'boolean' | {Type} 'double' | {Type} 'String' | */base=BaseType | java=JavaReference | 'acme''::'acme=AcmeReference + /*{Type} 'int' | {Type} 'boolean' | {Type} 'double' | {Type} 'String' | */base=BaseType | ref=[ecore::EObject|FQN] + //refjava=JavaReference | 'acme''::'acme=AcmeReference ; -AcmeReference: - referable=[acme::AnyTypeRef|FQN] -; +//AcmeReference: +// referable=[acme::AnyTypeRef|FQN] +//; enum BaseType: COMPONENT="component" | COMPONENT="Component" | diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/CombinedScope.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/CombinedScope.xtend new file mode 100644 index 000000000..8a6a0a41e --- /dev/null +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/CombinedScope.xtend @@ -0,0 +1,44 @@ +package org.sa.rainbow.configuration.scoping + +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.resource.IEObjectDescription + +class CombinedScope implements IScope { + + IScope[] m_scopes + + new(IScope... scopes) { + m_scopes = scopes; + } + + override getAllElements() { + m_scopes.map[it.getAllElements()].flatten + } + + override getElements(QualifiedName name) { + m_scopes.map[it.getElements(name)].flatten + } + + override getElements(EObject object) { + m_scopes.map[it.getElements(object)].flatten + } + + override getSingleElement(QualifiedName name) { + var IEObjectDescription se = null; + for (var i = 0; i < m_scopes.length && se === null; i++) { + se = m_scopes.get(i).getSingleElement(name); + } + se + } + + override getSingleElement(EObject object) { + var IEObjectDescription se = null; + for (var i = 0; i < m_scopes.length && se === null; i++) { + se = m_scopes.get(i).getSingleElement(object); + } + se + } + +} diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclGlobalScopeProvider.java b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclGlobalScopeProvider.java index d2187b552..d2f729de2 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclGlobalScopeProvider.java +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclGlobalScopeProvider.java @@ -19,7 +19,9 @@ software and associated documentation files (the "Software"), to deal in the Sof DEALINGS IN THE SOFTWARE. */ import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.impl.EReferenceImpl; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.common.types.TypesPackage; import org.eclipse.xtext.common.types.xtext.AbstractTypeScopeProvider; @@ -28,6 +30,7 @@ software and associated documentation files (the "Software"), to deal in the Sof import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider; +import org.sa.rainbow.configuration.rcl.RclPackage; import com.google.common.base.Predicate; import com.google.inject.Inject; @@ -49,6 +52,9 @@ software and associated documentation files (the "Software"), to deal in the Sof @SuppressWarnings("restriction") public class RclGlobalScopeProvider extends ImportUriGlobalScopeProvider { + + + /* * AbstractTypeScopeProvider is bound to * org.eclipse.xtext.common.types.xtext.ClasspathBasedTypeScopeProvider in the @@ -65,11 +71,22 @@ public class RclGlobalScopeProvider extends ImportUriGlobalScopeProvider { @Override public IScope getScope(Resource resource, EReference reference, Predicate filter) { - if (EcoreUtil2.isAssignableFrom(TypesPackage.Literals.JVM_TYPE, reference.getEReferenceType())) { + if (EcoreUtil2.isAssignableFrom(TypesPackage.Literals.JVM_TYPE, + reference.getEReferenceType()) /* + * || reference.equals(RclPackage.Literals.TYPE__REF) + */) { IScope typeScope = typeScopeProvider.getScope(resource, reference, filter); return typeScope; - } else { + } else if (reference.equals(RclPackage.Literals.TYPE__REF)) { + EReferenceImpl javaReference = (EReferenceImpl )EcoreUtil.copy(reference); + javaReference.setEType(TypesPackage.eINSTANCE.getJvmType()); + return new CombinedScope(super.getScope(resource, reference, filter), typeScopeProvider.getScope(resource, javaReference, filter)); + } + else { return super.getScope(resource, reference, filter); } } + + + } \ No newline at end of file diff --git a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclScopeProvider.xtend b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclScopeProvider.xtend index e82af9f4b..089d3cbe2 100644 --- a/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclScopeProvider.xtend +++ b/ide/org.sa.rainbow.configuration.parent/org.sa.rainbow.configuration/src/org/sa/rainbow/configuration/scoping/RclScopeProvider.xtend @@ -3,8 +3,15 @@ */ package org.sa.rainbow.configuration.scoping +import org.acme.acme.AcmePackage import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.common.types.TypesPackage +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.impl.FilteringScope +import org.sa.rainbow.configuration.rcl.RclPackage +import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider +import org.sa.rainbow.configuration.rcl.Type /** * This class contains custom scoping description. @@ -12,7 +19,7 @@ import org.eclipse.emf.ecore.EReference * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping * on how and when to use it. */ -class RclScopeProvider extends AbstractRclScopeProvider { +class RclScopeProvider extends AbstractDeclarativeScopeProvider { override getScope(EObject context, EReference reference) { // if (reference == RclPackage.Literals.REFERENCE__REFERABLE) { // var ancestor = context; @@ -26,10 +33,18 @@ class RclScopeProvider extends AbstractRclScopeProvider { ////// return Scopes.scopeFor(pc.eContainer().); //// } // } + return super.getScope(context, reference); } // def getGlobalScope(EObject context, EReference reference) { // IScope globalScope = super.getGlobalScope(context, reference, null) // } + + def IScope scope_EObject(Type context, EReference ref) { + return new FilteringScope(delegateGetScope(context, ref)) [ + return TypesPackage.Literals.JVM_TYPE.isSuperTypeOf(it.EClass) || + AcmePackage.Literals.ANY_TYPE_REF.isSuperTypeOf(it.EClass) + ] + } } diff --git a/ide/org.sa.rainbow.stitch.parent/org.sa.rainbow.stitch.tests/src/org/sa/rainbow/stitch/tests/StitchJavaReferenceTest.xtend b/ide/org.sa.rainbow.stitch.parent/org.sa.rainbow.stitch.tests/src/org/sa/rainbow/stitch/tests/StitchJavaReferenceTest.xtend new file mode 100644 index 000000000..d15698730 --- /dev/null +++ b/ide/org.sa.rainbow.stitch.parent/org.sa.rainbow.stitch.tests/src/org/sa/rainbow/stitch/tests/StitchJavaReferenceTest.xtend @@ -0,0 +1,30 @@ +package org.sa.rainbow.stitch.tests + +import com.google.inject.Inject +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.XtextRunner +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.Test +import org.junit.runner.RunWith +import org.sa.rainbow.stitch.stitch.script + +@RunWith(XtextRunner) +@InjectWith(StitchTestInjectorProvider) +class StitchJavaReferenceTest { + @Inject extension ParseHelper