Skip to content

Commit 855dca9

Browse files
committed
Add remaining nodes to implement RubySyntaxError and RubySystemExit
1 parent 337c3c6 commit 855dca9

File tree

12 files changed

+212
-63
lines changed

12 files changed

+212
-63
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/RubySyntaxError.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,27 @@
1818
import com.oracle.truffle.api.interop.UnsupportedMessageException;
1919
import com.oracle.truffle.api.library.ExportLibrary;
2020
import com.oracle.truffle.api.library.ExportMessage;
21-
import com.oracle.truffle.api.nodes.Node;
2221
import com.oracle.truffle.api.object.Shape;
2322
import com.oracle.truffle.api.source.SourceSection;
2423

2524
@ExportLibrary(InteropLibrary.class)
2625
public class RubySyntaxError extends RubyException {
2726

28-
public RubySyntaxError(RubyClass rubyClass, Shape shape, Object message, Backtrace backtrace, Object cause) {
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) {
2936
super(rubyClass, shape, message, backtrace, cause);
37+
this.sourceLocation = sourceLocation;
3038
}
3139

3240
// region Exception interop
41+
@Override
3342
@ExportMessage
3443
public ExceptionType getExceptionType() {
3544
return ExceptionType.PARSE_ERROR;
@@ -40,30 +49,18 @@ public boolean isExceptionIncompleteSource() {
4049
return false; // Unknown
4150
}
4251

43-
@TruffleBoundary
4452
@ExportMessage
4553
public boolean hasSourceLocation() {
46-
if (backtrace != null && backtrace.getSourceLocation() != null) {
47-
return true;
48-
} else {
49-
final Node location = getLocation();
50-
return location != null && location.getEncapsulatingSourceSection() != null;
51-
}
54+
return sourceLocation != null;
5255
}
5356

5457
@TruffleBoundary
5558
@ExportMessage
5659
public SourceSection getSourceLocation() throws UnsupportedMessageException {
57-
if (backtrace != null && backtrace.getSourceLocation() != null) {
58-
return backtrace.getSourceLocation();
60+
if (sourceLocation != null) {
61+
return sourceLocation;
5962
} else {
60-
final Node location = getLocation();
61-
SourceSection sourceSection = location != null ? location.getEncapsulatingSourceSection() : null;
62-
if (sourceSection != null) {
63-
return sourceSection;
64-
} else {
65-
throw UnsupportedMessageException.create();
66-
}
63+
throw UnsupportedMessageException.create();
6764
}
6865
}
6966
// endregion

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,21 @@
2121
@ExportLibrary(InteropLibrary.class)
2222
public class RubySystemExit extends RubyException {
2323

24-
public int exitStatus = 1;
25-
26-
public RubySystemExit(RubyClass rubyClass, Shape shape, Object message, Backtrace backtrace, Object cause) {
24+
public int exitStatus;
25+
26+
public RubySystemExit(
27+
RubyClass rubyClass,
28+
Shape shape,
29+
Object message,
30+
Backtrace backtrace,
31+
Object cause,
32+
int exitStatus) {
2733
super(rubyClass, shape, message, backtrace, cause);
34+
this.exitStatus = exitStatus;
2835
}
2936

3037
// region Exception interop
38+
@Override
3139
@ExportMessage
3240
public ExceptionType getExceptionType() {
3341
return ExceptionType.EXIT;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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.builtins.CoreMethod;
13+
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
14+
import org.truffleruby.builtins.CoreModule;
15+
import org.truffleruby.core.klass.RubyClass;
16+
import org.truffleruby.language.Visibility;
17+
import org.truffleruby.language.objects.AllocateHelperNode;
18+
import org.truffleruby.language.objects.AllocationTracing;
19+
20+
import com.oracle.truffle.api.dsl.Specialization;
21+
import com.oracle.truffle.api.object.Shape;
22+
23+
@CoreModule(value = "SyntaxError", isClass = true)
24+
public abstract class SyntaxErrorNodes {
25+
26+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
27+
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
28+
29+
@Child private AllocateHelperNode allocateNode = AllocateHelperNode.create();
30+
31+
@Specialization
32+
protected RubySyntaxError allocateSyntaxError(RubyClass rubyClass) {
33+
final Shape shape = allocateNode.getCachedShape(rubyClass);
34+
final RubySyntaxError instance = new RubySyntaxError(rubyClass, shape, nil, null, nil, null);
35+
AllocationTracing.trace(instance, this);
36+
return instance;
37+
}
38+
39+
}
40+
41+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.builtins.CoreMethod;
13+
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
14+
import org.truffleruby.builtins.CoreModule;
15+
import org.truffleruby.builtins.Primitive;
16+
import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
17+
import org.truffleruby.core.klass.RubyClass;
18+
import org.truffleruby.language.Visibility;
19+
import org.truffleruby.language.objects.AllocateHelperNode;
20+
import org.truffleruby.language.objects.AllocationTracing;
21+
22+
import com.oracle.truffle.api.dsl.Specialization;
23+
import com.oracle.truffle.api.object.Shape;
24+
25+
@CoreModule(value = "SystemExit", isClass = true)
26+
public abstract class SystemExitNodes {
27+
28+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
29+
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
30+
31+
@Child private AllocateHelperNode allocateNode = AllocateHelperNode.create();
32+
33+
@Specialization
34+
protected RubySystemExit allocateSytemExit(RubyClass rubyClass) {
35+
final Shape shape = allocateNode.getCachedShape(rubyClass);
36+
final RubySystemExit instance = new RubySystemExit(rubyClass, shape, nil, null, nil, 0);
37+
AllocationTracing.trace(instance, this);
38+
return instance;
39+
}
40+
41+
}
42+
43+
@CoreMethod(names = "status")
44+
public abstract static class StatusNode extends CoreMethodArrayArgumentsNode {
45+
46+
@Specialization
47+
protected int status(RubySystemExit self) {
48+
return self.exitStatus;
49+
}
50+
51+
}
52+
53+
@Primitive(name = "system_exit_set_status", lowerFixnum = 1)
54+
public abstract static class StatusSetNode extends PrimitiveArrayArgumentsNode {
55+
56+
@Specialization
57+
protected Object setStatus(RubySystemExit error, int exitStatus) {
58+
error.exitStatus = exitStatus;
59+
return exitStatus;
60+
}
61+
62+
}
63+
64+
}

src/main/java/org/truffleruby/core/kernel/AtExitManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import org.truffleruby.RubyContext;
1818
import org.truffleruby.core.exception.RubyException;
19+
import org.truffleruby.core.exception.RubySystemExit;
1920
import org.truffleruby.core.proc.ProcOperations;
2021
import org.truffleruby.core.proc.RubyProc;
2122
import org.truffleruby.language.control.ExitException;
@@ -83,9 +84,8 @@ public List<RubyProc> getHandlers() {
8384
}
8485

8586
public static boolean isSilentException(RubyContext context, RubyException rubyException) {
86-
final IsANode isANode = IsANode.getUncached();
87-
return isANode.executeIsA(rubyException, context.getCoreLibrary().systemExitClass) ||
88-
isANode.executeIsA(rubyException, context.getCoreLibrary().signalExceptionClass);
87+
return rubyException instanceof RubySystemExit ||
88+
IsANode.getUncached().executeIsA(rubyException, context.getCoreLibrary().signalExceptionClass);
8989
}
9090

9191
private static void handleAtExitException(RubyContext context, RubyException rubyException) {

src/main/java/org/truffleruby/core/thread/ThreadManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.truffleruby.collections.ConcurrentOperations;
2727
import org.truffleruby.core.basicobject.BasicObjectNodes.ObjectIDNode;
2828
import org.truffleruby.core.exception.RubyException;
29+
import org.truffleruby.core.exception.RubySystemExit;
2930
import org.truffleruby.core.fiber.FiberManager;
3031
import org.truffleruby.core.fiber.RubyFiber;
3132
import org.truffleruby.core.klass.RubyClass;
@@ -357,8 +358,7 @@ private void setException(RubyThread thread, RubyException exception, Node curre
357358
final RubyThread mainThread = context.getThreadManager().getRootThread();
358359

359360
if (thread != mainThread) {
360-
final boolean isSystemExit = exception.getLogicalClass() == context
361-
.getCoreLibrary().systemExitClass;
361+
final boolean isSystemExit = exception instanceof RubySystemExit;
362362

363363
if (!isSystemExit && thread.reportOnException) {
364364
context.send(

0 commit comments

Comments
 (0)