- Merged upstream changes
Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/58409300 Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/58409300 Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/58409300 Branch: refs/heads/feature/maven-migration-test Commit: 5840930016ccc94355666ae59657ae860c400742 Parents: 28f5f13 b4e4fad Author: Christofer Dutz <christofer.d...@codecentric.de> Authored: Fri Apr 22 15:13:05 2016 +0200 Committer: Christofer Dutz <christofer.d...@codecentric.de> Committed: Fri Apr 22 15:13:05 2016 +0200 ---------------------------------------------------------------------- .../compiler/clients/ExternCConfiguration.java | 54 +++++++++ .../externals/reference/ClassReference.java | 30 ++++- .../codegen/js/jx/PackageHeaderEmitter.java | 119 +++++++++++++------ .../codegen/js/node/NodeEmitterTokens.java | 21 ++++ .../internal/projects/FlexJSProject.java | 61 ++++++++++ externs/node/node-compile-config.xml | 64 +++++++++- 6 files changed, 312 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/58409300/compiler-jx/src/main/java/org/apache/flex/compiler/clients/ExternCConfiguration.java ---------------------------------------------------------------------- diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/clients/ExternCConfiguration.java index c15786a,0000000..c6e7212 mode 100644,000000..100644 --- a/compiler-jx/src/main/java/org/apache/flex/compiler/clients/ExternCConfiguration.java +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/ExternCConfiguration.java @@@ -1,364 -1,0 +1,418 @@@ +/* + * + * 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.clients; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.config.ConfigurationValue; +import org.apache.flex.compiler.exceptions.ConfigurationException.CannotOpen; +import org.apache.flex.compiler.exceptions.ConfigurationException.IncorrectArgumentCount; +import org.apache.flex.compiler.internal.codegen.externals.pass.ReferenceCompiler.ExternalFile; +import org.apache.flex.compiler.internal.codegen.externals.reference.BaseReference; +import org.apache.flex.compiler.internal.codegen.externals.reference.ClassReference; +import org.apache.flex.compiler.internal.codegen.externals.reference.FieldReference; +import org.apache.flex.compiler.internal.codegen.externals.reference.MemberReference; +import org.apache.flex.compiler.internal.config.annotations.Arguments; +import org.apache.flex.compiler.internal.config.annotations.Config; +import org.apache.flex.compiler.internal.config.annotations.InfiniteArguments; +import org.apache.flex.compiler.internal.config.annotations.Mapping; +import org.apache.flex.utils.FilenameNormalization; + +public class ExternCConfiguration extends Configuration +{ + private File jsRoot; + + private File asRoot; + + private File asClassRoot; + private File asInterfaceRoot; + private File asFunctionRoot; + private File asConstantRoot; + private File asTypeDefRoot; + private File asDuplicatesRoot; + + private List<ExternalFile> externals = new ArrayList<ExternalFile>(); + private List<ExternalFile> externalExterns = new ArrayList<ExternalFile>(); + ++ private List<String> namedModules = new ArrayList<String>(); ++ + private List<String> classToFunctions = new ArrayList<String>(); + private List<ExcludedMember> excludesClass = new ArrayList<ExcludedMember>(); + private List<ExcludedMember> excludesField = new ArrayList<ExcludedMember>(); + private List<ExcludedMember> excludes = new ArrayList<ExcludedMember>(); + + public ExternCConfiguration() + { + } + + public File getAsRoot() + { + return asRoot; + } + + @Config + @Mapping("as-root") + public void setASRoot(ConfigurationValue cfgval, String filename) throws CannotOpen + { + setASRoot(new File(FilenameNormalization.normalize(getOutputPath(cfgval, filename)))); + } + + public void setASRoot(File file) + { + this.asRoot = file; + + asClassRoot = new File(asRoot, "classes"); + asInterfaceRoot = new File(asRoot, "interfaces"); + asFunctionRoot = new File(asRoot, "functions"); + asConstantRoot = new File(asRoot, "constants"); + asTypeDefRoot = new File(asRoot, "typedefs"); + asDuplicatesRoot = new File(asRoot, "duplicates"); + } + + public File getAsClassRoot() + { + return asClassRoot; + } + + public File getAsInterfaceRoot() + { + return asInterfaceRoot; + } + + public File getAsFunctionRoot() + { + return asFunctionRoot; + } + + public File getAsConstantRoot() + { + return asConstantRoot; + } + + public File getAsTypeDefRoot() + { + return asTypeDefRoot; + } + + public File getAsDuplicatesRoot() + { + return asDuplicatesRoot; + } + + public Collection<ExternalFile> getExternals() + { + return externals; + } + + public Collection<ExternalFile> getExternalExterns() + { + return externalExterns; + } + + public boolean isClassToFunctions(String className) + { + return classToFunctions.contains(className); + } + + public void addClassToFunction(String className) + { + classToFunctions.add(className); + } + + public void addExternal(File file) throws IOException + { + if (!file.exists()) + throw new IOException(file.getAbsolutePath() + " does not exist."); + externals.add(new ExternalFile(file)); + } + + public void addExternal(String externalFile) throws IOException + { + addExternal(new File(FilenameNormalization.normalize(externalFile))); + } + + public void addExternalExtern(File file) throws IOException + { + if (!file.exists()) + throw new IOException(file.getAbsolutePath() + " does not exist."); + externalExterns.add(new ExternalFile(file)); + } + + public void addExternalExtern(String externalFile) throws IOException + { + addExternalExtern(new File(FilenameNormalization.normalize(externalFile))); + } + + @Config(allowMultiple = true) + @Mapping("class-to-function") + @Arguments(Arguments.CLASS) + public void setClassToFunctions(ConfigurationValue cfgval, List<String> values) throws IncorrectArgumentCount + { + addClassToFunction(values.get(0)); + } + + @Config(allowMultiple = true, isPath = true) + @Mapping("external") + @Arguments(Arguments.PATH_ELEMENT) + @InfiniteArguments + public void setExternal(ConfigurationValue cfgval, String[] vals) throws IOException, CannotOpen + { + for (String val : vals) + addExternal(resolvePathStrict(val, cfgval)); + } + + @Config(allowMultiple = true, isPath = true) + @Mapping("external-externs") + @Arguments(Arguments.PATH_ELEMENT) + @InfiniteArguments + public void setExternalExterns(ConfigurationValue cfgval, String[] vals) throws IOException, CannotOpen + { + for (String val : vals) + addExternalExtern(resolvePathStrict(val, cfgval)); + } + + public boolean isExternalExtern(BaseReference reference) + { + String sourceFileName = reference.getNode().getSourceFileName(); + for (ExternalFile file : externalExterns) + { + if (sourceFileName.equals("[" + file.getName() + "]")) + { + return true; + } + } + return false; + } + + public ExcludedMember isExcludedClass(ClassReference classReference) + { + for (ExcludedMember memeber : excludesClass) + { + if (memeber.isExcluded(classReference, null)) + return memeber; + } + return null; + } + + public ExcludedMember isExcludedMember(ClassReference classReference, + MemberReference memberReference) + { + if (memberReference instanceof FieldReference) + { + for (ExcludedMember memeber : excludesField) + { + if (memeber.isExcluded(classReference, memberReference)) + return memeber; + } + } + for (ExcludedMember memeber : excludes) + { + if (memeber.isExcluded(classReference, memberReference)) + return memeber; + } + return null; + } + + @Config(allowMultiple = true) + @Mapping("exclude") + @Arguments({"class", "name"}) + public void setExcludes(ConfigurationValue cfgval, List<String> values) throws IncorrectArgumentCount + { + final int size = values.size(); + if (size % 2 != 0) + throw new IncorrectArgumentCount(size + 1, size, cfgval.getVar(), cfgval.getSource(), cfgval.getLine()); + + for (int nameIndex = 0; nameIndex < size - 1; nameIndex += 2) + { + final String className = values.get(nameIndex); + final String name = values.get(nameIndex + 1); + addExclude(className, name); + } + } + + public void addExclude(String className, String name) + { + excludes.add(new ExcludedMember(className, name)); + } + + public void addExclude(String className, String name, String description) + { + excludes.add(new ExcludedMember(className, name, description)); + } + + @Config(allowMultiple = true) + @Mapping("field-exclude") + @Arguments({"class", "field"}) + public void setFieldExcludes(ConfigurationValue cfgval, List<String> values) throws IncorrectArgumentCount + { + final int size = values.size(); + if (size % 2 != 0) + throw new IncorrectArgumentCount(size + 1, size, cfgval.getVar(), cfgval.getSource(), cfgval.getLine()); + + for (int nameIndex = 0; nameIndex < size - 1; nameIndex += 2) + { + final String className = values.get(nameIndex); + final String fieldName = values.get(nameIndex + 1); + addFieldExclude(className, fieldName); + } + } + + public void addFieldExclude(String className, String fieldName) + { + excludesField.add(new ExcludedMember(className, fieldName, "")); + } + + @Config(allowMultiple = true) + @Mapping("class-exclude") + @Arguments("class") + public void setClassExcludes(ConfigurationValue cfgval, List<String> values) + { + for (String className : values) + addClassExclude(className); + } + public void addClassExclude(String className) + { + excludesClass.add(new ExcludedMember(className, null, "")); + } + ++ @Config(allowMultiple = true) ++ @Mapping("named-module") ++ @Arguments("module") ++ @InfiniteArguments ++ public void setNamedModules(ConfigurationValue cfgval, List<String> values) ++ { ++ for (String moduleName : values) ++ { ++ addNamedModule(moduleName); ++ } ++ } ++ public void addNamedModule(String moduleName) ++ { ++ namedModules.add(moduleName); ++ } ++ ++ public String isNamedModule(ClassReference classReference) ++ { ++ String basePackageName = classReference.getPackageName(); ++ int packageIndex = basePackageName.indexOf("."); ++ if (packageIndex != -1) ++ { ++ basePackageName = basePackageName.substring(0, packageIndex); ++ } ++ for (String module : namedModules) ++ { ++ //convert to camel case ++ String camelCaseModule = module; ++ int moduleIndex = camelCaseModule.indexOf("-"); ++ while (moduleIndex != -1 && moduleIndex < camelCaseModule.length() - 1) ++ { ++ camelCaseModule = camelCaseModule.substring(0, moduleIndex) ++ + camelCaseModule.substring(moduleIndex + 1, moduleIndex + 2).toUpperCase() ++ + camelCaseModule.substring(moduleIndex + 2); ++ moduleIndex = camelCaseModule.indexOf("-"); ++ } ++ if(basePackageName.length() == 0) ++ { ++ if (classReference.getBaseName().equals(camelCaseModule)) ++ { ++ return module; ++ } ++ continue; ++ } ++ if(basePackageName.equals(camelCaseModule)) ++ { ++ return module; ++ } ++ } ++ return null; ++ } ++ + public File getJsRoot() + { + return jsRoot; + } + + @Config + @Mapping("js-root") + public void setJSRoot(ConfigurationValue cfgval, String filename) throws CannotOpen + { + this.jsRoot = new File(filename); + } + + + public static class ExcludedMember + { + private String className; + private String name; + private String description; + + public String getClassName() + { + return className; + } + + public String getName() + { + return name; + } + + public String getDescription() + { + return description; + } + + public ExcludedMember(String className, String name) + { + this.className = className; + this.name = name; + } + + public ExcludedMember(String className, String name, String description) + { + this.className = className; + this.name = name; + this.description = description; + } + + public boolean isExcluded(ClassReference classReference, + MemberReference memberReference) + { + if (memberReference == null) + { + return classReference.getQualifiedName().equals(className); + } + return classReference.getQualifiedName().equals(className) + && memberReference.getQualifiedName().equals(name); + } + + public void print(StringBuilder sb) + { + if (description != null) + sb.append("// " + description + "\n"); + sb.append("//"); + } + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/58409300/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/externals/reference/ClassReference.java ---------------------------------------------------------------------- diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/externals/reference/ClassReference.java index b04fb0e,0000000..fc1df39 mode 100644,000000..100644 --- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/externals/reference/ClassReference.java +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/externals/reference/ClassReference.java @@@ -1,890 -1,0 +1,918 @@@ +/* + * + * 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.externals.reference; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.flex.compiler.internal.codegen.externals.utils.DebugLogUtils; +import org.apache.flex.compiler.internal.codegen.externals.utils.JSTypeUtils; + +import com.google.javascript.rhino.JSDocInfo; +import com.google.javascript.rhino.JSDocInfoBuilder; +import com.google.javascript.rhino.JSTypeExpression; +import com.google.javascript.rhino.Node; +import com.google.javascript.rhino.jstype.JSType; + +public class ClassReference extends BaseReference +{ + private boolean isFinal; + private boolean isDynamic; ++ private String moduleName; + private int enumConstantCounter = 0; + + private Set<String> imports = new HashSet<String>(); + private MethodReference constructor; + private Map<String, FieldReference> instanceFields = new HashMap<String, FieldReference>(); + private Map<String, FieldReference> staticFields = new HashMap<String, FieldReference>(); + private Map<String, MethodReference> instanceMethods = new HashMap<String, MethodReference>(); + private Map<String, MethodReference> staticMethods = new HashMap<String, MethodReference>(); + + private Node nameNode; + + private Node functionNode; + + @SuppressWarnings("unused") + private Node paramListNode; + + private boolean isNamespace; + + public final int getEnumConstant() + { + return enumConstantCounter; + } + + public final void nextEnumConstant() + { + enumConstantCounter++; + } + + public void setIsNamespace(boolean isNamespace) + { + this.isNamespace = isNamespace; + } + + public boolean isNamespace() + { + return isNamespace; + } + + public MethodReference getConstructor() + { + return constructor; + } + + public ArrayList<FieldReference> getAllFields() + { + ArrayList<FieldReference> allMethods = new ArrayList<FieldReference>(); + if (!isInterface()) + allMethods.addAll(staticFields.values()); + allMethods.addAll(instanceFields.values()); + return allMethods; + } + + public ArrayList<MethodReference> getAllMethods() + { + ArrayList<MethodReference> allMethods = new ArrayList<MethodReference>(); + if (!isInterface()) + allMethods.addAll(staticMethods.values()); + allMethods.addAll(instanceMethods.values()); + return allMethods; + } + + public FieldReference getStaticField(String name) + { + return staticFields.get(name); + } + + public FieldReference getInstanceField(String name) + { + return instanceFields.get(name); + } + + public MethodReference getStaticMethod(String name) + { + return staticMethods.get(name); + } + + public MethodReference getInstanceMethod(String name) + { + return instanceMethods.get(name); + } + + public boolean isDynamic() + { + return isDynamic; + } + + public void setDynamic(boolean isDynamic) + { + this.isDynamic = isDynamic; + } + + public boolean isFinal() + { + return isFinal; + } + + public void setFinal(boolean isFinal) + { + this.isFinal = isFinal; + } + ++ public String getModuleName() ++ { ++ return moduleName; ++ } ++ ++ public void setModuleName(String moduleName) ++ { ++ this.moduleName = moduleName; ++ } ++ + public final boolean isInterface() + { + return getComment().isInterface(); + } + + /** + * + * @param model + * @param node (FUNCTION [NAME, PARAM_LIST, BLOCK]), or (ASSIGN [FUNCTION [NAME, PARAM_LIST, BLOCK]]) + * @param qualifiedName + */ + public ClassReference(ReferenceModel model, Node node, String qualifiedName) + { + super(model, node, qualifiedName, node.getJSDocInfo()); + + indent = ""; + + nameNode = null; + functionNode = null; + paramListNode = null; + + if (comment.hasEnumParameterType()) + { + /* + var Foo = { ... + + VAR 35 [jsdoc_info: JSDocInfo] + NAME FontFaceSetLoadStatus + OBJECTLIT + STRING_KEY LOADED + STRING loaded + STRING_KEY LOADING + STRING loading + + Or.. + + foo.bar.baz.QualifiedEnum = { ... + + ASSIGN 50 [jsdoc_info: JSDocInfo] + GETPROP + GETPROP + ... + STRING QualifiedEnum + OBJECTLIT 50 + */ + + String overrideStringType = JSTypeUtils.toEnumTypeString(this); + + Node objLit = null; + if (node.isVar()) + { + objLit = node.getFirstChild().getFirstChild(); + } + else if (node.isAssign()) + { + objLit = node.getLastChild(); + } + + if (objLit != null) + { + for (Node stringKey : objLit.children()) + { + if (stringKey.isStringKey()) + { + Node valueNode = stringKey.getFirstChild(); + + JSDocInfoBuilder b = new JSDocInfoBuilder(true); + JSDocInfo fieldComment = b.build(); + String fieldName = stringKey.getString(); + FieldReference field = addField(stringKey, fieldName, fieldComment, true); + field.setConst(true); + field.setOverrideStringType(overrideStringType); + field.setConstantValueNode(valueNode); + } + } + } + } + else if (comment.getTypedefType() != null) + { + //System.out.println(node.toStringTree()); + /* + VAR 727 [jsdoc_info: JSDocInfo] [source_file: [w3c_rtc]] [length: 21] + NAME MediaConstraints 727 [source_file: [w3c_rtc]] [length: 16] + */ + } + else if (comment.isConstant()) + { + /* + VAR 882 [jsdoc_info: JSDocInfo] + NAME Math + OBJECTLIT + */ + constructor = new NullConstructorReference(model, this, node, getBaseName(), comment); + } + else if (node.isFunction()) + { + /* + FUNCTION FooVarArgs 43 [jsdoc_info: JSDocInfo] + NAME FooVarArgs + PARAM_LIST + NAME arg1 + NAME var_args + BLOCK 43 + */ + nameNode = node.getChildAtIndex(0); + functionNode = node; + paramListNode = functionNode.getChildAtIndex(1); + } + else if (node.isVar()) + { + /* + VAR 67 [jsdoc_info: JSDocInfo] + NAME VarAssignFooNoArgs + FUNCTION + NAME + PARAM_LIST + BLOCK + */ + nameNode = node.getChildAtIndex(0); + functionNode = nameNode.getChildAtIndex(0); + try + { + paramListNode = functionNode.getChildAtIndex(1); + } + catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + else if (node.isAssign() && node.getChildAtIndex(1).isFunction()) + { + /* + ASSIGN 60 [jsdoc_info: JSDocInfo] + NAME AssignFooNoArgs + FUNCTION + NAME + PARAM_LIST + BLOCK + */ + nameNode = node.getFirstChild(); + functionNode = node.getLastChild(); + // this is an anonymous function assignment, no name + //functionNameNode = functionNode.getChildAtIndex(0); + paramListNode = functionNode.getChildAtIndex(1); + } + + if (functionNode != null) + { + constructor = new MethodReference(model, this, functionNode, getBaseName(), comment, false); + } + ++ moduleName = model.getConfiguration().isNamedModule(this); ++ + } + + private static List<String> definedPackages = new ArrayList<String>(); + + @Override + public void emit(StringBuilder sb) + { + enumConstantCounter = 0; + + String packageName = getPackageName(); + + if (outputJS) + { + sb.append("/** @fileoverview Auto-generated Externs files\n * @externs\n */\n"); + if (!packageName.isEmpty()) + { + if (!definedPackages.contains(packageName)) + { + definedPackages.add(packageName); + String[] pieces = packageName.split("\\."); + String chain = ""; + int n = pieces.length; + for (int i = 0; i < n; i++) + { + String piece = pieces[i]; + sb.append("\n"); + sb.append("\n"); + sb.append("/**\n * @const\n * @suppress {duplicate|const} */\n"); + if (chain.isEmpty()) + sb.append("var " + piece + " = {};\n\n\n"); + else + sb.append(chain + "." + piece + " = {}\n\n\n"); + chain = chain + "." + piece; + } + } + } + } + else + { + sb.append("package "); + if (!packageName.equals("")) + sb.append(packageName).append(" "); + sb.append("{\n"); + sb.append("\n"); + + emitImports(sb); + } ++ ++ if (moduleName != null) ++ { ++ sb.append("[JSModule"); ++ if (packageName.length() > 0 || !getBaseName().equals(moduleName)) ++ { ++ sb.append("("); ++ sb.append("name=\""); ++ sb.append(moduleName); ++ sb.append("\""); ++ sb.append(")"); ++ } ++ sb.append("]"); ++ sb.append("\n"); ++ } + + emitComment(sb); + + boolean isInterface = isInterface(); + + if (isInterface) + { + emitInterface(sb); + } + else + { + emitClass(sb); + } + + if (!outputJS) + { + sb.append("{\n"); + sb.append("\n"); + } + + if (!isInterface) + { + emitConstructor(sb); + sb.append("\n"); + } + + emitFields(sb); + emitMethods(sb); + + if (!outputJS) + { + sb.append("}\n"); + sb.append("}\n"); // package + } + } + + public boolean hasSuperField(String fieldName) + { + List<ClassReference> list = getSuperClasses(); + for (ClassReference reference : list) + { + if (reference.hasInstanceField(fieldName)) + return true; + } + return false; + } + + public boolean hasSuperMethod(String methodName) + { + List<ClassReference> list = getSuperClasses(); + for (ClassReference reference : list) + { + if (reference.hasInstanceMethod(methodName)) + return true; + } + return false; + } + + public MethodReference getSuperMethod(String methodName) + { + List<ClassReference> list = getSuperClasses(); + for (ClassReference reference : list) + { + if (reference.hasInstanceMethod(methodName)) + return reference.getInstanceMethod(methodName); + } + + list = getAllImplInterfaces(); // return all our interfaces and all superclass + for (ClassReference reference : list) + { + if (reference.hasInstanceMethod(methodName)) + return reference.getInstanceMethod(methodName); + } + + return null; + } + + public List<ClassReference> getSuperClasses() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + ClassReference superClass = getSuperClass(); + while (superClass != null) + { + result.add(superClass); + superClass = superClass.getSuperClass(); + } + + return result; + } + + public List<ClassReference> getAllImplInterfaces() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + for (JSTypeExpression jsTypeExpression : getComment().getImplementedInterfaces()) + { + String interfaceName = getModel().evaluate(jsTypeExpression).getDisplayName(); + ClassReference classReference = getModel().getClassReference(interfaceName); + if (classReference != null) + result.add(classReference); + } + + return result; + } + + public List<ClassReference> getImplementedInterfaces() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + for (JSTypeExpression jsTypeExpression : getComment().getImplementedInterfaces()) + { + String interfaceName = getModel().evaluate(jsTypeExpression).toAnnotationString(); + ClassReference reference = getModel().getClassReference(interfaceName); + if (reference != null) + result.add(reference); + } + return result; + } + + public List<ClassReference> getExtendedInterfaces() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + for (JSTypeExpression jsTypeExpression : getComment().getExtendedInterfaces()) + { + String interfaceName = getModel().evaluate(jsTypeExpression).toAnnotationString(); + ClassReference reference = getModel().getClassReference(interfaceName); + if (reference != null) + result.add(reference); + } + return result; + } + + public List<ClassReference> getInterfaces() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + List<JSTypeExpression> implementedInterfaces = getComment().getImplementedInterfaces(); + for (JSTypeExpression jsTypeExpression : implementedInterfaces) + { + JSType jsType = getModel().evaluate(jsTypeExpression); + String interfaceName = jsType.toAnnotationString(); + result.add(getModel().getClassReference(interfaceName)); + } + return result; + } + + public List<ClassReference> getSuperInterfaces() + { + ArrayList<ClassReference> result = new ArrayList<ClassReference>(); + result.addAll(getInterfaces()); + + ClassReference superClass = getSuperClass(); + while (superClass != null) + { + result.addAll(superClass.getInterfaces()); + superClass = superClass.getSuperClass(); + } + + return result; + } + + public boolean hasInstanceField(String fieldName) + { + return instanceFields.containsKey(fieldName); + } + + public boolean hasStaticField(String fieldName) + { + return staticFields.containsKey(fieldName); + } + + public boolean hasInstanceMethod(String fieldName) + { + return instanceMethods.containsKey(fieldName); + } + + public boolean hasStaticMethod(String fieldName) + { + return staticMethods.containsKey(fieldName); + } + + public FieldReference addField(Node node, String fieldName, JSDocInfo comment, boolean isStatic) + { + if (isStatic ? hasStaticField(fieldName) : hasInstanceField(fieldName)) + { + // XXX Warning + return null; + } + + /* AJH This doesn't make sense to me + if (isNamespace) + isStatic = false; + */ + + if (comment == null) + { + DebugLogUtils.err("Field comment null for; " + node.getQualifiedName()); + //DebugLogUtils.err(node); + JSDocInfoBuilder b = new JSDocInfoBuilder(true); + b.recordBlockDescription("Generated doc for missing field JSDoc."); + comment = b.build(); + } + + FieldReference field = new FieldReference(getModel(), this, node, fieldName, comment, isStatic); + + if (isStatic) + staticFields.put(fieldName, field); + else + instanceFields.put(fieldName, field); + return field; + } + + public MethodReference addMethod(Node node, String functionName, JSDocInfo comment, boolean isStatic) + { + /* AJH This doesn't make sense to me + if (isNamespace) + isStatic = false; + */ + + if (comment == null) + { + DebugLogUtils.err("Method comment null for; " + node.getQualifiedName()); + //DebugLogUtils.err(node); + JSDocInfoBuilder b = new JSDocInfoBuilder(true); + b.recordBlockDescription("Generated doc for missing method JSDoc."); + comment = b.build(); + } + + MethodReference method = new MethodReference(getModel(), this, node, functionName, comment, isStatic); + + if (isStatic) + { + staticMethods.put(functionName, method); + } + else if (getQualifiedName().equals("Object") && functionName.equals("toString")) + { + // skipping Object.prototype.toString() allows toString(opt_radix) for Number, int and uint + } + else + { + instanceMethods.put(functionName, method); + } + return method; + } + + public boolean isMethodOverrideFromInterface(MethodReference reference) + { + boolean isMethodOverrideFromInterface = false; + + if (!hasImplementations()) + { + List<JSTypeExpression> implementedInterfaces = getComment().getImplementedInterfaces(); + for (JSTypeExpression jsTypeExpression : implementedInterfaces) + { + String interfaceName = getModel().evaluate(jsTypeExpression).getDisplayName(); + ClassReference classReference = getModel().getClassReference(interfaceName); + if (classReference.hasSuperMethod(reference.getQualifiedName())) + { + isMethodOverrideFromInterface = true; + break; + } + } + } + + return isMethodOverrideFromInterface; + } + + public MethodReference getMethodOverrideFromInterface(MethodReference reference) + { + // get all super classes, reverse and search top down + List<ClassReference> superClasses = getSuperClasses(); + superClasses.add(0, this); + Collections.reverse(superClasses); + + // for each superclass, get all implemented interfaces + for (ClassReference classReference : superClasses) + { + List<ClassReference> interfaces = classReference.getImplementedInterfaces(); + for (ClassReference interfaceReference : interfaces) + { + // check for the method on the interface + MethodReference method = interfaceReference.getInstanceMethod(reference.getBaseName()); + if (method != null) + return method; + } + } + + return null; + } + + public ClassReference getSuperClass() + { + if (getBaseName().equals("Object")) + return null; + + JSTypeExpression baseType = getComment().getBaseType(); + if (baseType != null) + { + JSType jsType = getModel().evaluate(baseType); + if (jsType != null) + return getModel().getClassReference(jsType.getDisplayName()); + } + else + { + return getModel().getObjectReference(); + } + + return null; + } + + public boolean hasSuperFieldConflict(FieldReference reference) + { + // ClassReference2 superClass = getSuperClass(); + // if (superClass != null) + // return superClass.getInstanceFields().containsKey( + // reference.getName()); + return false; + } + + public boolean isPropertyInterfaceImplementation(String fieldName) + { + List<ClassReference> superInterfaces = getSuperInterfaces(); + for (ClassReference interfaceRef : superInterfaces) + { + if (interfaceRef == null) + { + System.err.println("isPropertyInterfaceImplementation() null"); + continue; + } + if (interfaceRef.hasInstanceField(fieldName)) + return true; + } + return false; + } + + public boolean hasLocalMethodConflict(String functionName) + { + return instanceMethods.containsKey(functionName) || staticMethods.containsKey(functionName); + } + + public void addImport(ClassReference reference) + { + if (reference != null) + { + imports.add(reference.getQualifiedName()); + } + } + + public boolean hasImport(String qualifiedName) + { + return imports.contains(qualifiedName); + } + + private boolean hasImplementations() + { + return getComment().getImplementedInterfaceCount() > 0; + } + + private void emitImports(StringBuilder sb) + { + if (imports.size() > 0) + { + for (String anImport : imports) + { + sb.append("import ").append(anImport).append(";\n"); + } + sb.append("\n"); + } + } + + @Override + protected void emitCommentBody(StringBuilder sb) + { + super.emitCommentBody(sb); + if (isInterface()) + sb.append(" * @interface\n"); + else + sb.append(" * @constructor "); + if (getComment().hasBaseType()) + { + emitSuperClass(sb); + } + if (!isInterface()) + { + emitImplements(sb); + } + } + + private void emitClass(StringBuilder sb) + { + if (outputJS) + return; - ++ + sb.append("public "); + if (isDynamic) + { + sb.append("dynamic "); + } + + if (isFinal) + { + sb.append("final "); + } + + sb.append("class "); + sb.append(getBaseName()).append(" "); + + if (getComment().hasBaseType()) + { + emitSuperClass(sb); + sb.append(" "); + } + else + { + // XXX JSObject extends + //sb.append("extends JSObject "); + } + + if (!isInterface()) + { + emitImplements(sb); + } + } + + private void emitInterface(StringBuilder sb) + { + sb.append("public interface "); + + sb.append(getBaseName()).append(" "); + + List<JSTypeExpression> extendedInterfaces = getComment().getExtendedInterfaces(); + int len = extendedInterfaces.size(); + if (len > 0) + { + sb.append("extends "); + for (JSTypeExpression jsTypeExpression : extendedInterfaces) + { + String value = getModel().evaluate(jsTypeExpression).toAnnotationString(); + sb.append(value); + if (--len > 0) + sb.append(", "); + } + sb.append(" "); + } + } + + private void emitSuperClass(StringBuilder sb) + { + if (outputJS) + { + sb.append(" * @extends "); + String value = JSTypeUtils.toClassTypeString(this); + sb.append(value); + sb.append("\n"); + } + else + { + sb.append("extends "); + String value = JSTypeUtils.toClassTypeString(this); + sb.append(value); + } + } + + private void emitImplements(StringBuilder sb) + { + List<JSTypeExpression> implementedInterfaces = getComment().getImplementedInterfaces(); + if (implementedInterfaces.size() == 0) + return; + + if (outputJS) + sb.append(" * @implements "); + else + sb.append("implements "); + + int len = implementedInterfaces.size(); + for (int i = 0; i < len; i++) + { + String value = getModel().evaluate(implementedInterfaces.get(i)).getDisplayName(); + + sb.append(value); + if (outputJS) + sb.append("\n"); + else + { + if (i < len - 1) + sb.append(", "); + } + } + + sb.append(" "); + } + + private void emitConstructor(StringBuilder sb) + { + if (constructor != null) + { + constructor.emit(sb); + } + } + + private void emitFields(StringBuilder sb) + { + for (FieldReference field : getAllFields()) + { + field.emit(sb); + sb.append("\n"); + nextEnumConstant(); + } + } + + private void emitMethods(StringBuilder sb) + { + for (MethodReference method : getAllMethods()) + { + method.emit(sb); + sb.append("\n"); + } + } + + public File getFile(File asSourceRoot) + { + File jsRoot = getModel().getConfiguration().getJsRoot(); + if (jsRoot == null) + { + String packagePath = toPackagePath(); + return new File(asSourceRoot, packagePath + File.separator + getBaseName() + ".as"); + } + + return new File(jsRoot, getBaseName() + ".js"); + } + + private String toPackagePath() + { + String packageName = getPackageName(); + + String[] cname = packageName.split("\\."); + String sdirPath = ""; + if (cname.length > 0) + { + for (final String aCname : cname) + { + sdirPath += aCname + File.separator; + } + + return sdirPath; + } + + return ""; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/58409300/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java ---------------------------------------------------------------------- diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java index d47c6dc,0000000..6ce6328 mode 100644,000000..100644 --- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java @@@ -1,290 -1,0 +1,339 @@@ +/* + * + * 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.jx; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.flex.compiler.asdoc.flexjs.ASDocComment; +import org.apache.flex.compiler.codegen.ISubEmitter; +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +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.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSSubEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; ++import org.apache.flex.compiler.internal.codegen.js.node.NodeEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.utils.EmitterUtils; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.scopes.ASProjectScope; +import org.apache.flex.compiler.internal.scopes.PackageScope; +import org.apache.flex.compiler.internal.tree.as.ClassNode; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.scopes.IASScope; +import org.apache.flex.compiler.targets.ITarget.TargetType; +import org.apache.flex.compiler.tree.as.ITypeNode; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.compiler.utils.NativeUtils; + +public class PackageHeaderEmitter extends JSSubEmitter implements + ISubEmitter<IPackageDefinition> +{ + + public PackageHeaderEmitter(IJSEmitter emitter) + { + super(emitter); + } + + @Override + public void emit(IPackageDefinition definition) + { + IASScope containedScope = definition.getContainedScope(); + ITypeDefinition type = EmitterUtils.findType(containedScope + .getAllLocalDefinitions()); + String qname = null; + if (type != null) + { + qname = type.getQualifiedName(); + } + if (qname == null) + { + IFunctionDefinition fn = EmitterUtils.findFunction(containedScope + .getAllLocalDefinitions()); + if(fn != null) + { + qname = fn.getQualifiedName(); + } + } + if (qname == null) + { + IVariableDefinition variable = EmitterUtils.findVariable(containedScope + .getAllLocalDefinitions()); + if(variable != null) + { + qname = variable.getQualifiedName(); + } + } + if (qname == null) + { + return; + } + + FlexJSProject project = (FlexJSProject) getProject(); + List<File> sourcePaths = project.getSourcePath(); + String sourceName = definition.getSourcePath(); + for (File sourcePath : sourcePaths) + { + if (sourceName.startsWith(sourcePath.getAbsolutePath())) + { + sourceName = sourceName.substring(sourcePath.getAbsolutePath().length() + 1); + } + } + + writeNewline("/**"); + writeNewline(" * Generated by Apache Flex Cross-Compiler from " + sourceName); + writeNewline(" * " + qname); + writeNewline(" *"); + writeNewline(" * @fileoverview"); + writeNewline(" *"); + // need to suppress access controls so access to protected/private from defineProperties + // doesn't generate warnings. + writeNewline(" * @suppress {checkTypes|accessControls}"); + writeNewline(" */"); + writeNewline(); + + /* goog.provide('x');\n\n */ + write(JSGoogEmitterTokens.GOOG_PROVIDE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.SINGLE_QUOTE); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + writeNewline(); + } + + public void emitContents(IPackageDefinition definition) + { + // TODO (mschmalle) will remove this cast as more things get abstracted + JSFlexJSEmitter fjs = (JSFlexJSEmitter) getEmitter(); + + getEmitter().pushSourceMapName(definition.getNode()); + + PackageScope containedScope = (PackageScope) definition + .getContainedScope(); + + ArrayList<String> writtenRequires = new ArrayList<String>(); + + Collection<IDefinition> localDefinitions = containedScope.getAllLocalDefinitions(); + ITypeDefinition type = EmitterUtils.findType(localDefinitions); + IDefinition otherMainDefinition = null; + if (type == null) + { + if (localDefinitions.isEmpty()) + return; + // function or variable definition + otherMainDefinition = localDefinitions.iterator().next(); + } + else + { + ITypeNode typeNode = type.getNode(); + if (typeNode instanceof ClassNode) + { + ClassNode classNode = (ClassNode) typeNode; + ASDocComment asDoc = (ASDocComment) classNode.getASDocComment(); + if (asDoc != null) + { + String asDocString = asDoc.commentNoEnd(); + String ignoreToken = JSFlexJSEmitterTokens.IGNORE_IMPORT + .getToken(); + int ignoreIndex = asDocString.indexOf(ignoreToken); + while (ignoreIndex != -1) + { + String ignorable = asDocString.substring(ignoreIndex + + ignoreToken.length()); + int endIndex = ignorable.indexOf("\n"); + ignorable = ignorable.substring(0, endIndex); + ignorable = ignorable.trim(); + // pretend we've already written the goog.requires for this + writtenRequires.add(ignorable); + ignoreIndex = asDocString.indexOf(ignoreToken, + ignoreIndex + ignoreToken.length()); + } + } + } + } + + // if (project == null) + // project = getWalker().getProject(); + + FlexJSProject flexProject = (FlexJSProject) getProject(); + ASProjectScope projectScope = (ASProjectScope) flexProject.getScope(); + ICompilationUnit cu = projectScope + .getCompilationUnitForDefinition(type != null ? type : otherMainDefinition); + ArrayList<String> requiresList = flexProject.getRequires(cu); + ArrayList<String> interfacesList = flexProject.getInterfaces(cu); ++ ArrayList<String> externalRequiresList = flexProject.getExternalRequires(cu); + + String cname = (type != null) ? type.getQualifiedName() : otherMainDefinition.getQualifiedName(); + writtenRequires.add(cname); // make sure we don't add ourselves + ++ boolean emitsRequires = emitRequires(requiresList, writtenRequires, cname); ++ boolean emitsInterfaces = emitInterfaces(interfacesList, writtenRequires); ++ ++ // erikdebruin: Add missing language feature support, with e.g. 'is' and ++ // 'as' operators. We don't need to worry about requiring ++ // this in every project: ADVANCED_OPTIMISATIONS will NOT ++ // include any of the code if it is not used in the project. ++ boolean makingSWC = flexProject.getSWFTarget() != null && ++ flexProject.getSWFTarget().getTargetType() == TargetType.SWC; ++ boolean isMainCU = flexProject.mainCU != null ++ && cu.getName().equals(flexProject.mainCU.getName()); ++ if (isMainCU || makingSWC) ++ { ++ ICompilerProject project = this.getProject(); ++ if (project instanceof FlexJSProject) ++ { ++ if (((FlexJSProject)project).needLanguage) ++ { ++ write(JSGoogEmitterTokens.GOOG_REQUIRE); ++ write(ASEmitterTokens.PAREN_OPEN); ++ write(ASEmitterTokens.SINGLE_QUOTE); ++ write(JSFlexJSEmitterTokens.LANGUAGE_QNAME); ++ write(ASEmitterTokens.SINGLE_QUOTE); ++ write(ASEmitterTokens.PAREN_CLOSE); ++ writeNewline(ASEmitterTokens.SEMICOLON); ++ } ++ } ++ } ++ ++ boolean emitsExternalRequires = emitExternalRequires(externalRequiresList, writtenRequires); ++ ++ if (emitsRequires || emitsInterfaces || emitsExternalRequires || isMainCU) ++ { ++ writeNewline(); ++ } ++ ++ writeNewline(); ++ writeNewline(); ++ } ++ ++ private boolean emitRequires(List<String> requiresList, List<String> writtenRequires, String cname) ++ { + boolean emitsRequires = false; + if (requiresList != null) + { + Collections.sort(requiresList); + for (String imp : requiresList) + { + if (imp.contains(JSGoogEmitterTokens.AS3.getToken())) + continue; + + if (imp.equals(JSGoogEmitterTokens.GOOG_BIND.getToken())) + continue; + + if (imp.equals(cname)) + continue; + + if (NativeUtils.isNative(imp)) + { - if (!(imp.equals("QName") || imp.equals("Namespace") || imp.equals("XML") || imp.equals("XMLList"))) - continue; ++ if (!(imp.equals("QName") || imp.equals("Namespace") || imp.equals("XML") || imp.equals("XMLList"))) ++ continue; + } + + if (writtenRequires.indexOf(imp) == -1) + { + + /* goog.require('x');\n */ + write(JSGoogEmitterTokens.GOOG_REQUIRE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.SINGLE_QUOTE); - write(fjs.formatQualifiedName(imp)); ++ write(getEmitter().formatQualifiedName(imp)); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + + writtenRequires.add(imp); + + emitsRequires = true; + } + } + } - ++ return emitsRequires; ++ } ++ ++ private boolean emitInterfaces(List<String> interfacesList, List<String> writtenRequires) ++ { + boolean emitsInterfaces = false; + if (interfacesList != null) + { + Collections.sort(interfacesList); + for (String imp : interfacesList) + { + if (writtenRequires.indexOf(imp) == -1) + { + write(JSGoogEmitterTokens.GOOG_REQUIRE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.SINGLE_QUOTE); - write(fjs.formatQualifiedName(imp)); ++ write(getEmitter().formatQualifiedName(imp)); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + + emitsInterfaces = true; + } + } + } - - // erikdebruin: Add missing language feature support, with e.g. 'is' and - // 'as' operators. We don't need to worry about requiring - // this in every project: ADVANCED_OPTIMISATIONS will NOT - // include any of the code if it is not used in the project. - boolean makingSWC = flexProject.getSWFTarget() != null && - flexProject.getSWFTarget().getTargetType() == TargetType.SWC; - boolean isMainCU = flexProject.mainCU != null - && cu.getName().equals(flexProject.mainCU.getName()); - if (isMainCU || makingSWC) ++ return emitsInterfaces; ++ } ++ ++ private boolean emitExternalRequires(List<String> externalRequiresList, List<String> writtenRequires) ++ { ++ boolean emitsExternalRequires = false; ++ if (externalRequiresList != null) + { - ICompilerProject project = this.getProject(); - if (project instanceof FlexJSProject) ++ Collections.sort(externalRequiresList); ++ for (String imp : externalRequiresList) + { - if (((FlexJSProject)project).needLanguage) - { - write(JSGoogEmitterTokens.GOOG_REQUIRE); - write(ASEmitterTokens.PAREN_OPEN); - write(ASEmitterTokens.SINGLE_QUOTE); - write(JSFlexJSEmitterTokens.LANGUAGE_QNAME); - write(ASEmitterTokens.SINGLE_QUOTE); - write(ASEmitterTokens.PAREN_CLOSE); - writeNewline(ASEmitterTokens.SEMICOLON); - } - } - } ++ if (writtenRequires.indexOf(imp) == -1) ++ { ++ /* var x = require('x');\n */ ++ write(ASEmitterTokens.VAR); ++ write(ASEmitterTokens.SPACE); ++ write(imp); ++ write(ASEmitterTokens.SPACE); ++ write(ASEmitterTokens.EQUAL); ++ write(ASEmitterTokens.SPACE); ++ write(NodeEmitterTokens.REQUIRE); ++ write(ASEmitterTokens.PAREN_OPEN); ++ write(ASEmitterTokens.SINGLE_QUOTE); ++ write(imp); ++ write(ASEmitterTokens.SINGLE_QUOTE); ++ write(ASEmitterTokens.PAREN_CLOSE); ++ writeNewline(ASEmitterTokens.SEMICOLON); + - if (emitsRequires || emitsInterfaces || isMainCU) - { - writeNewline(); - } ++ writtenRequires.add(imp); + - writeNewline(); - writeNewline(); ++ emitsExternalRequires = true; ++ } ++ } ++ } ++ return emitsExternalRequires; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/58409300/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/node/NodeEmitterTokens.java ---------------------------------------------------------------------- diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/node/NodeEmitterTokens.java index 0000000,0000000..dddcf90 new file mode 100644 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/node/NodeEmitterTokens.java @@@ -1,0 -1,0 +1,21 @@@ ++package org.apache.flex.compiler.internal.codegen.js.node; ++ ++import org.apache.flex.compiler.codegen.IEmitterTokens; ++ ++public enum NodeEmitterTokens implements IEmitterTokens ++{ ++ REQUIRE("require"), ++ EXPORTS("exports"); ++ ++ private String token; ++ ++ private NodeEmitterTokens(String value) ++ { ++ token = value; ++ } ++ ++ public String getToken() ++ { ++ return token; ++ } ++} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/58409300/compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java ---------------------------------------------------------------------- diff --cc compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java index 67869ab,0000000..dab4843 mode 100644,000000..100644 --- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java @@@ -1,267 -1,0 +1,328 @@@ +/* + * + * 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.projects; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; ++import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.flex.compiler.common.DependencyType; +import org.apache.flex.compiler.definitions.IDefinition; ++import org.apache.flex.compiler.definitions.metadata.IMetaTag; ++import org.apache.flex.compiler.definitions.metadata.IMetaTagAttribute; +import org.apache.flex.compiler.internal.codegen.mxml.flexjs.MXMLFlexJSEmitterTokens; +import org.apache.flex.compiler.internal.css.codegen.CSSCompilationSession; +import org.apache.flex.compiler.internal.definitions.InterfaceDefinition; +import org.apache.flex.compiler.internal.driver.js.flexjs.JSCSSCompilationSession; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.internal.scopes.ASProjectScope.DefinitionPromise; +import org.apache.flex.compiler.internal.targets.LinkageChecker; +import org.apache.flex.compiler.internal.tree.mxml.MXMLClassDefinitionNode; +import org.apache.flex.compiler.internal.units.SWCCompilationUnit; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.units.ICompilationUnit; + +/** + * @author aharui + * + */ +public class FlexJSProject extends FlexProject +{ + + /** + * Constructor + * + * @param workspace The {@code Workspace} containing this project. + */ + public FlexJSProject(Workspace workspace) + { + super(workspace); + MXMLClassDefinitionNode.GENERATED_ID_BASE = MXMLFlexJSEmitterTokens.ID_PREFIX.getToken(); + } + + private HashMap<ICompilationUnit, HashMap<String, String>> interfaces = new HashMap<ICompilationUnit, HashMap<String, String>>(); + private HashMap<ICompilationUnit, HashMap<String, DependencyType>> requires = new HashMap<ICompilationUnit, HashMap<String, DependencyType>>(); ++ private HashMap<ICompilationUnit, HashMap<String, DependencyType>> jsModules = new HashMap<ICompilationUnit, HashMap<String, DependencyType>>(); + + public JSGoogConfiguration config; + + public ICompilationUnit mainCU; + + @Override + public void addDependency(ICompilationUnit from, ICompilationUnit to, + DependencyType dt, String qname) + { + // ToDo (erikdebruin): add VF2JS conditional -> only use check during full SDK compilation + List<IDefinition> dp = to.getDefinitionPromises(); + + if (dp.size() == 0) + return; + + IDefinition def = dp.get(0); + // IDefinition def = to.getDefinitionPromises().get(0); + IDefinition actualDef = ((DefinitionPromise) def).getActualDefinition(); + boolean isInterface = actualDef instanceof InterfaceDefinition; + if (!isInterface) + { + if (from != to) + { + HashMap<String, DependencyType> reqs; + if (requires.containsKey(from)) + reqs = requires.get(from); + else + { + reqs = new HashMap<String, DependencyType>(); + requires.put(from, reqs); + } + if (reqs.containsKey(qname)) + { + // inheritance is important so remember it + if (reqs.get(qname) != DependencyType.INHERITANCE) + { + if (!isExternalLinkage(to)) + reqs.put(qname, dt); + } + } + else if (!isExternalLinkage(to) || qname.equals("Namespace")) + { + if (qname.equals("XML")) + needXML = true; + reqs.put(qname, dt); + } ++ if (jsModules.containsKey(from)) ++ { ++ reqs = jsModules.get(from); ++ } ++ else ++ { ++ reqs = new HashMap<String, DependencyType>(); ++ jsModules.put(from, reqs); ++ } ++ IMetaTag tag = getJSModuleMetadata(to); ++ if (tag != null) ++ { ++ IMetaTagAttribute nameAttribute = tag.getAttribute("name"); ++ if (nameAttribute != null) ++ { ++ reqs.put(nameAttribute.getValue(), dt); ++ } ++ else ++ { ++ reqs.put(qname, dt); ++ } ++ } + } + } + else + { + if (from != to) + { + HashMap<String, String> interfacesArr; + + if (interfaces.containsKey(from)) + { + interfacesArr = interfaces.get(from); + } + else + { + interfacesArr = new HashMap<String, String>(); + interfaces.put(from, interfacesArr); + } + + if (!interfacesArr.containsKey(qname)) + { + if (qname.equals("org.apache.flex.core.IValuesImpl")) + needCSS = true; + interfacesArr.put(qname, qname); + } + } + } + + super.addDependency(from, to, dt, qname); + } + + public boolean needLanguage; + public boolean needCSS; + public boolean needXML; + + private LinkageChecker linkageChecker; + private ITargetSettings ts; + + // definitions that should be considered external linkage + public Collection<String> unitTestExterns; + ++ private IMetaTag getJSModuleMetadata(ICompilationUnit cu) ++ { ++ try ++ { ++ Iterator<IDefinition> iterator = cu.getFileScopeRequest().get().getExternallyVisibleDefinitions().iterator(); ++ while(iterator.hasNext()) ++ { ++ IDefinition def = iterator.next(); ++ if (def.hasMetaTagByName("JSModule")) ++ { ++ return def.getMetaTagByName("JSModule"); ++ } ++ } ++ } ++ catch (Exception ex) ++ { ++ //it's safe to ignore an exception here ++ } ++ return null; ++ } ++ + private boolean isExternalLinkage(ICompilationUnit cu) + { + if (linkageChecker == null) + { + ts = getTargetSettings(); + linkageChecker = new LinkageChecker(this, ts); + } + // in unit tests, ts may be null and LinkageChecker NPEs + if (ts == null) + { + if (unitTestExterns != null) + { + try { + if (!(cu instanceof SWCCompilationUnit)) + if (unitTestExterns.contains(cu.getQualifiedNames().get(0))) + return true; + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return false; + } + + List<String> qnames; + try { + qnames = cu.getQualifiedNames(); + String qname = qnames.get(0); + if (qname.equals("QName")) + return false; + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + try + { + return linkageChecker.isExternal(cu); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + public ArrayList<String> getInterfaces(ICompilationUnit from) + { + if (interfaces.containsKey(from)) + { + HashMap<String, String> map = interfaces.get(from); + ArrayList<String> arr = new ArrayList<String>(); + Set<String> cus = map.keySet(); + for (String s : cus) + arr.add(s); + return arr; + } + return null; + } + + public ArrayList<String> getRequires(ICompilationUnit from) + { + if (requires.containsKey(from)) + { + HashMap<String, DependencyType> map = requires.get(from); + ArrayList<String> arr = new ArrayList<String>(); + Set<String> cus = map.keySet(); + for (String s : cus) + arr.add(s); + return arr; + } + return null; + } + ++ public ArrayList<String> getExternalRequires(ICompilationUnit from) ++ { ++ if (jsModules.containsKey(from)) ++ { ++ HashMap<String, DependencyType> map = jsModules.get(from); ++ ArrayList<String> arr = new ArrayList<String>(); ++ Set<String> cus = map.keySet(); ++ for (String s : cus) ++ arr.add(s); ++ return arr; ++ } ++ return null; ++ } ++ + JSCSSCompilationSession cssSession = new JSCSSCompilationSession(); + + @Override + public CSSCompilationSession getCSSCompilationSession() + { + // When building SWFs, each MXML document may have its own styles + // specified by fx:Style blocks. The CSS is separately compiled and + // stored in the class definition for the MXML document. That helps + // with deferred loading of classes. The styles and thus the + // classes for an MXML document are not initialized until the MXML + // class is initialized. + // For JS compilation, the CSS for non-standard CSS could be done the + // same way, but AFAICT, standard CSS properties are best loaded by + // specifying a .CSS file in the HTML. The CSS is probably less text + // than its codegen'd representation, and the browser can probably + // load a .CSS file faster than us trying to run code to update the + // styles. + // So, for FlexJS, all style blocks from all MXML files are gathered into + // one .css file and a corresponding codegen block that is output as + // part of the main .JS file. + return cssSession; + } + + private HashMap<IASNode, String> astCache = new HashMap<IASNode, String>(); + + @Override + public void addToASTCache(IASNode ast) + { + astCache.put(ast, ""); + } + + @Override + public void setTargetSettings(ITargetSettings value) + { + super.setTargetSettings(value); + ts = value; + linkageChecker = new LinkageChecker(this, value); + try { + linkageChecker.initExterns(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +}