use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class GenerateJsVisitor method addInterfaceToPrototype.
private void addInterfaceToPrototype(ClassOrInterface type, final Tree.InterfaceDefinition interfaceDef, InitDeferrer initDeferrer) {
if (type.isDynamic())
return;
TypeGenerator.interfaceDefinition(interfaceDef, this, initDeferrer);
Interface d = interfaceDef.getDeclarationModel();
if (d.isStatic()) {
out(names.name(type), ".$st$.", names.name(d), "=", names.name(d));
} else {
out(names.self(type), ".", names.name(d), "=", names.name(d));
}
endLine(true);
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class GenerateJsVisitor method addToPrototype.
void addToPrototype(Node node, ClassOrInterface d, List<Tree.Statement> statements) {
final boolean isSerial = d instanceof Class && ((Class) d).isSerializable();
boolean enter = opts.isOptimize();
ArrayList<Parameter> plist = null;
final boolean isAbstractNative = TypeUtils.makeAbstractNative(d);
final String typename = names.name(d);
final boolean overrideToString = d.getDirectMember("toString", null, true) == null;
if (enter) {
enter = !statements.isEmpty() | overrideToString;
if (d instanceof Class) {
ParameterList cpl = ((Class) d).getParameterList();
if (cpl != null) {
plist = new ArrayList<>(cpl.getParameters().size());
plist.addAll(cpl.getParameters());
enter |= !plist.isEmpty();
}
}
}
if (enter || isSerial) {
final List<? extends Statement> prevStatements = currentStatements;
currentStatements = statements;
out("(function(", names.self(d), ")");
beginBlock();
if (enter) {
// First of all, add an object to store statics only if needed
for (Statement s : statements) {
}
// Generated attributes with corresponding parameters will remove them from the list
if (plist != null) {
for (Parameter p : plist) {
generateAttributeForParameter(node, (Class) d, p);
}
}
boolean statics = false;
InitDeferrer initDeferrer = new InitDeferrer();
for (Statement s : statements) {
if (!statics && s instanceof Tree.Declaration) {
Declaration sd = ((Tree.Declaration) s).getDeclarationModel();
if (sd.isStatic()) {
statics = true;
out(names.name(d), ".$st$={};");
}
}
if (!(s instanceof Tree.ClassOrInterface) && !(s instanceof Tree.AttributeDeclaration && ((Tree.AttributeDeclaration) s).getDeclarationModel().isParameter())) {
addToPrototype(d, s, plist, initDeferrer);
}
}
for (Statement s : statements) {
if (s instanceof Tree.ClassOrInterface) {
addToPrototype(d, s, plist, initDeferrer);
} else if (s instanceof Tree.Enumerated) {
// Add a simple attribute which really returns the singleton from the class
final Tree.Enumerated vc = (Tree.Enumerated) s;
Value vcd = vc.getDeclarationModel();
defineAttribute(names.self(d), names.name(vcd));
out("{return ", typename, names.constructorSeparator(vcd), names.name(vcd), "();},undefined,");
TypeUtils.encodeForRuntime(vc, vcd, vc.getAnnotationList(), this);
out(");");
}
}
for (String stmt : initDeferrer.deferred) {
out(stmt);
endLine();
}
if (d.isMember()) {
ClassOrInterface coi = ModelUtil.getContainingClassOrInterface(d.getContainer());
if (coi != null && d.inherits(coi)) {
out(names.self(d), ".", typename, "=", typename, ";");
}
}
}
if (isSerial && !isAbstractNative) {
SerializationHelper.addSerializer(node, (Class) d, this);
}
if (overrideToString) {
out(names.self(d), ".", "toString=function(){return this.string.valueOf();};");
}
endBlock();
out(")(", typename, ".$$.prototype)");
endLine(true);
currentStatements = prevStatements;
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class GenerateJsVisitor method stitchNative.
/**
* Reads a file with hand-written snippet and outputs it to the current writer.
*/
boolean stitchNative(final Declaration d, final Tree.Declaration n) {
final VirtualFile f = compiler.getStitchedFile(d, ".js");
if (f != null && f.exists()) {
if (compiler.isCompilingLanguageModule()) {
jsout.outputFile(f);
}
if (d.isClassOrInterfaceMember()) {
if (d instanceof Value || n instanceof Tree.Constructor) {
// Constructor metamodel is done in TypeGenerator.classConstructor
return true;
}
out(names.self((TypeDeclaration) d.getContainer()), ".");
} else if (n instanceof Tree.AttributeDeclaration || n instanceof Tree.AttributeGetterDefinition) {
return true;
}
out(names.name(d), ".$crtmm$=");
TypeUtils.encodeForRuntime(n, d, n.getAnnotationList(), this);
endLine(true);
return true;
} else {
if (!(d instanceof ClassOrInterface || n instanceof Tree.MethodDefinition || (n instanceof Tree.MethodDeclaration && ((Tree.MethodDeclaration) n).getSpecifierExpression() != null) || n instanceof Tree.AttributeGetterDefinition || (n instanceof Tree.AttributeDeclaration && ((Tree.AttributeDeclaration) n).getSpecifierOrInitializerExpression() != null))) {
String missingDeclarationName = d.getName();
if (missingDeclarationName == null && d instanceof Constructor) {
missingDeclarationName = "default constructor";
} else {
missingDeclarationName = "'" + missingDeclarationName + "'";
}
final String err = "no native implementation for backend: native " + missingDeclarationName + " is not implemented for the 'js' backend";
n.addError(err, Backend.JavaScript);
out("/*", err, "*/");
}
return false;
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class GenerateJsVisitor method qualifiedPath.
public String qualifiedPath(final Node that, final Declaration d, final boolean inProto) {
if (d instanceof Constructor) {
Class c = (Class) d.getContainer();
final String rval = qualifiedPath(that, c, inProto);
return rval.isEmpty() ? names.name(c) : rval + "." + names.name(c);
}
final boolean isMember = d.isClassOrInterfaceMember();
final boolean imported = isImported(that == null ? null : that.getUnit().getPackage(), d);
if (!isMember && imported) {
return names.moduleAlias(d.getUnit().getPackage().getModule());
} else if (opts.isOptimize() && !inProto) {
if (isMember && !(d.isParameter() && !d.isJsCaptured())) {
TypeDeclaration id = that.getScope().getInheritingDeclaration(d);
TypeDeclaration nd = null;
if (id == null) {
// a local declaration of some kind,
// perhaps in an outer scope
id = (TypeDeclaration) d.getContainer();
if (id.isNativeHeader()) {
nd = (TypeDeclaration) ModelUtil.getNativeDeclaration(id, Backend.JavaScript);
}
}
Scope scope = ModelUtil.getRealScope(that.getScope());
if (scope instanceof Value && !(ModelUtil.getRealScope(scope) instanceof ClassOrInterface)) {
scope = ModelUtil.getRealScope(scope.getContainer());
}
if ((scope != null) && (that instanceof Tree.ClassDeclaration || that instanceof Tree.InterfaceDeclaration || that instanceof Tree.Constructor)) {
// class/interface aliases have no own "this"
scope = scope.getContainer();
}
final StringBuilder path = new StringBuilder();
final Declaration innermostDeclaration = ModelUtil.getContainingDeclarationOfScope(scope);
while (scope != null) {
if (scope instanceof Constructor && scope == innermostDeclaration) {
TypeDeclaration consCont = (TypeDeclaration) scope.getContainer();
if (that instanceof Tree.BaseTypeExpression) {
path.append(names.name(consCont));
} else if (d.isStatic()) {
path.append(names.name(consCont)).append(".$st$");
} else {
path.append(names.self(consCont));
}
if (scope == id || (nd != null && scope == nd)) {
break;
}
scope = consCont;
} else if (scope instanceof TypeDeclaration) {
if (path.length() > 0) {
if (scope instanceof Constructor == false) {
Constructor constr = scope instanceof Class ? ((Class) scope).getDefaultConstructor() : null;
if ((constr == null || !ModelUtil.contains(constr, (Scope) innermostDeclaration)) && !d.isStatic()) {
path.append(".outer$");
}
}
} else if (d instanceof Constructor && ModelUtil.getContainingDeclaration(d) == scope) {
if (!d.getName().equals(((TypeDeclaration) scope).getName())) {
if (path.length() > 0) {
path.append('.');
}
path.append(names.name((TypeDeclaration) scope));
}
} else {
if (path.length() > 0) {
path.append('.');
}
if (d.isStatic()) {
if (d instanceof TypedDeclaration) {
TypedDeclaration orig = ((TypedDeclaration) d).getOriginalDeclaration();
path.append(names.name((ClassOrInterface) (orig == null ? d : orig).getContainer())).append(".$st$");
} else if (d instanceof TypeDeclaration) {
path.append(names.name((ClassOrInterface) d.getContainer())).append(".$st$");
}
} else {
path.append(names.self((TypeDeclaration) scope));
}
}
} else {
path.setLength(0);
}
if (scope == id || (nd != null && scope == nd)) {
break;
}
scope = scope.getContainer();
}
if (id != null && path.length() == 0 && !ModelUtil.contains(id, that.getScope())) {
// Import of toplevel object or constructor
if (imported) {
path.append(names.moduleAlias(id.getUnit().getPackage().getModule())).append('.');
}
if (id.isAnonymous()) {
path.append(names.objectName(id));
} else {
Import imp = findImport(that, d);
if (imp == null) {
path.append(names.name(id));
} else {
path.append(names.objectName(imp.getTypeDeclaration()));
}
}
}
return path.toString();
}
} else if (d != null) {
if (isMember && (d.isShared() || inProto || !d.isParameter() && AttributeGenerator.defineAsProperty(d))) {
TypeDeclaration id = d instanceof TypeAlias ? (TypeDeclaration) d : that.getScope().getInheritingDeclaration(d);
if (id == null) {
// a local declaration of some kind,
// perhaps in an outer scope
id = (TypeDeclaration) d.getContainer();
if (id.isToplevel() && !ModelUtil.contains(id, that.getScope())) {
// Import of toplevel object or constructor
final StringBuilder sb = new StringBuilder();
if (imported) {
sb.append(names.moduleAlias(id.getUnit().getPackage().getModule())).append('.');
}
sb.append(id.isAnonymous() ? names.objectName(id) : names.name(id));
return sb.toString();
} else if (d instanceof Constructor) {
return names.name(id);
} else {
// a shared local declaration
return names.self(id);
}
} else {
// inherited by an outer scope
return names.self(id);
}
}
}
return "";
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ClassGenerator method classDefinition.
static void classDefinition(final Tree.ClassDefinition that, final GenerateJsVisitor gen, InitDeferrer initDeferrer) {
// Don't even bother with nodes that have errors
if (TypeGenerator.errVisitor.hasErrors(that))
return;
final Class d = that.getDeclarationModel();
// If it's inside a dynamic interface, don't generate anything
if (d.isClassOrInterfaceMember() && ((ClassOrInterface) d.getContainer()).isDynamic())
return;
final Class natd = (Class) ModelUtil.getNativeDeclaration(d, Backend.JavaScript);
final boolean headerWithoutBackend = NativeUtil.isHeaderWithoutBackend(that, Backend.JavaScript);
if (natd != null && (headerWithoutBackend || NativeUtil.isNativeHeader(that))) {
// It's a native header, remember it for later when we deal with its implementation
gen.saveNativeHeader(that);
return;
}
if (!(NativeUtil.isForBackend(that, Backend.JavaScript) || headerWithoutBackend)) {
return;
}
final Tree.ParameterList plist = that.getParameterList();
// final Tree.SatisfiedTypes sats = that.getSatisfiedTypes();
final List<Tree.Statement> stmts;
if (NativeUtil.isForBackend(d, Backend.JavaScript)) {
Tree.Declaration nh = gen.getNativeHeader(d);
if (nh == null && NativeUtil.hasNativeMembers(d)) {
nh = that;
}
stmts = NativeUtil.mergeStatements(that.getClassBody(), nh, Backend.JavaScript);
} else {
stmts = that.getClassBody().getStatements();
}
// Find the constructors, if any
final List<Tree.Constructor> constructors;
Tree.Constructor defconstr = null;
final boolean hasConstructors = d.hasConstructors() || (natd != null && natd.hasConstructors());
final boolean hasEnumerated = d.hasEnumerated() || (natd != null && natd.hasEnumerated());
if (hasConstructors) {
constructors = new ArrayList<>(3);
for (Tree.Statement st : stmts) {
if (st instanceof Tree.Constructor) {
Tree.Constructor constr = (Tree.Constructor) st;
constructors.add(constr);
if (constr.getDeclarationModel().getName() == null) {
defconstr = constr;
}
}
}
} else {
constructors = null;
}
gen.comment(that);
final boolean isAbstractNative = d.isNativeHeader() && natd != null;
final String typeName = gen.getNames().name(d);
if (TypeUtils.isNativeExternal(d)) {
boolean bye = false;
if (hasConstructors && defconstr == null) {
gen.out(GenerateJsVisitor.function, typeName);
gen.out("(){");
gen.generateThrow("Exception", d.getQualifiedNameString() + " has no default constructor.", that);
gen.out(";}");
gen.endLine();
}
if (gen.stitchNative(d, that)) {
if (d.isShared()) {
gen.share(d);
}
TypeGenerator.initializeType(that, gen, initDeferrer);
bye = true;
}
if (hasConstructors) {
for (Tree.Constructor cnstr : constructors) {
Constructors.classConstructor(cnstr, that, constructors, gen);
}
}
if (bye)
return;
}
gen.out(GenerateJsVisitor.function, typeName);
// If there's a default constructor, create a different function with this code
if (hasConstructors || hasEnumerated) {
if (defconstr == null) {
gen.out("(){");
gen.generateThrow("Exception", d.getQualifiedNameString() + " has no default constructor.", that);
gen.out(";}");
gen.endLine();
gen.out(GenerateJsVisitor.function, typeName);
}
gen.out("$$c");
}
// counterparts
if (isAbstractNative) {
if (plist != null) {
for (Parameter p : d.getParameterList().getParameters()) {
gen.getNames().forceName(natd.getParameter(p.getName()).getModel(), gen.getNames().name(p));
}
}
for (Declaration hd : d.getMembers()) {
if (!hd.isShared()) {
gen.getNames().forceName(natd.getMember(hd.getName(), null, false), gen.getNames().name(hd));
}
}
}
final boolean withTargs = TypeGenerator.generateParameters(that.getTypeParameterList(), plist, d, gen);
gen.beginBlock();
if (!hasConstructors) {
// This takes care of top-level attributes defined before the class definition
gen.out("$init$", typeName, "();");
gen.endLine();
gen.declareSelf(d);
gen.referenceOuter(d);
}
final String me = gen.getNames().self(d);
if (withTargs) {
gen.out(gen.getClAlias(), "set_type_args(", me, ",$$targs$$);");
gen.endLine();
}
addFunctionTypeArguments(d, me, gen);
List<Tree.Parameter> defparams = null;
if (plist != null) {
defparams = gen.initParameters(plist, d, null);
}
callSupertypes(that, d, typeName, gen);
if (!gen.opts.isOptimize() && plist != null) {
// Fix #231 for lexical scope
for (Tree.Parameter p : plist.getParameters()) {
if (!p.getParameterModel().isHidden()) {
gen.generateAttributeForParameter(that, d, p.getParameterModel());
}
}
}
if (!hasConstructors) {
if (TypeUtils.isNativeExternal(d)) {
gen.stitchConstructorHelper(that, "_cons_before");
}
gen.visitStatements(stmts);
if (TypeUtils.isNativeExternal(d)) {
gen.stitchConstructorHelper(that, "_cons_after");
}
gen.out("return ", me, ";");
}
gen.endBlockNewLine();
if (defconstr != null) {
// Define a function as the class and call the default constructor in there
String _this = "undefined";
if (!d.isToplevel()) {
final ClassOrInterface coi = ModelUtil.getContainingClassOrInterface(d.getContainer());
if (coi != null) {
if (d.isClassOrInterfaceMember()) {
_this = "this";
} else {
_this = gen.getNames().self(coi);
}
}
}
gen.out(GenerateJsVisitor.function, typeName, "(){return ", typeName, gen.getNames().constructorSeparator(defconstr.getDeclarationModel()), gen.getNames().name(defconstr.getDeclarationModel()), ".apply(", _this, ",arguments);}");
gen.endLine();
}
if (hasConstructors) {
for (Tree.Constructor cnstr : constructors) {
Constructors.classConstructor(cnstr, that, constructors, gen);
}
}
if (hasEnumerated) {
for (Tree.Statement st : stmts) {
if (st instanceof Tree.Enumerated) {
Singletons.valueConstructor(that, (Tree.Enumerated) st, gen);
}
}
}
if (defparams != null) {
for (Tree.Parameter p : defparams) {
final SpecifierOrInitializerExpression expr = gen.getDefaultExpression(p);
if (expr != null) {
// Optimizing for certain expressions such as null and literals is tempting
// but we need to put them in functions if we want them to work in subtypes
gen.out(typeName, ".$defs$", p.getParameterModel().getName(), "=function(", me);
for (Parameter otherP : d.getParameterList().getParameters()) {
if (!otherP.equals(p.getParameterModel())) {
gen.out(",", gen.getNames().name(otherP));
}
}
gen.out("){return ");
gen.generateParameterExpression(p, expr, d);
gen.out("};");
}
}
}
// Add reference to metamodel
gen.out(typeName, ".$crtmm$=");
TypeUtils.encodeForRuntime(that, d, that.getAnnotationList(), gen);
gen.endLine(true);
if (!isAbstractNative) {
gen.share(d);
}
TypeGenerator.initializeType(that, gen, initDeferrer);
if (d.isSerializable()) {
SerializationHelper.addDeserializer(that, d, gen);
}
}
Aggregations