Initial start on source maps
Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/c9751606 Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/c9751606 Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/c9751606 Branch: refs/heads/develop Commit: c9751606fe2e589407b6d708159631537bacb764 Parents: f053f21 Author: Josh Tynjala <[email protected]> Authored: Wed Mar 23 15:50:07 2016 -0700 Committer: Josh Tynjala <[email protected]> Committed: Wed Mar 23 15:50:07 2016 -0700 ---------------------------------------------------------------------- .../apache/flex/compiler/clients/MXMLJSC.java | 43 +++- .../compiler/codegen/ISourceMapEmitter.java | 30 +++ .../flex/compiler/codegen/js/IJSEmitter.java | 20 ++ .../flex/compiler/codegen/js/IJSWriter.java | 10 + .../flex/compiler/driver/js/IJSBackend.java | 29 +++ .../compiler/internal/codegen/as/ASEmitter.java | 24 +++ .../compiler/internal/codegen/as/ASWriter.java | 3 +- .../compiler/internal/codegen/js/JSEmitter.java | 208 +++++++++++++++++++ .../internal/codegen/js/JSSourceMapEmitter.java | 67 ++++++ .../compiler/internal/codegen/js/JSWriter.java | 93 ++++++++- .../codegen/js/flexjs/JSFlexJSEmitter.java | 26 +-- .../internal/codegen/js/jx/FieldEmitter.java | 6 +- .../codegen/js/jx/FunctionCallEmitter.java | 12 ++ .../codegen/js/jx/IdentifierEmitter.java | 2 + .../internal/codegen/js/jx/LiteralEmitter.java | 2 + .../codegen/js/jx/MemberAccessEmitter.java | 9 +- .../internal/codegen/js/jx/MethodEmitter.java | 15 +- .../codegen/js/jx/PackageFooterEmitter.java | 1 + .../codegen/js/jx/VarDeclarationEmitter.java | 6 + .../compiler/internal/driver/js/JSBackend.java | 12 +- 20 files changed, 570 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/clients/MXMLJSC.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/clients/MXMLJSC.java b/compiler.jx/src/org/apache/flex/compiler/clients/MXMLJSC.java index b534f59..98cd4d2 100644 --- a/compiler.jx/src/org/apache/flex/compiler/clients/MXMLJSC.java +++ b/compiler.jx/src/org/apache/flex/compiler/clients/MXMLJSC.java @@ -37,6 +37,7 @@ import org.apache.flex.compiler.clients.problems.ProblemQueryProvider; import org.apache.flex.compiler.clients.problems.WorkspaceProblemFormatter; import org.apache.flex.compiler.codegen.as.IASWriter; import org.apache.flex.compiler.codegen.js.IJSPublisher; +import org.apache.flex.compiler.codegen.js.IJSWriter; import org.apache.flex.compiler.config.Configuration; import org.apache.flex.compiler.config.ConfigurationBuffer; import org.apache.flex.compiler.config.Configurator; @@ -448,21 +449,29 @@ public class MXMLJSC implements JSCompilerEntryPoint, ProblemQueryProvider, ICompilationUnit unit = cu; - IASWriter writer; + IJSWriter writer; if (cuType == ICompilationUnit.UnitType.AS_UNIT) { - writer = JSSharedData.backend.createWriter(project, + writer = (IJSWriter) JSSharedData.backend.createWriter(project, errors, unit, false); } else { - writer = JSSharedData.backend.createMXMLWriter( + writer = (IJSWriter) JSSharedData.backend.createMXMLWriter( project, errors, unit, false); } BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(outputClassFile)); - writer.writeTo(out); + + File outputSourceMapFile = null; + if (project.config.getSourceMap()) + { + outputSourceMapFile = getOutputSourceMapFile( + cu.getQualifiedNames().get(0), outputFolder); + } + + writer.writeTo(out, outputSourceMapFile); out.flush(); out.close(); writer.close(); @@ -596,6 +605,32 @@ public class MXMLJSC implements JSCompilerEntryPoint, ProblemQueryProvider, } /** + * @param qname + * @param outputFolder + * @return output source map file path + */ + private File getOutputSourceMapFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + JSSharedData.OUTPUT_EXTENSION + ".map"); + } + + /** * Mxmlc uses target file as the main compilation unit and derive the output * SWF file name from this file. * http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/codegen/ISourceMapEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/codegen/ISourceMapEmitter.java b/compiler.jx/src/org/apache/flex/compiler/codegen/ISourceMapEmitter.java new file mode 100644 index 0000000..3fef28e --- /dev/null +++ b/compiler.jx/src/org/apache/flex/compiler/codegen/ISourceMapEmitter.java @@ -0,0 +1,30 @@ +/* + * + * 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.codegen; + +/** + * Base interface for source map emitters. + * + * @author Josh Tynjala + */ +public interface ISourceMapEmitter +{ + String emitSourceMap(String sourceFilePath, String sourceMapPath, String sourceRoot); +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSEmitter.java b/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSEmitter.java index 4972b39..f660fc3 100644 --- a/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSEmitter.java @@ -20,10 +20,15 @@ package org.apache.flex.compiler.codegen.js; import java.io.Writer; +import java.util.List; +import com.google.debugging.sourcemap.FilePosition; +import com.google.debugging.sourcemap.SourceMapGenerator; import org.apache.flex.compiler.codegen.as.IASEmitter; +import org.apache.flex.compiler.common.ISourceLocation; import org.apache.flex.compiler.internal.codegen.js.JSSessionModel; import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.ITypeNode; import org.apache.flex.compiler.visitor.IASNodeStrategy; /** @@ -35,9 +40,24 @@ import org.apache.flex.compiler.visitor.IASNodeStrategy; public interface IJSEmitter extends IASEmitter { JSSessionModel getModel(); + List<SourceMapMapping> getSourceMapMappings(); String formatQualifiedName(String name); + void startMapping(ISourceLocation node); + void endMapping(ISourceLocation node); + + void emitSourceMapDirective(ITypeNode node); + void emitClosureStart(); void emitClosureEnd(IASNode node); + + class SourceMapMapping + { + public String sourcePath; + public String name; + public FilePosition sourceStartPosition; + public FilePosition destStartPosition; + public FilePosition destEndPosition; + } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSWriter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSWriter.java b/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSWriter.java index 2e711fa..aae8011 100644 --- a/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSWriter.java +++ b/compiler.jx/src/org/apache/flex/compiler/codegen/js/IJSWriter.java @@ -19,6 +19,9 @@ package org.apache.flex.compiler.codegen.js; +import java.io.File; +import java.io.OutputStream; + import org.apache.flex.compiler.codegen.as.IASWriter; /** @@ -29,5 +32,12 @@ import org.apache.flex.compiler.codegen.as.IASWriter; */ public interface IJSWriter extends IASWriter { + /** + * Write JS file and source map. + * + * @param jsOut JS output stream + * @param sourceMapOut Source map file + */ + void writeTo(OutputStream jsOut, File sourceMapOut); } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/driver/js/IJSBackend.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/driver/js/IJSBackend.java b/compiler.jx/src/org/apache/flex/compiler/driver/js/IJSBackend.java new file mode 100644 index 0000000..eb0f4e2 --- /dev/null +++ b/compiler.jx/src/org/apache/flex/compiler/driver/js/IJSBackend.java @@ -0,0 +1,29 @@ +/* + * + * 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.driver.js; + +import org.apache.flex.compiler.codegen.ISourceMapEmitter; +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.driver.IBackend; + +public interface IJSBackend extends IBackend +{ + ISourceMapEmitter createSourceMapEmitter(IJSEmitter emitter); +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASEmitter.java index 107e809..14ae6c5 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASEmitter.java @@ -182,6 +182,20 @@ public class ASEmitter implements IASEmitter, IEmitter public void setDocEmitter(IDocEmitter value) { } + + private int currentLine = 0; + + protected int getCurrentLine() + { + return currentLine; + } + + private int currentColumn = 0; + + protected int getCurrentColumn() + { + return currentColumn; + } public ASEmitter(FilterWriter out) { @@ -206,6 +220,16 @@ public class ASEmitter implements IASEmitter, IEmitter { try { + int newLineCount = value.length() - value.replace("\n", "").length(); + currentLine += newLineCount; + if (newLineCount > 0) + { + currentColumn = value.length() - value.lastIndexOf("\n") - 1; + } + else + { + currentColumn += value.length(); + } if (!bufferWrite) out.write(value); else http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASWriter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASWriter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASWriter.java index 32e1671..9d127e4 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASWriter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/as/ASWriter.java @@ -26,6 +26,7 @@ import java.io.OutputStream; import java.util.List; import org.apache.flex.compiler.codegen.as.IASEmitter; +import org.apache.flex.compiler.codegen.as.IASWriter; import org.apache.flex.compiler.codegen.js.IJSWriter; import org.apache.flex.compiler.internal.codegen.js.JSSharedData; import org.apache.flex.compiler.problems.ICompilerProblem; @@ -33,7 +34,7 @@ import org.apache.flex.compiler.projects.IASProject; import org.apache.flex.compiler.units.ICompilationUnit; import org.apache.flex.compiler.visitor.as.IASBlockWalker; -public class ASWriter implements IJSWriter +public class ASWriter implements IASWriter { private IASProject project; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java index c5d3e2b..e903094 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSEmitter.java @@ -20,14 +20,34 @@ package org.apache.flex.compiler.internal.codegen.js; import java.io.FilterWriter; +import java.util.ArrayList; +import java.util.List; +import com.google.debugging.sourcemap.FilePosition; +import org.apache.flex.compiler.clients.JSConfiguration; import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.common.ASModifier; +import org.apache.flex.compiler.common.ISourceLocation; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; import org.apache.flex.compiler.internal.codegen.as.ASEmitter; import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.utils.EmitterUtils; +import org.apache.flex.compiler.internal.projects.FlexJSProject; import org.apache.flex.compiler.internal.tree.as.FunctionNode; +import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IDefinitionNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; import org.apache.flex.compiler.tree.as.IFunctionNode; import org.apache.flex.compiler.tree.as.IFunctionObjectNode; +import org.apache.flex.compiler.tree.as.IKeywordNode; +import org.apache.flex.compiler.tree.as.INumericLiteralNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.IReturnNode; +import org.apache.flex.compiler.tree.as.ITypeNode; +import org.apache.flex.compiler.tree.as.IVariableNode; +import org.apache.flex.compiler.visitor.IBlockWalker; /** * @author Michael Schmalle @@ -41,12 +61,22 @@ public class JSEmitter extends ASEmitter implements IJSEmitter { return model; } + + private SourceMapMapping lastMapping; + + private List<SourceMapMapping> sourceMapMappings; + + public List<SourceMapMapping> getSourceMapMappings() + { + return sourceMapMappings; + } public JSEmitter(FilterWriter out) { super(out); model = new JSSessionModel(); + sourceMapMappings = new ArrayList<SourceMapMapping>(); } @Override @@ -58,10 +88,12 @@ public class JSEmitter extends ASEmitter implements IJSEmitter @Override public void emitLocalNamedFunction(IFunctionNode node) { + startMapping(node); FunctionNode fnode = (FunctionNode)node; write(ASEmitterTokens.FUNCTION); write(ASEmitterTokens.SPACE); write(fnode.getName()); + endMapping(node); emitParameters(fnode.getParameterNodes()); emitFunctionScope(fnode.getScopedNode()); } @@ -69,8 +101,10 @@ public class JSEmitter extends ASEmitter implements IJSEmitter @Override public void emitFunctionObject(IFunctionObjectNode node) { + startMapping(node); FunctionNode fnode = node.getFunctionNode(); write(ASEmitterTokens.FUNCTION); + endMapping(node); emitParameters(fnode.getParameterNodes()); emitFunctionScope(fnode.getScopedNode()); } @@ -84,5 +118,179 @@ public class JSEmitter extends ASEmitter implements IJSEmitter { } + + public void emitSourceMapDirective(ITypeNode node) + { + boolean sourceMap = false; + + IBlockWalker walker = getWalker(); + FlexJSProject project = (FlexJSProject) walker.getProject(); + if (project != null) + { + JSConfiguration config = project.config; + if (config != null) + { + sourceMap = config.getSourceMap(); + } + } + + if (sourceMap) + { + writeNewline(); + write("//# sourceMappingURL=./" + node.getName() + ".js.map"); + } + } + + public void emitParameters(IParameterNode[] nodes) + { + write(ASEmitterTokens.PAREN_OPEN); + int len = nodes.length; + for (int i = 0; i < len; i++) + { + IParameterNode node = nodes[i]; + getWalker().walk(node); //emitParameter + if (i < len - 1) + { + writeToken(ASEmitterTokens.COMMA); + } + } + write(ASEmitterTokens.PAREN_CLOSE); + } + + @Override + public void emitParameter(IParameterNode node) + { + startMapping(node); + super.emitParameter(node); + endMapping(node); + } + + @Override + public void emitNumericLiteral(INumericLiteralNode node) + { + startMapping((ISourceLocation) node); + super.emitNumericLiteral(node); + endMapping((ISourceLocation) node); + } + + @Override + public void emitReturn(IReturnNode node) + { + startMapping(node); + write(ASEmitterTokens.RETURN); + endMapping(node); + IExpressionNode rnode = node.getReturnValueNode(); + if (rnode != null && rnode.getNodeID() != ASTNodeID.NilID) + { + write(ASEmitterTokens.SPACE); + getWalker().walk(rnode); + } + } + + @Override + public void emitMemberKeyword(IDefinitionNode node) + { + IKeywordNode keywordNode = null; + for(int i = 0; i < node.getChildCount(); i++) + { + IASNode childNode = node.getChild(i); + if (childNode instanceof IKeywordNode) + { + keywordNode = (IKeywordNode) childNode; + break; + } + } + if (keywordNode != null) + { + startMapping(keywordNode); + } + if (node instanceof IFunctionNode) + { + writeToken(ASEmitterTokens.FUNCTION); + } + else if (node instanceof IVariableNode) + { + writeToken(ASEmitterTokens.VAR); + } + if (keywordNode != null) + { + endMapping(keywordNode); + } + } + + public void startMapping(ISourceLocation node) + { + if (lastMapping != null) + { + FilePosition sourceStartPosition = lastMapping.sourceStartPosition; + throw new IllegalStateException("Cannot start new mapping when another mapping is already started. " + + "Previous mapping at Line " + sourceStartPosition.getLine() + + " and Column " + sourceStartPosition.getColumn() + + " in file " + lastMapping.sourcePath); + } + + String sourcePath = node.getSourcePath(); + if (sourcePath == null) + { + //if the source path is null, this node may have been generated by + //the compiler automatically. for example, an untyped variable will + //have a node for the * type. + if (node instanceof IASNode) + { + IASNode parentNode = ((IASNode) node).getParent(); + if (parentNode != null) + { + //try the parent node + startMapping(parentNode); + } + } + return; + } + + String nodeName = null; + if (node instanceof IDefinitionNode) + { + IDefinitionNode definitionNode = (IDefinitionNode) node; + nodeName = definitionNode.getQualifiedName(); + + ITypeDefinition typeDef = EmitterUtils.getTypeDefinition(definitionNode); + if (typeDef != null) + { + boolean isConstructor = node instanceof IFunctionNode && + ((IFunctionNode) node).isConstructor(); + boolean isStatic = definitionNode.hasModifier(ASModifier.STATIC); + if (isConstructor) + { + nodeName = typeDef.getQualifiedName() + ".constructor"; + } + else if (isStatic) + { + nodeName = typeDef.getQualifiedName() + "." + nodeName; + } + else + { + nodeName = typeDef.getQualifiedName() + ".prototype." + nodeName; + } + } + } + SourceMapMapping mapping = new SourceMapMapping(); + mapping.sourcePath = sourcePath; + mapping.name = nodeName; + mapping.sourceStartPosition = new FilePosition(node.getLine(), node.getColumn()); + mapping.destStartPosition = new FilePosition(getCurrentLine(), getCurrentColumn()); + lastMapping = mapping; + } + + public void endMapping(ISourceLocation node) + { + if (lastMapping == null) + { + throw new IllegalStateException("Cannot end mapping when a mapping has not been started"); + } + + lastMapping.destEndPosition = new FilePosition(getCurrentLine(), getCurrentColumn()); + sourceMapMappings.add(lastMapping); + lastMapping = null; + } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSSourceMapEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSSourceMapEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSSourceMapEmitter.java new file mode 100644 index 0000000..bcdeed5 --- /dev/null +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSSourceMapEmitter.java @@ -0,0 +1,67 @@ +/* + * + * 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; + +import java.io.IOException; +import java.util.List; + +import org.apache.flex.compiler.codegen.ISourceMapEmitter; +import org.apache.flex.compiler.codegen.js.IJSEmitter; + +import com.google.debugging.sourcemap.SourceMapGeneratorV3; + +public class JSSourceMapEmitter implements ISourceMapEmitter +{ + private IJSEmitter emitter; + private SourceMapGeneratorV3 sourceMapGenerator; + + public JSSourceMapEmitter(IJSEmitter emitter) + { + this.emitter = emitter; + sourceMapGenerator = new SourceMapGeneratorV3(); + } + + public String emitSourceMap(String fileName, String sourceMapPath, String sourceRoot) + { + List<IJSEmitter.SourceMapMapping> mappings = this.emitter.getSourceMapMappings(); + for (IJSEmitter.SourceMapMapping mapping : mappings) + { + sourceMapGenerator.addMapping(mapping.sourcePath, mapping.name, + mapping.sourceStartPosition, + mapping.destStartPosition, mapping.destEndPosition); + } + if (sourceRoot != null) + { + sourceMapGenerator.setSourceRoot(sourceRoot); + } + + StringBuilder builder = new StringBuilder(); + try + { + sourceMapGenerator.appendTo(builder, fileName); + } + catch (IOException e) + { + e.printStackTrace(); + } + + return builder.toString(); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSWriter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSWriter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSWriter.java index 16a4d4d..0e60a93 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSWriter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/JSWriter.java @@ -19,14 +19,19 @@ package org.apache.flex.compiler.internal.codegen.js; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; +import java.util.Stack; -import org.apache.flex.compiler.codegen.as.IASEmitter; +import org.apache.flex.compiler.codegen.ISourceMapEmitter; +import org.apache.flex.compiler.codegen.js.IJSEmitter; import org.apache.flex.compiler.codegen.js.IJSWriter; +import org.apache.flex.compiler.driver.js.IJSBackend; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.projects.IASProject; import org.apache.flex.compiler.units.ICompilationUnit; @@ -67,28 +72,96 @@ public class JSWriter implements IJSWriter @Override public void writeTo(OutputStream out) { - JSFilterWriter writer = (JSFilterWriter) JSSharedData.backend - .createWriterBuffer(project); - IASEmitter emitter = JSSharedData.backend.createEmitter(writer); - IASBlockWalker walker = JSSharedData.backend.createWalker(project, + writeTo(out, null); + } + + @Override + public int writeTo(File out) throws FileNotFoundException, IOException + { + return 0; + } + + public void writeTo(OutputStream jsOut, File sourceMapOut) + { + IJSBackend backend = (IJSBackend) JSSharedData.backend; + JSFilterWriter writer = (JSFilterWriter) backend.createWriterBuffer(project); + IJSEmitter emitter = (IJSEmitter) backend.createEmitter(writer); + IASBlockWalker walker = backend.createWalker(project, problems, emitter); walker.visitCompilationUnit(compilationUnit); try { - out.write(emitter.postProcess(writer.toString()).getBytes()); + jsOut.write(emitter.postProcess(writer.toString()).getBytes()); } catch (IOException e) { e.printStackTrace(); } - } - @Override - public int writeTo(File out) throws FileNotFoundException, IOException + if (sourceMapOut != null) + { + convertMappingSourcePathsToRelative(emitter, sourceMapOut); + + + File compilationUnitFile = new File(compilationUnit.getAbsoluteFilename()); + ISourceMapEmitter sourceMapEmitter = backend.createSourceMapEmitter(emitter); + try + { + String fileName = compilationUnitFile.getName(); + fileName = fileName.replace(".as", ".js"); + String sourceMap = sourceMapEmitter.emitSourceMap(fileName, sourceMapOut.getAbsolutePath(), null); + BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(sourceMapOut)); + outStream.write(sourceMap.getBytes()); + outStream.flush(); + outStream.close(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + } + + private void convertMappingSourcePathsToRelative(IJSEmitter emitter, File relativeToFile) { - return 0; + List<IJSEmitter.SourceMapMapping> mappings = emitter.getSourceMapMappings(); + for (IJSEmitter.SourceMapMapping mapping : mappings) + { + mapping.sourcePath = relativePath(mapping.sourcePath, relativeToFile.getAbsolutePath()); + } } + //if we ever support Java 7, the java.nio.file.Path relativize() method + //should be able to replace this method + private String relativePath(String filePath, String relativeToFilePath) + { + File currentFile = new File(filePath); + Stack<String> stack = new Stack<String>(); + stack.push(currentFile.getName()); + currentFile = currentFile.getParentFile(); + while (currentFile != null) + { + String absoluteCurrentFile = currentFile.getAbsolutePath() + File.separator; + if (relativeToFilePath.startsWith(absoluteCurrentFile)) + { + String relativeRelativeToFile = relativeToFilePath.substring(absoluteCurrentFile.length()); + int separatorCount = relativeRelativeToFile.length() - relativeRelativeToFile.replace(File.separator, "").length(); + String result = ""; + while (separatorCount > 0) + { + result += ".." + File.separator; + separatorCount--; + } + while (stack.size() > 0) + { + result += stack.pop(); + } + return result; + } + stack.push(currentFile.getName() + File.separator); + currentFile = currentFile.getParentFile(); + } + return null; + } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java index c4c72da..a907ea7 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/flexjs/JSFlexJSEmitter.java @@ -81,7 +81,6 @@ 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.IInterfaceNode; -import org.apache.flex.compiler.tree.as.ILiteralContainerNode; import org.apache.flex.compiler.tree.as.ILiteralNode; import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode; import org.apache.flex.compiler.tree.as.INamespaceNode; @@ -137,6 +136,8 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter @Override public String postProcess(String output) { + output = super.postProcess(output); + String[] lines = output.split("\n"); ArrayList<String> finalLines = new ArrayList<String>(); boolean sawRequires = false; @@ -152,7 +153,7 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter String s = line.substring(c + 14, c2 - 1); sawRequires = true; if (!usedNames.contains(s)) - continue; + continue; } else if (sawRequires) stillSearching = false; @@ -239,12 +240,6 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter } @Override - public void emitLiteralContainer(ILiteralContainerNode node) - { - super.emitLiteralContainer(node); - } - - @Override public void emitLocalNamedFunction(IFunctionNode node) { IFunctionNode fnNode = (IFunctionNode)node.getAncestorOfType(IFunctionNode.class); @@ -308,19 +303,6 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter } @Override - public void emitMemberKeyword(IDefinitionNode node) - { - if (node instanceof IFunctionNode) - { - writeToken(ASEmitterTokens.FUNCTION); - } - else if (node instanceof IVariableNode) - { - writeToken(ASEmitterTokens.VAR); - } - } - - @Override public void emitNamespace(INamespaceNode node) { write(formatQualifiedName(node.getName())); @@ -424,7 +406,7 @@ public class JSFlexJSEmitter extends JSGoogEmitter implements IJSFlexJSEmitter getModel().getInternalClasses().put(className, mainClassName + "." + className); } } - + packageHeaderEmitter.emit(definition); } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FieldEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FieldEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FieldEmitter.java index 756d07e..b22c41d 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FieldEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FieldEmitter.java @@ -85,8 +85,10 @@ public class FieldEmitter extends JSSubEmitter implements definition = ndef.getContainingScope().getDefinition(); write(getEmitter().formatQualifiedName(definition.getQualifiedName()) - + ASEmitterTokens.MEMBER_ACCESS.getToken() + root - + node.getName()); + + ASEmitterTokens.MEMBER_ACCESS.getToken() + root); + getEmitter().startMapping(node); + write(node.getName()); + getEmitter().endMapping(node); } if (node.getNodeID() == ASTNodeID.BindableVariableID) http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FunctionCallEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FunctionCallEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FunctionCallEmitter.java index c38d820..a71b4dd 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FunctionCallEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/FunctionCallEmitter.java @@ -71,7 +71,9 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu { if (!(node.getChild(1) instanceof VectorLiteralNode)) { + getEmitter().startMapping(node.getNewKeywordNode()); writeToken(ASEmitterTokens.NEW); + getEmitter().endMapping(node.getNewKeywordNode()); } else { @@ -104,7 +106,11 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu def = node.resolveCalledExpression(getProject()); // all new calls to a class should be fully qualified names if (def instanceof ClassDefinition) + { + getEmitter().startMapping(node); write(getEmitter().formatQualifiedName(def.getQualifiedName())); + getEmitter().endMapping(node); + } else { IExpressionNode nameNode = node.getNameNode(); @@ -119,9 +125,15 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu if (nameNode.hasParenthesis()) write(ASEmitterTokens.PAREN_CLOSE); } + getEmitter().startMapping(node.getArgumentsNode()); write(ASEmitterTokens.PAREN_OPEN); + getEmitter().endMapping(node.getArgumentsNode()); + fjs.walkArguments(node.getArgumentNodes()); + + getEmitter().startMapping(node.getArgumentsNode()); write(ASEmitterTokens.PAREN_CLOSE); + getEmitter().endMapping(node.getArgumentsNode()); } else if (!isClassCast) { http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java index 7d64896..69217c1 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/IdentifierEmitter.java @@ -217,6 +217,7 @@ public class IdentifierEmitter extends JSSubEmitter implements //member access expression, it shouldn't be fully qualified needsFormattedName = parentMemberAccessNode.getLeftOperandNode() == node; } + getEmitter().startMapping(node); if (parentNodeId == ASTNodeID.MemberAccessExpressionID) { if (needsFormattedName) @@ -234,6 +235,7 @@ public class IdentifierEmitter extends JSSubEmitter implements write(getEmitter().formatQualifiedName(qname)); else write(qname); + getEmitter().endMapping(node); } else write(node.getName()); http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java index a4b276c..e3827e6 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/LiteralEmitter.java @@ -122,7 +122,9 @@ public class LiteralEmitter extends JSSubEmitter implements if (!isWritten) { + getEmitter().startMapping(node); write(s); + getEmitter().endMapping(node); } } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java index 305b2e9..5175a79 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MemberAccessEmitter.java @@ -63,12 +63,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements IASNode leftNode = node.getLeftOperandNode(); IASNode rightNode = node.getRightOperandNode(); - - String leftName = ""; - if (leftNode instanceof IdentifierNode) - { - leftName = ((IdentifierNode)leftNode).getName(); - } + JSFlexJSEmitter fjs = (JSFlexJSEmitter)getEmitter(); IDefinition def = node.resolve(getProject()); if (def == null) @@ -314,7 +309,9 @@ public class MemberAccessEmitter extends JSSubEmitter implements } else { + getEmitter().startMapping(leftNode); write(ASEmitterTokens.THIS); + getEmitter().endMapping(leftNode); } return true; } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MethodEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MethodEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MethodEmitter.java index 66210ca..15d9fa7 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MethodEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/MethodEmitter.java @@ -27,6 +27,7 @@ import org.apache.flex.compiler.common.ASModifier; import org.apache.flex.compiler.definitions.IFunctionDefinition; import org.apache.flex.compiler.definitions.ITypeDefinition; import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSEmitter; import org.apache.flex.compiler.internal.codegen.js.JSEmitterTokens; import org.apache.flex.compiler.internal.codegen.js.JSSessionModel; import org.apache.flex.compiler.internal.codegen.js.JSSubEmitter; @@ -80,8 +81,16 @@ public class MethodEmitter extends JSSubEmitter implements } if (qname != null && !qname.equals("")) { + if (isConstructor) + { + getEmitter().startMapping(node); + } write(fjs.formatQualifiedName(qname)); - if (!isConstructor) + if (isConstructor) + { + getEmitter().endMapping(node); + } + else { write(ASEmitterTokens.MEMBER_ACCESS); if (!fn.hasModifier(ASModifier.STATIC)) @@ -92,7 +101,11 @@ public class MethodEmitter extends JSSubEmitter implements } } if (!isConstructor) + { + getEmitter().startMapping(node); fjs.emitMemberName(node); + getEmitter().endMapping(node); + } } write(ASEmitterTokens.SPACE); http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/PackageFooterEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/PackageFooterEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/PackageFooterEmitter.java index fa99a54..eab3413 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/PackageFooterEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/PackageFooterEmitter.java @@ -72,6 +72,7 @@ public class PackageFooterEmitter extends JSSubEmitter implements if (type == null) return; + getEmitter().emitSourceMapDirective(type.getNode()); } public void emitClassInfo(ITypeNode tnode) http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java index 171be76..b945282 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java @@ -56,15 +56,21 @@ public class VarDeclarationEmitter extends JSSubEmitter implements IExpressionNode avnode = node.getAssignedValueNode(); if (avnode != null) { + getEmitter().startMapping(node.getVariableTypeNode()); IDefinition def = avnode.resolveType(getWalker().getProject()); String opcode = avnode.getNodeID().getParaphrase(); if (opcode != "AnonymousFunction") + { fjs.getDocEmitter().emitVarDoc(node, def, getWalker().getProject()); + } + getEmitter().endMapping(node.getVariableTypeNode()); } else { + getEmitter().startMapping(node.getVariableTypeNode()); fjs.getDocEmitter().emitVarDoc(node, null, getWalker().getProject()); + getEmitter().endMapping(node.getVariableTypeNode()); } if (!(node instanceof ChainedVariableNode) && node.isConst()) http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c9751606/compiler.jx/src/org/apache/flex/compiler/internal/driver/js/JSBackend.java ---------------------------------------------------------------------- diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/driver/js/JSBackend.java b/compiler.jx/src/org/apache/flex/compiler/internal/driver/js/JSBackend.java index 20ff965..a8b7737 100644 --- a/compiler.jx/src/org/apache/flex/compiler/internal/driver/js/JSBackend.java +++ b/compiler.jx/src/org/apache/flex/compiler/internal/driver/js/JSBackend.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.flex.compiler.clients.JSConfiguration; import org.apache.flex.compiler.codegen.IDocEmitter; +import org.apache.flex.compiler.codegen.ISourceMapEmitter; import org.apache.flex.compiler.codegen.as.IASEmitter; import org.apache.flex.compiler.codegen.js.IJSEmitter; import org.apache.flex.compiler.codegen.js.IJSWriter; @@ -33,6 +34,7 @@ import org.apache.flex.compiler.config.Configuration; import org.apache.flex.compiler.config.Configurator; import org.apache.flex.compiler.driver.IBackend; import org.apache.flex.compiler.driver.IPublisher; +import org.apache.flex.compiler.driver.js.IJSBackend; import org.apache.flex.compiler.internal.codegen.as.ASAfterNodeStrategy; import org.apache.flex.compiler.internal.codegen.as.ASBeforeNodeStrategy; import org.apache.flex.compiler.internal.codegen.as.ASBlockWalker; @@ -40,6 +42,7 @@ import org.apache.flex.compiler.internal.codegen.js.JSDocEmitter; import org.apache.flex.compiler.internal.codegen.js.JSEmitter; import org.apache.flex.compiler.internal.codegen.js.JSFilterWriter; import org.apache.flex.compiler.internal.codegen.js.JSPublisher; +import org.apache.flex.compiler.internal.codegen.js.JSSourceMapEmitter; import org.apache.flex.compiler.internal.codegen.js.JSWriter; import org.apache.flex.compiler.internal.projects.ISourceFileHandler; import org.apache.flex.compiler.internal.targets.JSTarget; @@ -61,9 +64,8 @@ import org.apache.flex.compiler.visitor.mxml.IMXMLBlockWalker; * * @author Michael Schmalle */ -public class JSBackend implements IBackend +public class JSBackend implements IJSBackend { - @Override public String getOutputExtension() { @@ -137,6 +139,12 @@ public class JSBackend implements IBackend } @Override + public ISourceMapEmitter createSourceMapEmitter(IJSEmitter emitter) + { + return new JSSourceMapEmitter(emitter); + } + + @Override public IDocEmitter createDocEmitter(IASEmitter emitter) { return new JSDocEmitter((IJSEmitter) emitter);
