mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 20:21:44 +03:00
Atom fields are visible in debugger (#10661)
Atom fields are now visible in the debugger (both chrome inspector and VSCode's debug adapter protocol): ![image](https://github.com/user-attachments/assets/c3d19475-c271-46b6-a44e-e9aebf414b8d)
This commit is contained in:
parent
f31c084f43
commit
f849634db3
@ -0,0 +1,131 @@
|
||||
package org.enso.interpreter.test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import org.enso.test.utils.ContextUtils;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests various {@link com.oracle.truffle.api.interop.InteropLibrary interop} contracts for {@link
|
||||
* org.enso.interpreter.runtime.data.atom.Atom atoms}.
|
||||
*/
|
||||
public class AtomInteropTest {
|
||||
private Context ctx;
|
||||
|
||||
@Before
|
||||
public void initCtx() {
|
||||
ctx = ContextUtils.createDefaultContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void disposeCtx() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void atomMembersAreConstructorFields_SingleConstructor() {
|
||||
var myTypeAtom =
|
||||
ContextUtils.evalModule(
|
||||
ctx,
|
||||
"""
|
||||
type My_Type
|
||||
Cons field_1 field_2
|
||||
|
||||
main =
|
||||
My_Type.Cons 1 2
|
||||
""");
|
||||
assertThat(myTypeAtom.hasMembers(), is(true));
|
||||
var memberNames = myTypeAtom.getMemberKeys();
|
||||
assertThat("Has two fields", memberNames.size(), is(2));
|
||||
assertThat(
|
||||
"Member names are not qualified", memberNames, containsInAnyOrder("field_1", "field_2"));
|
||||
for (var memberName : memberNames) {
|
||||
var member = myTypeAtom.getMember(memberName);
|
||||
assertThat("Member " + memberName + " should be readable", member, is(notNullValue()));
|
||||
assertThat("All fields are numbers", member.isNumber(), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void atomIsNotMetaObject() {
|
||||
var myTypeAtom =
|
||||
ContextUtils.evalModule(
|
||||
ctx,
|
||||
"""
|
||||
type My_Type
|
||||
Cons field_1 field_2
|
||||
|
||||
main =
|
||||
My_Type.Cons 1 2
|
||||
""");
|
||||
assertThat(myTypeAtom.isMetaObject(), is(false));
|
||||
assertThat(myTypeAtom.getMetaObject().getMetaSimpleName(), is("My_Type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeHasAnyAsSuperType() {
|
||||
var myTypeAtom =
|
||||
ContextUtils.evalModule(
|
||||
ctx,
|
||||
"""
|
||||
type My_Type
|
||||
Cons
|
||||
|
||||
main = My_Type.Cons
|
||||
""");
|
||||
var myType = myTypeAtom.getMetaObject();
|
||||
assertThat(myType.hasMetaParents(), is(true));
|
||||
var metaParents = myType.getMetaParents();
|
||||
assertThat(metaParents.hasArrayElements(), is(true));
|
||||
assertThat("Has just one meta parent - Any", metaParents.getArraySize(), is(1L));
|
||||
var anyType = metaParents.getArrayElement(0);
|
||||
assertThat(anyType.getMetaSimpleName(), is("Any"));
|
||||
}
|
||||
|
||||
@Ignore("https://github.com/enso-org/enso/issues/10675")
|
||||
@Test
|
||||
public void atomMembersAreConstructorFields_ManyConstructors() {
|
||||
var myTypeAtom =
|
||||
ContextUtils.evalModule(
|
||||
ctx,
|
||||
"""
|
||||
type My_Type
|
||||
Cons_1 f1 f2 f3 f4 f5 f6
|
||||
Cons_2 g1 g2 g3
|
||||
Cons_3 h1 h2 h3 h4 h5 h6 h7 h8 h9
|
||||
|
||||
main = My_Type.Cons_2 "g1" "g2" "g3"
|
||||
""");
|
||||
assertThat(
|
||||
"Member names correspond to constructor field names for a single constructor",
|
||||
myTypeAtom.getMemberKeys(),
|
||||
containsInAnyOrder("g1", "g2", "g3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeMembersAreConstructors() {
|
||||
var myType =
|
||||
ContextUtils.evalModule(
|
||||
ctx,
|
||||
"""
|
||||
type My_Type
|
||||
Cons_1
|
||||
Cons_2
|
||||
|
||||
main = My_Type
|
||||
""");
|
||||
assertThat("type has constructors as members", myType.hasMembers(), is(true));
|
||||
assertThat(myType.getMemberKeys(), containsInAnyOrder("Cons_1", "Cons_2"));
|
||||
assertThat(
|
||||
"Constructor (type member) is instantiable",
|
||||
myType.getMember("Cons_1").canInstantiate(),
|
||||
is(true));
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DebuggingEnsoTest {
|
||||
@ -434,6 +435,95 @@ public class DebuggingEnsoTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAtomFieldsAreReadable() {
|
||||
var fooFunc =
|
||||
createEnsoMethod(
|
||||
"""
|
||||
type My_Type
|
||||
Cons field_1 field_2
|
||||
|
||||
foo x =
|
||||
obj = My_Type.Cons 1 2
|
||||
obj
|
||||
""",
|
||||
"foo");
|
||||
try (DebuggerSession session =
|
||||
debugger.startSession(
|
||||
(SuspendedEvent event) -> {
|
||||
switch (event.getSourceSection().getCharacters().toString().strip()) {
|
||||
case "obj" -> {
|
||||
DebugScope scope = event.getTopStackFrame().getScope();
|
||||
DebugValue objValue = scope.getDeclaredValue("obj");
|
||||
assertThat(objValue.isReadable(), is(true));
|
||||
assertThat(objValue.isInternal(), is(false));
|
||||
assertThat(objValue.hasReadSideEffects(), is(false));
|
||||
|
||||
var field1Prop = objValue.getProperty("field_1");
|
||||
assertThat(field1Prop.isReadable(), is(true));
|
||||
assertThat(field1Prop.isNumber(), is(true));
|
||||
assertThat(field1Prop.asInt(), is(1));
|
||||
|
||||
assertThat(objValue.getProperties().size(), is(2));
|
||||
for (var prop : objValue.getProperties()) {
|
||||
assertThat(
|
||||
"Property '" + prop.getName() + "' should be readable",
|
||||
prop.isReadable(),
|
||||
is(true));
|
||||
assertThat(prop.isNumber(), is(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
event.getSession().suspendNextExecution();
|
||||
})) {
|
||||
session.suspendNextExecution();
|
||||
fooFunc.execute(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("https://github.com/enso-org/enso/issues/10675")
|
||||
@Test
|
||||
public void testAtomFieldAreReadable_MultipleConstructors() {
|
||||
var fooFunc =
|
||||
createEnsoMethod(
|
||||
"""
|
||||
type My_Type
|
||||
Cons_1 f1 f2
|
||||
Cons_2 g1 g2 g3
|
||||
|
||||
foo x =
|
||||
obj = My_Type.Cons_1 1 2
|
||||
obj
|
||||
""",
|
||||
"foo");
|
||||
try (DebuggerSession session =
|
||||
debugger.startSession(
|
||||
(SuspendedEvent event) -> {
|
||||
switch (event.getSourceSection().getCharacters().toString().strip()) {
|
||||
case "obj" -> {
|
||||
DebugScope scope = event.getTopStackFrame().getScope();
|
||||
DebugValue objValue = scope.getDeclaredValue("obj");
|
||||
assertThat(objValue.isReadable(), is(true));
|
||||
assertThat(objValue.isInternal(), is(false));
|
||||
assertThat(objValue.hasReadSideEffects(), is(false));
|
||||
|
||||
assertThat("Has fields f1 and f2", objValue.getProperties().size(), is(2));
|
||||
for (var prop : objValue.getProperties()) {
|
||||
assertThat(
|
||||
"Property '" + prop.getName() + "' should be readable",
|
||||
prop.isReadable(),
|
||||
is(true));
|
||||
assertThat(prop.isNumber(), is(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
event.getSession().suspendNextExecution();
|
||||
})) {
|
||||
session.suspendNextExecution();
|
||||
fooFunc.execute(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests stepping through the given source.
|
||||
*
|
||||
|
@ -142,7 +142,7 @@ public abstract class Atom implements EnsoObject {
|
||||
*/
|
||||
@ExportMessage
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
EnsoObject getMembers(boolean includeInternal) throws UnsupportedMessageException {
|
||||
EnsoObject getMembers(boolean includeInternal) {
|
||||
Set<Function> members =
|
||||
constructor.getDefinitionScope().getMethodsForType(constructor.getType());
|
||||
Set<Function> allFuncMembers = new HashSet<>();
|
||||
|
@ -50,7 +50,7 @@ final class GetFieldNode extends EnsoRootNode {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return type.getName() + "." + name;
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user