Skip to content

Commit

Permalink
ti: support for local types
Browse files Browse the repository at this point in the history
  • Loading branch information
panchenko committed Dec 20, 2012
1 parent 9ba2806 commit 1b9b885
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 14 deletions.
Expand Up @@ -12,13 +12,12 @@
package org.eclipse.dltk.internal.javascript.ti;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.eclipse.core.runtime.Assert;
import org.eclipse.dltk.annotations.Internal;
Expand All @@ -34,6 +33,7 @@
import org.eclipse.dltk.javascript.typeinference.ReferenceKind;
import org.eclipse.dltk.javascript.typeinfo.AttributeKey;
import org.eclipse.dltk.javascript.typeinfo.IElementResolver;
import org.eclipse.dltk.javascript.typeinfo.ILocalTypeReference;
import org.eclipse.dltk.javascript.typeinfo.IMemberEvaluator;
import org.eclipse.dltk.javascript.typeinfo.IModelBuilder;
import org.eclipse.dltk.javascript.typeinfo.IRMember;
Expand Down Expand Up @@ -140,7 +140,97 @@ public IValueCollection currentCollection() {
return visitor.peekContext();
}

private final ConcurrentMap<String, Type> types = new ConcurrentHashMap<String, Type>();
/**
* Implementation of the {@link ILocalTypeReference}
*/
private static class LocalType implements ILocalTypeReference {
final Type type;
private boolean enabled;

public LocalType(Type type) {
this.type = type;
this.enabled = true;
}

public Type getType() {
return type;
}

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean value) {
this.enabled = value;
}

@Override
public String toString() {
return "(" + type + ", enabled=" + enabled + ")";
}
}

/**
* Container for potentially multiple local types with the same name.
*/
@SuppressWarnings("serial")
private static class LocalTypeBucket extends ArrayList<LocalType> {
public LocalTypeBucket() {
super(1);
}

Type unknownType;
}

/**
* Local (i.e. per-module) types, which are manually registered using
* {@link ITypeInfoContext#registerLocalType(Type, Object)}.
*/
private final Map<String, LocalTypeBucket> localTypes = new HashMap<String, LocalTypeBucket>();

/*
* @see ITypeInfoContext#registerLocalType(Type)
*/
public ILocalTypeReference registerLocalType(Type type) {
assert type != null;
final String name = type.getName();
assert name != null;
assert type.eResource() == null;
final LocalType result;
synchronized (localTypes) {
LocalTypeBucket locals = localTypes.get(name);
if (locals == null) {
locals = new LocalTypeBucket();
localTypes.put(name, locals);
} else {
for (LocalType localType : locals) {
if (type.equals(localType.type)) {
return localType;
}
}
}
result = new LocalType(type);
typeRS.addToResource(type);
locals.add(result);
}
return result;
}

/*
* @see ITypeInfoContext#getLocalTypes(String)
*/
public ILocalTypeReference[] getLocalTypes(String name) {
synchronized (localTypes) {
LocalTypeBucket locals = localTypes.get(name);
if (locals != null) {
return locals.toArray(new ILocalTypeReference[locals.size()]);
} else {
return new ILocalTypeReference[0];
}
}
}

private final Map<String, Type> types = new HashMap<String, Type>();

