http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/graph/VF2JSDepsWriter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/graph/VF2JSDepsWriter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/graph/VF2JSDepsWriter.java new file mode 100644 index 0000000..4d625d4 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/graph/VF2JSDepsWriter.java @@ -0,0 +1,406 @@ +/* + * + * 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.graph; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Scanner; + +import org.apache.commons.io.FileUtils; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.problems.FileNotFoundProblem; + +import com.google.common.io.Files; + +public class VF2JSDepsWriter { + + public VF2JSDepsWriter(File outputFolder, String mainClassName, JSGoogConfiguration config) + { + this.outputFolderPath = outputFolder.getAbsolutePath(); + this.mainName = mainClassName; + otherPaths = config.getSDKJSLib(); + } + + private ProblemQuery problems; + private String outputFolderPath; + private String mainName; + private List<String> otherPaths; + private boolean problemsFound = false; + + private HashMap<String,GoogDep> depMap = new HashMap<String,GoogDep>(); + + public ArrayList<String> getListOfFiles() throws InterruptedException + { + buildDB(); + ArrayList<GoogDep> dps = sort(mainName); + ArrayList<String> files = new ArrayList<String>(); + for (GoogDep gd : dps) + { + files.add(gd.filePath); + } + return files; + } + + public boolean generateDeps(ProblemQuery problems, StringBuilder depsFileData) + throws InterruptedException, FileNotFoundException + { + problemsFound = false; + this.problems = problems; + buildDB(); + ArrayList<GoogDep> dps = sort(mainName); + String outString = "// generated by FalconJS" + "\n"; + int n = dps.size(); + for (int i = n - 1; i >= 0; i--) + { + GoogDep gd = dps.get(i); + if (!isGoogClass(gd.className)) + { + String s = "goog.addDependency('"; + s += relativePath(gd.filePath); + s += "', ['"; + s += gd.className; + s += "'], ["; + s += getDependencies(gd.deps); + s += "]);\n"; + outString += s; + } + } + depsFileData.append(outString); + return !problemsFound; + } + + private boolean isGoogClass(String className) + { + return className.startsWith("goog."); + } + + private void buildDB() + { + addDeps(mainName); + } + + public ArrayList<String> filePathsInOrder = new ArrayList<String>(); + + public ArrayList<String> additionalHTML = new ArrayList<String>(); + + private HashMap<String, GoogDep> visited = new HashMap<String, GoogDep>(); + + private ArrayList<GoogDep> sort(String rootClassName) + { + ArrayList<GoogDep> arr = new ArrayList<GoogDep>(); + GoogDep current = depMap.get(rootClassName); + sortFunction(current, arr); + return arr; + } + + private void sortFunction(GoogDep current, ArrayList<GoogDep> arr) + { + visited.put(current.className, current); + + filePathsInOrder.add(current.filePath); + System.out.println("Dependencies calculated for '" + current.filePath + "'"); + + ArrayList<String> deps = current.deps; + for (String className : deps) + { + if (!visited.containsKey(className) && !isGoogClass(className)) + { + GoogDep gd = depMap.get(className); + sortFunction(gd, arr); + } + } + arr.add(current); + } + + private void addDeps(String className) + { + if (depMap.containsKey(className) || isGoogClass(className)) + return; + + // build goog dependency list + GoogDep gd = new GoogDep(); + gd.className = className; + gd.filePath = getFilePath(className); + depMap.put(gd.className, gd); + ArrayList<String> deps = getDirectDependencies(gd.filePath); + + gd.deps = new ArrayList<String>(); + ArrayList<String> circulars = new ArrayList<String>(); + for (String dep : deps) + { + if (depMap.containsKey(dep) && !isGoogClass(dep)) + { + circulars.add(dep); + continue; + } + gd.deps.add(dep); + } + for (String dep : deps) + { + addDeps(dep); + } + if (circulars.size() > 0) + { + // remove requires that would cause circularity + try + { + List<String> fileLines = Files.readLines(new File(gd.filePath), + Charset.defaultCharset()); + ArrayList<String> finalLines = new ArrayList<String>(); + + //String inherits = getBaseClass(fileLines, className); + + for (String line : fileLines) + { + int c = line.indexOf("goog.require"); + if (c > -1) + { + int c2 = line.indexOf(")"); + String s = line.substring(c + 14, c2 - 1); + if (circulars.contains(s) /* && !s.equals(inherits) */ ) + continue; + } + finalLines.add(line); + } + File file = new File(gd.filePath); + PrintWriter out = new PrintWriter(new FileWriter(file)); + for (String s : finalLines) + { + out.println(s); + } + out.close(); + + } + catch (IOException e) + { + e.printStackTrace(); + } + + } + } + + String getBaseClass(List<String> lines, String className) + { + int n = lines.size(); + for (int i = 0; i < n; i++) + { + String line = lines.get(i); + int c2; + int c = line.indexOf("goog.inherits"); + if (c > -1) + { + String inheritLine = ""; + while (true) + { + inheritLine += line; + c2 = line.indexOf(")"); + if (c2 > -1) + break; + else + { + i++; + line = lines.get(i); + } + } + c = inheritLine.indexOf(","); + c2 = inheritLine.indexOf(")"); + return inheritLine.substring(c + 1, c2).trim(); + } + } + return null; + } + + String getFilePath(String className) + { + String fn; + File destFile; + File f; + + String classPath = className.replace(".", File.separator); + + fn = outputFolderPath + File.separator + classPath + ".js"; + f = new File(fn); + if (f.exists()) + { + return fn; + } + + for (String otherPath : otherPaths) + { + fn = otherPath + File.separator + classPath + ".js"; + f = new File(fn); + if (f.exists()) + { + fn = outputFolderPath + File.separator + classPath + ".js"; + destFile = new File(fn); + // copy source to output + try { + FileUtils.copyFile(f, destFile); + + // (erikdebruin) copy class assets files + if (className.indexOf("org.apache.flex") > -1) + { + File assetsDir = new File(f.getParentFile(), "assets"); + if (assetsDir.exists()) + { + String nameOfClass = className.substring(className.lastIndexOf('.') + 1); + + File[] assetsList = assetsDir.listFiles(); + for (int i = 0; i < assetsList.length; i++) + { + File assetFile = assetsList[i]; + String assetFileName = assetFile.getName(); + + if (assetFile.isFile() && assetFileName.indexOf(nameOfClass) == 0) + { + String pathOfClass = ""; + pathOfClass = className.substring(0, className.lastIndexOf('.')); + pathOfClass = pathOfClass.replace(".", File.separator); + + destFile = new File(outputFolderPath + + File.separator + pathOfClass + + File.separator + "assets" + + File.separator + assetFileName); + FileUtils.copyFile(assetFile, destFile); + + destFile = new File(outputFolderPath.replace("js-debug", "js-release") + + File.separator + pathOfClass + + File.separator + "assets" + + File.separator + assetFileName); + FileUtils.copyFile(assetFile, destFile); + + System.out.println("Copied assets of the '" + nameOfClass + "' class"); + } + } + } + } + } catch (IOException e) { + System.out.println("Error copying file for class: " + className); + } + return fn; + } + } + + System.out.println("Could not find file for class: " + className); + problems.add(new FileNotFoundProblem(className)); + problemsFound = true; + return ""; + } + + private ArrayList<String> getDirectDependencies(String fn) + { + ArrayList<String> deps = new ArrayList<String>(); + + FileInputStream fis; + try { + fis = new FileInputStream(fn); + Scanner scanner = new Scanner(fis, "UTF-8"); + boolean inInjectHTML = false; + while (scanner.hasNextLine()) + { + String s = scanner.nextLine(); + if (s.indexOf("goog.inherits") > -1) + break; + if (inInjectHTML) + { + int c = s.indexOf("</inject_html>"); + if (c > -1) + { + inInjectHTML = false; + continue; + } + } + if (inInjectHTML) + { + additionalHTML.add(s); + continue; + } + int c = s.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken()); + if (c > -1) + { + int c2 = s.indexOf(")"); + s = s.substring(c + 14, c2 - 1); + deps.add(s); + } + c = s.indexOf("<inject_html>"); + if (c > -1) + { + inInjectHTML = true; + } + } + scanner.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return deps; + } + + private String getDependencies(ArrayList<String> deps) + { + String s = ""; + for (String dep : deps) + { + if (s.length() > 0) + { + s += ", "; + } + s += "'" + dep + "'"; + } + return s; + } + + String relativePath(String path) + { + if (path.indexOf(outputFolderPath) == 0) + { + path = path.replace(outputFolderPath, "../../.."); + } + else + { + for (String otherPath : otherPaths) + { + if (path.indexOf(otherPath) == 0) + { + path = path.replace(otherPath, "../../.."); + + } + } + } + // paths are actually URIs and always have forward slashes + path = path.replace('\\', '/'); + return path; + } + private class GoogDep + { + public String filePath; + public String className; + public ArrayList<String> deps; + + } +}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/parsing/as/FlexJSASDocDelegate.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/parsing/as/FlexJSASDocDelegate.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/parsing/as/FlexJSASDocDelegate.java new file mode 100644 index 0000000..868e5d7 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/parsing/as/FlexJSASDocDelegate.java @@ -0,0 +1,143 @@ +/* + * + * 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.parsing.as; + + + + +import antlr.Token; + +import org.apache.flex.compiler.asdoc.IASDocComment; +import org.apache.flex.compiler.asdoc.IASDocDelegate; +import org.apache.flex.compiler.asdoc.IASParserASDocDelegate; +import org.apache.flex.compiler.asdoc.IMetadataParserASDocDelegate; +import org.apache.flex.compiler.asdoc.IPackageDITAParser; +import org.apache.flex.compiler.asdoc.flexjs.ASDocComment; +import org.apache.flex.compiler.common.ISourceLocation; +import org.apache.flex.compiler.definitions.IDocumentableDefinition; +import org.apache.flex.compiler.tree.as.IDocumentableDefinitionNode; + +/** + * Default implementation of {@link IASDocDelegate} that does not have any code + * model or eclipse dependencies. + */ +public final class FlexJSASDocDelegate implements IASDocDelegate +{ + private static final FlexJSASDocDelegate INSTANCE = new FlexJSASDocDelegate(); + + /** + * Gets the single instance of this delegate. + * + * @return The single instance of this delegate. + */ + public static IASDocDelegate get() + { + return INSTANCE; + } + + public FlexJSASDocDelegate() + { + } + + @Override + public IASParserASDocDelegate getASParserASDocDelegate() + { + return new ASDelegate(); + } + + @Override + public IASDocComment createASDocComment(ISourceLocation location, IDocumentableDefinition definition) + { + return null; + } + + @Override + public IPackageDITAParser getPackageDitaParser() + { + return IPackageDITAParser.NIL_PARSER; + } + + private static final class ASDelegate implements IASParserASDocDelegate + { + @SuppressWarnings("unused") + static final ASDelegate INSTANCE = new ASDelegate(); + + @Override + public void beforeVariable() + { + } + + @Override + public void afterVariable() + { + } + + Token currentToken; + + @Override + public void setCurrentASDocToken(Token asDocToken) + { + currentToken = asDocToken; + } + + @Override + public IASDocComment afterDefinition(IDocumentableDefinitionNode definitionNode) + { + if (currentToken == null) + return null; + + ASDocComment comment = new ASDocComment(currentToken); + currentToken = null; + return comment; + } + + @Override + public IMetadataParserASDocDelegate getMetadataParserASDocDelegate() + { + return MetadataDelegate.INSTANCE; + } + + } + + private static final class MetadataDelegate implements IMetadataParserASDocDelegate + { + static final MetadataDelegate INSTANCE = new MetadataDelegate(); + + @Override + public void setCurrentASDocToken(Token asDocToken) + { + } + + @Override + public IASDocComment afterDefinition(IDocumentableDefinitionNode definitionNode) + { + return null; + } + + @Override + public void clearMetadataComment(String metaDataTagName) + { + } + + @Override + public void afterMetadata(int metaDataEndOffset) + { + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java ---------------------------------------------------------------------- diff --git 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 new file mode 100644 index 0000000..67869ab --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/projects/FlexJSProject.java @@ -0,0 +1,267 @@ +/* + * + * 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.List; +import java.util.Set; + +import org.apache.flex.compiler.common.DependencyType; +import org.apache.flex.compiler.definitions.IDefinition; +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>>(); + + 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); + } + } + } + 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 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; + } + + 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(); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSSWCTarget.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSSWCTarget.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSSWCTarget.java new file mode 100644 index 0000000..339e3a8 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSSWCTarget.java @@ -0,0 +1,303 @@ +/* + * + * 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.targets; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.apache.flex.compiler.common.XMLName; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.references.IResolvedQualifiersReference; +import org.apache.flex.compiler.definitions.references.ReferenceFactory; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.projects.SourcePathManager; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.problems.NoCompilationUnitForDefinitionProblem; +import org.apache.flex.compiler.problems.NoSourceForClassInNamespaceProblem; +import org.apache.flex.compiler.problems.NoSourceForClassProblem; +import org.apache.flex.compiler.projects.IASProject; +import org.apache.flex.compiler.targets.IJSTarget; +import org.apache.flex.compiler.targets.ITargetProgressMonitor; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.compiler.units.ICompilationUnit.UnitType; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class FlexJSSWCTarget extends JSTarget implements IJSTarget +{ + protected ICompilationUnit mainCU; + protected RootedCompilationUnits rootedCompilationUnits; + + /** + * Initialize a JS target with the owner project and root compilation units. + * + * @param project the owner project + */ + public FlexJSSWCTarget(IASProject project, ITargetSettings targetSettings, + ITargetProgressMonitor progressMonitor) + { + super(project, targetSettings, progressMonitor); + flexProject = (FlexJSProject)project; + } + + private FlexJSProject flexProject; + + @Override + protected Target.RootedCompilationUnits computeRootedCompilationUnits() throws InterruptedException + { + final Set<ICompilationUnit> rootCompilationUnits = new HashSet<ICompilationUnit>(); + + final Collection<File> includedSourceFiles = targetSettings.getIncludeSources(); + final Set<String> includeClassNameSet = ImmutableSet.copyOf(targetSettings.getIncludeClasses()); + final Set<String> includedNamespaces = ImmutableSet.copyOf(targetSettings.getIncludeNamespaces()); + + final ArrayList<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + + // Select definitions according to configurations. + + // include-namespace + final Collection<ICompilationUnit> includeNamespaceUnits = + getCompilationUnitsForIncludedNamespaces(includedNamespaces, problems); + rootCompilationUnits.addAll(includeNamespaceUnits); + + // include-class + include-namespace + rootCompilationUnits.addAll(getCompilationUnitsFromClassNames(null, includeClassNameSet, problems)); + + // include-source + for (final File includedSourceFileName : includedSourceFiles) + { + // Get all the compilation units in the project that reference the specified file. + Collection<ICompilationUnit> compilationUnitsForFile = project.getWorkspace().getCompilationUnits(includedSourceFileName.getAbsolutePath(), project); + + // For compilation units with that differ by qname, choose the compilation that + // appears first on the source-path. + if (compilationUnitsForFile.size() > 1) + { + compilationUnitsForFile = filterUnitsBasedOnSourcePath(compilationUnitsForFile); + } + + for (ICompilationUnit cu : compilationUnitsForFile) + { + // IFilter out any compilation unit in the list where the specified file is not the root + // source file compiled by the compilation unit. + if (cu.getAbsoluteFilename().equals(includedSourceFileName.getAbsolutePath())) + rootCompilationUnits.add(cu); + } + } + + //Add compilation units for included resource bundles + for (ICompilationUnit rbCompUnit : getIncludedResourceBundlesCompilationUnits(problems)) + rootCompilationUnits.add(rbCompUnit); + + // -include and -include-libraries + rootCompilationUnits.addAll(getIncludesCompilationUnits()); + rootCompilationUnits.addAll(getIncludeLibrariesCompilationUnits()); + + return new Target.RootedCompilationUnits(rootCompilationUnits, problems); + } + + /** + * For compilation units with the same absolute source path, filter based on + * the source path. The compilation unit found on the highest priority + * source path wins. The rest of the compilation units with qnames are + * discared. If a unit is not on the source path or does not have a qname or + * more than one qname, then let it thru the filter. + * + * @param compilationUnitsForFile list of compilation units to filter. + * @return filtered compilation units. + * @throws InterruptedException + */ + private Collection<ICompilationUnit> filterUnitsBasedOnSourcePath(Collection<ICompilationUnit> compilationUnitsForFile) throws InterruptedException + { + List<ICompilationUnit> sourcePathUnits = new ArrayList<ICompilationUnit>(compilationUnitsForFile); + boolean foundHighestPriorityUnit = false; + for (File sourcePath : flexProject.getSourcePath()) + { + for (ICompilationUnit unit : sourcePathUnits) + { + // We only care about filtering units on the source path + // that follow the single definition rule. + UnitType unitType = unit.getCompilationUnitType(); + if (unitType == UnitType.AS_UNIT || unitType == UnitType.FXG_UNIT || + unitType == UnitType.MXML_UNIT || unitType == UnitType.CSS_UNIT) + { + Collection<String> qnames = unit.getQualifiedNames(); + if (qnames.size() > 1) + continue; + + String unitQname = qnames.isEmpty() ? "" : qnames.iterator().next(); + String computedQname = SourcePathManager.computeQName(sourcePath, new File(unit.getAbsoluteFilename())); + + if (unitQname.equals(computedQname)) + { + // We found a unit on the source path. Only keep the + // first unit found on the source path and remove the + // others. + if (foundHighestPriorityUnit) + compilationUnitsForFile.remove(unit); + + foundHighestPriorityUnit = true; + break; // should only be one compilation unit on a source path + } + } + } + } + + return compilationUnitsForFile; + } + + /** + * Get the compilation units for the given included namespaces. Also perform error + * checking. + * + * @param namespaces the namespaces included in this swc target. + * @param problems A collection where detected problems are added. + * @return A collection of compilation units. + * @throws InterruptedException + */ + private Collection<ICompilationUnit> getCompilationUnitsForIncludedNamespaces( + Collection<String> namespaces, + Collection<ICompilerProblem> problems) throws InterruptedException + { + final Collection<ICompilationUnit> allUnits = new HashSet<ICompilationUnit>(); + + for (String namespace : namespaces) + { + // For each namespace get the set of classes. + // From the classes get the the compilation units. + // Validate the compilation units are resolved to source + // files unless there are lookupOnly entries. + final Collection<String> includeNamespaceQualifiedNames = + flexProject.getQualifiedClassNamesForManifestNamespaces( + Collections.singleton(namespace)); + final Collection<ICompilationUnit> units = + getCompilationUnitsFromClassNames(namespace, includeNamespaceQualifiedNames, problems); + validateIncludeNamespaceEntries(namespace, units, problems); + allUnits.addAll(units); + } + return allUnits; + } + + /** + * Validate that the manifest entries in the included namespaces resolve to + * source files, not classes from other SWCs. The exception is for entries + * that are "lookupOnly". + * + * @param namespace The target namespace. + * @param units The compilation units found in that namespace. + * @param problems detected problems are added to this list. + * @throws InterruptedException + */ + private void validateIncludeNamespaceEntries(String namespace, + Collection<ICompilationUnit> units, + Collection<ICompilerProblem> problems) throws InterruptedException + { + for (ICompilationUnit unit : units) + { + List<String> classNames = unit.getQualifiedNames(); + String className = classNames.get(classNames.size() - 1); + Collection<XMLName> xmlNames = flexProject.getTagNamesForClass(className); + for (XMLName xmlName : xmlNames) + { + if (namespace.equals(xmlName.getXMLNamespace())) + { + if (!flexProject.isManifestComponentLookupOnly(xmlName) && + unit.getCompilationUnitType() == UnitType.SWC_UNIT) + { + problems.add(new NoSourceForClassInNamespaceProblem(namespace, className)); + } + break; + } + } + } + } + + /** + * Return a collection of compilation units for a collection of class names. + * + * @param namespace the namespace of the classes. Null if there is no namespace. + * @param classNames + * @param problems detected problems are added to this list. + * @return a collection of compilation units. + */ + private Collection<ICompilationUnit> getCompilationUnitsFromClassNames(String namespace, + Collection<String> classNames, + final Collection<ICompilerProblem> problems) + { + Collection<String> compilableClassNames = new ArrayList<String>(); + for (String className : classNames) + { + Collection<XMLName> tagNames = flexProject.getTagNamesForClass(className); + boolean okToAdd = true; + for (XMLName tagName : tagNames) + { + if (flexProject.isManifestComponentLookupOnly(tagName)) + okToAdd = false; + } + if (okToAdd) + compilableClassNames.add(className); + } + + // Class names are turned into references and then info compilation units. + final Iterable<IResolvedQualifiersReference> references = + Iterables.transform(compilableClassNames, new Function<String, IResolvedQualifiersReference>() + { + @Override + public IResolvedQualifiersReference apply(String qualifiedName) + { + return ReferenceFactory.packageQualifiedReference(project.getWorkspace(), qualifiedName, true); + } + }); + + Collection<ICompilationUnit> units = new LinkedList<ICompilationUnit>(); + for (IResolvedQualifiersReference reference : references) + { + IDefinition def = reference.resolve(flexProject); + if (def == null) + { + if (namespace == null) + problems.add(new NoSourceForClassProblem(reference.getDisplayString())); + else + problems.add(new NoSourceForClassInNamespaceProblem(namespace, reference.getDisplayString())); + } + else + { + ICompilationUnit defCU = project.getScope().getCompilationUnitForDefinition(def); + if (defCU == null) + problems.add(new NoCompilationUnitForDefinitionProblem(def.getBaseName())); + else + units.add(defCU); + } + } + + return units; + } + + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSTarget.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSTarget.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSTarget.java new file mode 100644 index 0000000..dd3fe6f --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/FlexJSTarget.java @@ -0,0 +1,295 @@ +/* + * + * 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.targets; + +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.flex.compiler.css.ICSSDocument; +import org.apache.flex.compiler.css.ICSSManager; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.internal.css.semantics.ActivatedStyleSheets; +import org.apache.flex.compiler.internal.driver.js.flexjs.JSCSSCompilationSession; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.units.SWCCompilationUnit; +import org.apache.flex.compiler.problems.FileNotFoundProblem; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.projects.IASProject; +import org.apache.flex.compiler.targets.IJSTarget; +import org.apache.flex.compiler.targets.ITargetProgressMonitor; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.compiler.units.ICompilationUnit.UnitType; + +import com.google.common.collect.ImmutableList; + +public class FlexJSTarget extends JSTarget implements IJSTarget +{ + /** + * Initialize a JS target with the owner project and root compilation units. + * + * @param project the owner project + */ + public FlexJSTarget(IASProject project, ITargetSettings targetSettings, + ITargetProgressMonitor progressMonitor) + { + super(project, targetSettings, progressMonitor); + flexProject = (FlexJSProject)project; + } + + private final FlexJSProject flexProject; + + /////////// + // + // Copied from FlexAppSWFTarget.java then modified + // + /////////// + /** + * Discovers dependent compilation units from a set of root compilation + * units. + * <p> + * For each public visible definition in all the compilation units, if + * there's an applicable CSS rule, check if the CSS rule pulls in any + * dependencies. (i.e. embedded assets, skin classes) Add the dependencies + * to the list of compilation units, and check if they have any applicable + * CSS rules which could pull in more dependencies. Loop until we reach a + * stable set of compilation units. + * <p> + * CSS rules in these CSS documents can introduce class dependencies. If any + * candidate rule matches a class known to be linked into the target, the + * candidate rule's dependencies are selected for linking. Those selected + * dependencies will be included in the next iteration of the dependency + * discovery loop. + * <p> + * Once a CSS document is "activated", it stays in this collection and its + * rules are tested against all classes introduced in the + * "dependency discovery loop". + * <p> + * For example: Suppose in project P, there are "A.as" and "styles.css", and + * class "A" is selected for linking.<br> + * In "styles.css", there're two rules: + * + * <pre> + * A { xSkin : ClassReference("B"); } + * K { xSkin : ClassReference("L"); } + * </pre> + * + * In the 1st iteration, rule "A" is matched, which introduces dependency on + * "B". <br> + * "B" is defined in a SWC library "myskins.swc", and there's a + * "defaults.css" in "myskins.swc". + * + * <pre> + * B { ySkin : ClassReference("C"); } + * A { ySkin : ClassReference("D"); } + * K { ySkin : ClassReference("M"); } + * </pre> + * + * In the 2nd iteration, rule "A" and rule "B" in "defaults.css" are + * matched, which introduces dependencies on "C" and "D". However, "K" has + * not been selected so far, so "L" and "M" are not selected. + * <p> + * Now imagine, "C" is defined in "anotherSkin.swc", and there's a + * "defaults.css" in "anotherSkin.swc" as well. + * + * <pre> + * C { zSkin : ClassReference("K"); } + * </pre> + * + * In the 3rd iteration, rule "C" is matched because "C" was selected in the + * previous iteration, which makes "K" the selected dependency. + * <p> + * At the beginning of the 4th iteration, the classes selected for linking + * are "A", "B", "C", "D" and "K". In this iteration, these classes will be + * tested against all the "activated style sheets" - "styles.css" and two + * "defaults.css" in "myskins.swc" and "anotherSkin.swc". "K" rules in + * "styles.css" and "myskins.swc" are now matched, which introduces new + * dependencies on "L" and "M". + * <p> + * In the 5th iteration, the classes to link are "A", "B", "C", "D", "K", + * "L" and "M". They are tested against all the activate CSS. No more + * dependencies are introduced by CSS rules, making it the last iteration of + * the loop. + * + * @param compilationUnits Collection of compilation units known to be + * linked in. + * @param problems Collection of {@link ICompilerProblem}'s that the each + * found {@link ICompilationUnit} is added to. + * @return All compilation units which were compiled + * @throws InterruptedException + */ + @Override + protected Set<ICompilationUnit> findAllCompilationUnitsToLink(final Collection<ICompilationUnit> compilationUnits, + final Collection<ICompilerProblem> problems) + throws InterruptedException + { + JSCSSCompilationSession cssCompilationSession = (JSCSSCompilationSession) flexProject.getCSSCompilationSession(); + cssCompilationSession.setKeepAllTypeSelectors(targetSettings.keepAllTypeSelectors()); + + // Performance heuristic: let's start compilation on all of the compilation + // units we know about up front. This is particularly useful on SWC projects where + // we are using "include-sources" to force a bunch of possibly unrelated classes to be + // compiled. + // Note that by putting the code here, we will start aggressive early compilation for + // all projects. Limited data so far shows this this is a good thing. But down the + // road it's possible that we might find tests cases that force us to reconsider / refine + // this "shotgun" approach. + for (ICompilationUnit cu : compilationUnits) + cu.startBuildAsync(getTargetType()); + + + assert compilationUnits != null : "compilation units can't be null"; + assert problems != null : "problems can't be null"; + + // Collection of all the compilation units that will be linked in the target. + final Set<ICompilationUnit> allCompilationUnitsInTarget = + new HashSet<ICompilationUnit>(compilationUnits); + + // Collection of all the referenced CSS. Once a CSS is activated, it's always + // included in the dependency checking, even none of its rules are matched. + final ActivatedStyleSheets activatedStyleSheets = new ActivatedStyleSheets(); + + final ICSSManager cssManager = flexProject.getCSSManager(); + + collectThemes(cssManager, activatedStyleSheets, problems); + collectDefaultCSS(cssManager, activatedStyleSheets, problems); + + // The dependency discovery loop. + // It terminates when no more dependencies are introduced by CSS. + boolean done = false; + while (!done) + { + //LoggingProfiler.onStartIteration(); + + // Get all non-CSS dependencies. + final Set<ICompilationUnit> dependencies = + getDependentCompilationUnits(allCompilationUnitsInTarget, problems); + //LoggingProfiler.onCompilationUnitDependenciesChanged(allCompilationUnitsInTarget, dependencies); + allCompilationUnitsInTarget.addAll(dependencies); + + // Get all activated defaults.css from SWCs. + final Map<ICSSDocument, File> activatedDefaultCSSList = + getAllDefaultCSS(cssManager, allCompilationUnitsInTarget); + for (final Map.Entry<ICSSDocument, File> entry : activatedDefaultCSSList.entrySet()) + { + activatedStyleSheets.addLibraryCSS(entry.getKey(), entry.getValue().getAbsolutePath()); + } + //LoggingProfiler.onDefaultsCSSCollectionChanged(activatedStyleSheets); + + // Get all dependencies introduced by defaults.css from SWCs. + final ImmutableList<IDefinition> definitions = + Target.getAllExternallyVisibleDefinitions(allCompilationUnitsInTarget); + final Collection<ICompilationUnit> cssDependencies = new HashSet<ICompilationUnit>(); + for (final ICSSDocument cssDocument : activatedStyleSheets.all()) + { + // Side-effects of this method: + // 1. Resolve all type selectors in the CSS model to IClassDefinition definitions. + // 2. Activate CSS rules whose subject is in the definition set. + final Collection<ICompilationUnit> dependentCUListFromCSS = + cssManager.getDependentCompilationUnitsFromCSS( + cssCompilationSession, + cssDocument, + definitions, + problems); + cssDependencies.addAll(dependentCUListFromCSS); + //LoggingProfiler.onCSSDependenciesChanged(dependentCUListFromCSS); + } + + // If there's more dependencies introduced by CSS, the loop continues. + done = !allCompilationUnitsInTarget.addAll(cssDependencies); + } + + // add to front so user specified css overrides defaults + cssCompilationSession.cssDocuments.addAll(0, activatedStyleSheets.sort()); + + return super.findAllCompilationUnitsToLink(compilationUnits, problems); + } + + /** + * Collect CSS from themes. + */ + private void collectThemes( + final ICSSManager cssManager, + final ActivatedStyleSheets activatedStyleSheets, + final Collection<ICompilerProblem> problems) + { + final Collection<ICSSDocument> cssFromThemes = cssManager.getCSSFromThemes(problems); + for (final ICSSDocument themeCSS : cssFromThemes) + { + // Theme files are sorted by declaration order instead of filenames, so we needn't + // their filenames here. + activatedStyleSheets.addThemeCSS(themeCSS); + } + } + + /** + * Collect CSS from 'defaults-css-files' configuration option. + */ + private void collectDefaultCSS( + final ICSSManager cssManager, + final ActivatedStyleSheets activatedStyleSheets, + final Collection<ICompilerProblem> problems) + { + for (final String defaultsCSSPath : getTargetSettings().getDefaultsCSSFiles()) + { + final ICSSDocument defaultsCSSModel = cssManager.getCSS(defaultsCSSPath); + if (defaultsCSSModel == null) + problems.add(new FileNotFoundProblem(defaultsCSSPath)); + else + activatedStyleSheets.addDefaultCSS(defaultsCSSModel); + } + } + + /** + * Find all the {@link SWCCompilationUnit}'s, and return the default CSS + * model in the SWCs. + * + * @param cssManager Project-level CSS manager. + * @param compilationUnits All the compilation units. Non-SWC compilation + * units are ignored. + * @return Model of the default CSS in the SWCs. The map keys are CSS + * models; the values are the enclosing SWC file. + */ + private static Map<ICSSDocument, File> getAllDefaultCSS( + final ICSSManager cssManager, + final Collection<ICompilationUnit> compilationUnits) + { + assert cssManager != null : "Expected CSS manager."; + assert compilationUnits != null : "Expected collection of compilation units."; + + final Map<ICSSDocument, File> result = new HashMap<ICSSDocument, File>(); + for (final ICompilationUnit compilationUnit : compilationUnits) + { + if (compilationUnit.getCompilationUnitType() == UnitType.SWC_UNIT) + { + final File swcFile = new File(compilationUnit.getAbsoluteFilename()); + final ICSSDocument defaultCSS = cssManager.getDefaultCSS(swcFile); + if (defaultCSS != null) + result.put(defaultCSS, swcFile); + } + } + return result; + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/JSTarget.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/JSTarget.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/JSTarget.java new file mode 100644 index 0000000..adba905 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/targets/JSTarget.java @@ -0,0 +1,231 @@ +/* + * + * 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.targets; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.flex.compiler.driver.js.IJSApplication; +import org.apache.flex.compiler.exceptions.BuildCanceledException; +import org.apache.flex.compiler.internal.codegen.js.JSSharedData; +import org.apache.flex.compiler.internal.driver.js.JSApplication; +import org.apache.flex.compiler.internal.projects.CompilerProject; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.projects.IASProject; +import org.apache.flex.compiler.targets.IJSTarget; +import org.apache.flex.compiler.targets.ITargetProgressMonitor; +import org.apache.flex.compiler.targets.ITargetReport; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class JSTarget extends Target implements IJSTarget +{ + protected ICompilationUnit mainCU; + protected RootedCompilationUnits rootedCompilationUnits; + + /** + * Initialize a JS target with the owner project and root compilation units. + * + * @param project the owner project + */ + public JSTarget(IASProject project, ITargetSettings targetSettings, + ITargetProgressMonitor progressMonitor) + { + super((CompilerProject) project, targetSettings, progressMonitor); + } + + @Override + public TargetType getTargetType() + { + // can't do anything, TargetType is only swf|swc + return null; + } + + @Override + protected ITargetReport computeTargetReport() throws InterruptedException + { + // TODO Should return a new TargetReport relating to the js app? + return null; + } + + @Override + protected RootedCompilationUnits computeRootedCompilationUnits() + throws InterruptedException + { + if (mainCU != null) + { + return new Target.RootedCompilationUnits(ImmutableSet.of(mainCU), + Collections.<ICompilerProblem> emptyList()); + } + return new Target.RootedCompilationUnits( + Collections.<ICompilationUnit> emptySet(), + Collections.<ICompilerProblem> emptyList()); + } + + @Override + public RootedCompilationUnits getRootedCompilationUnits() + throws InterruptedException + { + if (rootedCompilationUnits == null) + rootedCompilationUnits = computeRootedCompilationUnits(); + return rootedCompilationUnits; + } + + @Override + public IJSApplication build(Collection<ICompilerProblem> problems) + { + buildStarted(); + try + { + Iterable<ICompilerProblem> fatalProblems = getFatalProblems(); + if (!Iterables.isEmpty(fatalProblems)) + { + Iterables.addAll(problems, fatalProblems); + return null; + } + + Set<ICompilationUnit> compilationUnitSet = new HashSet<ICompilationUnit>(); + Target.RootedCompilationUnits rootedCompilationUnits = getRootedCompilationUnits(); + Iterables.addAll(problems, rootedCompilationUnits.getProblems()); + + compilationUnitSet.addAll(rootedCompilationUnits.getUnits()); + + buildAndCollectProblems(compilationUnitSet, problems); + + List<ICompilationUnit> reachableCompilationUnits = project + .getReachableCompilationUnitsInSWFOrder(rootedCompilationUnits + .getUnits()); + + IJSApplication application = initializeApplication(reachableCompilationUnits); + + // ISWF swf = initializeSWF(reachableCompilationUnits); + // + // // make main frame for DoABC tags + // final SWFFrame mainFrame = new SWFFrame(); + // swf.addFrame(mainFrame); + // + // // Add definitions. + // for (final ICompilationUnit cu : compilationUnitSet) + // { + // // ignore externals + // if (isLinkageExternal(cu, targetSettings)) + // continue; + // + // // ignore any resource bundles + // if (cu instanceof ResourceBundleCompilationUnit) + // continue; + // + // // Create a DoABC tag per compilation unit. + // + // // Please add this API to SWFTarget. Thx. + // // protected Boolean addToFrame(ICompilationUnit cu, SWFFrame mainFrame) throws InterruptedException + // // final boolean tagsAdded = cu.getSWFTagsRequest().get().addToFrame(mainFrame); + // final boolean tagsAdded = addToFrame(cu, mainFrame); + // if (!tagsAdded) + // { + // ICompilerProblem problem = new UnableToBuildSWFTagProblem(cu.getAbsoluteFilename()); + // problems.add(problem); + // } + // } + // + // createLinkReport(problems); + + return application; + } + catch (BuildCanceledException bce) + { + return null; + } + catch (InterruptedException ie) + { + return null; + } + finally + { + buildFinished(); + } + } + + protected IJSApplication initializeApplication( + List<ICompilationUnit> reachableCompilationUnits) + { + JSApplication result = new JSApplication(); + // TODO set properties of the application + return result; + } + + protected void buildAndCollectProblems( + final Set<ICompilationUnit> compilationUnits, + final Collection<ICompilerProblem> problems) + throws InterruptedException + { + final JSSharedData sharedData = JSSharedData.instance; + sharedData.beginCodeGen(); + + BuiltCompilationUnitSet builtCompilationUnits = getBuiltCompilationUnitSet(); + + // if (JSSharedData.OUTPUT_ISOLATED) + // { + final ICompilationUnit rootCU = getRootClassCompilationUnit(); + compilationUnits.clear(); + compilationUnits.add(rootCU); + + // i added + Iterables.addAll(problems, builtCompilationUnits.problems); + // } + // else + // { + // final List<ICompilationUnit> allUnits = new ArrayList<ICompilationUnit>(); + // allUnits.addAll(project + // .getReachableCompilationUnitsInSWFOrder(builtCompilationUnits.compilationUnits)); + // final List<ICompilationUnit> cuList = sortCompilationUnits(allUnits); + // compilationUnits.clear(); + // for (ICompilationUnit cu : cuList) + // compilationUnits.add(cu); + // } + sharedData.endCodeGen(); + } + + private ICompilationUnit getRootClassCompilationUnit() + { + String rootClassFileName = targetSettings.getRootSourceFileName(); + if (rootClassFileName == null) + return null; + + Collection<ICompilationUnit> rootClassCompilationUnits = project + .getCompilationUnits(rootClassFileName); + assert rootClassCompilationUnits.size() == 1 : "There must only be a single compilation unit for the root source file!"; + return Iterables.getOnlyElement(rootClassCompilationUnits); + } + + public IJSApplication build(ICompilationUnit unit, + Collection<ICompilerProblem> problems) + { + mainCU = unit; + return build(problems); + } + +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeHandler.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeHandler.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeHandler.java new file mode 100644 index 0000000..168c0dd --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeHandler.java @@ -0,0 +1,87 @@ +/* + * + * 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.visitor.as; + +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.visitor.IASNodeStrategy; + +/** + * A concrete implementation of the {@link IASNodeStrategy} that allows a + * subclass to either implement the {@link IASNode} handling directly or pass a + * child {@link IASNodeStrategy} that this class will delegate it's + * {@link #handle(IASNode)} method to. + * + * @author Michael Schmalle + * + * @see BeforeAfterStrategy + */ +public class ASNodeHandler implements IASNodeStrategy +{ + private IASNodeStrategy handler; + + /** + * Returns the {@link IASNodeStrategy} currently being used to handle + * {@link IASNode} AST. + * + * @return The current strategy. + */ + public IASNodeStrategy getHandler() + { + return handler; + } + + /** + * Sets the {@link IASNode} handler strategy. + * + * @param handler The {@link IASNodeStrategy} to handle the specific + * {@link IASNode}. + */ + public void setHandler(IASNodeStrategy handler) + { + this.handler = handler; + } + + /** + * Constructor, used when this handler directly implements + * {@link #handle(IASNode)} and does not composite a child + * {@link IASNodeStrategy}. + */ + public ASNodeHandler() + { + } + + /** + * Constructor, creates a node strategy that composites a child + * {@link IASNodeStrategy} implemented in the {@link #handle(IASNode)} + * method. + * + * @param handler The {@link IASNode} handler to be used in this strategy. + */ + public ASNodeHandler(IASNodeStrategy handler) + { + this.handler = handler; + } + + @Override + public void handle(IASNode node) + { + handler.handle(node); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeSwitch.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeSwitch.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeSwitch.java new file mode 100644 index 0000000..d925b6d --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/ASNodeSwitch.java @@ -0,0 +1,386 @@ +/* + * + * 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.visitor.as; + +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorAsNode; +import org.apache.flex.compiler.internal.tree.as.BinaryOperatorIsNode; +import org.apache.flex.compiler.internal.tree.as.ConfigConditionBlockNode; +import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode; +import org.apache.flex.compiler.internal.tree.as.NamespaceAccessExpressionNode; +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.IBlockNode; +import org.apache.flex.compiler.tree.as.ICatchNode; +import org.apache.flex.compiler.tree.as.IClassNode; +import org.apache.flex.compiler.tree.as.IContainerNode; +import org.apache.flex.compiler.tree.as.IDefaultXMLNamespaceNode; +import org.apache.flex.compiler.tree.as.IDynamicAccessNode; +import org.apache.flex.compiler.tree.as.IEmbedNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IFileNode; +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.IFunctionObjectNode; +import org.apache.flex.compiler.tree.as.IGetterNode; +import org.apache.flex.compiler.tree.as.IIdentifierNode; +import org.apache.flex.compiler.tree.as.IIfNode; +import org.apache.flex.compiler.tree.as.IImportNode; +import org.apache.flex.compiler.tree.as.IInterfaceNode; +import org.apache.flex.compiler.tree.as.IIterationFlowNode; +import org.apache.flex.compiler.tree.as.IKeywordNode; +import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode; +import org.apache.flex.compiler.tree.as.ILiteralNode; +import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode; +import org.apache.flex.compiler.tree.as.INamespaceAccessExpressionNode; +import org.apache.flex.compiler.tree.as.INamespaceNode; +import org.apache.flex.compiler.tree.as.INumericLiteralNode; +import org.apache.flex.compiler.tree.as.IObjectLiteralValuePairNode; +import org.apache.flex.compiler.tree.as.IPackageNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.IReturnNode; +import org.apache.flex.compiler.tree.as.ISetterNode; +import org.apache.flex.compiler.tree.as.ISwitchNode; +import org.apache.flex.compiler.tree.as.ITerminalNode; +import org.apache.flex.compiler.tree.as.ITernaryOperatorNode; +import org.apache.flex.compiler.tree.as.IThrowNode; +import org.apache.flex.compiler.tree.as.ITryNode; +import org.apache.flex.compiler.tree.as.ITypedExpressionNode; +import org.apache.flex.compiler.tree.as.IUnaryOperatorNode; +import org.apache.flex.compiler.tree.as.IUseNamespaceNode; +import org.apache.flex.compiler.tree.as.IVariableExpressionNode; +import org.apache.flex.compiler.tree.as.IVariableNode; +import org.apache.flex.compiler.tree.as.IWhileLoopNode; +import org.apache.flex.compiler.tree.as.IWithNode; +import org.apache.flex.compiler.tree.metadata.IMetaTagNode; +import org.apache.flex.compiler.tree.metadata.IMetaTagsNode; +import org.apache.flex.compiler.visitor.IASNodeStrategy; +import org.apache.flex.compiler.visitor.IBlockVisitor; +import org.apache.flex.compiler.visitor.as.IASBlockVisitor; + +/** + * The {@link ASNodeSwitch} class is an {@link IASNodeStrategy} implementation + * that handles {@link IASNode} types based on the node interface type. + * <p> + * All traversable {@link ASTNodeID} node visitor methods are found within the + * class {@link #handle(IASNode)} method's if else statements. + * + * @author Michael Schmalle + */ +public class ASNodeSwitch implements IASNodeStrategy +{ + private IASBlockVisitor visitor; + + /** + * Creates a new node switch using the {@link #visitor} to handle the + * {@link IASNode} in the current traverse. + * + * @param visitor The {@link IASBlockVisitor} strategy that will visit an + * {@link IASNode} based on it's type. + */ + public ASNodeSwitch(IBlockVisitor visitor) + { + this.visitor = (IASBlockVisitor) visitor; + } + + @Override + public void handle(IASNode node) + { + // ToDo (erikdebruin): add VF2JS conditional -> only use check during full SDK compilation + if (node == null) + return; + + // TODO (mschmalle) Still working on the switch, its complication in the expressions + switch (node.getNodeID()) + { + case ContainerID: + visitor.visitContainer((IContainerNode) node); + return; + + case ConfigBlockID: + ConfigConditionBlockNode condcomp = (ConfigConditionBlockNode)node; + if (condcomp.getChildCount() > 0) // will be 0 if conditional compile variable is false + visitor.visitBlock((IBlockNode) node); + return; + + case E4XFilterID: + visitor.visitE4XFilter((IMemberAccessExpressionNode) node); + return; + + case FileID: + visitor.visitFile((IFileNode) node); + return; + + case PackageID: + visitor.visitPackage((IPackageNode) node); + return; + + case ClassID: + visitor.visitClass((IClassNode) node); + return; + + case InterfaceID: + visitor.visitInterface((IInterfaceNode) node); + return; + + case GetterID: + visitor.visitGetter((IGetterNode) node); + return; + + case SetterID: + visitor.visitSetter((ISetterNode) node); + return; + + case FunctionID: + visitor.visitFunction((IFunctionNode) node); + return; + + case ArgumentID: + case ArgumentRestID: + visitor.visitParameter((IParameterNode) node); + return; + + case VariableID: + case BindableVariableID: + visitor.visitVariable((IVariableNode) node); + return; + + case NamespaceID: + visitor.visitNamespace((INamespaceNode) node); + return; + + case CatchID: + visitor.visitCatch((ICatchNode) node); + return; + + case ForEachLoopID: + case ForLoopID: + visitor.visitForLoop((IForLoopNode) node); + return; + + case FinallyID: + case DefaultID: + case ElseID: + case TerminalID: + visitor.visitTerminal((ITerminalNode) node); + return; + + case TryID: + visitor.visitTry((ITryNode) node); + return; + + case WithID: + visitor.visitWith((IWithNode) node); + return; + + case IfStatementID: + visitor.visitIf((IIfNode) node); + return; + + case SwitchID: + visitor.visitSwitch((ISwitchNode) node); + return; + + case WhileLoopID: + case DoWhileLoopID: + visitor.visitWhileLoop((IWhileLoopNode) node); + return; + + case FunctionCallID: + visitor.visitFunctionCall((IFunctionCallNode) node); + return; + + case TypedExpressionID: + visitor.visitTypedExpression((ITypedExpressionNode) node); + return; + + case IdentifierID: + case NamespaceIdentifierID: + case NonResolvingIdentifierID: + if (node instanceof ILanguageIdentifierNode) + { + visitor.visitLanguageIdentifierNode((ILanguageIdentifierNode) node); + return; + } + visitor.visitIdentifier((IIdentifierNode) node); + return; + + //case LiteralIntegerZeroID: + case LiteralIntegerID: + //case LiteralIntegerZeroID: + case LiteralUintID: + visitor.visitNumericLiteral((INumericLiteralNode) node); + return; + + // case LiteralArrayID: + // case LiteralBooleanID: + // case LiteralNullID: + // case LiteralNumberID: + // case LiteralObjectID: + // case LiteralRegexID: + // case LiteralStringID: + // case LiteralVoidID: + // case LiteralXMLID: + // case LiteralID: + // visitor.visitLiteral((ILiteralNode) node); + // return; + + // case MemberAccessExpressionID: + // visitor.visitMemberAccessExpression((IMemberAccessExpressionNode) node); + // return; + + case ArrayIndexExpressionID: + visitor.visitDynamicAccess((IDynamicAccessNode) node); + return; + + // case NamespaceAccessExpressionID: + // visitor.visitNamespaceAccessExpression((NamespaceAccessExpressionNode) node); + // return; + + // case TODO: + // visitor.visitBinaryOperator((IBinaryOperatorNode) node); + // break; + // + // case TODO: + // visitor.visitUnaryOperator((IUnaryOperatorNode) node); + // break; + + case ReturnStatementID: + visitor.visitReturn((IReturnNode) node); + return; + + case ThrowsStatementID: + visitor.visitThrow((IThrowNode) node); + return; + + case TernaryExpressionID: + visitor.visitTernaryOperator((ITernaryOperatorNode) node); + return; + + case BlockID: + visitor.visitBlock((IBlockNode) node); + return; + + case LabledStatementID: + visitor.visitLabeledStatement((LabeledStatementNode) node); + return; + + case BreakID: + case ContinueID: + case GotoID: + visitor.visitIterationFlow((IIterationFlowNode) node); + return; + + // case ObjectLiteralValuePairID: + // visitor.visitObjectLiteralValuePair((IObjectLiteralValuePairNode) node); + // return; + + case SuperID: + case VoidID: + // XXX this should be removed + visitor.visitLanguageIdentifierNode((ILanguageIdentifierNode) node); + return; + + case DefaultXMLStatementID: + visitor.visitDefaultXMLNamespace((IDefaultXMLNamespaceNode) node); + return; + + // case TODO: + // visitor.visitKeyword((IKeywordNode) node); + // break; + case VariableExpressionID: + visitor.visitVariableExpression((IVariableExpressionNode) node); + return; + case FunctionObjectID: + case AnonymousFunctionID: + visitor.visitFunctionObject((IFunctionObjectNode) node); + return; + + default: + break; + } + + // IExpressionNode + if (node instanceof IUseNamespaceNode) + { + visitor.visitUseNamespace((IUseNamespaceNode) node); + } + else if (node instanceof IEmbedNode) + { + visitor.visitEmbed((IEmbedNode) node); + } + else if (node instanceof IObjectLiteralValuePairNode) + { + visitor.visitObjectLiteralValuePair((IObjectLiteralValuePairNode) node); + } + else if (node instanceof NamespaceAccessExpressionNode) + { + visitor.visitNamespaceAccessExpression((INamespaceAccessExpressionNode) node); + } + else if (node instanceof IMemberAccessExpressionNode) + { + visitor.visitMemberAccessExpression((IMemberAccessExpressionNode) node); + } + else if (node instanceof IBinaryOperatorNode) + { + if (node instanceof BinaryOperatorAsNode) + visitor.visitAsOperator((IBinaryOperatorNode) node); + else if (node instanceof BinaryOperatorIsNode) + visitor.visitIsOperator((IBinaryOperatorNode) node); + else + visitor.visitBinaryOperator((IBinaryOperatorNode) node); + } + // IUnaryOperatorNode > IOperator + else if (node instanceof IUnaryOperatorNode) + { + visitor.visitUnaryOperator((IUnaryOperatorNode) node); + } + else if (node instanceof IKeywordNode) + { + visitor.visitKeyword((IKeywordNode) node); + } + else if (node instanceof IMetaTagsNode) + { + visitor.visitMetaTags((IMetaTagsNode) node); + } + else if (node instanceof IMetaTagNode) + { + visitor.visitMetaTag((IMetaTagNode) node); + } + else if (node instanceof IImportNode) + { + visitor.visitImport((IImportNode) node); + } + else if (node instanceof ILiteralNode) + { + visitor.visitLiteral((ILiteralNode) node); + } + else if (node instanceof IExpressionNode) + { + visitor.visitExpression((IExpressionNode) node); + } + else + { + throw new RuntimeException("handle() not found " + + node.getClass().getName()); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/BeforeAfterStrategy.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/BeforeAfterStrategy.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/BeforeAfterStrategy.java new file mode 100644 index 0000000..5b5bf95 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/visitor/as/BeforeAfterStrategy.java @@ -0,0 +1,141 @@ +/* + * + * 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.visitor.as; + +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IBlockNode; +import org.apache.flex.compiler.visitor.IASNodeStrategy; + +/** + * The {@link BeforeAfterStrategy} implements a before and after {@link IASNode} + * handler. + * <p> + * When {@link #handle(IASNode)} is called on an instance of this class, the + * default {@link #handle(IASNode)} method will first call the + * {@link #getBefore()} handle() method , the will call the supers handle() + * implementation which is to call the {@link #getHandler()} handle() method. + * Finally, the {@link #getAfter()} handler's handle() method will be called. + * <p> + * Currently, this strategy is used for indenting and {@link IBlockNode} pre and + * post symbol management. + * + * @author Michael Schmalle + */ +public class BeforeAfterStrategy extends ASNodeHandler +{ + private IASNodeStrategy before; + + /** + * Returns the {@link IASNodeStrategy} called before the + * {@link #getHandler()}'s handle() method. + * + * @return The before handler. + */ + public IASNodeStrategy getBefore() + { + return before; + } + + /** + * Sets the before handler. + * + * @param before The before handler. + */ + public void setBefore(IASNodeStrategy value) + { + this.before = value; + } + + private IASNodeStrategy after; + + /** + * Returns the {@link IASNodeStrategy} called after the + * {@link #getHandler()}'s handle() method. + * + * @return The after handler. + */ + public IASNodeStrategy getAfter() + { + return after; + } + + /** + * Sets the after handler. + * + * @param after The after handler. + */ + public void setAfter(IASNodeStrategy value) + { + this.after = value; + } + + /** + * Constructor, creates a strategy that implements a before and after + * {@link IASNodeStrategy}. + * + * @param handler The handler that will be called between the before and + * after {@link #handle(IASNode)} method. + * @param before The before handler. + * @param after The after handler. + */ + public BeforeAfterStrategy(IASNodeStrategy handler, IASNodeStrategy before, + IASNodeStrategy after) + { + super(handler); + this.before = before; + this.after = after; + } + + @Override + public void handle(IASNode node) + { + before(node); + super.handle(node); + after(node); + } + + /** + * Called before the {@link #handle(IASNode)} method. + * <p> + * If the {@link #getAfter()} strategy is <code>null</code>, this method + * does nothing. + * + * @param node The current {@link IASNode} being handled by the strategy. + */ + protected void after(IASNode node) + { + if (after != null) + after.handle(node); + } + + /** + * Called after the {@link #handle(IASNode)} method. + * <p> + * If the {@link #getBefore()} strategy is <code>null</code>, this method + * does nothing. + * + * @param node The current {@link IASNode} being handled by the strategy. + */ + protected void before(IASNode node) + { + if (before != null) + before.handle(node); + } +}