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

Implement hasLanguage interop message for all enso objects #11538

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
02e77fc
EnsoObject is an abstract class, not an interface.
Akirathan Nov 12, 2024
3ab4f73
Implement public getters in BranchResult
Akirathan Nov 12, 2024
5c5b0b7
Fix compilation of EnsoFile
Akirathan Nov 12, 2024
0e48f21
Add test that all enso values must have language
Akirathan Nov 12, 2024
aa419c0
Revert EnsoException - remove
Akirathan Nov 12, 2024
b30f396
DataflowError and PanicException implement hasLanguage and getLanguage
Akirathan Nov 12, 2024
613f380
DataflowError is not EnsoObject - change signatures in some builtins
Akirathan Nov 12, 2024
c5508db
Merge branch 'develop' into wip/akirathan/enso-object-abstract
Akirathan Nov 13, 2024
c682df0
Add more members to Module.isMemberInvocable.
Akirathan Nov 13, 2024
993399a
Revert "DataflowError and PanicException implement hasLanguage and ge…
Akirathan Nov 13, 2024
130180c
Update the test - test only non-primitive and non-exception values
Akirathan Nov 13, 2024
bea21a6
Fix indexes in CodeLocationsTest
Akirathan Nov 13, 2024
a59a72a
Add more members to Function.isMemberInvocable
Akirathan Nov 13, 2024
1140546
EnsoObject.toDisplayString delegates to toString method
Akirathan Nov 14, 2024
7fa2022
EnsoObject.toDisplayString is behind TruffleBoundary
Akirathan Nov 14, 2024
f0dae47
Warning exports InteropLibrary which delegates to value.
Akirathan Nov 14, 2024
5955ff3
WithWarnings needs to explicitly export toDisplayString.
Akirathan Nov 14, 2024
db225ed
EnsoObject.toDisplayString just throws AssertionError
Akirathan Nov 14, 2024
06d1d4c
AssertionError is behind TruffleBoundary
Akirathan Nov 14, 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 @@ -9,12 +9,14 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.oracle.truffle.api.interop.InteropLibrary;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.enso.common.MethodNames;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.type.ConstantsGen;
Expand Down Expand Up @@ -272,6 +274,33 @@ public void numbersAreEitherIntegerOrFloat() throws Exception {
}
}

/**
* Primitive values and exceptions currently don't have an associated language.
*
* <p>TODO[PM]: Will be implemented in https://github.com/enso-org/enso/pull/11468
*/
@Test
public void allEnsoNonPrimitiveValuesHaveLanguage() throws Exception {
var gen = ValuesGenerator.create(ctx, Language.ENSO);
Predicate<Value> isPrimitiveOrException =
(val) -> val.fitsInInt() || val.fitsInDouble() || val.isBoolean() || val.isException();
var nonPrimitiveValues =
gen.allValues().stream().filter(isPrimitiveOrException.negate()).toList();
var interop = InteropLibrary.getUncached();
ContextUtils.executeInContext(
ctx,
() -> {
for (var value : nonPrimitiveValues) {
var unwrappedValue = ContextUtils.unwrapValue(ctx, value);
assertThat(
"Value " + unwrappedValue + " should have associated language",
interop.hasLanguage(unwrappedValue),
is(true));
}
return null;
});
}

