package com.redhat.ceylon.eclipse.code.complete;
import static com.redhat.ceylon.eclipse.code.complete.CompletionUtil.getDefaultValueDescription;
import static com.redhat.ceylon.eclipse.code.outline.CeylonLabelProvider.appendTypeName;
import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.PARAMETER_TYPES_IN_COMPLETIONS;
import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.RETURN_TYPES_IN_OUTLINES;
import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.utilJ2C;
import static com.redhat.ceylon.eclipse.util.Highlights.ANN_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.ARROW_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.KW_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.MEMBER_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.TYPE_ID_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.TYPE_STYLER;
import static com.redhat.ceylon.eclipse.util.Highlights.styleIdentifier;
import static com.redhat.ceylon.ide.common.util.OccurrenceLocation.EXTENDS;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.intersectionOfSupertypes;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isConstructor;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isTypeUnknown;
import java.util.Collections;
import java.util.List;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.swt.graphics.Font;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;
import com.redhat.ceylon.eclipse.ui.CeylonPlugin;
import com.redhat.ceylon.ide.common.util.OccurrenceLocation;
import com.redhat.ceylon.ide.common.util.escaping_;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.DeclarationWithProximity;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
import com.redhat.ceylon.model.typechecker.model.Functional;
import com.redhat.ceylon.model.typechecker.model.Generic;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Package;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.ParameterList;
import com.redhat.ceylon.model.typechecker.model.Reference;
import com.redhat.ceylon.model.typechecker.model.Setter;
import com.redhat.ceylon.model.typechecker.model.SiteVariance;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeAlias;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypedReference;
import com.redhat.ceylon.model.typechecker.model.Unit;
import com.redhat.ceylon.model.typechecker.model.Value;
public class CodeCompletions {
private static boolean forceExplicitTypeArgs(
Declaration d, OccurrenceLocation ol) {
if (ol==EXTENDS) {
return true;
}
else {
//TODO: this is a pretty limited implementation
// for now, but eventually we could do
// something much more sophisticated to
// guess if explicit type args will be
// necessary (variance, etc)
if (d instanceof Functional) {
Functional fun = (Functional) d;
List<ParameterList> pls =
fun.getParameterLists();
return pls.isEmpty() ||
pls.get(0)
.getParameters()
.isEmpty();
}
else {
return false;
}
}
}
static String getTextForDocLink(
CeylonParseController cpc, Declaration decl) {
Package pkg = decl.getUnit().getPackage();
String qname = decl.getQualifiedNameString();
// handle language package or same module and package
Unit unit = cpc.getLastCompilationUnit().getUnit();
if (pkg!=null &&
(Module.LANGUAGE_MODULE_NAME
.equals(pkg.getNameAsString())
|| (unit!=null && pkg.equals(unit.getPackage())))) {
if (decl.isToplevel()) {
return decl.getNameAsString();
}
else { // not top level in language module
int loc = qname.indexOf("::");
if (loc>=0) {
return qname.substring(loc + 2);
}
else {
return qname;
}
}
}
else {
return qname;
}
}
public static String getTextFor(Declaration dec, Unit unit) {
StringBuilder result = new StringBuilder();
result.append(escaping_.get_().escapeName(dec, unit));
appendTypeParameters(dec, result);
return result.toString();
}
public static String getPositionalInvocationTextFor(
Declaration dec, OccurrenceLocation ol,
Reference pr, Unit unit, boolean includeDefaulted,
String typeArgs) {
StringBuilder result =
new StringBuilder(escaping_.get_().escapeName(dec, unit));
if (typeArgs!=null) {
result.append(typeArgs);
}
else if (forceExplicitTypeArgs(dec, ol)) {
appendTypeParameters(dec, result);
}
appendPositionalArgs(dec, pr, unit, result,
includeDefaulted, false);
appendSemiToVoidInvocation(result, dec);
return result.toString();
}
public static String getNamedInvocationTextFor(
Declaration dec, Reference pr, Unit unit,
boolean includeDefaulted,
String typeArgs) {
StringBuilder result =
new StringBuilder(escaping_.get_().escapeName(dec, unit));
if (typeArgs!=null) {
result.append(typeArgs);
}
else if (forceExplicitTypeArgs(dec, null)) {
appendTypeParameters(dec, result);
}
appendNamedArgs(dec, pr, unit, result,
includeDefaulted, false);
appendSemiToVoidInvocation(result, dec);
return result.toString();
}
private static void appendSemiToVoidInvocation(
StringBuilder result, Declaration dd) {
if (dd instanceof Function) {
Function fun = (Function) dd;
if (fun.isDeclaredVoid() &&
fun.getParameterLists().size()==1) {
result.append(';');
}
}
}
public static String getDescriptionFor(
Declaration dec, Unit unit) {
StringBuilder result =
new StringBuilder(dec.getName(unit));
appendTypeParameters(dec, result);
return result.toString();
}
public static String getDescriptionFor(
DeclarationWithProximity dwp, Unit unit, boolean addTypeParameters) {
StringBuilder result =
new StringBuilder();
Declaration dec = dwp.getDeclaration();
if(dwp.isAlias()){
result.append(dwp.getName());
result.append(" \u2192 ");
}
result.append(dec.getName(unit));
if(addTypeParameters)
appendTypeParameters(dec, result);
return result.toString();
}
public static String getPositionalInvocationDescriptionFor(
DeclarationWithProximity dwp, Declaration dec, OccurrenceLocation ol,
Reference pr, Unit unit,
boolean includeDefaulted,
String typeArgs) {
StringBuilder result =
new StringBuilder();
if(dwp != null && dwp.isAlias()){
result.append(dwp.getName());
result.append(" \u2192 ");
}
result.append(dec.getName(unit));
if (typeArgs!=null) {
result.append(typeArgs);
}
else if (forceExplicitTypeArgs(dec, ol)) {
appendTypeParameters(dec, result);
}
appendPositionalArgs(dec, pr, unit, result,
includeDefaulted, true);
return result.toString();
}
public static String getNamedInvocationDescriptionFor(
Declaration dec, Reference pr, Unit unit,
boolean includeDefaulted,
String typeArgs) {
StringBuilder result =
new StringBuilder(dec.getName(unit));
if (typeArgs!=null) {
result.append(typeArgs);
}
else if (forceExplicitTypeArgs(dec, null)) {
appendTypeParameters(dec, result);
}
appendNamedArgs(dec, pr, unit, result,
includeDefaulted, true);
return result.toString();
}
public static String getRefinementTextFor(
Declaration d, Reference pr, Unit unit,
boolean isInterface,
ClassOrInterface ci, String indent,
boolean containsNewline) {
return getRefinementTextFor(d, pr, unit,
isInterface, ci, indent, containsNewline,
true);
}
public static String getRefinementTextFor(
Declaration d, Reference pr, Unit unit,
boolean isInterface,
ClassOrInterface ci, String indent,
boolean containsNewline,
boolean preamble) {
StringBuilder result = new StringBuilder();
if (preamble) {
result.append("shared actual ");
if (isVariable(d) && !isInterface) {
result.append("variable ");
}
}
appendDeclarationHeaderText(d, pr, unit, result);
appendTypeParameters(d, result);
appendParametersText(d, pr, unit, result);
if (d instanceof Class) {
String extraIndent =
extraIndent(extraIndent(indent, containsNewline),
containsNewline);
result.append(extraIndent)
.append(" extends super.")
.append(escaping_.get_().escapeName(d));
appendPositionalArgs(d, pr, unit, result, true, false);
}
appendConstraints(d, pr, unit, indent, containsNewline, result);
appendImplText(d, pr, isInterface, unit, indent, result, ci);
return result.toString();
}
private static void appendConstraints(Declaration d,
Reference pr, Unit unit, String indent,
boolean containsNewline,
StringBuilder result) {
if (d instanceof Generic) {
Generic generic = (Generic) d;
for (TypeParameter tp: generic.getTypeParameters()) {
List<Type> sts = tp.getSatisfiedTypes();
if (!sts.isEmpty()) {
String extraIndent =
extraIndent(extraIndent(indent, containsNewline),
containsNewline);
result.append(extraIndent)
.append("given ")
.append(tp.getName())
.append(" satisfies ");
boolean first = true;
for (Type st: sts) {
if (first) {
first = false;
}
else {
result.append("&");
}
if (pr instanceof Type) {
st = st.substitute((Type) pr);
}
else {
st = st.substitute((TypedReference) pr);
}
result.append(st.asSourceCodeString(unit));
}
}
}
}
}
static String getInlineFunctionTextFor(Parameter p,
Reference pr, Unit unit, String indent) {
StringBuilder result = new StringBuilder();
appendNamedArgumentHeader(p, pr, result, false);
appendTypeParameters(p.getModel(), result);
appendParametersText(p.getModel(), pr, unit, result);
if (p.isDeclaredVoid()) {
result.append(" {}");
}
else {
result.append(" => nothing;");
}
return result.toString();
}
public static boolean isVariable(Declaration d) {
if (d instanceof TypedDeclaration) {
TypedDeclaration td = (TypedDeclaration) d;
return td.isVariable();
}
else {
return false;
}
}
static String getRefinementDescriptionFor(
Declaration d, Reference pr, Unit unit) {
StringBuilder result =
new StringBuilder("shared actual ");
if (isVariable(d)) {
result.append("variable ");
}
appendDeclarationHeaderDescription(d, pr, unit, result);
appendTypeParameters(d, result);
appendParametersDescription(d, pr, unit, result);
/*result.append(" \u2014 refine declaration in ")
.append(((Declaration) d.getContainer()).getName());*/
return result.toString();
}
static String getInlineFunctionDescriptionFor(
Parameter p, Reference pr, Unit unit) {
StringBuilder result = new StringBuilder();
appendNamedArgumentHeader(p, pr, result, true);
appendTypeParameters(p.getModel(), result);
appendParametersDescription(p.getModel(), pr, unit, result);
return result.toString();
}
public static String getLabelDescriptionFor(
Declaration d) {
return getLabelDescriptionFor(d, true, true);
}
public static String getLabelDescriptionFor(
Declaration d,
boolean typeParams, boolean params) {
StringBuilder result = new StringBuilder();
if (d!=null) {
appendDeclarationAnnotations(d, result);
appendDeclarationHeaderDescription(d, d.getUnit(), result);
if (typeParams) appendTypeParameters(d, result, true);
if (params) appendParametersDescription(d, result, null);
}
return result.toString();
}
private static void appendDeclarationAnnotations(
Declaration d, StringBuilder result) {
if (d.isActual()) {
result.append("actual ");
}
if (d.isFormal()) {
result.append("formal ");
}
if (d.isDefault()) {
result.append("default ");
}
if (isVariable(d)) {
result.append("variable ");
}
}
public static String getDocDescriptionFor(
Declaration d, Reference pr, Unit unit) {
StringBuilder result = new StringBuilder();
appendDeclarationHeaderDescription(d, pr, unit, result);
appendTypeParameters(d, pr, result, true, unit);
appendParametersDescription(d, pr, unit, result);
return result.toString();
}
public static StyledString getQualifiedDescriptionFor(
Declaration d) {
return getQualifiedDescriptionFor(d, true, true, true,
CeylonPlugin.getPreferences()
.getBoolean(RETURN_TYPES_IN_OUTLINES));
}
public static StyledString getQualifiedDescriptionFor(
Declaration d,
boolean typeParameters, boolean parameters, boolean parameterTypes,
boolean types) {
return getQualifiedDescriptionFor(d,
typeParameters, parameters, parameterTypes,
types, null, null);
}
public static StyledString getQualifiedDescriptionFor(
Declaration d,
boolean typeParameters, boolean parameters, boolean parameterTypes,
boolean types, String prefix, Font font) {
StyledString result = new StyledString();
if (d!=null) {
appendDeclarationDescription(d, result);
result.append(' ');
if (d.isClassOrInterfaceMember()) {
Declaration ci =
(Declaration)
d.getContainer();
appendQualifyingTypeName(result, ci, prefix, font);
appendMemberName(d, result, prefix, font);
}
else {
appendDeclarationName(d, result, prefix, font);
}
if (typeParameters) {
appendTypeParameters(d, result, true);
}
if (parameters||parameterTypes) {
appendParametersDescription(d, result,
parameters, parameterTypes);
}
if (d instanceof TypedDeclaration) {
if (types) {
TypedDeclaration td =
(TypedDeclaration) d;
if (!td.isParameter() &&
!td.isDynamicallyTyped() &&
!(td instanceof Function &&
((Function) td).isDeclaredVoid())) {
Type t = td.getType();
if (t!=null) {
result.append(" ∊ ");
appendTypeName(result, t, ARROW_STYLER);
}
}
}
}
/*result.append(" \u2014 refines declaration in ")
.append(((Declaration) d.getContainer()).getName());*/
}
return result;
}
private static void appendQualifyingTypeName(
StyledString result,
Declaration ci, String prefix, Font font) {
String name = ci.getName();
if (prefix!=null) {
int loc = prefix.indexOf('.');
if (loc>0) {
prefix = prefix.substring(0, loc);
}
styleIdentifier(result, prefix, name,
TYPE_ID_STYLER, font);
}
else {
result.append(name, TYPE_ID_STYLER);
}
result.append('.');
}
public static StyledString getStyledDescriptionFor(
Declaration d) {
StyledString result = new StyledString();
if (d!=null) {
appendDeclarationAnnotations(d, result);
appendDeclarationDescription(d, result);
result.append(' ');
appendDeclarationName(d, result);
appendTypeParameters(d, result, true);
appendParametersDescription(d, result, true, true);
if (d instanceof TypedDeclaration) {
if (CeylonPlugin.getPreferences()
.getBoolean(RETURN_TYPES_IN_OUTLINES)) {
TypedDeclaration td =
(TypedDeclaration) d;
if (!td.isParameter() &&
!td.isDynamicallyTyped() &&
!(td instanceof Function &&
((Function) td).isDeclaredVoid())) {
Type t = td.getType();
if (t!=null) {
result.append(" ∊ ");
appendTypeName(result, t, ARROW_STYLER);
}
}
}
}
/*result.append(" \u2014 refines declaration in ")
.append(((Declaration) d.getContainer()).getName());*/
}
return result;
}
private static void appendDeclarationAnnotations(Declaration d,
StyledString result) {
if (d.isActual()) {
result.append("actual ", ANN_STYLER);
}
if (d.isFormal()) {
result.append("formal ", ANN_STYLER);
}
if (d.isDefault()) {
result.append("default ", ANN_STYLER);
}
if (isVariable(d)) {
result.append("variable ", ANN_STYLER);
}
}
public static void appendPositionalArgs(Declaration dec,
Unit unit, StringBuilder result, boolean includeDefaulted,
boolean descriptionOnly) {
appendPositionalArgs(dec, dec.getReference(),
unit, result, includeDefaulted,
descriptionOnly);
}
private static void appendPositionalArgs(
Declaration d, Reference pr,
Unit unit, StringBuilder result, boolean includeDefaulted,
boolean descriptionOnly) {
if (d instanceof Functional) {
List<Parameter> params = getParameters((Functional) d,
includeDefaulted, false);
if (params.isEmpty()) {
result.append("()");
}
else {
boolean paramTypes =
descriptionOnly &&
CeylonPlugin.getPreferences()
.getBoolean(PARAMETER_TYPES_IN_COMPLETIONS);
result.append("(");
for (Parameter p: params) {
TypedReference typedParameter =
pr.getTypedParameter(p);
if (p.getModel() instanceof Functional) {
if (p.isDeclaredVoid()) {
result.append("void ");
}
appendParameters(p.getModel(),
typedParameter,
unit, result,
descriptionOnly);
if (p.isDeclaredVoid()) {
result.append(" {}");
}
else {
result.append(" => ")
.append("nothing");
}
}
else {
Type pt = typedParameter.getType();
if (paramTypes && !isTypeUnknown(pt)) {
if (p.isSequenced()) {
pt = unit.getSequentialElementType(pt);
}
result.append(pt.asString(unit));
if (p.isSequenced()) {
result.append(p.isAtLeastOne()?'+':'*');
}
result.append(" ");
}
else if (p.isSequenced()) {
result.append("*");
}
result.append(descriptionOnly || p.getModel()==null ?
p.getName() : escaping_.get_().escapeName(p.getModel()));
}
result.append(", ");
}
result.setLength(result.length()-2);
result.append(")");
}
}
}
static void appendSuperArgsText(Declaration d,
Reference pr, Unit unit, StringBuilder result,
boolean includeDefaulted) {
if (d instanceof Functional) {
List<Parameter> params =
getParameters((Functional) d,
includeDefaulted, false);
if (params.isEmpty()) {
result.append("()");
}
else {
result.append("(");
for (Parameter p: params) {
if (p.isSequenced()) {
result.append("*");
}
result.append(escaping_.get_().escapeName(p.getModel()))
.append(", ");
}
result.setLength(result.length()-2);
result.append(")");
}
}
}
private static List<Parameter> getParameters(Functional fd,
boolean includeDefaults, boolean namedInvocation) {
List<ParameterList> plists = fd.getParameterLists();
if (plists==null || plists.isEmpty()) {
return Collections.<Parameter>emptyList();
}
else {
return CompletionUtil.getParameters(plists.get(0),
includeDefaults, namedInvocation);
}
}
private static void appendNamedArgs(
Declaration d, Reference pr,
Unit unit, StringBuilder result,
boolean includeDefaulted,
boolean descriptionOnly) {
if (d instanceof Functional) {
List<Parameter> params =
getParameters((Functional) d,
includeDefaulted, true);
if (params.isEmpty()) {
result.append(" {}");
}
else {
boolean paramTypes =
descriptionOnly &&
CeylonPlugin.getPreferences()
.getBoolean(PARAMETER_TYPES_IN_COMPLETIONS);
result.append(" { ");
for (Parameter p: params) {
String name = descriptionOnly ?
p.getName() :
escaping_.get_().escapeName(p.getModel());
if (p.getModel() instanceof Functional) {
if (p.isDeclaredVoid()) {
result.append("void ");
}
else {
if (paramTypes &&
!isTypeUnknown(p.getType())) {
String ptn = p.getType().asString(unit);
result.append(ptn).append(" ");
}
else {
result.append("function ");
}
}
result.append(name);
appendParameters(p.getModel(),
pr.getTypedParameter(p),
unit, result,
descriptionOnly);
if (descriptionOnly) {
result.append("; ");
}
else if (p.isDeclaredVoid()) {
result.append(" {} ");
}
else {
result.append(" => ")
//.append(CeylonQuickFixAssistant.defaultValue(p.getUnit(), p.getType()))
.append("nothing; ");
}
}
else {
if (p==params.get(params.size()-1) &&
!isTypeUnknown(p.getType()) &&
unit.isIterableParameterType(p.getType())) {
// result.append(" ");
}
else {
if (paramTypes &&
!isTypeUnknown(p.getType())) {
String ptn = p.getType().asString(unit);
result.append(ptn).append(" ");
}
result.append(name)
.append(" = ")
//.append(CeylonQuickFixAssistant.defaultValue(p.getUnit(), p.getType()))
.append("nothing")
.append("; ");
}
}
}
result.append("}");
}
}
}
private static void appendTypeParameters(
Declaration d, StringBuilder result) {
appendTypeParameters(d, result, false);
}
private static void appendTypeParameters(
Declaration d, StringBuilder result,
boolean variances) {
if (d instanceof Generic) {
Generic g = (Generic) d;
List<TypeParameter> types =
g.getTypeParameters();
if (!types.isEmpty()) {
result.append("<");
for (TypeParameter tp: types) {
if (variances) {
if (tp.isCovariant()) {
result.append("out ");
}
if (tp.isContravariant()) {
result.append("in ");
}
}
result.append(tp.getName())
.append(", ");
}
result.setLength(result.length()-2);
result.append(">");
}
}
}
private static void appendTypeParameters(
Declaration d, Reference pr,
StringBuilder result,
boolean variances, Unit unit) {
if (d instanceof Generic) {
Generic g = (Generic) d;
List<TypeParameter> types =
g.getTypeParameters();
if (!types.isEmpty()) {
result.append("<");
boolean first = true;
for (TypeParameter tp: types) {
if (first) {
first = false;
}
else {
result.append(", ");
}
Type arg = pr==null ? null :
pr.getTypeArguments().get(tp);
if (arg == null) {
if (variances) {
if (tp.isCovariant()) {
result.append("out ");
}
else if (tp.isContravariant()) {
result.append("in ");
}
}
result.append(tp.getName());
}
else {
if (pr instanceof Type) {
if (variances) {
Type t = (Type) pr;
SiteVariance variance =
t.getVarianceOverrides()
.get(tp);
if (variance==null) {
if (tp.isCovariant()) {
result.append("out ");
}
else if (tp.isContravariant()) {
result.append("in ");
}
}
else if (variance==SiteVariance.OUT) {
result.append("out ");
}
else if (variance==SiteVariance.IN) {
result.append("in ");
}
}
}
result.append(arg.asString(unit));
}
}
result.append(">");
}
}
}
private static void appendTypeParameters(
Declaration d, StyledString result,
boolean variances) {
if (d instanceof Generic) {
Generic g = (Generic) d;
List<TypeParameter> types =
g.getTypeParameters();
if (!types.isEmpty()) {
result.append("<");
int len = types.size(), i = 0;
for (TypeParameter tp: types) {
if (variances) {
if (tp.isCovariant()) {
result.append("out ", KW_STYLER);
}
if (tp.isContravariant()) {
result.append("in ", KW_STYLER);
}
}
result.append(tp.getName(), TYPE_STYLER);
if (++i<len) {
result.append(", ");
}
}
result.append(">");
}
}
}
private static void appendDeclarationHeaderDescription(
Declaration d, Unit unit,
StringBuilder result) {
appendDeclarationHeader(d, null, unit, result, true);
}
private static void appendDeclarationHeaderDescription(
Declaration d, Reference pr, Unit unit,
StringBuilder result) {
appendDeclarationHeader(d, pr, unit, result, true);
}
private static void appendDeclarationHeaderText(
Declaration d, Reference pr, Unit unit,
StringBuilder result) {
appendDeclarationHeader(d, pr, unit, result, false);
}
private static void appendDeclarationHeader(
Declaration d, Reference pr, Unit unit,
StringBuilder result,
boolean descriptionOnly) {
if (d instanceof TypeAlias && d.isAnonymous()) {
return;
}
if (isConstructor(d)) {
result.append("new");
}
else if (d instanceof Class) {
if (d.isAnonymous()) {
result.append("object");
}
else {
result.append("class");
}
}
else if (d instanceof Interface) {
result.append("interface");
}
else if (d instanceof TypeAlias) {
result.append("alias");
}
else if (d instanceof TypedDeclaration) {
TypedDeclaration td = (TypedDeclaration) d;
FunctionOrValue fov = (FunctionOrValue) d;
boolean isSequenced =
d.isParameter() &&
fov.getInitializerParameter()
.isSequenced();
Type type;
if (pr == null) {
type = td.getType();
}
else {
type = pr.getType();
}
if (isSequenced && type!=null) {
// type = unit.getIteratedType(type);
//TODO: nasty workaround because unit can be null
// in docs for Open dialogs
List<Type> args = type.getTypeArgumentList();
if (args.size()>0) {
type = args.get(0);
}
}
if (type==null) {
type = unit.getUnknownType();
}
String typeName =
descriptionOnly ?
type.asString(unit) :
type.asSourceCodeString(unit);
if (td.isDynamicallyTyped()) {
result.append("dynamic");
}
else if (td instanceof Value &&
type.getDeclaration()
.isAnonymous() &&
!type.isTypeConstructor()) {
result.append("object");
}
else if (d instanceof Function) {
Functional fun = (Functional) d;
if (fun.isDeclaredVoid()) {
result.append("void");
}
else {
result.append(typeName);
}
}
else {
result.append(typeName);
}
if (isSequenced) {
if (fov.getInitializerParameter()
.isAtLeastOne()) {
result.append("+");
}
else {
result.append("*");
}
}
}
result.append(" ");
if (d.getName()!=null) {
result.append(descriptionOnly ?
d.getName() : escaping_.get_().escapeName(d));
}
}
private static void appendNamedArgumentHeader(
Parameter p, Reference pr,
StringBuilder result,
boolean descriptionOnly) {
if (p.getModel() instanceof Functional) {
Functional fp = (Functional) p.getModel();
result.append(fp.isDeclaredVoid() ? "void" : "function");
}
else {
result.append("value");
}
result.append(" ")
.append(descriptionOnly ?
p.getName() :
escaping_.get_().escapeName(p.getModel()));
}
private static void appendDeclarationDescription(
Declaration d, StyledString result) {
if (isConstructor(d)) {
result.append("new", KW_STYLER);
}
else if (d instanceof Class) {
if (d.isAnonymous()) {
result.append("object", KW_STYLER);
}
else {
result.append("class", KW_STYLER);
}
}
else if (d instanceof Interface) {
result.append("interface", KW_STYLER);
}
else if (d instanceof TypeAlias) {
result.append("alias", KW_STYLER);
}
else if (d.isParameter()) {
TypedDeclaration td = (TypedDeclaration) d;
Type type = td.getType();
if (td.isDynamicallyTyped()) {
result.append("dynamic", KW_STYLER);
}
else if (type!=null) {
FunctionOrValue fov = (FunctionOrValue) d;
boolean isSequenced = //d.isParameter() &&
fov.getInitializerParameter()
.isSequenced();
if (isSequenced) {
type = d.getUnit().getIteratedType(type);
}
/*if (td instanceof Value &&
td.getTypeDeclaration().isAnonymous()) {
result.append("object", KW_STYLER);
}
else*/ if (d instanceof Function) {
Functional fun = (Functional) d;
if (fun.isDeclaredVoid()) {
result.append("void", KW_STYLER);
}
else {
appendTypeName(result, type);
}
}
else {
appendTypeName(result, type);
}
if (isSequenced) {
result.append("*");
}
}
}
else if (d instanceof Value) {
Value v = (Value) d;
if (v.isDynamicallyTyped()) {
result.append("dynamic", KW_STYLER);
}
else if (v.getTypeDeclaration()!=null &&
v.getTypeDeclaration().isAnonymous()) {
result.append("object", KW_STYLER);
}
else {
result.append("value", KW_STYLER);
}
}
else if (d instanceof Function) {
Function m = (Function) d;
if (m.isDynamicallyTyped()) {
result.append("dynamic", KW_STYLER);
}
else if (m.isDeclaredVoid()) {
result.append("void", KW_STYLER);
}
else {
result.append("function", KW_STYLER);
}
}
else if (d instanceof Setter) {
result.append("assign", KW_STYLER);
}
}
private static void appendMemberName(
Declaration d,
StyledString result,
String prefix, Font font) {
String name = d.getName();
if (name!=null) {
Styler styler =
d instanceof TypeDeclaration ?
TYPE_STYLER : MEMBER_STYLER;
if (prefix!=null) {
int loc = prefix.indexOf('.');
if (loc>0) {
prefix = prefix.substring(loc);
}
styleIdentifier(result, prefix, name,
styler, font);
}
else {
result.append(name, styler);
}
}
}
private static void appendDeclarationName(
Declaration d,
StyledString result,
String prefix, Font font) {
String name = d.getName();
if (name!=null) {
Styler styler =
d instanceof TypeDeclaration ?
TYPE_STYLER : MEMBER_STYLER;
if (prefix!=null) {
styleIdentifier(result, prefix, name,
styler, font);
}
else {
result.append(name, styler);
}
}
}
private static void appendDeclarationName(
Declaration d,
StyledString result) {
appendDeclarationName(d, result, null, null);
}
/*private static void appendPackage(Declaration d, StringBuilder result) {
if (d.isToplevel()) {
result.append(" \u2014 ").append(getPackageLabel(d));
}
if (d.isClassOrInterfaceMember()) {
result.append(" \u2014 ");
ClassOrInterface td = (ClassOrInterface) d.getContainer();
result.append( td.getName() );
appendPackage(td, result);
}
}*/
private static void appendImplText(
Declaration d, Reference pr,
boolean isInterface, Unit unit,
String indent, StringBuilder result,
ClassOrInterface ci) {
if (d instanceof Function) {
Function fun = (Function) d;
if (ci!=null && !ci.isAnonymous()) {
if (d.getName().equals("equals")) {
List<ParameterList> pl =
fun.getParameterLists();
if (!pl.isEmpty()) {
List<Parameter> ps =
pl.get(0).getParameters();
if (!ps.isEmpty()) {
appendEqualsImpl(unit, indent,
result, ci, ps);
return;
}
}
}
}
if (!d.isFormal()) {
result.append(" => super.")
.append(d.getName());
appendSuperArgsText(d, pr, unit, result, true);
result.append(";");
}
else {
if (fun.isDeclaredVoid()) {
result.append(" {}");
}
else {
result.append(" => nothing;");
}
}
}
else if (d instanceof Value) {
if (ci!=null && !ci.isAnonymous()) {
if (d.getName().equals("hash")) {
appendHashImpl(unit, indent, result, ci);
return;
}
}
if (isInterface/*||d.isParameter()*/) {
//interfaces can't have references,
//so generate a setter for variables
if (d.isFormal()) {
result.append(" => nothing;");
}
else {
result.append(" => super.")
.append(d.getName())
.append(";");
}
if (isVariable(d)) {
result.append(indent)
.append("assign ")
.append(d.getName())
.append(" {}");
}
}
else {
//we can have a references, so use = instead
//of => for variables
String arrow =
isVariable(d) ? " = " : " => ";
if (d.isFormal()) {
result.append(arrow)
.append("nothing;");
}
else {
result.append(arrow)
.append("super.")
.append(d.getName())
.append(";");
}
}
}
else {
//TODO: in the case of a class, formal member refinements!
result.append(" {}");
}
}
private static void appendHashImpl(Unit unit, String indent,
StringBuilder result, ClassOrInterface ci) {
if (hasUniqueMemberForHash(unit, ci)) {
Value value = getUniqueMemberForHash(unit, ci);
result.append(" => ")
.append(value.getName());
if (!value.getType().isInteger()) {
result.append(".hash");
}
result.append(";");
}
else {
result.append(" {")
.append(indent).append(utilJ2C().indents().getDefaultIndent())
.append("variable value hash = 1;")
.append(indent).append(utilJ2C().indents().getDefaultIndent());
String ind = indent + utilJ2C().indents().getDefaultIndent();
appendMembersToHash(unit, ind, result, ci);
result.append("return hash;")
.append(indent)
.append("}");
}
}
private static void appendEqualsImpl(Unit unit, String indent,
StringBuilder result, ClassOrInterface ci, List<Parameter> ps) {
Parameter p = ps.get(0);
StringBuilder targs = new StringBuilder();
if (!ci.getTypeParameters().isEmpty()) {
targs.append("<");
for (TypeParameter tp: ci.getTypeParameters()) {
if (targs.length()>1) {
targs.append(",");
}
String bounds =
unit.denotableType(intersectionOfSupertypes(tp))
.asSourceCodeString(unit);
if (tp.isCovariant()) {
targs.append(bounds);
}
else if (tp.isContravariant()) {
targs.append("Nothing");
}
else {
targs.append("out ").append(bounds);
}
}
targs.append(">");
}
result.append(" {")
.append(indent).append(utilJ2C().indents().getDefaultIndent())
.append("if (is ").append(ci.getName()).append(targs).append(" ").append(p.getName()).append(") {")
.append(indent).append(utilJ2C().indents().getDefaultIndent()).append(utilJ2C().indents().getDefaultIndent())
.append("return ");
String ind = indent+utilJ2C().indents().getDefaultIndent()+utilJ2C().indents().getDefaultIndent()+utilJ2C().indents().getDefaultIndent();
appendMembersToEquals(unit, ind, result, ci, p);
result.append(indent).append(utilJ2C().indents().getDefaultIndent())
.append("}")
.append(indent).append(utilJ2C().indents().getDefaultIndent())
.append("else {")
.append(indent).append(utilJ2C().indents().getDefaultIndent()).append(utilJ2C().indents().getDefaultIndent())
.append("return false;")
.append(indent).append(utilJ2C().indents().getDefaultIndent())
.append("}")
.append(indent)
.append("}");
}
private static boolean isObjectField(Declaration m) {
String name = m.getName();
return name!=null &&
(name.equals("hash") ||
name.equals("string"));
}
private static void appendMembersToEquals(Unit unit,
String indent, StringBuilder result,
ClassOrInterface ci, Parameter p) {
boolean found = false;
Type nt = unit.getNullValueDeclaration().getType();
for (Declaration m: ci.getMembers()) {
if (m instanceof Value &&
!isObjectField(m) && !isConstructor(m)) {
Value value = (Value) m;
if (!value.isTransient()) {
if (!nt.isSubtypeOf(value.getType())) {
result.append(value.getName())
.append("==")
.append(p.getName())
.append(".")
.append(value.getName())
.append(" && ")
.append(indent);
found = true;
}
}
}
}
if (found) {
result.setLength(result.length()-4-indent.length());
result.append(";");
}
else {
result.append("true;");
}
}
private static void appendMembersToHash(Unit unit,
String indent, StringBuilder result,
ClassOrInterface ci) {
Type nt = unit.getNullValueDeclaration().getType();
for (Declaration m: ci.getMembers()) {
if (m instanceof Value &&
!isObjectField(m) && !isConstructor(m)) {
Value value = (Value) m;
if (!value.isTransient() &&
!nt.isSubtypeOf(value.getType())) {
result.append("hash = 31*hash + ")
.append(value.getName());
if (!value.getType().isInteger()) {
result.append(".hash");
}
result.append(";").append(indent);
}
}
}
}
private static boolean hasUniqueMemberForHash(Unit unit,
ClassOrInterface ci) {
int count = 0;
Type nt = unit.getNullValueDeclaration().getType();
for (Declaration m: ci.getMembers()) {
if (m instanceof Value &&
!isObjectField(m) && !isConstructor(m)) {
Value value = (Value) m;
if (!value.isTransient() &&
!nt.isSubtypeOf(value.getType())) {
count++;
}
}
}
return count==1;
}
private static Value getUniqueMemberForHash(Unit unit,
ClassOrInterface ci) {
Type nt = unit.getNullValueDeclaration().getType();
for (Declaration m: ci.getMembers()) {
if (m instanceof Value &&
!isObjectField(m) && !isConstructor(m)) {
Value value = (Value) m;
if (!value.isTransient() &&
!nt.isSubtypeOf(value.getType())) {
return value;
}
}
}
return null;
}
private static String extraIndent(String indent, boolean containsNewline) {
return containsNewline ? indent + utilJ2C().indents().getDefaultIndent() : indent;
}
public static void appendParametersDescription(Declaration d, StringBuilder result,
CeylonParseController cpc) {
appendParameters(d, null, d.getUnit(), result, cpc, true);
}
public static void appendParametersText(Declaration d, Reference pr,
Unit unit, StringBuilder result) {
appendParameters(d, pr, unit, result, null, false);
}
private static void appendParametersDescription(Declaration d, Reference pr,
Unit unit, StringBuilder result) {
appendParameters(d, pr, unit, result, null, true);
}
private static void appendParameters(Declaration d, Reference pr,
Unit unit, StringBuilder result, boolean descriptionOnly) {
appendParameters(d, pr, unit, result, null, descriptionOnly);
}
private static void appendParameters(Declaration d, Reference pr,
Unit unit, StringBuilder result, CeylonParseController cpc,
boolean descriptionOnly) {
if (d instanceof Functional) {
List<ParameterList> plists = ((Functional) d).getParameterLists();
if (plists!=null) {
for (ParameterList params: plists) {
if (params.getParameters().isEmpty()) {
result.append("()");
}
else {
result.append("(");
for (Parameter p: params.getParameters()) {
appendParameter(result, pr, p, unit,
descriptionOnly);
if (cpc!=null) {
result.append(getDefaultValueDescription(p, cpc));
}
result.append(", ");
}
result.setLength(result.length()-2);
result.append(")");
}
}
}
}
}
public static void appendParameterText(StringBuilder result,
Reference pr, Parameter p, Unit unit) {
appendParameter(result, pr, p, unit, false);
}
private static void appendParameter(StringBuilder result,
Reference pr, Parameter p, Unit unit,
boolean descriptionOnly) {
if (p.getModel() == null) {
result.append(p.getName());
}
else {
TypedReference ppr = pr==null ?
null : pr.getTypedParameter(p);
appendDeclarationHeader(p.getModel(), ppr, unit, result,
descriptionOnly);
appendParameters(p.getModel(), ppr, unit, result,
descriptionOnly);
}
}
public static void appendParameterContextInfo(StringBuilder result,
Reference pr, Parameter p, Unit unit,
boolean namedInvocation, boolean isListedValues) {
if (p.getModel() == null) {
result.append(p.getName());
}
else {
TypedReference ppr = pr==null ?
null : pr.getTypedParameter(p);
String typeName;
Type type = ppr.getType();
if (isListedValues && namedInvocation) {
Type et = unit.getIteratedType(type);
typeName = et.asString(unit);
if (unit.isEntryType(et)) {
typeName = '<' + typeName + '>';
}
typeName += unit.isNonemptyIterableType(type) ? '+' : '*';
}
else if (p.isSequenced() && !namedInvocation) {
Type et = unit.getSequentialElementType(type);
typeName = et.asString(unit);
if (unit.isEntryType(et)) {
typeName = '<' + typeName + '>';
}
typeName += p.isAtLeastOne() ? '+' : '*';
}
else {
typeName = type.asString(unit);
}
result.append(typeName).append(" ").append(p.getName());
appendParametersDescription(p.getModel(), ppr, unit, result);
}
if (namedInvocation && !isListedValues) {
result.append(p.getModel() instanceof Function ?
" => ... " : " = ... " );
}
}
private static void appendParametersDescription(Declaration d, StyledString result,
boolean names, boolean types) {
if (d instanceof Functional) {
List<ParameterList> plists = ((Functional) d).getParameterLists();
if (plists!=null) {
for (ParameterList params: plists) {
if (params.getParameters().isEmpty()) {
result.append("()");
}
else {
result.append("(");
int len = params.getParameters().size();
int i=0;
for (Parameter p: params.getParameters()) {
if (p.getModel()==null) {
if (names) {
result.append(p.getName());
}
}
else {
if (types) {
appendDeclarationDescription(p.getModel(), result);
}
if (names && types) {
result.append(' ');
}
if (names) {
appendDeclarationName(p.getModel(), result);
}
appendParametersDescription(p.getModel(), result, names, types);
/*result.append(p.getType().asString(), TYPE_STYLER)
.append(" ").append(p.getName(), ID_STYLER);
if (p instanceof FunctionalParameter) {
result.append("(");
FunctionalParameter fp = (FunctionalParameter) p;
List<Parameter> fpl = fp.getParameterLists().get(0).getParameters();
int len2 = fpl.size(), j=0;
for (Parameter pp: fpl) {
result.append(pp.getType().asString(), TYPE_STYLER)
.append(" ").append(pp.getName(), ID_STYLER);
if (++j<len2) result.append(", ");
}
result.append(")");
}*/
}
if (++i<len) result.append(", ");
}
result.append(")");
}
}
}
}
}
}