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

Builtins expose Enso methods #11687

Open
wants to merge 56 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f9a00c6
Add BuiltinsExposeMethodsTest
Akirathan Nov 27, 2024
587904a
typo in docs
Akirathan Nov 27, 2024
bdbe60f
Test iteartes all the builtins and checks that all methods are invoca…
Akirathan Nov 29, 2024
7f0d4bf
Add TypesExposeConstructorsTest
Akirathan Nov 29, 2024
59710b9
Merge branch 'develop' into wip/akirathan/11589-builtins-expose-methods
Akirathan Dec 3, 2024
48005e6
Naive implementation of BuiltinObject base class.
Akirathan Dec 4, 2024
477de23
Ref extends BuiltinObject
Akirathan Dec 4, 2024
86c360b
Builtin type anot processor ensures that a class must extend BuiltinO…
Akirathan Dec 4, 2024
bac459e
Enrich BuiltinsExposeMethodsTest
Akirathan Dec 4, 2024
a9681e3
All builtin types extend BuiltinObject
Akirathan Dec 4, 2024
ab7a246
Text is BuiltinObject
Akirathan Dec 4, 2024
4c9ea78
EnsoBigInteger is BuiltinObject
Akirathan Dec 4, 2024
e806f9f
BuiltinObject does no asserts in constructor
Akirathan Dec 4, 2024
3b98c60
ArrayProxy is BuiltinObject
Akirathan Dec 4, 2024
643aa36
Test skips host values and Nothing
Akirathan Dec 4, 2024
5a8ef4e
fmt
Akirathan Dec 4, 2024
7cd6469
Remove outdated test.
Akirathan Dec 4, 2024
475819a
EqualsComplexNode: Timezone and duration are not treated as object wi…
Akirathan Dec 4, 2024
7856324
Fix DebuggingEnsoTest - Date in js is date time, not date
Akirathan Dec 4, 2024
a00ef60
Fix DateTest - ensoDate now has members
Akirathan Dec 4, 2024
0658ca5
Add interop.readMember test to BuiltinsExposeMethodsTest
Akirathan Dec 4, 2024
c1d8f41
VectorSortTest is executed in context
Akirathan Dec 4, 2024
47125a7
Add tests that invoke builtin methods on particular builtin types
Akirathan Dec 4, 2024
e8ed818
member methods on BuiltinObject are behind TruffleBoundary
Akirathan Dec 4, 2024
7dfb427
Cache builtin type in BuiltinObject.
Akirathan Dec 4, 2024
193db45
Reuse context in DebuggingEnsoTest.
Akirathan Dec 5, 2024
934afe1
Merge branch 'develop' into wip/akirathan/11589-builtins-expose-methods
Akirathan Dec 10, 2024
8acb04a
Reuse hardcoded builtinName constants from annotation
Akirathan Dec 10, 2024
f187211
Move BuiltinObject to package org.enso.interpreter.runtime.builtin
Akirathan Dec 10, 2024
0cc0b72
Fix FQN of BuiltinObject in the annotation processor
Akirathan Dec 10, 2024
6f31ebf
Make exported messages on BuiltinObject final
Akirathan Dec 10, 2024
2462523
Update generated class names in Builtins.
Akirathan Dec 10, 2024
e441fab
Exported messages in BuiltinObject are not behind TruffleBoundary
Akirathan Dec 10, 2024
a77691c
[WIP] Add BuiltinsJavaInteropTest
Akirathan Dec 11, 2024
b6ec2ae
Storage.vectorizedOrFallbackBinaryMap accepts Value as parameter
Akirathan Dec 11, 2024
752ac90
Builtin types expose methods, not BuiltinObject
Akirathan Dec 12, 2024
3a3f302
BuiltinObject has no members
Akirathan Dec 12, 2024
6f40c65
Remove test Text.is_empty
Akirathan Dec 12, 2024
c34408b
Fix tests - invocation is done via static methods
Akirathan Dec 12, 2024
b21384a
Type.InvokeMember uses InvokeFunctionNode instead of UnresolvedSymbol
Akirathan Dec 12, 2024
70a18c6
fmt
Akirathan Dec 12, 2024
3969177
Type.InvokeMember prepends receiver argument
Akirathan Dec 12, 2024
a001eab
Test invocation of File.path
Akirathan Dec 12, 2024
def1f6b
Test invocation of Vector.to_text
Akirathan Dec 12, 2024
eb125ba
Method fetching is done behind truffle boundary
Akirathan Dec 12, 2024
0b5758c
Reassigning @CompilationFinal field should deoptimize
JaroslavTulach Dec 13, 2024
7f8b62c
Merge branch 'develop' into wip/akirathan/11589-builtins-expose-methods
Akirathan Jan 8, 2025
50b43cd
Fixes after merge
Akirathan Jan 8, 2025
8ee8ea2
Add TruffleBoundary
Akirathan Jan 9, 2025
139952e
Revert DateTest
Akirathan Jan 9, 2025
3edfc9c
Fix PrivateConstructor test
Akirathan Jan 9, 2025
82701e7
Methods on Type are internal members
Akirathan Jan 9, 2025
29de01a
fmt
Akirathan Jan 9, 2025
83f4bcd
Add TruffleBoundary
Akirathan Jan 10, 2025
bfcaca9
Revert Storage to develop
Akirathan Jan 10, 2025
4d6fce1
Remove FIXME comment
Akirathan Jan 10, 2025
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
@@ -0,0 +1,18 @@
package org.enso.example;

