blob: 0fc7b0b80e2b07542a63bfd194dff353fd5f932a [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.compiler.internal.codegen.js.jx;
import java.util.ArrayList;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel.ImplicitBindableImplementation;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
import org.apache.royale.compiler.internal.tree.as.FunctionNode;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IClassNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
public class MethodEmitter extends JSSubEmitter implements
ISubEmitter<IFunctionNode>
{
public MethodEmitter(IJSEmitter emitter)
{
super(emitter);
}
@Override
public void emit(IFunctionNode node)
{
getModel().getMethods().add(node);
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
FunctionNode fn = (FunctionNode) node;
fn.parseFunctionBody(new ArrayList<ICompilerProblem>());
ICompilerProject project = getWalker().getProject();
fjs.getDocEmitter().emitMethodDoc(node, project);
boolean isConstructor = node.isConstructor();
boolean addingBindableImplementsSupport = isConstructor &&
getModel().getImplicitBindableImplementation() == ImplicitBindableImplementation.IMPLEMENTS;
boolean addingBindableExtendsSupport = !addingBindableImplementsSupport
&& isConstructor
&& getModel().getImplicitBindableImplementation() == ImplicitBindableImplementation.EXTENDS;
String qname = null;
IFunctionDefinition.FunctionClassification classification = fn.getFunctionClassification();
if(classification == IFunctionDefinition.FunctionClassification.FILE_MEMBER ||
classification == IFunctionDefinition.FunctionClassification.PACKAGE_MEMBER)
{
write(fjs.formatQualifiedName(fn.getQualifiedName()));
}
else
{
startMapping(node.getNameExpressionNode());
ITypeDefinition typeDef = EmitterUtils.getTypeDefinition(node);
if (typeDef != null)
{
qname = typeDef.getQualifiedName();
}
if (qname != null && !qname.equals(""))
{
write(fjs.formatQualifiedName(qname));
if (!isConstructor)
{
if (!fn.hasModifier(ASModifier.STATIC))
{
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSEmitterTokens.PROTOTYPE);
}
if (!fjs.isCustomNamespace(fn))
write(ASEmitterTokens.MEMBER_ACCESS);
}
}
if (!isConstructor)
{
fjs.emitMemberName(node);
}
endMapping(node.getNameExpressionNode());
}
if (node.getMetaTags() != null) {
//offset mapping by any metadata tags that will be in the first child node
startMapping(node.getChild(1));
} else {
startMapping(node);
}
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.FUNCTION);
endMapping(node);
fjs.emitParameters(node.getParametersContainerNode());
boolean hasSuperClass = EmitterUtils.hasSuperClass(project, node);
if (isConstructor && node.getScopedNode().getChildCount() == 0)
{
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.BLOCK_OPEN);
if (hasSuperClass && !getEmitter().getModel().isExterns)
fjs.emitSuperCall(node, JSSessionModel.CONSTRUCTOR_EMPTY);
//add whatever variant of the bindable implementation is necessary inside the constructor
if (addingBindableImplementsSupport) {
writeNewline("",true);
fjs.getBindableEmitter().emitBindableImplementsConstructorCode(true);
} else if (addingBindableExtendsSupport) {
IClassDefinition classDefinition = (IClassDefinition) node.getDefinition().getAncestorOfType(IClassDefinition.class);
fjs.getBindableEmitter().emitBindableExtendsConstructorCode(classDefinition.getQualifiedName(),true);
} else
writeNewline();
IClassNode cnode = (IClassNode) node.getAncestorOfType(IClassNode.class);
fjs.emitComplexInitializers(cnode);
write(ASEmitterTokens.BLOCK_CLOSE);
}
if (!isConstructor || node.getScopedNode().getChildCount() > 0)
{
fjs.emitMethodScope(node.getScopedNode());
}
if (isConstructor && !getEmitter().getModel().isExterns)
{
if (hasSuperClass) {
writeNewline(ASEmitterTokens.SEMICOLON);
write(JSGoogEmitterTokens.GOOG_INHERITS);
write(ASEmitterTokens.PAREN_OPEN);
write(fjs.formatQualifiedName(qname));
writeToken(ASEmitterTokens.COMMA);
String sname = EmitterUtils.getSuperClassDefinition(node, project)
.getQualifiedName();
write(fjs.formatQualifiedName(sname));
write(ASEmitterTokens.PAREN_CLOSE);
} else if (addingBindableExtendsSupport) {
//add goog.inherits for the 'extends' bindable implementation support
writeNewline(ASEmitterTokens.SEMICOLON);
writeNewline("// Compiler generated Binding support implementation:");
write(JSGoogEmitterTokens.GOOG_INHERITS);
write(ASEmitterTokens.PAREN_OPEN);
write(fjs.formatQualifiedName(qname));
writeToken(ASEmitterTokens.COMMA);
write(fjs.formatQualifiedName(BindableEmitter.DISPATCHER_CLASS_QNAME));
write(ASEmitterTokens.PAREN_CLOSE);
}
}
}
}