This is an automated email from the ASF dual-hosted git repository. gregdove pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
commit b2b85131d9c994dfb45e69edd3e9c8cd227cc074 Author: greg-dove <[email protected]> AuthorDate: Mon Dec 6 15:15:45 2021 +1300 Fixes #199 --- .../royale/compiler/codegen/js/IJSEmitter.java | 4 + .../compiler/internal/codegen/js/JSEmitter.java | 12 ++ .../internal/codegen/js/jx/CatchEmitter.java | 4 + .../internal/codegen/js/jx/TryEmitter.java | 237 ++++++++++++++++++++- .../codegen/js/royale/JSRoyaleEmitter.java | 8 + .../royale/compiler/utils/DefinitionUtils.java | 15 ++ .../codegen/js/goog/TestGoogStatements.java | 6 +- .../codegen/js/royale/TestRoyaleStatements.java | 6 +- .../js/sourcemaps/TestSourceMapStatements.java | 36 ++-- 9 files changed, 302 insertions(+), 26 deletions(-) diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java index c20261c..99af8d7 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java @@ -24,6 +24,8 @@ import java.io.Writer; import org.apache.royale.compiler.codegen.as.IASEmitter; import org.apache.royale.compiler.definitions.IDefinition; import org.apache.royale.compiler.internal.codegen.js.JSSessionModel; +import org.apache.royale.compiler.internal.tree.as.BinaryOperatorNodeBase; +import org.apache.royale.compiler.internal.tree.as.ExpressionNodeBase; import org.apache.royale.compiler.tree.as.IASNode; import org.apache.royale.compiler.tree.as.IExpressionNode; import org.apache.royale.compiler.tree.as.ITypeNode; @@ -49,4 +51,6 @@ public interface IJSEmitter extends IASEmitter, IMappingEmitter void emitClosureEnd(IASNode node, IDefinition nodeDef); void emitAssignmentCoercion(IExpressionNode assignedNode, IDefinition definition); + + BinaryOperatorNodeBase getGeneratedTypeCheck(ExpressionNodeBase leftOperand, ExpressionNodeBase rightOperand); } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java index 292746c..6ba481c 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java @@ -68,6 +68,7 @@ import org.apache.royale.compiler.internal.codegen.js.jx.WhileLoopEmitter; import org.apache.royale.compiler.internal.codegen.js.jx.WithEmitter; import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter; import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens; +import org.apache.royale.compiler.internal.definitions.ParameterDefinition; import org.apache.royale.compiler.internal.projects.RoyaleJSProject; import org.apache.royale.compiler.internal.semantics.SemanticUtils; import org.apache.royale.compiler.internal.tree.as.*; @@ -103,6 +104,7 @@ import org.apache.royale.compiler.tree.as.IWithNode; import com.google.debugging.sourcemap.FilePosition; import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.royale.compiler.utils.DefinitionUtils; import org.apache.royale.compiler.utils.NativeUtils; /** @@ -767,6 +769,10 @@ public class JSEmitter extends ASEmitter implements IJSEmitter getModel().needLanguage = true; return; } + //special case for 'rewritten' multicatch support - we avoid coercion because it is assured via an injected 'is' check immediately prior to declaration/assignment + if (DefinitionUtils.isRewrittenMultiCatchParam(assignedDef)) { + avoidCoercion = true; + } if (coercionStart == null && !avoidCoercion && assignedTypeDef !=null @@ -930,4 +936,10 @@ public class JSEmitter extends ASEmitter implements IJSEmitter } } + public BinaryOperatorNodeBase getGeneratedTypeCheck(ExpressionNodeBase leftOperand, ExpressionNodeBase rightOperand) { + //default to using 'instanceof' for compiler-generated type-checks, because it is native JS + BinaryOperatorInstanceOfNode check = new BinaryOperatorInstanceOfNode(null,leftOperand, rightOperand); + return check; + } + } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/CatchEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/CatchEmitter.java index 12cb8bc..f9ed090 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/CatchEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/CatchEmitter.java @@ -47,6 +47,10 @@ public class CatchEmitter extends JSSubEmitter implements startMapping(node, paramNode); writeToken(ASEmitterTokens.PAREN_CLOSE); endMapping(node); + if (TryEmitter.ROYALE_MULTI_CATCH_ERROR_NAME.equals(paramNode.getName())) { + //it is probably already obvious, but let's be explicit: + write("/* implicit multi-catch wrapper */ "); + } getWalker().walk(node.getStatementContentsNode()); } } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/TryEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/TryEmitter.java index 943ba73..39cdfb5 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/TryEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/TryEmitter.java @@ -21,10 +21,21 @@ package org.apache.royale.compiler.internal.codegen.js.jx; import org.apache.royale.compiler.codegen.ISubEmitter; import org.apache.royale.compiler.codegen.js.IJSEmitter; +import org.apache.royale.compiler.constants.IASLanguageConstants; import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter; -import org.apache.royale.compiler.tree.as.ITerminalNode; -import org.apache.royale.compiler.tree.as.ITryNode; +import org.apache.royale.compiler.internal.parsing.as.ASToken; +import org.apache.royale.compiler.internal.parsing.as.ASTokenTypes; +import org.apache.royale.compiler.internal.scopes.ASScope; +import org.apache.royale.compiler.internal.scopes.CatchScope; +import org.apache.royale.compiler.internal.semantics.PostProcessStep; +import org.apache.royale.compiler.internal.tree.as.*; +import org.apache.royale.compiler.problems.ICompilerProblem; +import org.apache.royale.compiler.scopes.IASScope; +import org.apache.royale.compiler.tree.as.*; + +import java.util.Collection; +import java.util.EnumSet; public class TryEmitter extends JSSubEmitter implements ISubEmitter<ITryNode> @@ -41,10 +52,14 @@ public class TryEmitter extends JSSubEmitter implements writeToken(ASEmitterTokens.TRY); endMapping(node); getWalker().walk(node.getStatementContentsNode()); - for (int i = 0; i < node.getCatchNodeCount(); i++) - { - getWalker().walk(node.getCatchNode(i)); + if (node.getCatchNodeCount() >= 1) { + if (node.getCatchNodeCount() == 1) { + getWalker().walk(node.getCatchNode(0)); + } else { + getWalker().walk(codeGenMultipleCatchSupport(node)); + } } + ITerminalNode fnode = node.getFinallyNode(); if (fnode != null) { @@ -55,4 +70,216 @@ public class TryEmitter extends JSSubEmitter implements getWalker().walk(fnode); } } + + + //Everything below here is specific to Multi-Catch support + //-------------------------------------------------------- + public static final String ROYALE_MULTI_CATCH_ERROR_NAME = "$$royaleMultiCatchErr"; + + private final EnumSet<PostProcessStep> postProcess = EnumSet.of( + PostProcessStep.POPULATE_SCOPE); + + /** + * Create a new implementation of the multiple catch sequence to support the typed nature of the original + * implementation in the untyped JS runtime. Multiple catches of type catch (e:ErrorType) are expressed as + * if (caughtErr is ErrorType) { var e:ErrorType = caughtErr; ... original catch contents } else... other catch clauses else... throw caughtError + * @param node The original Try node to generate JS multi-catch support for + * @return a new Catch node that has the internally generated alternate implementation for multi-catch + */ + private ICatchNode codeGenMultipleCatchSupport(ITryNode node) { + int catchCount = node.getCatchNodeCount(); + boolean hasCatchAll = false; + IdentifierNode royaleErr = new IdentifierNode(ROYALE_MULTI_CATCH_ERROR_NAME); + IdentifierNode ErrorClassIdentifier = new IdentifierNode("Error"); + ParameterNode argumentNode = new ParameterNode(royaleErr, ErrorClassIdentifier); + argumentNode.addChild(royaleErr); + argumentNode.addChild(royaleErr); + CatchNode wrapper = new CatchNode(argumentNode); + wrapper.setParent((NodeBase) node); + argumentNode.setParent(wrapper); + BlockNode wrapperBlock = wrapper.getContentsNode(); + wrapperBlock.setContainerType(IContainerNode.ContainerType.BRACES); + wrapperBlock.setParent(wrapper); + wrapper.setSourcePath(node.getSourcePath()); + wrapper.setLine(node.getEndLine()); + wrapper.setEndLine(node.getEndLine()); + wrapper.setColumn(node.getEndColumn()+1); + wrapper.setEndColumn(node.getEndColumn()+1); + IfNode ifNode = new IfNode(null); + + for (int i = 0; i < catchCount; i++) + { + BaseStatementNode rewrittenCatch; + ICatchNode childCatch = node.getCatchNode(i); + int childChildren = childCatch.getStatementContentsNode().getChildCount(); + ParameterNode catchParam = (ParameterNode)childCatch.getCatchParameterNode(); + + if (catchParam.getTypeNode().resolve(getProject()).equals(getProject().getBuiltinType(IASLanguageConstants.BuiltinType.ANY_TYPE))) { + hasCatchAll = true; + //if we are at first catch node when we encounter this, just short-circuit and return it, 'nothing else matters' + if (i == 0) { + return childCatch; + } + } + + if (hasCatchAll) { + TerminalNode terminalNode = createTerminalCatchAllNode(catchParam, royaleErr, (CatchNode) childCatch); + ifNode.addBranch(terminalNode); + rewrittenCatch = terminalNode; + + } else { + ConditionalNode conditionalNode = createConditionalNode(catchParam, royaleErr, (CatchNode) childCatch); + ifNode.addBranch(conditionalNode); + + conditionalNode.setSourceLocation(childCatch); + rewrittenCatch = conditionalNode; + } + + for (int j = 0; j < childChildren; j++) { + rewrittenCatch.getContentsNode().addChild((NodeBase) childCatch.getStatementContentsNode().getChild(j)); + } + if (hasCatchAll) { + //no point continuing, any following catch clauses will never execute, 'nothing else matters' + break; + } + } + if (!hasCatchAll) { //then we need to re-throw the original top-level error, as an 'uncaught' error + TerminalNode terminalNode = createTerminalThrowNode(royaleErr); + ifNode.addBranch(terminalNode); + } + wrapperBlock.addChild(ifNode); + wrapper.runPostProcess(postProcess,((NodeBase) node).getASScope()); + return wrapper; + } + + private void addVarStartToRewrittenCatch(ParameterNode parameterNode, IdentifierNode assignedValue, BaseStatementNode parentNode, PseudoCatchBlock content, CatchNode originalCatch) { + content.setParent(parentNode); + content.setContainerType(IContainerNode.ContainerType.BRACES); + content.setSourceLocation(originalCatch.getContentsNode()); + IdentifierNode name = new IdentifierNode(parameterNode.getName()); + name.setSourceLocation(parameterNode.getNameExpressionNode()); + ExpressionNodeBase type = parameterNode.getTypeNode().copyForInitializer(originalCatch); + + VariableNode varNode = new VariableNode(name,type); + varNode.setAssignedValue(null, assignedValue); + + content.addChild(varNode); + } + + private ConditionalNode createConditionalNode(ParameterNode parameterNode,IdentifierNode hoistedError, CatchNode originalCatch) { + // [else] if (hoistedError is parameterNodeClass) { + // var parameterNodeName = $$royaleMultiCatchErr; + // (followed by)...original catch clause contents + // } + PseudoCatchParam conditionalNode = new PseudoCatchParam((CatchScope) originalCatch.getScope()); + BinaryOperatorNodeBase check = getEmitter().getGeneratedTypeCheck(hoistedError, parameterNode.getTypeNode()); + check.setSourceLocation(parameterNode); + conditionalNode.setConditionalExpression(check); + check.setParent(conditionalNode); + + addVarStartToRewrittenCatch(parameterNode, hoistedError, conditionalNode, (PseudoCatchBlock)conditionalNode.getContentsNode(), originalCatch ); + + return conditionalNode; + } + + + private TerminalNode createTerminalThrowNode(IdentifierNode hoistedError) { + // else { throw hoistedError; } + TerminalNode terminalNode = new TerminalNode(getElseToken()); + //throw hoistedError (from ROYALE_MULTI_CATCH_ERROR_NAME) + ThrowNode throwNode = new ThrowNode(null); + //clone the Identifier to avoid issues with parenting chains + IdentifierNode localCopy = new IdentifierNode(hoistedError.getName()); + localCopy.setSourceLocation(hoistedError); + throwNode.setStatementExpression(localCopy); + BlockNode contents = terminalNode.getContentsNode(); + contents.setContainerType(IContainerNode.ContainerType.BRACES); + contents.setParent(terminalNode); + contents.addChild(throwNode); + return terminalNode; + } + + private TerminalNode createTerminalCatchAllNode(ParameterNode parameterNode,IdentifierNode hoistedError, CatchNode originalCatch) { + // else { + // var parameterNodeName = $$royaleMultiCatchErr; + // (followed by)...original catch clause contents + // } + PseudoCatchAllParam terminalNode = new PseudoCatchAllParam((CatchScope) originalCatch.getScope()); + + addVarStartToRewrittenCatch(parameterNode, hoistedError, terminalNode, (PseudoCatchBlock)terminalNode.getContentsNode(), originalCatch ); + + terminalNode.setSourceLocation(originalCatch); + return terminalNode; + } + + static ASToken getElseToken(){ + return new ASToken(ASTokenTypes.TOKEN_KEYWORD_ELSE, -1,-1, -1, -1, "else"); + } +} + + +/** + * The following mainly exists because the original catch scope allows for multiple 'same name' catch parameter definitions + * that would otherwise clash if they were hoisted to the containing scope. + * This serves to simulate the same thing for the rewritten catch parameter definitions. + */ +class PseudoCatchBlock extends BlockNode implements IScopedNode { + + protected ASScope scope; + + public PseudoCatchBlock(CatchScope catchScope){ + super(); + scope = catchScope; + + } + + public ASScope getASScope(){ + return scope; + } + + @Override + public IASScope getScope(){ + return scope; + } + + @Override + protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems) + { + if (set.contains(PostProcessStep.POPULATE_SCOPE) || + set.contains(PostProcessStep.RECONNECT_DEFINITIONS)) + { + if (this.scope == null) { + this.scope = new CatchScope(scope); + } + this.scope.setContainingScope(scope); + } + + super.analyze(set, this.scope, problems); + } + + @Override + public void getAllImports(Collection<String> imports) + { + getContainingScope().getAllImports(imports); + } + + @Override + public void getAllImportNodes(Collection<IImportNode> imports) + { + getContainingScope().getAllImportNodes(imports); + } +} + +class PseudoCatchParam extends ConditionalNode{ + public PseudoCatchParam(CatchScope scope){ + super(null); + this.contentsNode = new PseudoCatchBlock(scope); + } +} + +class PseudoCatchAllParam extends TerminalNode{ + public PseudoCatchAllParam(CatchScope scope){ + super(TryEmitter.getElseToken()); + this.contentsNode = new PseudoCatchBlock(scope); + } } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java index 6cfd566..10bc04b 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java @@ -1649,4 +1649,12 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter } } + @Override + public BinaryOperatorNodeBase getGeneratedTypeCheck(ExpressionNodeBase leftOperand, ExpressionNodeBase rightOperand) { + //using 'is' in this case for compiler-generated type-checks, because it is more robust with the framework support + BinaryOperatorIsNode check = new BinaryOperatorIsNode(null,leftOperand, rightOperand); + getModel().needLanguage = true; + return check; + } + } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java index 7da8710..dfb52bd 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java @@ -22,6 +22,9 @@ package org.apache.royale.compiler.utils; import org.apache.royale.compiler.definitions.IClassDefinition; import org.apache.royale.compiler.definitions.IDefinition; import org.apache.royale.compiler.definitions.IInterfaceDefinition; +import org.apache.royale.compiler.internal.codegen.js.jx.TryEmitter; +import org.apache.royale.compiler.internal.definitions.ParameterDefinition; +import org.apache.royale.compiler.internal.scopes.CatchScope; import org.apache.royale.compiler.projects.ICompilerProject; import org.apache.royale.compiler.tree.as.IDocumentableDefinitionNode; @@ -61,5 +64,17 @@ public class DefinitionUtils return ret; } + /** + * Utility method for checking if an assigned definition represents the rewritten part of a + * multi-catch sequence - currently needed to avoid implicit coercions. + * This check ultimately relies on the TryEmitter.ROYALE_MULTI_CATCH_ERROR_NAME naming scheme. + */ + public static final boolean isRewrittenMultiCatchParam(IDefinition definition) { + return (definition instanceof ParameterDefinition && + definition.getContainingScope() instanceof CatchScope && + definition.getBaseName().equals(TryEmitter.ROYALE_MULTI_CATCH_ERROR_NAME) + ); + } + } diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java index b768192..94a11c3 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java @@ -29,6 +29,7 @@ import org.apache.royale.compiler.tree.as.IIfNode; import org.apache.royale.compiler.tree.as.ISwitchNode; import org.apache.royale.compiler.tree.as.ITryNode; import org.apache.royale.compiler.tree.as.IVariableNode; +import org.junit.Ignore; import org.junit.Test; /** @@ -230,12 +231,11 @@ public class TestGoogStatements extends TestStatements @Test public void testVisitTry_Catch_Catch_Finally() { - // TODO (erikdebruin) handle multiple 'catch' statements (FW in Wiki) ITryNode node = (ITryNode) getNode( - "try { a; } catch (e:Error) { b; } catch (f:Error) { c; } finally { d; }", + "try { a; } catch (e:ReferenceError) { b; } catch (f:Error) { c; } finally { d; }", ITryNode.class); asBlockWalker.visitTry(node); - assertOut("try {\n\ta;\n} catch (e) {\n\tb;\n} catch (f) {\n\tc;\n} finally {\n\td;\n}"); + assertOut("try {\n\ta;\n} catch ($$royaleMultiCatchErr) /* implicit multi-catch wrapper */ {\n\tif ($$royaleMultiCatchErr instanceof ReferenceError) {\n\t\tvar /** @type {ReferenceError} */ e = $$royaleMultiCatchErr;\n\t\tb;\n\t} else if ($$royaleMultiCatchErr instanceof Error) {\n\t\tvar /** @type {Error} */ f = $$royaleMultiCatchErr;\n\t\tc;\n\t} else {\n\t\tthrow $$royaleMultiCatchErr;\n\t}\n} finally {\n\td;\n}"); } @Override diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java index 8684665..46d66de 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java @@ -37,6 +37,7 @@ import org.apache.royale.compiler.tree.as.ITryNode; import org.apache.royale.compiler.tree.as.IVariableNode; import org.apache.royale.compiler.tree.as.IWhileLoopNode; import org.apache.royale.compiler.tree.as.IWithNode; +import org.junit.Ignore; import org.junit.Test; /** @@ -435,12 +436,11 @@ public class TestRoyaleStatements extends TestGoogStatements @Test public void testVisitTry_Catch_Catch_Finally() { - // TODO (erikdebruin) handle multiple 'catch' statements (FW in Wiki) ITryNode node = (ITryNode) getNode( - "try { a; } catch (e:Error) { b; } catch (f:Error) { c; } finally { d; }", + "try { a; } catch (e:ReferenceError) { b; } catch (f:Error) { c; } finally { d; }", ITryNode.class); asBlockWalker.visitTry(node); - assertOut("try {\n a;\n} catch (e) {\n b;\n} catch (f) {\n c;\n} finally {\n d;\n}"); + assertOut("try {\n a;\n} catch ($$royaleMultiCatchErr) /* implicit multi-catch wrapper */ {\n if (org.apache.royale.utils.Language.is($$royaleMultiCatchErr, ReferenceError)) {\n var /** @type {ReferenceError} */ e = $$royaleMultiCatchErr;\n b;\n } else if (org.apache.royale.utils.Language.is($$royaleMultiCatchErr, Error)) {\n var /** @type {Error} */ f = $$royaleMultiCatchErr;\n c;\n } else {\n throw $$royaleMultiCatchErr;\n }\n} finally {\n d;\n}"); } @Override diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java index 0e306d1..8d3b492 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java @@ -28,6 +28,10 @@ import org.apache.royale.compiler.tree.as.ITryNode; import org.apache.royale.compiler.tree.as.IVariableNode; import org.apache.royale.compiler.tree.as.IWithNode; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +import org.junit.Ignore; import org.junit.Test; public class TestSourceMapStatements extends SourceMapTestBase @@ -344,26 +348,28 @@ public class TestSourceMapStatements extends SourceMapTestBase public void testVisitTry_Catch_Catch_Finally() { ITryNode node = (ITryNode) getNode( - "try { a; } catch (e:Error) { b; } catch (f:Error) { c; } finally { d; }", + "try { a; } catch (e:ReferenceError) { b; } catch (f:Error) { c; } finally { d; }", ITryNode.class); asBlockWalker.visitTry(node); - //try {\n a;\n} catch (e) {\n b;\n} catch (f) {\n c;\n} finally {\n d;\n} + //try {\n a;\n} catch ($$royaleMultiCatchErr) /* implicit multi-catch wrapper */ {\n if (org.apache.royale.utils.Language.is($$royaleMultiCatchErr, ReferenceError)) {\n var /** @type {ReferenceError} */ e = $$royaleMultiCatchErr;\n b;\n } else if (org.apache.royale.utils.Language.is($$royaleMultiCatchErr, Error)) {\n var /** @type {Error} */ f = $$royaleMultiCatchErr;\n c;\n } else {\n throw $$royaleMultiCatchErr;\n }\n} finally {\n d;\n} assertMapping(node, 0, 0, 0, 0, 0, 4); // try assertMapping(node, 0, 4, 0, 4, 0, 5); // { assertMapping(node, 0, 9, 2, 0, 2, 1); // } - assertMapping(node, 0, 11, 2, 1, 2, 9); // catch( - assertMapping(node, 0, 18, 2, 9, 2, 10); // e - assertMapping(node, 0, 25, 2, 10, 2, 12); // ) - assertMapping(node, 0, 27, 2, 12, 2, 13); // { - assertMapping(node, 0, 32, 4, 0, 4, 1); // } - assertMapping(node, 0, 34, 4, 1, 4, 9); // catch( - assertMapping(node, 0, 41, 4, 9, 4, 10); // f - assertMapping(node, 0, 48, 4, 10, 4, 12); // ) - assertMapping(node, 0, 50, 4, 12, 4, 13); // { - assertMapping(node, 0, 55, 6, 0, 6, 1); // } - assertMapping(node, 0, 57, 6, 1, 6, 10); // finally - assertMapping(node, 0, 65, 6, 10, 6, 11); // { - assertMapping(node, 0, 70, 8, 0, 8, 1); // } + assertMapping(node, 0, 11, 3, 2, 3, 6); // catch( --> if ( + assertMapping(node, 0, 18, 4, 38, 4, 39); // e + assertMapping(node, 0, 20, 3, 65, 3, 79); // ReferenceError + assertMapping(node, 0, 34, 3, 80, 3, 82); // ) + assertMapping(node, 0, 36, 3, 82, 3, 83); // { + assertMapping(node, 0, 41, 6, 2, 6, 3); // } + assertMapping(node, 0, 43, 6, 4, 6, 13); // catch( --> else if ( + assertMapping(node, 0, 50, 7, 29, 7, 30); // f + assertMapping(node, 0, 52, 6, 72, 6, 77); // Error + assertMapping(node, 0, 57, 6, 78, 6, 80); // ) + assertMapping(node, 0, 59, 6, 80, 6, 81); // { + assertMapping(node, 0, 64, 9, 2, 9, 3); // } + assertMapping(node, 0, 66, 12, 1, 12, 10); // finally + assertMapping(node, 0, 74, 12, 10, 12, 11);// { + assertMapping(node, 0, 79, 14, 0, 14, 1); // } } @Test
