Skip to content

Commit 935f11d

Browse files
committed
[GR-18411] Use separate subclasses for SyntaxError and SystemExit to cleanup the code
PullRequest: truffleruby/2124
2 parents d6f5f85 + efa8338 commit 935f11d

17 files changed

+319
-163
lines changed

src/main/java/org/truffleruby/RubyLanguage.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import org.truffleruby.core.exception.RubyFrozenError;
3030
import org.truffleruby.core.exception.RubyNameError;
3131
import org.truffleruby.core.exception.RubyNoMethodError;
32+
import org.truffleruby.core.exception.RubySyntaxError;
3233
import org.truffleruby.core.exception.RubySystemCallError;
34+
import org.truffleruby.core.exception.RubySystemExit;
3335
import org.truffleruby.core.fiber.RubyFiber;
3436
import org.truffleruby.core.hash.RubyHash;
3537
import org.graalvm.options.OptionValues;
@@ -196,7 +198,9 @@ public final class RubyLanguage extends TruffleLanguage<RubyContext> {
196198
public final Shape regexpShape = createShape(RubyRegexp.class);
197199
public final Shape sizedQueueShape = createShape(RubySizedQueue.class);
198200
public final Shape stringShape = createShape(RubyString.class);
201+
public final Shape syntaxErrorShape = createShape(RubySyntaxError.class);
199202
public final Shape systemCallErrorShape = createShape(RubySystemCallError.class);
203+
public final Shape systemExitShape = createShape(RubySystemExit.class);
200204
public final Shape threadBacktraceLocationShape = createShape(RubyBacktraceLocation.class);
201205
public final Shape threadShape = createShape(RubyThread.class);
202206
public final Shape timeShape = createShape(RubyTime.class);

src/main/java/org/truffleruby/builtins/BuiltinsClasses.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@
5454
import org.truffleruby.core.exception.NameErrorNodesFactory;
5555
import org.truffleruby.core.exception.NoMethodErrorNodesBuiltins;
5656
import org.truffleruby.core.exception.NoMethodErrorNodesFactory;
57+
import org.truffleruby.core.exception.SyntaxErrorNodesBuiltins;
58+
import org.truffleruby.core.exception.SyntaxErrorNodesFactory;
5759
import org.truffleruby.core.exception.SystemCallErrorNodesBuiltins;
5860
import org.truffleruby.core.exception.SystemCallErrorNodesFactory;
61+
import org.truffleruby.core.exception.SystemExitNodesBuiltins;
62+
import org.truffleruby.core.exception.SystemExitNodesFactory;
5963
import org.truffleruby.core.fiber.FiberNodesBuiltins;
6064
import org.truffleruby.core.fiber.FiberNodesFactory;
6165
import org.truffleruby.core.hash.HashNodesBuiltins;
@@ -215,7 +219,9 @@ public static void setupBuiltinsLazy(CoreMethodNodeManager coreManager) {
215219
SizedQueueNodesBuiltins.setup(coreManager);
216220
StringNodesBuiltins.setup(coreManager);
217221
SymbolNodesBuiltins.setup(coreManager);
222+
SyntaxErrorNodesBuiltins.setup(coreManager);
218223
SystemCallErrorNodesBuiltins.setup(coreManager);
224+
SystemExitNodesBuiltins.setup(coreManager);
219225
ThreadBacktraceLocationNodesBuiltins.setup(coreManager);
220226
ThreadNodesBuiltins.setup(coreManager);
221227
TimeNodesBuiltins.setup(coreManager);
@@ -291,7 +297,9 @@ public static void setupBuiltinsLazyPrimitives(PrimitiveManager primitiveManager
291297
SizedQueueNodesBuiltins.setupPrimitives(primitiveManager);
292298
StringNodesBuiltins.setupPrimitives(primitiveManager);
293299
SymbolNodesBuiltins.setupPrimitives(primitiveManager);
300+
SyntaxErrorNodesBuiltins.setupPrimitives(primitiveManager);
294301
SystemCallErrorNodesBuiltins.setupPrimitives(primitiveManager);
302+
SystemExitNodesBuiltins.setupPrimitives(primitiveManager);
295303
ThreadBacktraceLocationNodesBuiltins.setupPrimitives(primitiveManager);
296304
ThreadNodesBuiltins.setupPrimitives(primitiveManager);
297305
TimeNodesBuiltins.setupPrimitives(primitiveManager);
@@ -368,7 +376,9 @@ public static List<List<? extends NodeFactory<? extends RubyNode>>> getCoreNodeF
368376
SizedQueueNodesFactory.getFactories(),
369377
StringNodesFactory.getFactories(),
370378
SymbolNodesFactory.getFactories(),
379+
SyntaxErrorNodesFactory.getFactories(),
371380
SystemCallErrorNodesFactory.getFactories(),
381+
SystemExitNodesFactory.getFactories(),
372382
ThreadBacktraceLocationNodesFactory.getFactories(),
373383
ThreadNodesFactory.getFactories(),
374384
TimeNodesFactory.getFactories(),

src/main/java/org/truffleruby/core/CoreLibrary.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ public CoreLibrary(RubyContext context, RubyLanguage language) {
386386
RubyClass scriptErrorClass = defineClass(exceptionClass, "ScriptError");
387387
loadErrorClass = defineClass(scriptErrorClass, "LoadError");
388388
notImplementedErrorClass = defineClass(scriptErrorClass, "NotImplementedError");
389-
syntaxErrorClass = defineClass(scriptErrorClass, "SyntaxError");
389+
syntaxErrorClass = defineClass(scriptErrorClass, "SyntaxError", language.syntaxErrorShape);
390390

391391
// SecurityError
392392
securityErrorClass = defineClass(exceptionClass, "SecurityError");
@@ -396,7 +396,7 @@ public CoreLibrary(RubyContext context, RubyLanguage language) {
396396
defineClass(signalExceptionClass, "Interrupt");
397397

398398
// SystemExit
399-
systemExitClass = defineClass(exceptionClass, "SystemExit");
399+
systemExitClass = defineClass(exceptionClass, "SystemExit", language.systemExitShape);
400400

401401
// SystemStackError
402402
systemStackErrorClass = defineClass(exceptionClass, "SystemStackError");

src/main/java/org/truffleruby/core/exception/CoreExceptions.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -921,17 +921,25 @@ public RubyException zeroDivisionError(Node currentNode, ArithmeticException exc
921921
// SyntaxError
922922

923923
@TruffleBoundary
924-
public RubyException syntaxErrorInvalidRetry(Node currentNode) {
924+
public RubySyntaxError syntaxErrorInvalidRetry(Node currentNode) {
925925
return syntaxError("Invalid retry", currentNode, currentNode.getEncapsulatingSourceSection());
926926
}
927927

928928
@TruffleBoundary
929-
public RubyException syntaxError(String message, Node currentNode, SourceSection sourceLocation) {
929+
public RubySyntaxError syntaxError(String message, Node currentNode, SourceSection sourceLocation) {
930930
RubyClass exceptionClass = context.getCoreLibrary().syntaxErrorClass;
931-
RubyString errorMessage = StringOperations
931+
final RubyString messageString = StringOperations
932932
.createString(context, language, StringOperations.encodeRope(message, UTF8Encoding.INSTANCE));
933-
return ExceptionOperations
934-
.createRubyException(context, exceptionClass, errorMessage, currentNode, sourceLocation, null);
933+
final Backtrace backtrace = context.getCallStack().getBacktrace(currentNode);
934+
final Object cause = ThreadGetExceptionNode.getLastException(context);
935+
showExceptionIfDebug(exceptionClass, messageString, backtrace);
936+
return new RubySyntaxError(
937+
exceptionClass,
938+
language.syntaxErrorShape,
939+
messageString,
940+
backtrace,
941+
cause,
942+
sourceLocation);
935943
}
936944

937945
// FloatDomainError
@@ -1174,14 +1182,20 @@ public RubyException ffiNullPointerError(String message, Node currentNode) {
11741182
// SystemExit
11751183

11761184
@TruffleBoundary
1177-
public RubyException systemExit(int exitStatus, Node currentNode) {
1185+
public RubySystemExit systemExit(int exitStatus, Node currentNode) {
11781186
final RubyString message = StringOperations
11791187
.createString(context, language, StringOperations.encodeRope("exit", UTF8Encoding.INSTANCE));
1180-
RubyClass exceptionClass = context.getCoreLibrary().systemExitClass;
1181-
final RubyException systemExit = ExceptionOperations
1182-
.createRubyException(context, exceptionClass, message, currentNode, null);
1183-
DynamicObjectLibrary.getUncached().put(systemExit, "@status", exitStatus);
1184-
return systemExit;
1188+
final RubyClass exceptionClass = context.getCoreLibrary().systemExitClass;
1189+
final Backtrace backtrace = context.getCallStack().getBacktrace(currentNode);
1190+
final Object cause = ThreadGetExceptionNode.getLastException(context);
1191+
showExceptionIfDebug(exceptionClass, message, backtrace);
1192+
return new RubySystemExit(
1193+
exceptionClass,
1194+
language.systemExitShape,
1195+
message,
1196+
backtrace,
1197+
cause,
1198+
exitStatus);
11851199
}
11861200

11871201
// ClosedQueueError

src/main/java/org/truffleruby/core/exception/ExceptionNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ private void initializeNameErrorCopy(RubyNameError self, RubyNameError from) {
127127
private void initializeExceptionCopy(RubyException self, RubyException from) {
128128
Backtrace backtrace = from.backtrace;
129129
if (backtrace != null) {
130-
self.backtrace = backtrace.copy(getContext(), self);
130+
self.backtrace = backtrace.copy(self);
131131
} else {
132132
self.backtrace = null;
133133
}

src/main/java/org/truffleruby/core/exception/ExceptionOperations.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
2222
import com.oracle.truffle.api.nodes.Node;
2323
import com.oracle.truffle.api.object.Shape;
24-
import com.oracle.truffle.api.source.SourceSection;
2524
import org.truffleruby.language.library.RubyStringLibrary;
2625

2726
public abstract class ExceptionOperations {
@@ -38,7 +37,7 @@ public static String getMessage(Throwable throwable) {
3837
}
3938

4039
@TruffleBoundary
41-
private static String messageFieldToString(RubyContext context, RubyException exception) {
40+
private static String messageFieldToString(RubyException exception) {
4241
Object message = exception.message;
4342
RubyStringLibrary strings = RubyStringLibrary.getUncached();
4443
if (message == null || message == Nil.INSTANCE) {
@@ -63,17 +62,12 @@ public static String messageToString(RubyContext context, RubyException exceptio
6362
} catch (Throwable e) {
6463
// Fall back to the internal message field
6564
}
66-
return messageFieldToString(context, exception);
65+
return messageFieldToString(exception);
6766
}
6867

6968
public static RubyException createRubyException(RubyContext context, RubyClass rubyClass, Object message,
7069
Node node, Throwable javaException) {
71-
return createRubyException(context, rubyClass, message, node, null, javaException);
72-
}
73-
74-
public static RubyException createRubyException(RubyContext context, RubyClass rubyClass, Object message,
75-
Node node, SourceSection sourceLocation, Throwable javaException) {
76-
final Backtrace backtrace = context.getCallStack().getBacktrace(node, sourceLocation, javaException);
70+
final Backtrace backtrace = context.getCallStack().getBacktrace(node, 0, javaException);
7771
return createRubyException(context, rubyClass, message, backtrace);
7872
}
7973

src/main/java/org/truffleruby/core/exception/RubyException.java

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,12 @@
1111

1212
import java.util.Set;
1313

14-
import com.oracle.truffle.api.CompilerDirectives;
15-
import com.oracle.truffle.api.dsl.Cached;
1614
import com.oracle.truffle.api.dsl.CachedContext;
1715
import com.oracle.truffle.api.interop.ExceptionType;
1816
import com.oracle.truffle.api.interop.InteropLibrary;
19-
import com.oracle.truffle.api.interop.UnsupportedMessageException;
20-
import com.oracle.truffle.api.library.CachedLibrary;
2117
import com.oracle.truffle.api.library.ExportLibrary;
2218
import com.oracle.truffle.api.library.ExportMessage;
2319
import com.oracle.truffle.api.nodes.Node;
24-
import com.oracle.truffle.api.object.DynamicObjectLibrary;
25-
import com.oracle.truffle.api.source.SourceSection;
2620
import org.truffleruby.RubyContext;
2721
import org.truffleruby.RubyLanguage;
2822
import org.truffleruby.core.VMPrimitiveNodes.VMRaiseExceptionNode;
@@ -34,7 +28,6 @@
3428
import org.truffleruby.language.Nil;
3529
import org.truffleruby.language.RubyDynamicObject;
3630
import org.truffleruby.language.backtrace.Backtrace;
37-
import org.truffleruby.language.objects.IsANode;
3831
import org.truffleruby.language.objects.ObjectGraph;
3932
import org.truffleruby.language.objects.ObjectGraphNode;
4033

@@ -100,78 +93,9 @@ public RuntimeException throwException(
10093
throw VMRaiseExceptionNode.reRaiseException(context, this);
10194
}
10295

103-
// TODO (eregon, 01 Nov 2020): these message implementations would be nicer with separate subclasses for SystemExit and SyntaxError.
104-
105-
@ExportMessage
106-
public ExceptionType getExceptionType(
107-
@Cached IsANode isANode) {
108-
// @CachedContext does not work here when running "mx tck"
109-
final RubyContext context = getMetaClass().fields.getContext();
110-
if (isANode.executeIsA(this, context.getCoreLibrary().systemExitClass)) {
111-
return ExceptionType.EXIT;
112-
} else if (isANode.executeIsA(this, context.getCoreLibrary().syntaxErrorClass)) {
113-
return ExceptionType.PARSE_ERROR;
114-
} else {
115-
return ExceptionType.RUNTIME_ERROR;
116-
}
117-
}
118-
119-
@ExportMessage
120-
public int getExceptionExitStatus(
121-
@CachedLibrary("this") InteropLibrary interopLibrary,
122-
@CachedLibrary("this") DynamicObjectLibrary objectLibrary) throws UnsupportedMessageException {
123-
if (interopLibrary.getExceptionType(this) == ExceptionType.EXIT) {
124-
return (int) objectLibrary.getOrDefault(this, "@status", 1);
125-
} else {
126-
throw UnsupportedMessageException.create();
127-
}
128-
}
129-
130-
@ExportMessage
131-
public boolean isExceptionIncompleteSource(
132-
@CachedLibrary("this") InteropLibrary interopLibrary) throws UnsupportedMessageException {
133-
if (interopLibrary.getExceptionType(this) == ExceptionType.PARSE_ERROR) {
134-
return false; // Unknown
135-
} else {
136-
throw UnsupportedMessageException.create();
137-
}
138-
}
139-
140-
@TruffleBoundary
141-
@ExportMessage
142-
public boolean hasSourceLocation(
143-
@CachedLibrary("this") InteropLibrary interopLibrary) {
144-
try {
145-
if (interopLibrary.getExceptionType(this) == ExceptionType.PARSE_ERROR &&
146-
backtrace != null &&
147-
backtrace.getSourceLocation() != null) {
148-
return true;
149-
} else {
150-
final Node location = getLocation();
151-
return location != null && location.getEncapsulatingSourceSection() != null;
152-
}
153-
} catch (UnsupportedMessageException e) {
154-
throw CompilerDirectives.shouldNotReachHere(e);
155-
}
156-
}
157-
158-
@TruffleBoundary
15996
@ExportMessage
160-
public SourceSection getSourceLocation(
161-
@CachedLibrary("this") InteropLibrary interopLibrary) throws UnsupportedMessageException {
162-
if (interopLibrary.getExceptionType(this) == ExceptionType.PARSE_ERROR &&
163-
backtrace != null &&
164-
backtrace.getSourceLocation() != null) {
165-
return backtrace.getSourceLocation();
166-
} else {
167-
final Node location = getLocation();
168-
SourceSection sourceSection = location != null ? location.getEncapsulatingSourceSection() : null;
169-
if (sourceSection != null) {
170-
return sourceSection;
171-
} else {
172-
throw UnsupportedMessageException.create();
173-
}
174-
}
97+
public ExceptionType getExceptionType() {
98+
return ExceptionType.RUNTIME_ERROR;
17599
}
176100
// endregion
177101

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.exception;
11+
12+
import org.truffleruby.core.klass.RubyClass;
13+
import org.truffleruby.language.backtrace.Backtrace;
14+
15+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
16+
import com.oracle.truffle.api.interop.ExceptionType;
17+
import com.oracle.truffle.api.interop.InteropLibrary;
18+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
19+
import com.oracle.truffle.api.library.ExportLibrary;
20+
import com.oracle.truffle.api.library.ExportMessage;
21+
import com.oracle.truffle.api.object.Shape;
22+
import com.oracle.truffle.api.source.SourceSection;
23+
24+
@ExportLibrary(InteropLibrary.class)
25+
public class RubySyntaxError extends RubyException {
26+
27+
private final SourceSection sourceLocation; // this is where the syntax error happened in the file being parsed
28+
29+
public RubySyntaxError(
30+
RubyClass rubyClass,
31+
Shape shape,
32+
Object message,
33+
Backtrace backtrace,
34+
Object cause,
35+
SourceSection sourceLocation) {
36+
super(rubyClass, shape, message, backtrace, cause);
37+
this.sourceLocation = sourceLocation;
38+
}
39+
40+
// region Exception interop
41+
@Override
42+
@ExportMessage
43+
public ExceptionType getExceptionType() {
44+
return ExceptionType.PARSE_ERROR;
45+
}
46+
47+
@ExportMessage
48+
public boolean isExceptionIncompleteSource() {
49+
return false; // Unknown
50+
}
51+
52+
@ExportMessage
53+
public boolean hasSourceLocation() {
54+
return sourceLocation != null;
55+
}
56+
57+
@TruffleBoundary
58+
@ExportMessage
59+
public SourceSection getSourceLocation() throws UnsupportedMessageException {
60+
if (sourceLocation != null) {
61+
return sourceLocation;
62+
} else {
63+
throw UnsupportedMessageException.create();
64+
}
65+
}
66+
// endregion
67+
68+
}

0 commit comments

Comments
 (0)