import java.time.LocalDate;
import org.graalvm.polyglot.Value;

public class PolyglotTestClass {
public static boolean isPolyglotDate_Object(Object obj) {
return obj instanceof Value polyglotVal && polyglotVal.isDate();
}

public static boolean isPolyglotDate_LocalDate(LocalDate date) {
return date != null;
}

public static boolean isPolyglotDate_Value(Value val) {
return val != null && val.isDate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,23 @@
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.IOAccess;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
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();
private static Context context;
private static Engine engine;
private static Debugger debugger;
private static final ByteArrayOutputStream out = new ByteArrayOutputStream();

@Before
public void initContext() {
out.reset();
@BeforeClass
public static void initContext() {
engine =
Engine.newBuilder()
.allowExperimentalOptions(true)
Expand All @@ -85,12 +85,18 @@ public void initContext() {
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
}

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

@Before
public void resetOut() {
out.reset();
}

/** Only print warnings from the compiler if a test fails. */
Expand Down Expand Up @@ -307,10 +313,10 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() {

foo _ =
d_enso = Date.new 2024 12 15
d_js = js_date
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"
dt_js = js_date
str_enso = "Hello_World"
str_js = js_str
str_java = String.new "Hello_World"
Expand All @@ -335,13 +341,13 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() {

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

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

DebugValue ensoString = scope.getDeclaredValue("str_enso");
DebugValue javaString = scope.getDeclaredValue("str_java");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,23 @@ public static void disposeCtx() {

@Theory
public void testSortHandlesAllValues(Value value1, Value value2) {
Assume.assumeFalse(isNan(value1) || isNan(value2));
Value res = sortFunc.execute(value1, value2);
assertTrue(res.hasArrayElements());
assertEquals(2, res.getArraySize());
List<Value> resArray = readPolyglotArray(res);
// check that value1 is there unchanged on some index, and the same for value2
assertTrue(
"Sorted vector should contain the first value at any index",
invokeEquals(value1, resArray.get(0)) || invokeEquals(value1, resArray.get(1)));
assertTrue(
"Sorted vector should contain the second value at any index",
invokeEquals(value2, resArray.get(0)) || invokeEquals(value2, resArray.get(1)));
ContextUtils.executeInContext(
context,
() -> {
Assume.assumeFalse(isNan(value1) || isNan(value2));
Value res = sortFunc.execute(value1, value2);
assertTrue(res.hasArrayElements());
assertEquals(2, res.getArraySize());
List<Value> resArray = readPolyglotArray(res);
// check that value1 is there unchanged on some index, and the same for value2
assertTrue(
"Sorted vector should contain the first value at any index",
invokeEquals(value1, resArray.get(0)) || invokeEquals(value1, resArray.get(1)));
assertTrue(
"Sorted vector should contain the second value at any index",
invokeEquals(value2, resArray.get(0)) || invokeEquals(value2, resArray.get(1)));
return null;
});
}

private boolean isNan(Value value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.enso.interpreter.test.builtins;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

import java.util.ArrayList;
import java.util.List;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
import org.enso.interpreter.test.ValuesGenerator;
import org.enso.interpreter.test.ValuesGenerator.Language;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
* Gathers all the builtin objects from {@link ValuesGenerator}. From their types, gathers all their
* methods via their {@link org.enso.interpreter.runtime.scope.ModuleScope definition scope} and
* checks that {@link Value#canInvokeMember(String)} returns true.
*/
@RunWith(Parameterized.class)
public class BuiltinTypesExposeMethodsTest {
private static Context ctx;

private final Value type;

public BuiltinTypesExposeMethodsTest(Value type) {
this.type = type;
}

private static Context ctx() {
if (ctx == null) {
ctx = ContextUtils.createDefaultContext();
}
return ctx;
}

@Parameters(name = "{index}: {0}")
public static Iterable<Value> generateBuiltinObjects() {
var valuesGenerator = ValuesGenerator.create(ctx(), Language.ENSO);
var builtinTypes = new ArrayList<Value>();
ContextUtils.executeInContext(
ctx(),
() -> {
valuesGenerator.allTypes().stream()
.filter(
val -> {
var asType = getType(val);
return !shouldSkipType(asType);
})
.forEach(builtinTypes::add);
return null;
});
return builtinTypes;
}

private static Type getType(Value object) {
var unwrapped = ContextUtils.unwrapValue(ctx(), object);
return TypeOfNode.getUncached().findTypeOrNull(unwrapped);
}

@AfterClass
public static void disposeCtx() {
if (ctx != null) {
ctx.close();
ctx = null;
}
}

@Test
public void builtinExposeMethods() {
ContextUtils.executeInContext(
ctx(),
() -> {
assertThat(type, is(notNullValue()));
var typeDefScope = getType(type).getDefinitionScope();
var methodsDefinedInScope = typeDefScope.getMethodsForType(getType(type));
if (methodsDefinedInScope != null) {
for (var methodInScope : methodsDefinedInScope) {
var methodName = methodInScope.getName();
if (methodName.contains(".")) {
var items = methodName.split("\\.");
methodName = items[items.length - 1];
}
assertThat(
"Builtin type " + type + " should have members", type.hasMembers(), is(true));
assertThat(
"Member " + methodName + " should be present",
type.hasMember(methodName),
is(true));
assertThat(
"Member " + methodName + " should be invocable",
type.canInvokeMember(methodName),
is(true));
}
}
return null;
});
}

private static boolean shouldSkipType(Type type) {
if (type == null) {
return true;
}
if (!type.isBuiltin()) {
return true;
}
var builtins = ContextUtils.leakContext(ctx()).getBuiltins();
var typesToSkip =
List.of(
builtins.function(), builtins.dataflowError(), builtins.warning(), builtins.nothing());
var shouldBeSkipped = typesToSkip.stream().anyMatch(toSkip -> toSkip == type);
return shouldBeSkipped;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.enso.interpreter.test.builtins;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import java.io.ByteArrayOutputStream;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class BuiltinsJavaInteropTest {
private static Context ctx;
private static final ByteArrayOutputStream out = new ByteArrayOutputStream();

@BeforeClass
public static void prepareCtx() {
ctx = ContextUtils.createDefaultContext(out);
}

@AfterClass
public static void disposeCtx() {
ctx.close();
ctx = null;
}

@After
public void resetOutput() {
out.reset();
}

@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsObject() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_Object dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}

@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsLocalDate() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_LocalDate dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}

@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsValue() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_Value dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}
}
Loading
Loading