/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.tvl.goworks.editor.go.semantics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.netbeans.api.annotations.common.NonNull;
import org.openide.util.Parameters;
import org.tvl.goworks.editor.go.codemodel.CodeElementModel;
import org.tvl.goworks.editor.go.codemodel.IntrinsicKind;
import org.tvl.goworks.editor.go.codemodel.IntrinsicTypeModels;
import org.tvl.goworks.editor.go.codemodel.PackageModel;
import org.tvl.goworks.editor.go.codemodel.TypeAliasModel;
import org.tvl.goworks.editor.go.codemodel.TypeArrayModel;
import org.tvl.goworks.editor.go.codemodel.TypeChannelModel;
import org.tvl.goworks.editor.go.codemodel.TypeIntrinsicModel;
import org.tvl.goworks.editor.go.codemodel.TypeMapModel;
import org.tvl.goworks.editor.go.codemodel.TypeModel;
import org.tvl.goworks.editor.go.codemodel.TypePointerModel;
import org.tvl.goworks.editor.go.codemodel.TypeSliceModel;
import org.tvl.goworks.editor.go.codemodel.VarModel;
import org.tvl.goworks.editor.go.codemodel.impl.AbstractCodeElementModel;
/**
*
* @author Sam Harwell
*/
public class RangeClauseResultReference extends CodeElementReference {
private final CodeElementReference exprType;
public RangeClauseResultReference(@NonNull CodeElementReference exprType) {
Parameters.notNull("exprType", exprType);
this.exprType = exprType;
}
@Override
public Collection<? extends CodeElementModel> resolve(GoAnnotatedParseTree annotatedParseTree, PackageModel currentPackage, Map<String, Collection<PackageModel>> resolvedPackages) {
Collection<? extends CodeElementModel> indexableType = exprType.resolve(annotatedParseTree, currentPackage, resolvedPackages);
if (indexableType.isEmpty()) {
return indexableType;
}
List<CodeElementModel> resolvedTypes = new ArrayList<>();
for (CodeElementModel model : indexableType) {
if (model instanceof VarModel) {
model = ((VarModel)model).getVarType();
}
if (model instanceof TypeModel) {
resolvedTypes.addAll(((TypeModel)model).resolve());
} else {
resolvedTypes.add(model);
}
}
Collection<CodeElementModel> elements = new ArrayList<>();
for (CodeElementModel model : resolvedTypes) {
if (!(model instanceof TypeModel)) {
elements.add(model);
continue;
}
while (model instanceof TypeAliasModel) {
model = ((TypeAliasModel)model).getType();
}
if (model instanceof TypeChannelModel) {
// only has a first value
elements.add(((TypeChannelModel)model).getElementType());
} else if (model instanceof TypeMapModel) {
AbstractCodeElementModel firstValue = (AbstractCodeElementModel)((TypeMapModel)model).getKeyType();
AbstractCodeElementModel secondValue = (AbstractCodeElementModel)((TypeMapModel)model).getValueType();
elements.add(new BundledReturnTypeModel(Arrays.asList(firstValue, secondValue)));
} else if (model instanceof TypeIntrinsicModel) {
if (((TypeIntrinsicModel)model).getIntrinsicKind() == IntrinsicKind.STRING) {
elements.add(new BundledReturnTypeModel(Arrays.asList((AbstractCodeElementModel)IntrinsicTypeModels.INT, (AbstractCodeElementModel)IntrinsicTypeModels.RUNE)));
}
} else {
CodeElementModel unwrappedModel = model;
if (unwrappedModel instanceof TypePointerModel) {
Collection<? extends CodeElementModel> resolvedElement = ((TypePointerModel)unwrappedModel).getElementType().resolve();
if (resolvedElement.isEmpty()) {
continue;
}
if (resolvedElement.size() > 0) {
LOGGER.log(Level.WARNING, "Pointer element type resolved to multiple targets, using the first.");
}
unwrappedModel = resolvedElement.iterator().next();
}
if (unwrappedModel instanceof TypeArrayModel) {
unwrappedModel = ((TypeArrayModel)unwrappedModel).getElementType();
} else if (unwrappedModel instanceof TypeSliceModel) {
unwrappedModel = ((TypeSliceModel)unwrappedModel).getElementType();
} else {
unwrappedModel = null;
}
if (unwrappedModel != null) {
elements.add(new BundledReturnTypeModel(Arrays.asList((AbstractCodeElementModel)IntrinsicTypeModels.INT, (AbstractCodeElementModel)unwrappedModel)));
}
}
}
return elements;
}
}