Skip to content

Commit

Permalink
fixed transitive import complexity (fixes #113)
Browse files Browse the repository at this point in the history
  • Loading branch information
svenefftinge committed Nov 9, 2016
1 parent 701fcc6 commit 9c62e2e
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ class SadlLinkingTest extends AbstractLinkingTest {

@Test
def void testImportPerformance() {
for (i : 99 .. 100) {
for (i : 1 .. 19) {
val started = Stopwatch.createStarted
val resource = '''
uri "http://sadl.org/NS1.sadl«i»" alias ns«i».
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class ScopingTest {
described by when with values of type dateTime,
described by openingEvent with a single value of type Event,
described by closingEvent with a single value of type Event.
Circus is a class,
described by event with values of type Event.
Expand All @@ -199,19 +199,5 @@ class ScopingTest {
]

}

@Test def void testScopingSlowdown() {
for (i:1 ..< 10) {
var modeltext = "uri \"http://com.ge.research.sadl/scopingscaletest\".\n"
for (j:0 ..< i*100) {
modeltext += "Pr" + j + " is a property.\n"
}
// print(modeltext)
var t1 = System.currentTimeMillis
var model = modeltext.parse
validationTestHelper.assertNoErrors(model.eResource)
var t2 = System.currentTimeMillis;
print(i*100 + "," + (t2-t1) + "ms\n")
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ import org.eclipse.xtend.lib.annotations.Data
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.util.OnChangeEvictingCache
import org.eclipse.xtext.validation.CheckMode
import com.ge.research.sadl.processing.IModelProcessor.ProcessorContext
import org.eclipse.xtext.util.IAcceptor
import com.ge.research.sadl.builder.MessageManager.SadlMessage

class SadlModelProcessorProvider implements IModelProcessorProvider {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopeProvider;
import org.eclipse.xtext.scoping.impl.MapBasedScope;

import com.google.inject.Inject;

Expand Down Expand Up @@ -67,19 +66,6 @@ public List<EObject> getLinkedObjects(EObject context, EReference ref, INode nod
return Collections.emptyList();
}

// protected IScope getScope(EObject context, EReference ref) {
// Resource rsrc = context.eResource();
// IScope scope = TestScopeProvider.find(rsrc);
// if (scope == null) {
// scope = super.getScope(context, ref);
// if (scope instanceof MapBasedScope) {
// TestScopeProvider.attach(rsrc, scope);
//// System.out.println("Attaching scope to '" + rsrc.toString() + "': " + scope.toString());
// }
// }
// return scope;
// }

protected void createAndAddDiagnostic(Resource resource, INode node, String message, String commaSeparatedAlternatives) {
resource.getErrors().add(new XtextLinkingDiagnostic(node, message, ISSUE_CODE, commaSeparatedAlternatives));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ import com.ge.research.sadl.sADL.BinaryOperation
import com.ge.research.sadl.sADL.EquationStatement
import com.ge.research.sadl.sADL.Expression
import com.ge.research.sadl.sADL.PropOfSubject
import com.ge.research.sadl.sADL.QueryStatement
import com.ge.research.sadl.sADL.RuleStatement
import com.ge.research.sadl.sADL.SADLPackage
import com.ge.research.sadl.sADL.SadlClassOrPropertyDeclaration
import com.ge.research.sadl.sADL.SadlImport
import com.ge.research.sadl.sADL.SadlInstance
import com.ge.research.sadl.sADL.SadlModel
import com.ge.research.sadl.sADL.SadlMustBeOneOf
import com.ge.research.sadl.sADL.SadlProperty
import com.ge.research.sadl.sADL.SadlResource
import com.ge.research.sadl.sADL.SubjHasProp
import com.ge.research.sadl.sADL.TestStatement
import com.google.common.base.Predicate
import com.google.inject.Inject
import java.util.List
import java.util.Map
import java.util.Set
import org.eclipse.emf.ecore.EObject
Expand All @@ -53,9 +55,6 @@ import org.eclipse.xtext.scoping.IScope
import org.eclipse.xtext.scoping.impl.AbstractGlobalScopeDelegatingScopeProvider
import org.eclipse.xtext.scoping.impl.MapBasedScope
import org.eclipse.xtext.util.OnChangeEvictingCache
import com.ge.research.sadl.sADL.SadlInstance
import com.ge.research.sadl.sADL.QueryStatement
import com.ge.research.sadl.sADL.TestStatement

/**
* This class contains custom scoping description.
Expand All @@ -79,7 +78,8 @@ class SADLScopeProvider extends AbstractGlobalScopeDelegatingScopeProvider {
return super.getGlobalScope(context.eResource, reference)
}
if (SADLPackage.Literals.SADL_RESOURCE.isSuperTypeOf(reference.EReferenceType)) {
return getSadlResourceScope(context, reference)
val result = getSadlResourceScope(context, reference)
return result
}
throw new UnsupportedOperationException(
"Couldn't build scope for elements of type " + reference.EReferenceType.name)
Expand Down Expand Up @@ -181,8 +181,11 @@ class SADLScopeProvider extends AbstractGlobalScopeDelegatingScopeProvider {
return MapBasedScope.createScope(parent, map.values)
}

@Data static class LocalSymbols {
}

protected def IScope createResourceScope(Resource resource, String alias, Set<Resource> importedResources) {
return cache.get('resource_scope'->alias, resource) [
return cache.get('resource_scope' -> alias, resource) [
val shouldWrap = importedResources.empty
if (!importedResources.add(resource)) {
return IScope.NULLSCOPE
Expand Down Expand Up @@ -288,116 +291,68 @@ class SADLScopeProvider extends AbstractGlobalScopeDelegatingScopeProvider {

protected def IScope createImportScope(Resource resource, Set<Resource> importedResources) {
val imports = resource.contents.head.eContents.filter(SadlImport).toList.reverseView
var importScopes = newArrayList
val importedSymbols = <QualifiedName, IEObjectDescription>newHashMap
for (imp : imports) {
val externalResource = imp.importedResource
if (!externalResource.eIsProxy)
importScopes += createResourceScope(externalResource.eResource, imp.alias, importedResources)
if (!externalResource.eIsProxy) {
createResourceScope(externalResource.eResource, imp.alias, importedResources).allElements.forEach[
val existing = importedSymbols.put(name, it)
val duplicateProblem = checkDuplicate(existing, it)
if (duplicateProblem !== null) {
importedSymbols.put(duplicateProblem.name, duplicateProblem)
}
]
}

}
if (importScopes.isEmpty) {
if (importedSymbols.isEmpty) {
if (!resource.URI.toString.endsWith("SadlImplicitModel.sadl")) {
val element = getGlobalScope(resource, SADLPackage.Literals.SADL_IMPORT__IMPORTED_RESOURCE).getSingleElement(QualifiedName.create("http://sadl.org/sadlimplicitmodel"))
if (element !== null) {
val eobject = resource.resourceSet.getEObject(element.EObjectURI, true)
if (eobject !== null) {
importScopes += createResourceScope(eobject.eResource, null, importedResources)
createResourceScope(eobject.eResource, null, importedResources).allElements.forEach[
importedSymbols.put(name, it)
]
}
}
}
}
return new ListCompositeScope(importScopes, converter, ambiguousNameDetection)
return new MapScope(IScope.NULLSCOPE, importedSymbols, false)
}

private def void addElement(Map<QualifiedName, IEObjectDescription> scope, QualifiedName qn, EObject obj) {
if (!scope.containsKey(qn)) {
scope.put(qn, new EObjectDescription(qn, obj, emptyMap))
}
}

@Data static class ListCompositeScope implements IScope {

List<IScope> delegates
IQualifiedNameConverter converter
boolean detectAmbiguousNames;

override getAllElements() {
delegates.map[allElements].reduce[p1, p2| p1 + p2] ?: #[]
}

override getElements(QualifiedName name) {
val registered = newHashSet
return delegates.map[getElements(name)].flatten.filter[registered.add(it.EObjectURI)]
}

override getElements(EObject object) {
return delegates.map[getElements(object)].flatten
def private IEObjectDescription checkDuplicate(IEObjectDescription first, IEObjectDescription second) {
if (!ambiguousNameDetection || first === null || second === null || first.EObjectURI == second.EObjectURI) {
return null
}
val imports = #[first, second].map[EObjectOrProxy.eResource.allContents.filter(SadlModel).head.baseUri]
val message = '''Ambiguously imported name '«first.name»' from «imports.map["'"+it+"'"].join(", ")». Please use an alias or choose different names.'''

override getSingleElement(QualifiedName name) {
if (!detectAmbiguousNames) {
for (s : delegates) {
val element = s.getSingleElement(name);
if (element !== null) {
return element
}
return new ForwardingEObjectDescription(first) {
override getUserData(String key) {
if (key.equals(ErrorAddingLinkingService.ERROR)) {
return message
}
return null;
}
var List<IEObjectDescription> candidates = null
var IEObjectDescription firstMatch = null
for (s : delegates) {
val candidate = s.getSingleElement(name)
if (candidate !== null && firstMatch !== candidate) {
if (firstMatch === null) {
firstMatch = candidate
} else {
if (candidates === null) {
candidates = newArrayList
candidates.add(firstMatch)
}
if (!candidates.contains(candidate))
candidates.add(candidate)
}
}
}
if (candidates === null) {
return firstMatch
} else {
val imports = candidates.map[EObjectOrProxy.eResource.allContents.filter(SadlModel).head.baseUri]
val message = '''Ambiguously imported name '«name»' from «imports.map["'"+it+"'"].join(", ")». Please use an alias or choose different names.'''
val alternatives = candidates.map[
desc |
this.getElements(desc.EObjectOrProxy)
.filter
[
qualifiedName != desc.qualifiedName
]
].flatten.toList

return new ForwardingEObjectDescription(candidates.head) {
override getUserData(String key) {
if (key.equals(ErrorAddingLinkingService.ERROR)) {
return message
}
if (key.equals(ErrorAddingLinkingService.ALTERNATIVES)) {
return alternatives.join(",", [converter.toString(name)])
}
super.getUserData(key)
}
if (key.equals(ErrorAddingLinkingService.ALTERNATIVES)) {
return first.qualifiedName+","+second.qualifiedName
}
super.getUserData(key)
}
}

override getSingleElement(EObject object) {
for (scope : delegates) {
val element = scope.getSingleElement(object)
if (element !== null) {
return element
}
}
return null
}

static class MapScope extends MapBasedScope {

new(IScope parent, Map<QualifiedName, IEObjectDescription> elements, boolean ignoreCase) {
super(parent, elements, ignoreCase)
}

}

private def void addElement(Map<QualifiedName, IEObjectDescription> scope, QualifiedName qn, EObject obj) {
if (!scope.containsKey(qn)) {
scope.put(qn, new EObjectDescription(qn, obj, emptyMap))
}
}

}

0 comments on commit 9c62e2e

Please sign in to comment.