http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/ExportWriter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/ExportWriter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/ExportWriter.java new file mode 100644 index 0000000..92244db --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/ExportWriter.java @@ -0,0 +1,230 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.amd; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.flex.compiler.definitions.ITypeDefinition; + +/** + * @author Michael Schmalle + */ +public class ExportWriter +{ + private static final String CLASSES_TYPES = "__CLASSES$TYPES__"; + + private static final String CLASSES_STRINGS = "__CLASSES$STRINGS__"; + + private static final String RUNTIME_TYPES = "__RUNTIME$TYPES__"; + + private static final String RUNTIME_STRINGS = "__RUNTIME$STRINGS__"; + + private final JSAMDEmitter emitter; + + private List<Dependency> runtime = new ArrayList<Dependency>(); + + private List<Dependency> types = new ArrayList<Dependency>(); + + public ExportWriter(JSAMDEmitter emitter) + { + this.emitter = emitter; + } + + public void queueExports(ITypeDefinition type, boolean outputString) + { + if (outputString) + { + emitter.write("["); + emitter.write("\"exports\""); + } + + emitter.write(", "); + + if (outputString) + emitter.write(RUNTIME_STRINGS); + else + emitter.write(RUNTIME_TYPES); + + //emitter.write(", "); + + if (outputString) + emitter.write(CLASSES_STRINGS); + else + emitter.write(CLASSES_TYPES); + + if (outputString) + { + emitter.write("]"); + } + } + + public void writeExports(ITypeDefinition type, boolean outputString) + { + StringBuilder sb = new StringBuilder(); + + int i = 0; + int len = runtime.size(); + + for (Dependency dependency : runtime) + { + sb.append(dependency.output(outputString, "runtime", outputString)); + + if (i < len - 1) + sb.append(", "); + i++; + } + + if (outputString) + { + int start = emitter.builder().indexOf(RUNTIME_STRINGS); + int end = start + RUNTIME_STRINGS.length(); + emitter.builder().replace(start, end, sb.toString()); + } + else + { + int start = emitter.builder().indexOf(RUNTIME_TYPES); + int end = start + RUNTIME_TYPES.length(); + emitter.builder().replace(start, end, sb.toString()); + } + + sb = new StringBuilder(); + + i = 0; + len = types.size(); + if (len > 0) + sb.append(", "); // trailing comma + + for (Dependency dependency : types) + { + sb.append(dependency.output(outputString, "classes", outputString)); + + if (i < len - 1) + sb.append(", "); + i++; + } + + if (outputString) + { + int start = emitter.builder().indexOf(CLASSES_STRINGS); + int end = start + CLASSES_STRINGS.length(); + emitter.builder().replace(start, end, sb.toString()); + } + else + { + int start = emitter.builder().indexOf(CLASSES_TYPES); + int end = start + CLASSES_TYPES.length(); + emitter.builder().replace(start, end, sb.toString()); + } + } + + void addImports(ITypeDefinition type) + { + Collection<String> imports = new ArrayList<String>(); + type.getContainedScope().getScopeNode().getAllImports(imports); + for (String imp : imports) + { + String name = toBaseName(imp); + if (!isExcludedImport(imp)) + addDependency(name, imp, false, false); + } + } + + void addFrameworkDependencies() + { + runtime.add(new Dependency("AS3", "AS3", false, false)); + } + + protected boolean isExcludedImport(String imp) + { + return imp.startsWith("__AS3__"); + } + + public void addDependency(String baseName, String qualifiedName, + boolean isNative, boolean isPlugin) + { + types.add(new Dependency(baseName, qualifiedName, isNative, isPlugin)); + } + + static String toBaseName(String name) + { + if (!name.contains(".")) + return name; + final String basename = name.substring(name.lastIndexOf(".") + 1); + return basename; + } + + static class Dependency + { + private final String baseName; + + private final String qualifiedName; + + public String getQualifiedName() + { + return qualifiedName; + } + + private final boolean isNative; + + public boolean isNative() + { + return isNative; + } + + @SuppressWarnings("unused") + private final boolean isPlugin; + + public Dependency(String baseName, String qualifiedName, + boolean isNative, boolean isPlugin) + { + this.baseName = baseName; + this.qualifiedName = qualifiedName; + this.isNative = isNative; + this.isPlugin = isPlugin; + } + + @Override + public String toString() + { + return qualifiedName; // TODO (mschmalle|AMD) native + } + + public String output(boolean outputString, String base, + boolean qualified) + { + StringBuilder sb = new StringBuilder(); + if (outputString) + { + sb.append("\"" + base + "/" + + qualifiedName.replaceAll("\\.", "/") + "\""); + } + else + { + if (qualified) + sb.append(qualifiedName); + else + sb.append(baseName); + } + return sb.toString(); + } + } +}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDDocEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDDocEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDDocEmitter.java new file mode 100644 index 0000000..c79dd3d --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDDocEmitter.java @@ -0,0 +1,37 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.amd; + +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.codegen.js.amd.IJSAMDDocEmitter; +import org.apache.flex.compiler.internal.codegen.js.JSDocEmitter; + +/** + * @author Michael Schmalle + */ +public class JSAMDDocEmitter extends JSDocEmitter implements IJSAMDDocEmitter +{ + + public JSAMDDocEmitter(IJSEmitter emitter) + { + super(emitter); + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitter.java new file mode 100644 index 0000000..fd19e42 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitter.java @@ -0,0 +1,971 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.amd; + +import java.io.FilterWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.flex.compiler.codegen.js.amd.IJSAMDDocEmitter; +import org.apache.flex.compiler.codegen.js.amd.IJSAMDEmitter; +import org.apache.flex.compiler.definitions.IAccessorDefinition; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IConstantDefinition; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +import org.apache.flex.compiler.definitions.IInterfaceDefinition; +import org.apache.flex.compiler.definitions.IPackageDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; +import org.apache.flex.compiler.definitions.IVariableDefinition; +import org.apache.flex.compiler.definitions.references.IReference; +import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSEmitter; +import org.apache.flex.compiler.internal.codegen.js.JSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.utils.EmitterUtils; +import org.apache.flex.compiler.internal.definitions.ClassTraitsDefinition; +import org.apache.flex.compiler.internal.tree.as.FunctionCallNode; +import org.apache.flex.compiler.internal.tree.as.FunctionNode; +import org.apache.flex.compiler.internal.tree.as.IdentifierNode; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.scopes.IASScope; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IAccessorNode; +import org.apache.flex.compiler.tree.as.IBlockNode; +import org.apache.flex.compiler.tree.as.IClassNode; +import org.apache.flex.compiler.tree.as.IContainerNode; +import org.apache.flex.compiler.tree.as.IDefinitionNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IFunctionCallNode; +import org.apache.flex.compiler.tree.as.IFunctionNode; +import org.apache.flex.compiler.tree.as.IGetterNode; +import org.apache.flex.compiler.tree.as.IIdentifierNode; +import org.apache.flex.compiler.tree.as.IInterfaceNode; +import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode; +import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.ISetterNode; +import org.apache.flex.compiler.tree.as.ITypeNode; +import org.apache.flex.compiler.tree.as.IVariableNode; +import org.apache.flex.compiler.utils.NativeUtils; + +/** + * Concrete implementation of the 'AMD' JavaScript production. + * + * @author Michael Schmalle + */ +public class JSAMDEmitter extends JSEmitter implements IJSAMDEmitter +{ + + private Map<String, IDefinitionNode> foundAccessors = new HashMap<String, IDefinitionNode>(); + + private int inheritenceLevel = -1; + + private ExportWriter exportWriter; + + private boolean initializingFieldsInConstructor; + + private List<IDefinition> baseClassCalls = new ArrayList<IDefinition>(); + + StringBuilder builder() + { + return getBuilder(); + } + + IJSAMDDocEmitter getDoc() + { + return (IJSAMDDocEmitter) getDocEmitter(); + } + + public JSAMDEmitter(FilterWriter out) + { + super(out); + + exportWriter = new ExportWriter(this); + } + + @Override + public void emitPackageHeader(IPackageDefinition definition) + { + // TODO (mschmalle|AMD) this is a hack but I know no other way to do replacements in a Writer + setBufferWrite(true); + + write(JSAMDEmitterTokens.DEFINE); + write(ASEmitterTokens.PAREN_OPEN); + + IASScope containedScope = definition.getContainedScope(); + ITypeDefinition type = findType(containedScope.getAllLocalDefinitions()); + if (type == null) + return; + + exportWriter.addFrameworkDependencies(); + exportWriter.addImports(type); + + exportWriter.queueExports(type, true); + + writeToken(ASEmitterTokens.COMMA); + } + + @Override + public void emitPackageHeaderContents(IPackageDefinition definition) + { + // nothing + } + + @Override + public void emitPackageContents(IPackageDefinition definition) + { + IASScope containedScope = definition.getContainedScope(); + ITypeDefinition type = findType(containedScope.getAllLocalDefinitions()); + if (type == null) + return; + + write("function($exports"); + + exportWriter.queueExports(type, false); + + write(") {"); + indentPush(); + writeNewline(); + write("\"use strict\"; "); + writeNewline(); + + ITypeNode tnode = findTypeNode(definition.getNode()); + if (tnode != null) + { + getWalker().walk(tnode); // IClassNode | IInterfaceNode + } + + indentPop(); + writeNewline(); + write("}"); // end returned function + } + + @Override + public void emitPackageFooter(IPackageDefinition definition) + { + IASScope containedScope = definition.getContainedScope(); + ITypeDefinition type = findType(containedScope.getAllLocalDefinitions()); + if (type == null) + return; + + exportWriter.writeExports(type, true); + exportWriter.writeExports(type, false); + + write(");"); // end define() + + // flush the buffer, writes the builder to out + flushBuilder(); + } + + private void emitConstructor(IFunctionNode node) + { + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(getProblems()); + + //IFunctionDefinition definition = node.getDefinition(); + + write("function "); + write(node.getName()); + emitParameters(node.getParametersContainerNode()); + if (!isImplicit((IContainerNode) node.getScopedNode())) + { + emitMethodScope(node.getScopedNode()); + } + else + { + // we have a synthesized constructor, implict + } + } + + @Override + public void emitInterface(IInterfaceNode node) + { + final IInterfaceDefinition definition = node.getDefinition(); + final String interfaceName = definition.getBaseName(); + + write("AS3.interface_($exports, {"); + indentPush(); + writeNewline(); + + write("package_: \""); + write(definition.getPackageName()); + write("\","); + writeNewline(); + + write("interface_: \""); + write(interfaceName); + write("\""); + + IReference[] references = definition.getExtendedInterfaceReferences(); + final int len = references.length; + if (len > 0) + { + writeNewline(); + write("extends_: ["); + indentPush(); + writeNewline(); + int i = 0; + for (IReference reference : references) + { + write(reference.getName()); + if (i < len - 1) + { + write(","); + writeNewline(); + } + i++; + } + indentPop(); + writeNewline(); + write("]"); + } + + indentPop(); + writeNewline(); + write("});"); // end compilation unit + } + + @Override + public void emitClass(IClassNode node) + { + //ICompilerProject project = getWalker().getProject(); + + IClassDefinition definition = node.getDefinition(); + getModel().setCurrentClass(definition); + + final String className = definition.getBaseName(); + + write("AS3.compilationUnit($exports, function($primaryDeclaration){"); + indentPush(); + writeNewline(); + + // write constructor + emitConstructor((IFunctionNode) definition.getConstructor().getNode()); + writeNewline(); + + // base class + IReference baseClassReference = definition.getBaseClassReference(); + boolean hasSuper = baseClassReference != null + && !baseClassReference.getName().equals("Object"); + if (hasSuper) + { + String baseName = baseClassReference.getName(); + write("var Super = (" + baseName + "._ || " + baseName + + "._$get());"); + writeNewline(); + write("var super$ = Super.prototype;"); + writeNewline(); + } + + write("$primaryDeclaration(AS3.class_({"); + indentPush(); + writeNewline(); + + // write out package + write("package_: \"" + definition.getPackageName() + "\","); + writeNewline(); + // write class + write("class_: \"" + definition.getBaseName() + "\","); + writeNewline(); + if (hasSuper) + { + write("extends_: Super,"); + writeNewline(); + } + + IReference[] references = definition + .getImplementedInterfaceReferences(); + int len = references.length; + + // write implements + write("implements_:"); + write(" ["); + + if (len > 0) + { + indentPush(); + writeNewline(); + } + + int i = 0; + for (IReference reference : references) + { + write(reference.getName()); + exportWriter.addDependency(reference.getName(), + reference.getDisplayString(), false, false); + if (i < len - 1) + { + write(","); + writeNewline(); + } + i++; + } + + if (len > 0) + { + indentPop(); + writeNewline(); + } + + write("],"); + writeNewline(); + + // write members + final IDefinitionNode[] members = node.getAllMemberNodes(); + + write("members: {"); + + indentPush(); + writeNewline(); + + // constructor + write("constructor: " + className); + if (members.length > 0) + { + write(","); + writeNewline(); + } + + List<IDefinitionNode> instanceMembers = new ArrayList<IDefinitionNode>(); + List<IDefinitionNode> staticMembers = new ArrayList<IDefinitionNode>(); + List<IASNode> staticStatements = new ArrayList<IASNode>(); + + TempTools.fillInstanceMembers(members, instanceMembers); + TempTools.fillStaticMembers(members, staticMembers, true, false); + TempTools.fillStaticStatements(node, staticStatements, false); + + len = instanceMembers.size(); + i = 0; + for (IDefinitionNode mnode : instanceMembers) + { + if (mnode instanceof IAccessorNode) + { + if (foundAccessors.containsKey(mnode.getName())) + { + len--; + continue; + } + + getWalker().walk(mnode); + } + else if (mnode instanceof IFunctionNode) + { + getWalker().walk(mnode); + } + else if (mnode instanceof IVariableNode) + { + getWalker().walk(mnode); + } + else + { + write(mnode.getName()); + } + + if (i < len - 1) + { + write(","); + writeNewline(); + } + i++; + } + + // base class super calls + len = baseClassCalls.size(); + i = 0; + if (len > 0) + { + write(","); + writeNewline(); + } + + for (IDefinition baseCall : baseClassCalls) + { + write(baseCall.getBaseName() + "$" + inheritenceLevel + ": super$." + + baseCall.getBaseName()); + + if (i < len - 1) + { + write(","); + writeNewline(); + } + } + + // end members + indentPop(); + writeNewline(); + write("},"); + writeNewline(); + + len = staticMembers.size(); + + write("staticMembers: {"); + + indentPush(); + writeNewline(); + + i = 0; + for (IDefinitionNode mnode : staticMembers) + { + if (mnode instanceof IAccessorNode) + { + // TODO (mschmalle|AMD) havn't taken care of static accessors + if (foundAccessors.containsKey(mnode.getName())) + continue; + + foundAccessors.put(mnode.getName(), mnode); + + getWalker().walk(mnode); + } + else if (mnode instanceof IFunctionNode) + { + getWalker().walk(mnode); + } + else if (mnode instanceof IVariableNode) + { + getWalker().walk(mnode); + } + + if (i < len - 1) + { + write(","); + writeNewline(); + } + i++; + } + indentPop(); + if (len > 0) + writeNewline(); + write("}"); + + indentPop(); + writeNewline(); + write("}));"); + + // static statements + len = staticStatements.size(); + if (len > 0) + writeNewline(); + + i = 0; + for (IASNode statement : staticStatements) + { + getWalker().walk(statement); + if (!(statement instanceof IBlockNode)) + write(";"); + + if (i < len - 1) + writeNewline(); + + i++; + } + + indentPop(); + writeNewline(); + write("});"); // end compilation unit + + } + + //-------------------------------------------------------------------------- + // + //-------------------------------------------------------------------------- + + @Override + public void emitField(IVariableNode node) + { + IVariableDefinition definition = (IVariableDefinition) node + .getDefinition(); + + if (definition.isStatic()) + { + IClassDefinition parent = (IClassDefinition) definition.getParent(); + write(parent.getBaseName()); + write("."); + write(definition.getBaseName()); + write(" = "); + emitFieldInitialValue(node); + return; + } + + String name = toPrivateName(definition); + write(name); + write(": "); + write("{"); + indentPush(); + writeNewline(); + // field value + write("value:"); + emitFieldInitialValue(node); + write(","); + writeNewline(); + // writable + write("writable:"); + write(!(definition instanceof IConstantDefinition) ? "true" : "false"); + indentPop(); + writeNewline(); + write("}"); + } + + private void emitFieldInitialValue(IVariableNode node) + { + ICompilerProject project = getWalker().getProject(); + IVariableDefinition definition = (IVariableDefinition) node + .getDefinition(); + + IExpressionNode valueNode = node.getAssignedValueNode(); + if (valueNode != null) + getWalker().walk(valueNode); + else + write(TempTools.toInitialValue(definition, project)); + } + + @Override + public void emitGetAccessor(IGetterNode node) + { + if (foundAccessors.containsKey(node.getName())) + return; + + foundAccessors.put(node.getName(), node); + + ICompilerProject project = getWalker().getProject(); + IAccessorDefinition getter = (IAccessorDefinition) node.getDefinition(); + IAccessorDefinition setter = getter + .resolveCorrespondingAccessor(project); + + emitGetterSetterPair(getter, setter); + } + + @Override + public void emitSetAccessor(ISetterNode node) + { + if (foundAccessors.containsKey(node.getName())) + return; + + foundAccessors.put(node.getName(), node); + + ICompilerProject project = getWalker().getProject(); + IAccessorDefinition setter = (IAccessorDefinition) node.getDefinition(); + IAccessorDefinition getter = setter + .resolveCorrespondingAccessor(project); + + emitGetterSetterPair(getter, setter); + } + + private void emitGetterSetterPair(IAccessorDefinition getter, + IAccessorDefinition setter) + { + write(getter.getBaseName()); + write(": {"); + indentPush(); + writeNewline(); + + if (getter != null) + { + emitAccessor("get", getter); + } + if (setter != null) + { + write(","); + writeNewline(); + emitAccessor("set", setter); + } + + indentPop(); + writeNewline(); + write("}"); + + } + + protected void emitAccessor(String kind, IAccessorDefinition definition) + { + IFunctionNode fnode = definition.getFunctionNode(); + + FunctionNode fn = (FunctionNode) fnode; + fn.parseFunctionBody(new ArrayList<ICompilerProblem>()); + + write(kind + ": function "); + write(definition.getBaseName() + "$" + kind); + emitParameters(fnode.getParametersContainerNode()); + emitMethodScope(fnode.getScopedNode()); + } + + @Override + public void emitMethod(IFunctionNode node) + { + if (node.isConstructor()) + { + emitConstructor(node); + return; + } + + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(new ArrayList<ICompilerProblem>()); + IFunctionDefinition definition = node.getDefinition(); + + String name = toPrivateName(definition); + write(name); + write(":"); + write(" function "); + write(node.getName()); + emitParameters(node.getParametersContainerNode()); + emitMethodScope(node.getScopedNode()); + } + + @Override + public void emitFunctionBlockHeader(IFunctionNode node) + { + IFunctionDefinition definition = node.getDefinition(); + + if (node.isConstructor()) + { + initializingFieldsInConstructor = true; + IClassDefinition type = (IClassDefinition) definition + .getAncestorOfType(IClassDefinition.class); + // emit public fields init values + List<IVariableDefinition> fields = TempTools.getFields(type, true); + for (IVariableDefinition field : fields) + { + if (TempTools.isVariableAParameter(field, + definition.getParameters())) + continue; + write("this."); + write(field.getBaseName()); + write(" = "); + emitFieldInitialValue((IVariableNode) field.getNode()); + write(";"); + writeNewline(); + } + initializingFieldsInConstructor = false; + } + + emitDefaultParameterCodeBlock(node); + } + + private void emitDefaultParameterCodeBlock(IFunctionNode node) + { + // TODO (mschmalle|AMD) test for ... rest + // if default parameters exist, produce the init code + IParameterNode[] pnodes = node.getParameterNodes(); + Map<Integer, IParameterNode> defaults = TempTools.getDefaults(pnodes); + if (pnodes.length == 0) + return; + + if (defaults != null) + { + boolean hasBody = node.getScopedNode().getChildCount() > 0; + + if (!hasBody) + { + indentPush(); + write(ASEmitterTokens.INDENT); + } + + final StringBuilder code = new StringBuilder(); + + List<IParameterNode> parameters = new ArrayList<IParameterNode>( + defaults.values()); + Collections.reverse(parameters); + + int len = defaults.size(); + // make the header in reverse order + for (IParameterNode pnode : parameters) + { + if (pnode != null) + { + code.setLength(0); + + code.append(ASEmitterTokens.IF.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.PAREN_OPEN.getToken()); + code.append(JSEmitterTokens.ARGUMENTS.getToken()); + code.append(ASEmitterTokens.MEMBER_ACCESS.getToken()); + code.append(JSAMDEmitterTokens.LENGTH.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.LESS_THAN.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(len); + code.append(ASEmitterTokens.PAREN_CLOSE.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.BLOCK_OPEN.getToken()); + + write(code.toString()); + + indentPush(); + writeNewline(); + } + len--; + } + + Collections.reverse(parameters); + for (int i = 0, n = parameters.size(); i < n; i++) + { + IParameterNode pnode = parameters.get(i); + + if (pnode != null) + { + code.setLength(0); + + code.append(pnode.getName()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.EQUAL.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(pnode.getDefaultValue()); + code.append(ASEmitterTokens.SEMICOLON.getToken()); + write(code.toString()); + + indentPop(); + writeNewline(); + + write(ASEmitterTokens.BLOCK_CLOSE); + + if (i == n - 1 && !hasBody) + indentPop(); + + writeNewline(); + } + } + } + } + + @Override + public void emitParameter(IParameterNode node) + { + getWalker().walk(node.getNameExpressionNode()); + } + + @Override + public void emitMemberAccessExpression(IMemberAccessExpressionNode node) + { + getWalker().walk(node.getLeftOperandNode()); + if (!(node.getLeftOperandNode() instanceof ILanguageIdentifierNode)) + write(node.getOperator().getOperatorText()); + getWalker().walk(node.getRightOperandNode()); + } + + @Override + public void emitFunctionCall(IFunctionCallNode node) + { + if (node.isNewExpression()) + { + write(ASEmitterTokens.NEW); + write(ASEmitterTokens.SPACE); + } + // IDefinition resolve = node.resolveType(project); + // if (NativeUtils.isNative(resolve.getBaseName())) + // { + // + // } + + getWalker().walk(node.getNameNode()); + + emitArguments(node.getArgumentsNode()); + } + + @Override + public void emitArguments(IContainerNode node) + { + IContainerNode newNode = node; + FunctionCallNode fnode = (FunctionCallNode) node.getParent(); + if (TempTools.injectThisArgument(fnode, false)) + { + IdentifierNode thisNode = new IdentifierNode("this"); + newNode = EmitterUtils.insertArgumentsBefore(node, thisNode); + } + + int len = newNode.getChildCount(); + write(ASEmitterTokens.PAREN_OPEN); + for (int i = 0; i < len; i++) + { + IExpressionNode inode = (IExpressionNode) newNode.getChild(i); + if (inode.getNodeID() == ASTNodeID.IdentifierID) + { + emitArgumentIdentifier((IIdentifierNode) inode); + } + else + { + getWalker().walk(inode); + } + + if (i < len - 1) + { + writeToken(ASEmitterTokens.COMMA); + } + } + write(ASEmitterTokens.PAREN_CLOSE); + } + + private void emitArgumentIdentifier(IIdentifierNode node) + { + ITypeDefinition type = node.resolveType(getWalker().getProject()); + if (type instanceof ClassTraitsDefinition) + { + String qualifiedName = type.getQualifiedName(); + write(qualifiedName); + } + else + { + // XXX A problem? + getWalker().walk(node); + } + } + + @Override + public void emitIdentifier(IIdentifierNode node) + { + ICompilerProject project = getWalker().getProject(); + + IDefinition resolve = node.resolve(project); + if (TempTools.isBinding(node, project)) + { + // AS3.bind( this,"secret$1"); + // this will happen on the right side of the = sign to bind a methof/function + // to a variable + + write("AS3.bind(this, \"" + toPrivateName(resolve) + "\")"); + } + else + { + IExpressionNode leftBase = TempTools.getNode(node, false, project); + if (leftBase == node) + { + if (TempTools.isValidThis(node, project)) + write("this."); + // in constructor and a type + if (initializingFieldsInConstructor + && resolve instanceof IClassDefinition) + { + String name = resolve.getBaseName(); + write("(" + name + "._ || " + name + "._$get())"); + return; + } + } + + if (resolve != null) + { + // TODO (mschmalle|AMD) optimize + String name = toPrivateName(resolve); + if (NativeUtils.isNative(name)) + exportWriter.addDependency(name, name, true, false); + + if (node.getParent() instanceof IMemberAccessExpressionNode) + { + IMemberAccessExpressionNode mnode = (IMemberAccessExpressionNode) node + .getParent(); + if (mnode.getLeftOperandNode().getNodeID() == ASTNodeID.SuperID) + { + IIdentifierNode lnode = (IIdentifierNode) mnode + .getRightOperandNode(); + + IClassNode cnode = (IClassNode) node + .getAncestorOfType(IClassNode.class); + + initializeInheritenceLevel(cnode.getDefinition()); + + // super.foo(); + write("this."); + + write(lnode.getName() + "$" + inheritenceLevel); + + baseClassCalls.add(resolve); + + return; + } + } + write(name); + } + else + { + // no definition, just plain ole identifer + write(node.getName()); + } + } + } + + @Override + protected void emitType(IExpressionNode node) + { + } + + @Override + public void emitLanguageIdentifier(ILanguageIdentifierNode node) + { + if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.ANY_TYPE) + { + write(""); + } + else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.REST) + { + write(""); + } + else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.SUPER) + { + IIdentifierNode inode = (IIdentifierNode) node; + if (inode.getParent() instanceof IMemberAccessExpressionNode) + { + + } + else + { + write("Super.call"); + } + } + else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.THIS) + { + write(""); + } + else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.VOID) + { + write(""); + } + } + + private String toPrivateName(IDefinition definition) + { + if (definition instanceof ITypeDefinition) + return definition.getBaseName(); + if (!definition.isPrivate()) + return definition.getBaseName(); + + initializeInheritenceLevel(definition); + + return definition.getBaseName() + "$" + inheritenceLevel; + } + + void initializeInheritenceLevel(IDefinition definition) + { + if (inheritenceLevel != -1) + return; + + IClassDefinition cdefinition = null; + if (definition instanceof IClassDefinition) + cdefinition = (IClassDefinition) definition; + else + cdefinition = (IClassDefinition) definition + .getAncestorOfType(IClassDefinition.class); + + ICompilerProject project = getWalker().getProject(); + IClassDefinition[] ancestry = cdefinition.resolveAncestry(project); + inheritenceLevel = ancestry.length - 1; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitterTokens.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitterTokens.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitterTokens.java new file mode 100644 index 0000000..122f711 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/JSAMDEmitterTokens.java @@ -0,0 +1,38 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.amd; + +import org.apache.flex.compiler.codegen.IEmitterTokens; + +public enum JSAMDEmitterTokens implements IEmitterTokens +{ + DEFINE("define"), LENGTH("length"), ; + + private String token; + + private JSAMDEmitterTokens(String value) + { + token = value; + } + + public String getToken() + { + return token; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/TempTools.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/TempTools.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/TempTools.java new file mode 100644 index 0000000..4d0d6f2 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/amd/TempTools.java @@ -0,0 +1,451 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.amd; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.flex.compiler.common.ASModifier; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +import org.apache.flex.compiler.definitions.IParameterDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; +import org.apache.flex.compiler.definitions.IVariableDefinition; +import org.apache.flex.compiler.definitions.references.IReference; +import org.apache.flex.compiler.internal.definitions.ClassTraitsDefinition; +import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase; +import org.apache.flex.compiler.internal.tree.as.FunctionCallNode; +import org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IBinaryOperatorNode; +import org.apache.flex.compiler.tree.as.IClassNode; +import org.apache.flex.compiler.tree.as.IDefinitionNode; +import org.apache.flex.compiler.tree.as.IDynamicAccessNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IForLoopNode; +import org.apache.flex.compiler.tree.as.IFunctionCallNode; +import org.apache.flex.compiler.tree.as.IFunctionNode; +import org.apache.flex.compiler.tree.as.IIdentifierNode; +import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode; +import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind; +import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.IUnaryOperatorNode; +import org.apache.flex.compiler.tree.as.IVariableNode; + +/** + * These tools need to be refactored into utility classes. + * + * @author Michael Schmalle + */ +public class TempTools +{ + + public static void fillStaticStatements(IClassNode node, + List<IASNode> list, boolean excludeFields) + { + int len = node.getScopedNode().getChildCount(); + for (int i = 0; i < len; i++) + { + IASNode child = node.getScopedNode().getChild(i); + if (child instanceof IExpressionNode) + list.add(child); + else if (child instanceof IDefinitionNode) + { + if (!excludeFields + && ((IDefinitionNode) child) + .hasModifier(ASModifier.STATIC) + && child instanceof IVariableNode) + list.add(child); + } + } + } + + public static void fillInstanceMembers(IDefinitionNode[] members, + List<IDefinitionNode> list) + { + for (IDefinitionNode node : members) + { + if (node instanceof IFunctionNode + && ((IFunctionNode) node).isConstructor()) + continue; + + if (!node.hasModifier(ASModifier.STATIC)) + { + list.add(node); + } + } + } + + public static void fillStaticMembers(IDefinitionNode[] members, + List<IDefinitionNode> list, boolean excludeFields, + boolean excludeFunctions) + { + for (IDefinitionNode node : members) + { + if (node.hasModifier(ASModifier.STATIC)) + { + if (!excludeFields && node instanceof IVariableNode) + list.add(node); + else if (!excludeFunctions && node instanceof IFunctionNode) + list.add(node); + } + } + } + + public static List<IVariableDefinition> getFields( + IClassDefinition definition, boolean excludePrivate) + { + ArrayList<IVariableDefinition> result = new ArrayList<IVariableDefinition>(); + Collection<IDefinition> definitions = definition.getContainedScope() + .getAllLocalDefinitions(); + for (IDefinition member : definitions) + { + if (!member.isImplicit() && member instanceof IVariableDefinition) + { + IVariableDefinition vnode = (IVariableDefinition) member; + if (!member.isStatic() + && (member.isPublic() || member.isProtected())) + result.add(vnode); + // TODO FIX the logic here, this won't add twice though + if (!excludePrivate && member.isPrivate()) + result.add(vnode); + } + } + return result; + } + + public static boolean isVariableAParameter(IVariableDefinition node, + IParameterDefinition[] parameters) + { + for (IParameterDefinition parameter : parameters) + { + if (node.getBaseName().equals(parameter.getBaseName())) + return true; + } + return false; + } + + public static Map<Integer, IParameterNode> getDefaults( + IParameterNode[] nodes) + { + Map<Integer, IParameterNode> result = new HashMap<Integer, IParameterNode>(); + int i = 0; + boolean hasDefaults = false; + for (IParameterNode node : nodes) + { + if (node.hasDefaultValue()) + { + hasDefaults = true; + result.put(i, node); + } + else + { + result.put(i, null); + } + i++; + } + + if (!hasDefaults) + return null; + + return result; + } + + public static boolean injectThisArgument(FunctionCallNode node, + boolean allowMembers) + { + // if super isSuper checks the nameNode + if (node.isSuperExpression() && !node.isNewExpression()) + return true; + + ExpressionNodeBase base = node.getNameNode(); + if (base.getNodeID() == ASTNodeID.IdentifierID) + return false; + + if (allowMembers && base instanceof IMemberAccessExpressionNode) + { + // foo.super() + IMemberAccessExpressionNode mnode = (IMemberAccessExpressionNode) base; + if (mnode.getLeftOperandNode().getNodeID() == ASTNodeID.SuperID) + return true; + } + + return false; + } + + public static String toInitialValue(IVariableDefinition field, + ICompilerProject project) + { + Object value = field.resolveInitialValue(project); + if (value != null) + return value.toString(); + IReference reference = field.getTypeReference(); + if (reference == null) + return "undefined"; + if (reference.getName().equals("int") + || reference.getName().equals("uint") + || reference.getName().equals("Number")) + return "0"; + return "null"; + } + + public static boolean isBinding(IIdentifierNode node, + ICompilerProject project) + { + IDefinition resolve = node.resolve(project); + + if (resolve != null && resolve.isPrivate() && !isField(resolve)) + { + //if (resolve instanceof IFunctionDefinition) + IExpressionNode rightSide = getNode(node, true, project); + IBinaryOperatorNode parent = (IBinaryOperatorNode) node + .getAncestorOfType(IBinaryOperatorNode.class); + if (isThisLeftOf(node)) + parent = (IBinaryOperatorNode) parent + .getAncestorOfType(IBinaryOperatorNode.class); + + IVariableNode vparent = (IVariableNode) node + .getAncestorOfType(IVariableNode.class); + if (vparent != null) + { + IExpressionNode indentFromThis = getIndentFromThis(node); + if (vparent.getAssignedValueNode() == node + || ((IBinaryOperatorNode) vparent + .getAssignedValueNode()).getRightOperandNode() == indentFromThis) + return true; + } + + if (rightSide == node && parent != null/*|| isThisLeftOf(node)*/) + { + return true; + } + } + + return false; + } + + private static boolean isField(IDefinition node) + { + return !(node instanceof IFunctionDefinition); + } + + public static boolean isValidThis(IIdentifierNode node, + ICompilerProject project) + { + // added super.foo(), wanted to 'this' behind foo + if (node.getParent() instanceof IMemberAccessExpressionNode) + { + IMemberAccessExpressionNode mnode = (IMemberAccessExpressionNode) node + .getParent(); + if (mnode.getLeftOperandNode().getNodeID() == ASTNodeID.SuperID) + return false; + + IExpressionNode indentFromThis = getIndentFromThis(node); + if (node == indentFromThis) + return true; + + // test that this is the base expression + ExpressionNodeBase enode = (ExpressionNodeBase) node; + ExpressionNodeBase baseExpression = enode.getBaseExpression(); + if (indentFromThis == null && baseExpression != null + && baseExpression != node) + return false; + + // check to see if the left is a type + ITypeDefinition type = mnode.getLeftOperandNode().resolveType( + project); + + // A.{foo} : Left is a Type + // XXX going to have to test packgeName to com.acme.A + if (type instanceof ClassTraitsDefinition + && mnode.getLeftOperandNode() == node) + { + return false; + } + // this.{foo} : explicit 'this', in js we are ignoring explicit this identifiers + // because we are inserting all of them with the emitter + else if (indentFromThis == null) + { + //return false; + } + + } + + IDefinition definition = node.resolve(project); + if (definition == null) + return false; // Is this correct? + if (definition instanceof IParameterDefinition) + return false; + if (definition.getParent() instanceof IMemberAccessExpressionNode) + return false; + if (!(definition.getParent() instanceof IClassDefinition)) + return false; + + if (definition instanceof IVariableDefinition) + { + IVariableDefinition variable = (IVariableDefinition) definition; + if (variable.isStatic()) + return false; + } + if (definition instanceof IFunctionDefinition) + { + IFunctionDefinition function = (IFunctionDefinition) definition; + if (function.isStatic()) + return false; + } + + return true; + } + + private static boolean isThisLeftOf(IIdentifierNode node) + { + if (node.getParent() instanceof IMemberAccessExpressionNode) + { + IMemberAccessExpressionNode parent = (IMemberAccessExpressionNode) node + .getParent(); + if (parent.getLeftOperandNode() instanceof ILanguageIdentifierNode + && ((ILanguageIdentifierNode) parent.getLeftOperandNode()) + .getKind() == LanguageIdentifierKind.THIS) + return true; + } + return false; + } + + public static IExpressionNode getNode(IASNode iNode, Boolean toRight, + ICompilerProject project) + { + try + { + IASNode node = iNode; + while (node != null) + { + if (node instanceof IBinaryOperatorNode + && !(node instanceof MemberAccessExpressionNode)) + { + if (toRight) + node = ((IBinaryOperatorNode) node) + .getRightOperandNode(); + else + node = ((IBinaryOperatorNode) node) + .getLeftOperandNode(); + } + else if (node instanceof IFunctionCallNode) + node = ((IFunctionCallNode) node).getNameNode(); + else if (node instanceof IDynamicAccessNode) + node = ((IDynamicAccessNode) node).getLeftOperandNode(); + else if (node instanceof IUnaryOperatorNode) + node = ((IUnaryOperatorNode) node).getOperandNode(); + else if (node instanceof IForLoopNode) + node = ((IForLoopNode) node).getChild(0).getChild(0); + else if (node instanceof IVariableNode) + { + if (toRight) + node = ((IVariableNode) node).getAssignedValueNode(); + else + node = ((IVariableNode) node).getVariableTypeNode(); + } + else if (node instanceof IExpressionNode) + { + // IDefinition def = ((IExpressionNode) node).resolve(project); + // if (def instanceof VariableDefinition) + // { + // final VariableDefinition variable = (VariableDefinition) def; + // def = variable.resolveType(project); + // } + // else if (def instanceof FunctionDefinition) + // { + // final FunctionDefinition functionDef = (FunctionDefinition) def; + // final IReference typeRef = functionDef + // .getReturnTypeReference(); + // if (typeRef != null) + // def = typeRef.resolve(project, + // (ASScope) getScopeFromNode(iNode), + // DependencyType.INHERITANCE, false); + // } + // else if (def instanceof IGetterDefinition) + // { + // final ITypeDefinition returnType = ((IGetterDefinition) def) + // .resolveReturnType(project); + // // def = m_sharedData.getDefinition(returnType + // // .getQualifiedName()); + // def = returnType; // XXX figure out + // } + // + // if (def != null && def instanceof ClassDefinition) + // { + // return def; + // } + return (IExpressionNode) node; + } + else + { + node = null; + } + } + } + catch (Exception e) + { + // getDefinitionForNode(iNode,toRight); + + // getDefinition() sometimes crashes, e.g. when looking at a cast to an interface in some cases, + // FunctionDefinition.getParameters() returns null and ExpressionNodeBase.determineIfFunction() chokes on it + // printWarning(iNode, "getDefinitionForNode() failed for" + iNode); + } + return null; + } + + private static IExpressionNode getIndentFromThis(IIdentifierNode node) + { + if (node.getParent() instanceof IMemberAccessExpressionNode) + { + IMemberAccessExpressionNode parent = (IMemberAccessExpressionNode) node + .getParent(); + if (parent.getLeftOperandNode() instanceof ILanguageIdentifierNode + && ((ILanguageIdentifierNode) parent.getLeftOperandNode()) + .getKind() == LanguageIdentifierKind.THIS) + return parent.getRightOperandNode(); + } + return null; + } + + public static String toPackageName(String name) + { + if (!name.contains(".")) + return name; + final String stem = name.substring(0, name.lastIndexOf(".")); + return stem; + } + + public static String toBaseName(String name) + { + if (!name.contains(".")) + return name; + final String basename = name.substring(name.lastIndexOf(".") + 1); + return basename; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSDocEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSDocEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSDocEmitter.java new file mode 100644 index 0000000..057bcf1 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSDocEmitter.java @@ -0,0 +1,391 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.flexjs; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.flex.compiler.asdoc.flexjs.ASDocComment; +import org.apache.flex.compiler.clients.MXMLJSC; +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.common.ASModifier; +import org.apache.flex.compiler.common.DependencyType; +import org.apache.flex.compiler.constants.IASKeywordConstants; +import org.apache.flex.compiler.constants.IASLanguageConstants; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; +import org.apache.flex.compiler.definitions.references.IReference; +import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogDocEmitter; +import org.apache.flex.compiler.internal.scopes.ASScope; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.as.IDefinitionNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IFunctionNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.IVariableNode; + +public class JSFlexJSDocEmitter extends JSGoogDocEmitter +{ + private List<String> classIgnoreList; + private List<String> ignoreList; + private List<String> coercionList; + + public JSFlexJSDocEmitter(IJSEmitter emitter) + { + super(emitter); + } + + public List<String> getClassIgnoreList() + { + return classIgnoreList; + } + + public void setClassIgnoreList(List<String> value) + { + this.classIgnoreList = value; + } + + @Override + protected String convertASTypeToJS(String name, String pname) + { + if (ignoreList != null) + { + if (ignoreList.contains(pname + "." + name)) + return IASLanguageConstants.Object; + } + if (coercionList != null) + { + if (!coercionList.contains(pname + "." + name)) + return IASLanguageConstants.Object; + } + if (classIgnoreList != null) + { + if (classIgnoreList.contains(pname + "." + name)) + return IASLanguageConstants.Object; + } + if (name.matches("Vector\\.<.*>")) + return IASLanguageConstants.Array; + + name = super.convertASTypeToJS(name, pname); + return formatQualifiedName(name); + } + + @Override + protected String formatQualifiedName(String name) + { + return ((JSFlexJSEmitter)emitter).formatQualifiedName(name, true); + } + + @Override + public void emitMethodDoc(IFunctionNode node, ICompilerProject project) + { + coercionList = null; + ignoreList = null; + + IClassDefinition classDefinition = resolveClassDefinition(node); + + ASDocComment asDoc = (ASDocComment) node.getASDocComment(); + + if (node instanceof IFunctionNode) + { + boolean hasDoc = false; + Boolean override = false; + + if (node.isConstructor()) + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + hasDoc = true; + + emitJSDocLine(JSEmitterTokens.CONSTRUCTOR); + + IClassDefinition parent = (IClassDefinition) node + .getDefinition().getParent(); + IClassDefinition superClass = parent.resolveBaseClass(project); + String qname = (superClass != null) ? project.getActualPackageName(superClass.getQualifiedName()) : null; + + if (superClass != null + && !qname.equals(IASLanguageConstants.Object)) + emitExtends(superClass, superClass.getPackageName()); + + IReference[] references = classDefinition + .getImplementedInterfaceReferences(); + for (IReference iReference : references) + { + ITypeDefinition type = (ITypeDefinition) iReference + .resolve(project, (ASScope) classDefinition + .getContainingScope(), + DependencyType.INHERITANCE, true); + if (type == null) { + System.out.println(iReference.getDisplayString() + + " not resolved in " + + classDefinition.getQualifiedName()); + } else { + emitImplements(type, project.getActualPackageName(type.getPackageName())); + } + } + } + else + { + // @override + override = node.hasModifier(ASModifier.OVERRIDE); + + String ns = node.getNamespace(); + if (ns != null) + { + if (asDoc != null && MXMLJSC.keepASDoc) + { + String docText = asDoc.commentNoEnd(); + String keepToken = JSFlexJSEmitterTokens.EMIT_COERCION + .getToken(); + if (docText.contains(keepToken)) + loadKeepers(docText); + String ignoreToken = JSFlexJSEmitterTokens.IGNORE_COERCION + .getToken(); + if (docText.contains(ignoreToken)) + loadIgnores(docText); + write(changeAnnotations(asDoc.commentNoEnd())); + } + else + begin(); + emitMethodAccess(node); + hasDoc = true; + } + } + + if (!override) + { + // @param + IParameterNode[] parameters = node.getParameterNodes(); + for (IParameterNode pnode : parameters) + { + if (!hasDoc) + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + emitMethodAccess(node); + hasDoc = true; + } + + IExpressionNode enode = pnode.getNameExpressionNode(); + + // ToDo (erikdebruin): add VF2JS conditional -> only use check during full SDK compilation + ITypeDefinition tdef = enode.resolveType(project); + if (tdef == null) + continue; + + emitParam(pnode, project.getActualPackageName(tdef.getPackageName())); + } + } + + if (!node.isConstructor()) + { + if (!override) + { + // @return + String returnType = node.getReturnType(); + if (returnType != "" + && returnType != ASEmitterTokens.VOID.getToken()) + { + if (!hasDoc) + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + emitMethodAccess(node); + hasDoc = true; + } + + ITypeDefinition tdef = ((IFunctionDefinition) node + .getDefinition()).resolveReturnType(project); + + String packageName = ""; + packageName = tdef != null ? tdef.getPackageName() : ""; + + emitReturn(node, project.getActualPackageName(packageName)); + } + } + + if (override) + { + if (!hasDoc) + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + emitMethodAccess(node); + hasDoc = true; + } + + emitOverride(node); + } + } + + if (hasDoc) + end(); + } + } + + private void loadIgnores(String doc) + { + ignoreList = new ArrayList<String>(); + String ignoreToken = JSFlexJSEmitterTokens.IGNORE_COERCION.getToken(); + int index = doc.indexOf(ignoreToken); + while (index != -1) + { + String ignore = doc.substring(index + ignoreToken.length()); + int endIndex = ignore.indexOf("\n"); + ignore = ignore.substring(0, endIndex); + ignore = ignore.trim(); + ignoreList.add(ignore); + index = doc.indexOf(ignoreToken, index + endIndex); + } + } + + private void loadKeepers(String doc) + { + coercionList = new ArrayList<String>(); + String keepToken = JSFlexJSEmitterTokens.EMIT_COERCION.getToken(); + int index = doc.indexOf(keepToken); + while (index != -1) + { + String keeper = doc.substring(index + keepToken.length()); + int endIndex = keeper.indexOf("\n"); + keeper = keeper.substring(0, endIndex); + keeper = keeper.trim(); + coercionList.add(keeper); + index = doc.indexOf(keepToken, index + endIndex); + } + } + + private String changeAnnotations(String doc) + { + // rename these tags so they don't conflict with generated + // jsdoc tags + String pass1 = doc.replaceAll("@param", "@asparam"); + String pass2 = pass1.replaceAll("@return", "@asreturn"); + String pass3 = pass2.replaceAll("@private", "@asprivate"); + return pass3; + } + + public void emitInterfaceMemberDoc(IDefinitionNode node, + ICompilerProject project) + { + boolean hasDoc = false; + + ASDocComment asDoc = (ASDocComment) ((IFunctionNode) node) + .getASDocComment(); + + String returnType = ((IFunctionNode) node).getReturnType(); + if (returnType != "" && returnType != ASEmitterTokens.VOID.getToken()) // has return + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + hasDoc = true; + + ITypeDefinition tdef = ((IFunctionDefinition) node.getDefinition()) + .resolveReturnType(project); + + emitReturn((IFunctionNode) node, tdef.getPackageName()); + } + + IParameterNode[] parameters = ((IFunctionNode) node) + .getParameterNodes(); + for (IParameterNode pnode : parameters) + { + if (!hasDoc) + { + if (asDoc != null && MXMLJSC.keepASDoc) + write(changeAnnotations(asDoc.commentNoEnd())); + else + begin(); + hasDoc = true; + } + + IExpressionNode enode = pnode.getNameExpressionNode(); + emitParam(pnode, enode.resolveType(project).getPackageName()); + } + + if (hasDoc) + end(); + } + + @Override + public void emitMethodAccess(IFunctionNode node) + { + String ns = node.getNamespace(); + if (ns == IASKeywordConstants.PRIVATE) + { + emitPrivate(node); + } + else if (ns == IASKeywordConstants.PROTECTED) + { + emitProtected(node); + } + else if (ns == IASKeywordConstants.PUBLIC) + { + emitPublic(node); + } + } + + @Override + public void emitFieldDoc(IVariableNode node, IDefinition def, ICompilerProject project) + { + begin(); + + String ns = node.getNamespace(); + if (ns == IASKeywordConstants.PRIVATE) + { + emitPrivate(node); + } + else if (ns == IASKeywordConstants.PROTECTED) + { + emitProtected(node); + } + else + { + emitPublic(node); + } + + if (node.isConst()) + emitConst(node); + + String packageName = ""; + if (def != null) + packageName = def.getPackageName(); + + emitType(node, project.getActualPackageName(packageName)); + + end(); + } + +}