Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix displaying of host values in chrome devtools #11468

Merged
merged 28 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
845e030
Remove leftover typo from tests
Akirathan Nov 1, 2024
b80e0b0
Add tests
Akirathan Nov 1, 2024
1f68c9a
Discard warnings from the compiler in the test.
Akirathan Nov 1, 2024
4289d6c
Remove the test for non-null properties
Akirathan Nov 1, 2024
b354f80
Update test to reflect that atom with builtin type has null properties
Akirathan Nov 1, 2024
ae14326
Try to convert HostObject in DebugLocalScope.readMember
Akirathan Nov 5, 2024
a7c110c
Fix testests
Akirathan Nov 8, 2024
c038f55
Implement getPolyglotConversionType
Akirathan Nov 8, 2024
d2cd44a
DebugLocalScope uses getPolyglotConversionType
Akirathan Nov 8, 2024
08c066f
Add tests
Akirathan Nov 8, 2024
c18ad2c
Remove unused method
Akirathan Nov 8, 2024
2c46980
Testing also js and py foreign languages
Akirathan Nov 11, 2024
9134e52
Polyglot conversion logic is in EnsoLanguage.getLanguageView
Akirathan Nov 11, 2024
19e3798
Use only PolyglotCallType
Akirathan Nov 11, 2024
e283355
long is wrapped in LanguageViewWrapper
Akirathan Nov 11, 2024
b95d4bb
ArrayBuilder exports hasLanguage and getLanguage messages
Akirathan Nov 11, 2024
61e363a
Call Value.asString instead of Value.toString
Akirathan Nov 11, 2024
5fab1da
Test that WithWarnings has meta object
Akirathan Nov 11, 2024
293811e
Implement hasLanguage and getLanguage messages for EnsoBigInt and Text
Akirathan Nov 11, 2024
f4b199b
EnsoLanguage.getLanguageView returns null by default
Akirathan Nov 11, 2024
95b8d09
Merge branch 'develop' into wip/akirathan/7890-java-values-devtools
Akirathan Nov 26, 2024
cdc0ba3
Classes that extend EnsoObject do not export getLanguage and hasLangu…
Akirathan Nov 26, 2024
b743106
Build fixes after merge
Akirathan Nov 26, 2024
368415f
Update WithWarning test - do not use primitive value.
Akirathan Nov 26, 2024
19328ac
Add test for polyglot semantics of Enso numbers
Akirathan Nov 26, 2024
1826dde
Add comments to BigNumberTest
Akirathan Nov 27, 2024
1d01221
A value that fits in double is double, not converted to BigInt
Akirathan Nov 27, 2024
65553f3
EnsoObject is returned from getLanguageView without any conversions
Akirathan Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
import com.oracle.truffle.api.debug.SuspendedCallback;
import com.oracle.truffle.api.debug.SuspendedEvent;
import com.oracle.truffle.api.nodes.LanguageInfo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -42,23 +45,30 @@
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class DebuggingEnsoTest {
private Context context;
private Engine engine;
private Debugger debugger;
private final ByteArrayOutputStream out = new ByteArrayOutputStream();

@Before
public void initContext() {
out.reset();
engine =
Engine.newBuilder()
.allowExperimentalOptions(true)
.option(
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
Paths.get("../../distribution/component").toFile().getAbsolutePath())
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
.logHandler(System.err)
.logHandler(out)
.err(out)
.out(out)
.build();

context =
Expand All @@ -76,13 +86,26 @@ public void initContext() {
}

@After
public void disposeContext() {
public void disposeContext() throws IOException {
context.close();
context = null;
engine.close();
engine = null;
}

/** Only print warnings from the compiler if a test fails. */
@Rule
public TestWatcher testWatcher =
new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
System.err.println("Test failed: " + description.getMethodName());
System.err.println("Error: " + e.getMessage());
System.err.println("Logs from the compiler and the engine: ");
System.err.println(out);
}
};

private static void expectStackFrame(
DebugStackFrame actualFrame, Map<String, String> expectedValues) {
Map<String, String> actualValues = new HashMap<>();
Expand Down Expand Up @@ -246,6 +269,86 @@ public void testHostValues() {
}
}

/**
* Both {@code Date.new 2024 12 15} and {@code Date.parse "2024-12-15"} should be seen by the
* debugger as the exact same objects. Internally, the value from {@code Date.parse} is a host
* value.
*/
@Test
public void hostValueIsTreatedAsItsEnsoCounterpart() {
Value fooFunc =
createEnsoMethod(
"""
from Standard.Base import Date, Date_Time, Dictionary
polyglot java import java.lang.String
polyglot java import java.util.List as JList
polyglot java import java.util.Map as JMap

foo _ =
d_enso = Date.new 2024 12 15
d_java = Date.parse "2024-12-15"
dt_enso = Date_Time.now
dt_java = Date_Time.parse "2020-05-06 04:30:20" "yyyy-MM-dd HH:mm:ss"
str_enso = "Hello_World"
str_java = String.new "Hello_World"
list_enso = [1, 2, 3]
list_java = JList.of 1 2 3
dict_enso = Dictionary.from_vector [["A", 1], ["B", 2]]
dict_java = JMap.of "A" 1 "B" 2
end = 42
""",
"foo");

try (DebuggerSession session =
debugger.startSession(
(SuspendedEvent event) -> {
switch (event.getSourceSection().getCharacters().toString().strip()) {
case "end = 42" -> {
DebugScope scope = event.getTopStackFrame().getScope();

DebugValue ensoDate = scope.getDeclaredValue("d_enso");
DebugValue javaDate = scope.getDeclaredValue("d_java");
assertSameProperties(ensoDate.getProperties(), javaDate.getProperties());

DebugValue ensoDateTime = scope.getDeclaredValue("dt_enso");
DebugValue javaDateTime = scope.getDeclaredValue("dt_java");
assertSameProperties(ensoDateTime.getProperties(), javaDateTime.getProperties());

DebugValue ensoString = scope.getDeclaredValue("str_enso");
DebugValue javaString = scope.getDeclaredValue("str_java");
assertSameProperties(ensoString.getProperties(), javaString.getProperties());

DebugValue ensoList = scope.getDeclaredValue("list_enso");
DebugValue javaList = scope.getDeclaredValue("list_java");
assertSameProperties(ensoList.getProperties(), javaList.getProperties());
Akirathan marked this conversation as resolved.
Show resolved Hide resolved

DebugValue ensoDict = scope.getDeclaredValue("dict_enso");
DebugValue javaDict = scope.getDeclaredValue("dict_java");
assertSameProperties(ensoDict.getProperties(), javaDict.getProperties());
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
}
}
event.getSession().suspendNextExecution();
})) {
session.suspendNextExecution();
fooFunc.execute(0);
}
}

/** Asserts that the given values have same property names. */
private void assertSameProperties(
Collection<DebugValue> expectedProps, Collection<DebugValue> actualProps) {
if (expectedProps == null) {
assertThat(actualProps, is(nullValue()));
return;
}
assertThat(actualProps.size(), is(expectedProps.size()));
var expectedPropNames =
expectedProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet());
var actualPropNames =
actualProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet());
assertThat(actualPropNames, is(expectedPropNames));
}