@Test
public void compareQualifiedAndSimpleTypeName() throws Exception {
var g = generator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,38 @@ class CodeLocationsTest extends InterpreterTest {

"be correct in simple arithmetic expressions" in
withLocationsInstrumenter { instrumenter =>
val code = "main = 2 + 45 * 20"
instrumenter.assertNodeExists(7, 11, classOf[ApplicationNode])
instrumenter.assertNodeExists(11, 7, classOf[ApplicationNode])
instrumenter.assertNodeExists(11, 2, classOf[LiteralNode])
val code =
"""from Standard.Base.Data.Numbers import all
|main = (2 + 45) * 20
|""".stripMargin.replace("\r", "")
instrumenter.assertNodeExists(50, 13, classOf[ApplicationNode])
instrumenter.assertNodeExists(51, 6, classOf[ApplicationNode])
instrumenter.assertNodeExists(51, 1, classOf[LiteralNode])
eval(code)
()
}

"be correct with parenthesized expressions" in
withLocationsInstrumenter { instrumenter =>
val code = "main = (2 + 45) * 20"
instrumenter.assertNodeExists(7, 13, classOf[ApplicationNode])
instrumenter.assertNodeExists(8, 6, classOf[ApplicationNode])
val code =
"""from Standard.Base.Data.Numbers import all
|main = (2 + 45) * 20
|""".stripMargin.replace("\r", "")
instrumenter.assertNodeExists(50, 13, classOf[ApplicationNode])
instrumenter.assertNodeExists(51, 6, classOf[ApplicationNode])
eval(code)
()
}

"be correct in applications and method calls" in
withLocationsInstrumenter { instrumenter =>
val code =
"""import Standard.Base.Data.List.List
|import Standard.Base.Any.Any
"""from Standard.Base import all
|
|main = (2-2 == 0).if_then_else (List.Cons 5 6) 0
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(73, 41, classOf[ApplicationNode])
instrumenter.assertNodeExists(98, 13, classOf[ApplicationNode])
instrumenter.assertNodeExists(38, 41, classOf[ApplicationNode])
instrumenter.assertNodeExists(63, 13, classOf[ApplicationNode])
eval(code)
()
}
Expand All @@ -69,18 +74,18 @@ class CodeLocationsTest extends InterpreterTest {
withLocationsInstrumenter { instrumenter =>
val code =
"""
|import Standard.Base.IO
|from Standard.Base import all
|
|main =
| x = 2 + 2 * 2
| y = x * x
| IO.println y
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(37, 13, classOf[AssignmentNode])
instrumenter.assertNodeExists(55, 9, classOf[AssignmentNode])
instrumenter.assertNodeExists(59, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(63, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(80, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(43, 13, classOf[AssignmentNode])
instrumenter.assertNodeExists(61, 9, classOf[AssignmentNode])
instrumenter.assertNodeExists(65, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(69, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(86, 1, classOf[ReadLocalVariableNode])
eval(code)
()
}
Expand All @@ -89,8 +94,7 @@ class CodeLocationsTest extends InterpreterTest {
withLocationsInstrumenter { instrumenter =>
val code =
"""
|import Standard.Base.Nothing
|import Standard.Base.IO
|from Standard.Base import all
|
|Nothing.method =
| foo = a -> b ->
Expand All @@ -102,10 +106,10 @@ class CodeLocationsTest extends InterpreterTest {
|main = Nothing.method
|""".stripMargin.linesIterator.mkString("\n")

instrumenter.assertNodeExists(137, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(155, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(151, 7, classOf[ApplicationNode])
instrumenter.assertNodeExists(163, 9, classOf[ApplicationNode])
instrumenter.assertNodeExists(114, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(132, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(128, 7, classOf[ApplicationNode])
instrumenter.assertNodeExists(140, 9, classOf[ApplicationNode])
eval(code)
()
}
Expand All @@ -114,7 +118,7 @@ class CodeLocationsTest extends InterpreterTest {
withLocationsInstrumenter { instrumenter =>
val code =
"""
|import Standard.Base.Data.List.List
|from Standard.Base import all
|
|main =
| x = List.Cons 1 2
Expand All @@ -131,18 +135,19 @@ class CodeLocationsTest extends InterpreterTest {
|
| foo x + foo y
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(127, 0, 114, 1, classOf[CaseNode])
instrumenter.assertNodeExists(178, 7, classOf[ApplicationNode])
instrumenter.assertNodeExists(198, 9, classOf[AssignmentNode])
instrumenter.assertNodeExists(235, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(121, 0, 114, 1, classOf[CaseNode])
instrumenter.assertNodeExists(172, 7, classOf[ApplicationNode])
instrumenter.assertNodeExists(192, 9, classOf[AssignmentNode])
instrumenter.assertNodeExists(229, 5, classOf[ApplicationNode])
eval(code)
()
}

"be correct for lambdas" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base import all
|
|main =
| f = a -> b -> a + b
| g = x -> y ->
Expand All @@ -151,39 +156,41 @@ class CodeLocationsTest extends InterpreterTest {
|
| f 1 (g 2 3)
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(16, 15, classOf[CreateFunctionNode])
instrumenter.assertNodeExists(40, 42, classOf[CreateFunctionNode])
instrumenter.assertNodeExists(46, 15, classOf[CreateFunctionNode])
instrumenter.assertNodeExists(70, 42, classOf[CreateFunctionNode])
eval(code)
()
}

"be correct for defaulted arguments" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base import all
|
|main =
| bar = x -> x + x * x
| foo = x -> (y = bar x) -> x + y
| foo 0
|""".stripMargin.linesIterator.mkString("\n")

instrumenter.assertNodeExists(53, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(53, 3, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(57, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(93, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(93, 1, classOf[ReadLocalVariableNode])
instrumenter.assertNodeExists(97, 1, classOf[ReadLocalVariableNode])
eval(code)
()
}

"be correct for lazy arguments" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base import all
|
|main =
| bar = a -> ~b -> ~c -> b
|
| bar 0 10 0
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(35, 1, classOf[ForceNode])
instrumenter.assertNodeExists(65, 1, classOf[ForceNode])
eval(code)
()
}
Expand All @@ -198,19 +205,21 @@ class CodeLocationsTest extends InterpreterTest {
"be correct for negated expressions" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base import all
|
|main =
| f = 1
| -f
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(22, 1, 2, 1, classOf[ApplicationNode])
instrumenter.assertNodeExists(52, 1, 2, 1, classOf[ApplicationNode])
eval(code)
}

"be correct in sugared method definitions" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base.Data.Numbers import all
|
|Test.foo a b = a * b - a
|
|main = Test.foo 2 3
Expand All @@ -221,36 +230,42 @@ class CodeLocationsTest extends InterpreterTest {
val method = mod.getMethod(tpe, "foo").get
method.value.invokeMember(
MethodNames.Function.GET_SOURCE_START
) shouldEqual 1
) should (
equal(44) or
equal(45)
)
method.value.invokeMember(
MethodNames.Function.GET_SOURCE_LENGTH
) should (
equal(24) or
equal(25)
)

instrumenter.assertNodeExists(16, 9, classOf[ApplicationNode])
instrumenter.assertNodeExists(59, 9, classOf[ApplicationNode])

eval(code)
}

"be correct in sugared function definitions" in
withLocationsInstrumenter { instrumenter =>
val code =
"""|main =
"""|from Standard.Base import all
|
|main =
| f a b = a - b
| f 10 20
|""".stripMargin.linesIterator.mkString("\n")

instrumenter.assertNodeExists(11, 1, 13, 0, classOf[AssignmentNode])
instrumenter.assertNodeExists(19, 1, 5, 0, classOf[ApplicationNode])
instrumenter.assertNodeExists(41, 1, 13, 0, classOf[AssignmentNode])
instrumenter.assertNodeExists(49, 1, 5, 0, classOf[ApplicationNode])
eval(code)
}

"be correct in the presence of comments" in
withLocationsInstrumenter { instrumenter =>
val code =
"""
"""from Standard.Base import all
|
|# this is a comment
|#this too
|## But this is a doc.
Expand All @@ -260,8 +275,8 @@ class CodeLocationsTest extends InterpreterTest {
| # perform the addition
| x + y # the addition is performed here
|""".stripMargin.linesIterator.mkString("\n")
instrumenter.assertNodeExists(82, 1, classOf[LiteralNode])
instrumenter.assertNodeExists(164, 5, classOf[ApplicationNode])
instrumenter.assertNodeExists(112, 1, classOf[LiteralNode])
instrumenter.assertNodeExists(194, 5, classOf[ApplicationNode])
eval(code) shouldEqual 3
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public boolean isInstrumentable() {

/** A simple value class for function call information. */
@ExportLibrary(InteropLibrary.class)
public static final class FunctionCall implements EnsoObject {
public static final class FunctionCall extends EnsoObject {
private final Function function;
private final State state;
private final @CompilerDirectives.CompilationFinal(dimensions = 1) Object[] arguments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.data.EnsoObject;

record BranchResult(boolean isMatched, Object result) implements EnsoObject {
final class BranchResult extends EnsoObject {
private final boolean isMatched;
private final Object result;

BranchResult(boolean isMatched, Object result) {
this.isMatched = isMatched;
this.result = result;
}

public boolean isMatched() {
return isMatched;
}

public Object result() {
return result;
}

static BranchResult failure(Node node) {
return new BranchResult(false, EnsoContext.get(node).getBuiltins().nothing());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Object doExecute(
}

@ExportLibrary(InteropLibrary.class)
static final class HoleInAtom implements EnsoObject {
static final class HoleInAtom extends EnsoObject {
Atom result;
int index;
Function function;
Expand Down Expand Up @@ -140,7 +140,8 @@ Object invokeMember(
}

@ExportMessage
String toDisplayString(boolean pure) {
@Override
public String toDisplayString(boolean pure) {
return "Meta.atom_with_hole";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.enso.interpreter.runtime.instrument.Timer;
import org.enso.polyglot.debugger.IdExecutionService;

final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
final class Instrumentor extends EnsoObject implements IdExecutionService.Callbacks {

private final IdExecutionService service;
private final RootCallTarget target;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

/** Represents a source module with a known location. */
@ExportLibrary(InteropLibrary.class)
public final class Module implements EnsoObject {
public final class Module extends EnsoObject {
private ModuleSources sources;
private QualifiedName name;
private ModuleScope.Builder scopeBuilder;
Expand Down Expand Up @@ -772,6 +772,10 @@ boolean hasMembers() {
boolean isMemberInvocable(String member) {
return member.equals(MethodNames.Module.GET_METHOD)
|| member.equals(MethodNames.Module.REPARSE)
|| member.equals(MethodNames.Module.GATHER_IMPORT_STATEMENTS)
|| member.equals(MethodNames.Module.GENERATE_DOCS)
|| member.equals(MethodNames.Module.GET_NAME)
|| member.equals(MethodNames.Module.GET_TYPE)
|| member.equals(MethodNames.Module.SET_SOURCE)
|| member.equals(MethodNames.Module.SET_SOURCE_FILE)
|| member.equals(MethodNames.Module.GET_ASSOCIATED_TYPE)
Expand Down
Loading
Loading