package com.redhat.ceylon.eclipse.code.correct;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getCommandBinding;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getCurrentEditor;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isTypeUnknown;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.text.Region;
import org.eclipse.ui.IEditorPart;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.Scope;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.model.typechecker.model.Unit;
import com.redhat.ceylon.model.typechecker.model.Value;
public class CorrectionUtil {
static int levenshteinDistance(String x, String y) {
int n = x.length(); // length of s
int m = y.length(); // length of t
if (n == 0) return m;
if (m == 0) return n;
int p[] = new int[n+1]; //'previous' cost array, horizontally
int d[] = new int[n+1]; // cost array, horizontally
int _d[]; //placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char t_j; // jth character of t
int cost; // cost
for (i = 0; i<=n; i++) {
p[i] = i;
}
for (j = 1; j<=m; j++) {
t_j = y.charAt(j-1);
d[0] = j;
for (i=1; i<=n; i++) {
cost = x.charAt(i-1)==t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1), p[i-1]+cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
static Tree.Body getClassOrInterfaceBody(Tree.Declaration decNode) {
if (decNode instanceof Tree.ClassDefinition) {
Tree.ClassDefinition cd =
(Tree.ClassDefinition) decNode;
return cd.getClassBody();
}
else if (decNode instanceof Tree.InterfaceDefinition){
Tree.InterfaceDefinition id =
(Tree.InterfaceDefinition) decNode;
return id.getInterfaceBody();
}
else if (decNode instanceof Tree.ObjectDefinition){
Tree.ObjectDefinition od =
(Tree.ObjectDefinition) decNode;
return od.getClassBody();
}
else {
return null;
}
}
static Tree.CompilationUnit getRootNode(PhasedUnit unit) {
IEditorPart ce = getCurrentEditor();
if (ce instanceof CeylonEditor) {
CeylonEditor editor = (CeylonEditor) ce;
CeylonParseController cpc =
editor.getParseController();
if (cpc!=null) {
Tree.CompilationUnit rn = cpc.getTypecheckedRootNode();
if (rn!=null) {
Unit u = rn.getUnit();
if (u.equals(unit.getUnit())) {
return rn;
}
}
}
}
return unit.getCompilationUnit();
}
static String asIntersectionTypeString(List<Type> types) {
StringBuffer missingSatisfiedTypesText = new StringBuffer();
for( Type missingSatisfiedType: types ) {
if( missingSatisfiedTypesText.length() != 0 ) {
missingSatisfiedTypesText.append(" & ");
}
missingSatisfiedTypesText.append(
missingSatisfiedType.asString());
}
return missingSatisfiedTypesText.toString();
}
static String defaultValue(Unit unit, Type t) {
if (isTypeUnknown(t)) {
return "nothing";
}
if (unit.isOptionalType(t)) {
return "null";
}
if (t.isTypeAlias() ||
t.isClassOrInterface() &&
t.getDeclaration().isAlias()){
return defaultValue(unit,
t.getExtendedType());
}
if (t.isClass()) {
TypeDeclaration c = t.getDeclaration();
if (c.equals(unit.getBooleanDeclaration())) {
return "false";
}
else if (c.equals(unit.getIntegerDeclaration())) {
return "0";
}
else if (c.equals(unit.getFloatDeclaration())) {
return "0.0";
}
else if (c.equals(unit.getStringDeclaration())) {
return "\"\"";
}
else if (c.equals(unit.getByteDeclaration())) {
return "0.byte";
}
else if (c.equals(unit.getTupleDeclaration())) {
final int minimumLength =
unit.getTupleMinimumLength(t);
final List<Type> tupleTypes =
unit.getTupleElementTypes(t);
final StringBuilder sb = new StringBuilder();
for(int i = 0 ; i < minimumLength ; i++){
sb.append(sb.length() == 0 ? "[" : ", ");
Type currentType =
tupleTypes.get(i);
if(unit.isSequentialType(currentType)){
currentType =
unit.getSequentialElementType(currentType);
}
sb.append(defaultValue(unit, currentType));
}
sb.append(']');
return sb.toString();
}
else if (unit.isSequentialType(t)) {
final StringBuilder sb = new StringBuilder();
sb.append('[');
if (!unit.getEmptyType().isSubtypeOf(t)) {
sb.append(defaultValue(unit,
unit.getSequentialElementType(t)));
}
sb.append(']');
return sb.toString();
}
else if (unit.isIterableType(t)) {
final StringBuilder sb = new StringBuilder();
sb.append('{');
if (!unit.getEmptyType().isSubtypeOf(t)) {
sb.append(defaultValue(unit,
unit.getIteratedType(t)));
}
sb.append('}');
return sb.toString();
}
else {
return "nothing";
}
}
else {
return "nothing";
}
}
static Region computeSelection(int offset, String def) {
int length;
int loc = def.indexOf("= nothing");
if (loc<0) loc = def.indexOf("=> nothing");
if (loc<0) {
loc = def.indexOf("= ");
if (loc<0) loc = def.indexOf("=> ");
if (loc<0) {
loc = def.indexOf("{")+1;
length=0;
}
else {
loc = def.indexOf(" ", loc)+1;
int semi = def.indexOf(";", loc);
length = semi<0 ? def.length()-loc:semi-loc;
}
}
else {
loc = def.indexOf(" ", loc)+1;
length = 7;
}
return new Region(offset + loc, length);
}
static String getDescription(Declaration dec) {
String desc = "'" + dec.getName() + "'";
Scope container = dec.getContainer();
if (container instanceof TypeDeclaration) {
TypeDeclaration td = (TypeDeclaration) container;
desc += " in '" + td.getName() + "'";
}
return desc;
}
static Node getBeforeParenthesisNode(Tree.Declaration decNode) {
Node n = decNode.getIdentifier();
if (decNode instanceof Tree.TypeDeclaration) {
Tree.TypeDeclaration td =
(Tree.TypeDeclaration) decNode;
Tree.TypeParameterList tpl =
td
.getTypeParameterList();
if (tpl!=null) {
n = tpl;
}
}
if (decNode instanceof Tree.AnyMethod) {
Tree.AnyMethod am = (Tree.AnyMethod) decNode;
Tree.TypeParameterList tpl =
am.getTypeParameterList();
if (tpl!=null) {
n = tpl;
}
}
return n;
}
static List<TypedDeclaration> collectUninitializedMembers(
Tree.Body body) {
List<TypedDeclaration> uninitialized =
new ArrayList<TypedDeclaration>();
if (body!=null) {
List<Tree.Statement> statements =
body.getStatements();
for (Tree.Statement st: statements) {
if (st instanceof Tree.AttributeDeclaration) {
Tree.AttributeDeclaration ad =
(Tree.AttributeDeclaration) st;
if (ad.getSpecifierOrInitializerExpression()==null) {
Value v = ad.getDeclarationModel();
if (!v.isFormal()) {
uninitialized.add(v);
}
}
}
else if (st instanceof Tree.MethodDeclaration) {
Tree.MethodDeclaration md =
(Tree.MethodDeclaration) st;
if (md.getSpecifierExpression()==null) {
Function m = md.getDeclarationModel();
if (!m.isFormal()) {
uninitialized.add(m);
}
}
}
else if (st instanceof Tree.SpecifierStatement) {
Tree.SpecifierStatement ss =
(Tree.SpecifierStatement) st;
Tree.Term term = ss.getBaseMemberExpression();
if (term instanceof Tree.BaseMemberExpression) {
Tree.BaseMemberExpression bme =
(Tree.BaseMemberExpression) term;
uninitialized.remove(bme.getDeclaration());
}
}
}
}
return uninitialized;
}
public static String shortcut(String key) {
TriggerSequence binding =
getCommandBinding(key);
return binding==null ? "" :
" \u22ef " + binding.format();
}
}