@Test
public void testHostValueAsAtomField() {
Value fooFunc =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class TypeSignaturesTest
)
}

"XX resolve imported names" in {
"resolve imported names" in {
val code =
"""
|from project.Util import all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,46 @@ public boolean isInteropLibrary() {
}
}

/**
* Given a polyglot (foreign) object, this enum represents a target Enso type that the object
* should be converted to before further dispatch.
*
* <p>For example, a {@code java.lang.String}, or any other polyglot object that {@link
* InteropLibrary#isString(Object) is a string}, should be converted to the {@link
* org.enso.interpreter.runtime.data.text.Text} builtin Enso type.
*/
public enum PolyglotConversionType {
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
/** The object should be converted to {@link org.enso.interpreter.runtime.data.text.Text}. */
CONVERT_TO_TEXT,
/**
* The object should be converted to {@link org.enso.interpreter.runtime.number.EnsoBigInteger}.
*/
CONVERT_TO_BIG_INT,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.vector.Array}. */
CONVERT_TO_ARRAY,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDate}. */
CONVERT_TO_DATE,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */
CONVERT_TO_ZONED_DATE_TIME,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */
CONVERT_TO_DATE_TIME,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDuration}. */
CONVERT_TO_DURATION,
/**
* The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeOfDay}.
*/
CONVERT_TO_TIME_OF_DAY,
/** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeZone}. */
CONVERT_TO_TIME_ZONE,
/**
* The object should be converted to {@link org.enso.interpreter.runtime.data.hash.EnsoHashMap}.
*/
CONVERT_TO_HASH_MAP,

/** No need to convert the polyglot object, just pass it as is. */
NO_CONVERSION
}

private static final String NEW_NAME = "new";

static final int LIB_LIMIT = 3;
Expand Down Expand Up @@ -150,37 +190,46 @@ public static PolyglotCallType getPolyglotCallType(
UnresolvedSymbol symbol,
InteropLibrary library,
MethodResolverNode methodResolverNode) {
if (library.isDate(self)) {
if (library.isTime(self)) {
if (library.isTimeZone(self)) {
return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME;
} else {
return PolyglotCallType.CONVERT_TO_DATE_TIME;
}
} else {
var conversionType = getPolyglotConversionType(self, library);
switch (conversionType) {
case CONVERT_TO_TEXT -> {
return PolyglotCallType.CONVERT_TO_TEXT;
}
case CONVERT_TO_BIG_INT -> {
return PolyglotCallType.CONVERT_TO_BIG_INT;
}
case CONVERT_TO_DATE -> {
return PolyglotCallType.CONVERT_TO_DATE;
}
} else if (library.isTime(self)) {
return PolyglotCallType.CONVERT_TO_TIME_OF_DAY;
} else if (library.isDuration(self)) {
return PolyglotCallType.CONVERT_TO_DURATION;
} else if (library.isTimeZone(self)) {
return PolyglotCallType.CONVERT_TO_TIME_ZONE;
} else if (library.fitsInBigInteger(self)) {
return PolyglotCallType.CONVERT_TO_BIG_INT;
} else if (library.isString(self)) {
return PolyglotCallType.CONVERT_TO_TEXT;
} else if (library.hasArrayElements(self)) {
if (methodResolverNode != null) {
var ctx = EnsoContext.get(library);
var arrayType = ctx.getBuiltins().array();
var fn = methodResolverNode.execute(arrayType, symbol);
if (fn != null) {
return PolyglotCallType.CONVERT_TO_ARRAY;
case CONVERT_TO_ZONED_DATE_TIME -> {
return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME;
}
case CONVERT_TO_DATE_TIME -> {
return PolyglotCallType.CONVERT_TO_DATE_TIME;
}
case CONVERT_TO_DURATION -> {
return PolyglotCallType.CONVERT_TO_DURATION;
}
case CONVERT_TO_TIME_OF_DAY -> {
return PolyglotCallType.CONVERT_TO_TIME_OF_DAY;
}
case CONVERT_TO_TIME_ZONE -> {
return PolyglotCallType.CONVERT_TO_TIME_ZONE;
}
case CONVERT_TO_HASH_MAP -> {
return PolyglotCallType.CONVERT_TO_HASH_MAP;
}
case CONVERT_TO_ARRAY -> {
if (methodResolverNode != null) {
var ctx = EnsoContext.get(library);
var arrayType = ctx.getBuiltins().array();
var fn = methodResolverNode.execute(arrayType, symbol);
if (fn != null) {
return PolyglotCallType.CONVERT_TO_ARRAY;
}
}
}
} else if (library.hasHashEntries(self)) {
return PolyglotCallType.CONVERT_TO_HASH_MAP;
default -> {}
}

try {
Expand All @@ -198,6 +247,45 @@ public static PolyglotCallType getPolyglotCallType(
return PolyglotCallType.NOT_SUPPORTED;
}

/**
* Returns a target Enso builtin type that the {@code polyglotObj} should be converted to before
* further dispatch.
*
* <p>For example, {@code java.lang.String} should be converted to {@link
* org.enso.interpreter.runtime.data.text.Text}.
*
* @param polyglotObj Polyglot (foreign) object to check for conversion.
*/
public static PolyglotConversionType getPolyglotConversionType(
Object polyglotObj, InteropLibrary interop) {
if (interop.isDate(polyglotObj)) {
if (interop.isTime(polyglotObj)) {
if (interop.isTimeZone(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_ZONED_DATE_TIME;
} else {
return PolyglotConversionType.CONVERT_TO_DATE_TIME;
}
} else {
return PolyglotConversionType.CONVERT_TO_DATE;
}
} else if (interop.isTime(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_TIME_OF_DAY;
} else if (interop.isDuration(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_DURATION;
} else if (interop.isTimeZone(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_TIME_ZONE;
} else if (interop.fitsInBigInteger(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_BIG_INT;
} else if (interop.isString(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_TEXT;
} else if (interop.hasArrayElements(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_ARRAY;
} else if (interop.hasHashEntries(polyglotObj)) {
return PolyglotConversionType.CONVERT_TO_HASH_MAP;
}
return PolyglotConversionType.NO_CONVERSION;
}

/**
* Calls a method on an object, using a specified {@link PolyglotCallType}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public static HashMapInsertNode build() {
return HashMapInsertNodeGen.create();
}

public static HashMapInsertNode getUncached() {
return HashMapInsertNodeGen.getUncached();
}

public abstract EnsoHashMap execute(VirtualFrame frame, Object self, Object key, Object value);

@Specialization
Expand Down
Loading
Loading