You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2021/12/06 02:25:25 UTC
[royale-compiler] 01/02: Fixes #199
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 <gr...@gmail.com>
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