public Type getType(String typeName) {
if (typeName == null || typeName.length() == 0) {
Expand Down Expand Up @@ -239,17 +329,32 @@ private enum TypeResolveMode {
@Internal
Type getType(String typeName, TypeMode mode, boolean queryProviders,
boolean queryPredefined, boolean allowProxy, boolean allowUnknown) {
Type type = types.get(typeName);
if (type != null) {
if (!allowUnknown && type.getKind() == TypeKind.UNKNOWN) {
return null;
synchronized (localTypes) {
final LocalTypeBucket locals = localTypes.get(typeName);
if (locals != null) {
for (LocalType localType : locals) {
if (localType.isEnabled()) {
return localType.type;
}
}
if (locals.unknownType != null) {
return allowUnknown ? locals.unknownType : null;
}
}
}
Type type;
synchronized (types) {
type = types.get(typeName);
}
if (type != null) {
return type;
}
type = loadType(typeName, mode, queryProviders, queryPredefined);
if (type != null) {
validateTypeInfo(type);
types.put(typeName, type);
synchronized (types) {
types.put(typeName, type);
}
typeRS.addToResource(type);
return type;
}
Expand Down Expand Up @@ -281,13 +386,25 @@ Type createUnknown(String typeName) {
final Type type = TypeInfoModelFactory.eINSTANCE.createType();
type.setName(typeName);
type.setKind(TypeKind.UNKNOWN);
final Type previous = types.putIfAbsent(typeName, type);
if (previous != null) {
return previous;
} else {
typeRS.addToResource(type);
return type;
synchronized (localTypes) {
LocalTypeBucket locals = localTypes.get(typeName);
if (locals != null) {
for (LocalType localType : locals) {
if (localType.isEnabled()) {
return localType.type;
}
}
if (locals.unknownType != null) {
return locals.unknownType;
}
} else {
locals = new LocalTypeBucket();
localTypes.put(typeName, locals);
}
locals.unknownType = type;
}
typeRS.add(type);
return type;
}

private final Map<String, Boolean> activeTypeRequests = new HashMap<String, Boolean>();
Expand Down Expand Up @@ -386,6 +503,10 @@ protected synchronized void add(Type type) {
getResource().getContents().add(type);
}

protected synchronized void removeAll(Collection<Type> types) {
getResource().getContents().removeAll(types);
}

}

private final TypeResourceSet typeRS = new TypeResourceSet();
Expand Down Expand Up @@ -536,4 +657,28 @@ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
}
}

/**
* Removes all registered local types, this method is called by the
* {@link org.eclipse.dltk.internal.javascript.validation.TypeInfoValidator}
* after each module is processed.
*/
public void resetLocalState() {
final List<Type> copy;
synchronized (localTypes) {
copy = new ArrayList<Type>();
for (LocalTypeBucket locals : localTypes.values()) {
for (LocalType localType : locals) {
copy.add(localType.type);
}
if (locals.unknownType != null) {
copy.add(locals.unknownType);
}
}
localTypes.clear();
}
if (!copy.isEmpty()) {
typeRS.removeAll(copy);
}
}

}
Expand Up @@ -158,6 +158,7 @@ public void build(IBuildContext context) throws CoreException {
inferencer.setVisitor(visitor);
inferencer.doInferencing(script);
if (hasDependents) {
inferencer.resetLocalState();
context.set(TypeInfoValidator.ATTR_BINDINGS, visitor.bindings);
saveCachedBindings(script, new TemporaryBindings(inferencer,
visitor.bindings));
Expand Down
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2012 NumberFour AG
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* NumberFour AG - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.javascript.typeinfo;

import org.eclipse.dltk.internal.javascript.ti.TypeInferencer2;
import org.eclipse.dltk.javascript.typeinfo.model.Type;

/**
* Handle of the "local type" registered in the {@link TypeInferencer2} via
* {@link ITypeInfoContext#registerLocalType(Type)}. The idea is that it is
* something temporary, created based on the current module and it should not be
* available for other modules.
*/
public interface ILocalTypeReference {

/**
* Returns the model {@link Type} instance managed via this local type
* reference.
*/
Type getType();

/**
* Answers if this local type instance is enabled at the moment
*/
boolean isEnabled();

/**
* Enables or disables this local type instance
*/
void setEnabled(boolean value);

}
Expand Up @@ -90,4 +90,18 @@ public interface ITypeInfoContext extends ITypeSystem {
* evaluated code.
*/
IValueCollection currentCollection();

/**
* Returns the references to the registered local type with the specified
* name, if no such types registered then empty array is returned.
*/
ILocalTypeReference[] getLocalTypes(String name);

/**
* Registers the specified local type as "local" (if multiple types with the
* same name are registered then the first one which is enabled will be
* used). Returns the type reference, which can be used to disable it
* temporary.
*/
ILocalTypeReference registerLocalType(Type type);
}

0 comments on commit 1b9b885

Please sign in to comment.