Skip to content

Commit

Permalink
Adding java_exception.has_type method
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach committed Jul 17, 2022
1 parent 8b686b1 commit 60da5e7
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ type Engine

internal_pattern = maybe_java_pattern.map_error case _ of
Polyglot_Error err ->
if Java.is_instance err PatternSyntaxException . not then err else
if err.has_type PatternSyntaxException . not then err else
Regex.Syntax_Error err.getMessage
other -> other

Expand Down Expand Up @@ -823,8 +823,8 @@ type Match
handle_error : Any -> (Text | Integer) -> Any
handle_error error id = case error of
Polyglot_Error err ->
is_ioob = Java.is_instance err IndexOutOfBoundsException
is_iae = Java.is_instance err IllegalArgumentException
is_ioob = err.has_type IndexOutOfBoundsException
is_iae = err.has_type IllegalArgumentException
maps_to_no_such_group = is_ioob || is_iae

if maps_to_no_such_group.not then err else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ new year (month = 1) (day = 1) =
https://github.com/enso-org/enso/pull/3559
Then this should be switched to use `Panic.catch_java`.
Panic.recover Any (Date.internal_new year month day) . catch Any e-> case e of
Polyglot_Error err -> Error.throw (Time.Time_Error err)
ex -> Error.throw (Time.Time_Error ex)
Polyglot_Error err -> Error.throw (Time.Time_Error err.getMessage)
ex -> ex

## ALIAS Date from Text

Expand Down Expand Up @@ -137,8 +137,8 @@ parse text pattern=Nothing =
Text -> Date.internal_parse text pattern
_ -> Panic.throw (Time.Time_Error "An invalid pattern was provided.")
result . map_error <| case _ of
Polyglot_Error err -> Time.Time_Error err
ex -> Time.Time_Error ex
Polyglot_Error err -> Time.Time_Error err.getMessage
ex -> ex

type Date

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ type Panic
False -> Panic.throw caught_panic
True -> case caught_panic.payload of
Polyglot_Error java_exception ->
case Java.is_instance java_exception panic_type of
case java_exception.has_type panic_type of
True -> handler caught_panic
False -> Panic.throw caught_panic
_ -> Panic.throw caught_panic
Expand Down Expand Up @@ -392,7 +392,7 @@ type Panic
catch_java panic_type ~action handler =
Panic.catch_primitive action caught_panic-> case caught_panic.payload of
Polyglot_Error java_exception ->
case (panic_type == Any) || (Java.is_instance java_exception panic_type) of
case (panic_type == Any) || (java_exception.has_type panic_type) of
True -> handler java_exception
False -> Panic.throw caught_panic
_ -> Panic.throw caught_panic
Expand Down
8 changes: 4 additions & 4 deletions distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso
Original file line number Diff line number Diff line change
Expand Up @@ -955,10 +955,10 @@ handle_java_exceptions file ~action =

Converts a Java `IOException` into its Enso counterpart.
wrap_io_exception file io_exception =
if Java.is_instance io_exception NoSuchFileException then Error.throw (File_Not_Found file) else
if Java.is_instance io_exception FileAlreadyExistsException then Error.throw (File_Already_Exists_Error file) else
if Java.is_instance io_exception AccessDeniedException then Error.throw (Io_Error file "You do not have permission to access the file") else
Error.throw (Io_Error file "An IO error has occurred: "+io_exception.getMessage)
if io_exception.has_type NoSuchFileException then Error.throw (File_Not_Found file) else
if io_exception.has_type FileAlreadyExistsException then Error.throw (File_Already_Exists_Error file) else
if io_exception.has_type AccessDeniedException then Error.throw (Io_Error file "You do not have permission to access the file") else
Error.throw (Io_Error file "An IO error has occurred: "+io_exception.to_text)

## PRIVATE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.builtin.Error;
import org.enso.interpreter.runtime.data.text.Text;

@BuiltinMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public Builtins(Context context) {
builtinMethodNodes = readBuiltinMethodsMetadata(scope);
registerBuiltinMethods(builtinTypes, scope, language);

error = new Error(this);
error = new Error(this, context);
ordering = new Ordering(this);
system = new System(this);
number = new Number(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@
import org.enso.interpreter.runtime.data.text.Text;

import static com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import org.enso.interpreter.runtime.Context;

/** Container for builtin Error types */
public class Error {

private final Context context;
private final BuiltinAtomConstructor syntaxError;
private final BuiltinAtomConstructor typeError;
private final BuiltinAtomConstructor compileError;
Expand Down Expand Up @@ -43,7 +53,8 @@ public class Error {
private static final Text divideByZeroMessage = Text.create("Cannot divide by zero.");

/** Creates builders for error Atom Constructors. */
public Error(Builtins builtins) {
public Error(Builtins builtins, Context context) {
this.context = context;
syntaxError = new BuiltinAtomConstructor(builtins, SyntaxError.class);
typeError = new BuiltinAtomConstructor(builtins, TypeError.class);
compileError = new BuiltinAtomConstructor(builtins, CompileError.class);
Expand Down Expand Up @@ -133,15 +144,8 @@ public Atom makeTypeError(Object expected, Object actual, String name) {
* @param cause the cause of the error.
* @return a runtime representation of the polyglot error.
*/
public Atom makePolyglotError(Object cause) {
return polyglotError.newInstance(switch (cause) {
case TruffleObject truffle -> truffle;
case Throwable any -> any.getMessage();
default -> {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException("" + cause);
}
});
public Atom makePolyglotError(Throwable cause) {
return polyglotError.newInstance(WrapPlainException.wrap(cause, context));
}

/**
Expand Down Expand Up @@ -215,4 +219,112 @@ public Atom makeModuleDoesNotExistError(String name) {
public Atom makeNotInvokableError(Object target) {
return notInvokableError.newInstance(target);
}

/** Represents plain Java exception as a {@link TruffleObject}.
*/
@ExportLibrary(InteropLibrary.class)
static final class WrapPlainException extends AbstractTruffleException {
private final Throwable original;

private WrapPlainException(Throwable cause) {
super(cause.getMessage(), cause, AbstractTruffleException.UNLIMITED_STACK_TRACE, null);
this.original = cause;
}

private WrapPlainException(AbstractTruffleException prototype, Throwable original) {
super(prototype);
this.original = original;
}

static AbstractTruffleException wrap(Throwable cause, Context ctx) {
var env = ctx.getEnvironment();
if (env.isHostException(cause)) {
var orig = env.asHostException(cause);
return new WrapPlainException((AbstractTruffleException) cause, orig);
} else if (cause instanceof AbstractTruffleException truffleEx) {
return truffleEx;
} else {
return new WrapPlainException(cause);
}
}

@ExportMessage
boolean hasExceptionMessage() {
return getMessage() != null;
}

@ExportMessage
public Object getExceptionMessage() {
return Text.create(getMessage());
}

@ExportMessage
String toDisplayString(boolean sideEffects) {
return original.toString();
}

@ExportMessage
Object getMembers(boolean includeInternal) {
return Array.empty();
}

@ExportMessage
boolean hasMembers() {
return true;
}

@ExportMessage
boolean isMemberInvocable(String member) {
return
"has_type".equals(member) ||
"getMessage".equals(member);
}

@ExportMessage
Object invokeMember(String name, Object[] args, @CachedLibrary(limit="2") InteropLibrary iop) throws ArityException, UnknownIdentifierException, UnsupportedTypeException, UnsupportedMessageException {
if ("has_type".equals(name)) {
if (args.length != 1) {
throw ArityException.create(1,1, args.length);
}
Object meta;
if (iop.isString(args[0])) {
meta = args[0];
} else {
try {
meta = iop.getMetaQualifiedName(args[0]);
} catch (UnsupportedMessageException e) {
meta = args[0];
}
}
if (!iop.isString(meta)) {
throw UnsupportedTypeException.create(args, "Provide class or fully qualified name of class to check");
}

return hasType(iop.asString(meta), original.getClass());
}
if ("getMessage".equals(name)) {
return getExceptionMessage();
}
throw UnknownIdentifierException.create(name);
}

@CompilerDirectives.TruffleBoundary
private static boolean hasType(String fqn, Class<?> type) {
if (type == null) {
return false;
}
if (type.getName().equals(fqn)) {
return true;
}
if (hasType(fqn, type.getSuperclass())) {
return true;
}
for (Class<?> interfaceType : type.getInterfaces()) {
if (hasType(fqn, interfaceType)) {
return true;
}
}
return false;
}
}
}

0 comments on commit 60da5e7

Please sign in to comment.