Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1717c086853c
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fce94b535c0b
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Dec 15, 2016

  1. Copy the full SHA
    f791368 View commit details
  2. Add a spec for rescue clauses that combine a splatted list of excepti…

    …ons with a literal list of exceptions.
    nirvdrum committed Dec 15, 2016
    Copy the full SHA
    fce94b5 View commit details
Showing with 77 additions and 34 deletions.
  1. +22 −0 spec/ruby/language/rescue_spec.rb
  2. +55 −34 truffle/src/main/java/org/jruby/truffle/parser/BodyTranslator.java
22 changes: 22 additions & 0 deletions spec/ruby/language/rescue_spec.rb
Original file line number Diff line number Diff line change
@@ -63,6 +63,28 @@ class ArbitraryException < StandardError
end
end

it "can combine a splatted list of exceptions with a literal list of exceptions" do
caught_it = false
begin
raise SpecificExampleException, "not important"
rescue ArbitraryException, *exception_list
caught_it = true
end
caught_it.should be_true
caught = []
[lambda{raise ArbitraryException}, lambda{raise SpecificExampleException}].each do |block|
begin
block.call
rescue ArbitraryException, *exception_list
caught << $!
end
end
caught.size.should == 2
exception_list.each do |exception_class|
caught.map{|e| e.class}.should include(exception_class)
end
end

it "will only rescue the specified exceptions when doing a splat rescue" do
lambda do
begin
89 changes: 55 additions & 34 deletions truffle/src/main/java/org/jruby/truffle/parser/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -2961,42 +2961,29 @@ public RubyNode visitRescueNode(RescueParseNode node) {
} else {
while (rescueBody != null) {
if (rescueBody.getExceptionNodes() != null) {
if (rescueBody.getExceptionNodes() instanceof ArrayParseNode) {
final ParseNode[] exceptionNodes = ((ArrayParseNode) rescueBody.getExceptionNodes()).children();

final RubyNode[] handlingClasses = new RubyNode[exceptionNodes.length];

for (int n = 0; n < handlingClasses.length; n++) {
handlingClasses[n] = exceptionNodes[n].accept(this);
}

RubyNode translatedBody;

if (rescueBody.getBodyNode() == null || rescueBody.getBodyNode().getPosition() == InvalidSourcePosition.INSTANCE) {
translatedBody = nilNode(source, sourceSection);
final Deque<ParseNode> exceptionNodes = new ArrayDeque<>();
exceptionNodes.push(rescueBody.getExceptionNodes());

while (! exceptionNodes.isEmpty()) {
final ParseNode exceptionNode = exceptionNodes.pop();

if (exceptionNode instanceof ArrayParseNode) {
final RescueNode rescueNode = translateRescueArrayParseNode((ArrayParseNode) exceptionNode, rescueBody, sourceSection, fullSourceSection);
rescueNodes.add(rescueNode);
} else if (exceptionNode instanceof SplatParseNode) {
final RescueNode rescueNode = translateRescueSplatParseNode((SplatParseNode) exceptionNode, rescueBody, sourceSection, fullSourceSection);
rescueNodes.add(rescueNode);
} else if (exceptionNode instanceof ArgsCatParseNode) {
final ArgsCatParseNode argsCat = (ArgsCatParseNode) exceptionNode;
exceptionNodes.push(new SplatParseNode(argsCat.getSecondNode().getPosition(), argsCat.getSecondNode()));
exceptionNodes.push(argsCat.getFirstNode());
} else if (exceptionNode instanceof ArgsPushParseNode) {
final ArgsPushParseNode argsPush = (ArgsPushParseNode) exceptionNode;
exceptionNodes.push(new ArrayParseNode(argsPush.getSecondNode().getPosition(), argsPush.getSecondNode()));
exceptionNodes.push(argsPush.getFirstNode());
} else {
translatedBody = rescueBody.getBodyNode().accept(this);
throw new UnsupportedOperationException();
}

final RescueClassesNode rescueNode = new RescueClassesNode(context, fullSourceSection, handlingClasses, translatedBody);
rescueNodes.add(rescueNode);
} else if (rescueBody.getExceptionNodes() instanceof SplatParseNode) {
final SplatParseNode splat = (SplatParseNode) rescueBody.getExceptionNodes();

final RubyNode splatTranslated = translateNodeOrNil(sourceSection, splat.getValue());

RubyNode bodyTranslated;

if (rescueBody.getBodyNode() == null || rescueBody.getBodyNode().getPosition() == InvalidSourcePosition.INSTANCE) {
bodyTranslated = nilNode(source, sourceSection);
} else {
bodyTranslated = rescueBody.getBodyNode().accept(this);
}

final RescueSplatNode rescueNode = new RescueSplatNode(context, fullSourceSection, splatTranslated, bodyTranslated);
rescueNodes.add(rescueNode);
} else {
throw new UnsupportedOperationException();
}
} else {
RubyNode bodyNode;
@@ -3030,6 +3017,40 @@ public RubyNode visitRescueNode(RescueParseNode node) {
return addNewlineIfNeeded(node, ret);
}

private RescueNode translateRescueArrayParseNode(ArrayParseNode arrayParse, RescueBodyParseNode rescueBody, RubySourceSection sourceSection, SourceSection fullSourceSection) {
final ParseNode[] exceptionNodes = arrayParse.children();

final RubyNode[] handlingClasses = new RubyNode[exceptionNodes.length];

for (int n = 0; n < handlingClasses.length; n++) {
handlingClasses[n] = exceptionNodes[n].accept(this);
}

RubyNode translatedBody;

if (rescueBody.getBodyNode() == null || rescueBody.getBodyNode().getPosition() == InvalidSourcePosition.INSTANCE) {
translatedBody = nilNode(source, sourceSection);
} else {
translatedBody = rescueBody.getBodyNode().accept(this);
}

return new RescueClassesNode(context, fullSourceSection, handlingClasses, translatedBody);
}

private RescueNode translateRescueSplatParseNode(SplatParseNode splat, RescueBodyParseNode rescueBody, RubySourceSection sourceSection, SourceSection fullSourceSection) {
final RubyNode splatTranslated = translateNodeOrNil(sourceSection, splat.getValue());

RubyNode bodyTranslated;

if (rescueBody.getBodyNode() == null || rescueBody.getBodyNode().getPosition() == InvalidSourcePosition.INSTANCE) {
bodyTranslated = nilNode(source, sourceSection);
} else {
bodyTranslated = rescueBody.getBodyNode().accept(this);
}

return new RescueSplatNode(context, fullSourceSection, splatTranslated, bodyTranslated);
}

@Override
public RubyNode visitRetryNode(RetryParseNode node) {
final RubyNode ret = new RetryNode();