Skip to content

Commit

Permalink
Add base classes for basic, object, and array values to factorize code
Browse files Browse the repository at this point in the history
Make all message methods public to avoid visibility conflicts during
inheritance.
  • Loading branch information
HugoGGuerrier committed Dec 4, 2023
1 parent 41d9766 commit 8601955
Show file tree
Hide file tree
Showing 14 changed files with 471 additions and 524 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
package com.adacore.lkql_jit.built_ins.values;

import com.adacore.libadalang.Libadalang;
import com.adacore.lkql_jit.built_ins.values.interfaces.LKQLValue;
import com.adacore.lkql_jit.built_ins.values.bases.BasicLKQLValue;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
Expand All @@ -37,7 +37,7 @@
* all Libadalang objects will be wrapped in interop LKQL values (#154).
*/
@ExportLibrary(InteropLibrary.class)
public final class LKQLDepthNode implements LKQLValue {
public final class LKQLDepthNode extends BasicLKQLValue {

// ----- Attributes -----

Expand Down Expand Up @@ -69,7 +69,7 @@ public Libadalang.AdaNode getNode() {

/** Exported message to compare two LKQL depth nodes. */
@ExportMessage
static class IsIdenticalOrUndefined {
public static class IsIdenticalOrUndefined {
/** Compare two LKQL depth nodes. */
@Specialization
protected static TriState onNode(final LKQLDepthNode left, final LKQLDepthNode right) {
Expand All @@ -88,13 +88,13 @@ protected static TriState onOther(
/** Return the identity hash code for the given LKQL depth node. */
@ExportMessage
@CompilerDirectives.TruffleBoundary
static int identityHashCode(final LKQLDepthNode receiver) {
public static int identityHashCode(final LKQLDepthNode receiver) {
return System.identityHashCode(receiver);
}

/** Get the displayable string for the interop library. */
@ExportMessage
Object toDisplayString(@SuppressWarnings("unused") final boolean allowSideEffects) {
public String toDisplayString(@SuppressWarnings("unused") final boolean allowSideEffects) {
return this.node.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@

package com.adacore.lkql_jit.built_ins.values;

import com.adacore.lkql_jit.LKQLLanguage;
import com.adacore.lkql_jit.built_ins.values.interfaces.LKQLValue;
import com.adacore.lkql_jit.built_ins.values.bases.BasicLKQLValue;
import com.adacore.lkql_jit.nodes.expressions.Expr;
import com.adacore.lkql_jit.nodes.root_nodes.FunctionRootNode;
import com.adacore.lkql_jit.runtime.Closure;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
Expand All @@ -42,7 +40,7 @@

/** This class represents the function values in LKQL. */
@ExportLibrary(InteropLibrary.class)
public class LKQLFunction implements LKQLValue {
public class LKQLFunction extends BasicLKQLValue {

// ----- Attributes -----

Expand Down Expand Up @@ -137,21 +135,9 @@ public Expr getBody() {

// ----- Value methods -----

/** Tell the interop API that the value has an associated language. */
@ExportMessage
boolean hasLanguage() {
return true;
}

/** Give the LKQL language class to the interop library. */
@ExportMessage
Class<? extends TruffleLanguage<?>> getLanguage() {
return LKQLLanguage.class;
}

/** Exported message to compare two LKQL functions. */
@ExportMessage
static class IsIdenticalOrUndefined {
public static class IsIdenticalOrUndefined {
/** Compare two LKQL functions. */
@Specialization
protected static TriState onFunction(final LKQLFunction left, final LKQLFunction right) {
Expand All @@ -170,26 +156,27 @@ protected static TriState onOther(
/** Return the identity hash code for the given LKQL function. */
@ExportMessage
@CompilerDirectives.TruffleBoundary
static int identityHashCode(final LKQLFunction receiver) {
public static int identityHashCode(final LKQLFunction receiver) {
return System.identityHashCode(receiver);
}

/** Get the displayable string for the interop library. */
@Override
@ExportMessage
@CompilerDirectives.TruffleBoundary
Object toDisplayString(@SuppressWarnings("unused") final boolean allowSideEffects) {
public String toDisplayString(@SuppressWarnings("unused") final boolean allowSideEffects) {
return "function<" + this.name + ">";
}

/** Tell the interop library that the value is executable. */
@ExportMessage
boolean isExecutable() {
public boolean isExecutable() {
return true;
}

/** Inner class for the function execution. */
@ExportMessage
static class Execute {
public static class Execute {
/** Execute the function with the cached strategy. */
@Specialization(guards = "callTarget == directCallNode.getCallTarget()")
protected static Object doCached(
Expand All @@ -212,13 +199,13 @@ protected static Object doUncached(

/** Tell the interop library that this value has an executable name. */
@ExportMessage
boolean hasExecutableName() {
public boolean hasExecutableName() {
return true;
}

/** Return the function name to the interop library. */
@ExportMessage
Object getExecutableName() {
public Object getExecutableName() {
return this.name;
}

Expand All @@ -228,11 +215,4 @@ Object getExecutableName() {
public String lkqlDocumentation() {
return this.documentation;
}

// ----- Override methods -----

@Override
public String toString() {
return "function<" + this.name + ">";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,29 @@

package com.adacore.lkql_jit.built_ins.values;

import com.adacore.lkql_jit.LKQLLanguage;
import com.adacore.lkql_jit.built_ins.values.bases.ObjectLKQLValue;
import com.adacore.lkql_jit.built_ins.values.interfaces.LKQLValue;
import com.adacore.lkql_jit.built_ins.values.lists.LKQLList;
import com.adacore.lkql_jit.runtime.Cell;
import com.adacore.lkql_jit.utils.Constants;
import com.adacore.lkql_jit.utils.functions.ArrayUtils;
import com.adacore.lkql_jit.utils.functions.ObjectUtils;
import com.adacore.lkql_jit.utils.functions.StringUtils;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.utilities.TriState;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/** This class represents the namespaces in the LKQL language. */
@ExportLibrary(InteropLibrary.class)
public class LKQLNamespace extends DynamicObject implements LKQLValue {

// ----- Attributes -----

/** The dynamic object library to perform uncached operations on the LKQL namespace. */
private static final DynamicObjectLibrary objectLibrary = DynamicObjectLibrary.getUncached();
public class LKQLNamespace extends ObjectLKQLValue implements LKQLValue {

// ----- Constructors -----

Expand Down Expand Up @@ -85,43 +73,13 @@ public static LKQLNamespace createUncached(MaterializedFrame frame) {
// Return the new namespace
LKQLNamespace res = new LKQLNamespace(Shape.newBuilder().build());
for (String key : symbols.keySet()) {
objectLibrary.put(res, key, symbols.get(key));
uncachedObjectLibrary.put(res, key, symbols.get(key));
}
return res;
}

// ----- Instance methods -----

/**
* Get the value in the LKQL namespace at the given key with the uncached strategy. This method
* uses an uncached library so this is not design for performance critical usages.
*/
public Object getUncached(final Object key) {
return objectLibrary.getOrDefault(this, key, null);
}

/**
* Get the key array from the namespace value. This method uses an uncached library so this is
* not designed for performance critical usages.
*/
public Object[] keysUncached() {
return objectLibrary.getKeyArray(this);
}

// ----- Value methods -----

/** Tell the interop API that the value has an associated language. */
@ExportMessage
boolean hasLanguage() {
return true;
}

/** Give the LKQL language class to the interop library. */
@ExportMessage
Class<? extends TruffleLanguage<?>> getLanguage() {
return LKQLLanguage.class;
}

/** Exported message to compare two LKQL namespaces. */
@ExportMessage
static class IsIdenticalOrUndefined {
Expand All @@ -134,26 +92,8 @@ protected static TriState onLKQLNamespace(
@CachedLibrary("right") DynamicObjectLibrary rights,
@CachedLibrary(limit = Constants.DISPATCHED_LIB_LIMIT) InteropLibrary leftValues,
@CachedLibrary(limit = Constants.DISPATCHED_LIB_LIMIT) InteropLibrary rightValues) {
// Get the namespaces key sets and compare their size
Object[] leftKeys = lefts.getKeyArray(left);
Object[] rightKeys = rights.getKeyArray(right);
if (leftKeys.length != rightKeys.length) return TriState.FALSE;

// Then compare each value
for (Object key : leftKeys) {
if (!rights.containsKey(right, key)) return TriState.FALSE;
Object leftValue = lefts.getOrDefault(left, key, null);
Object rightValue = rights.getOrDefault(right, key, null);
if (leftValues.hasIdentity(leftValue)) {
if (!leftValues.isIdentical(leftValue, rightValue, rightValues))
return TriState.FALSE;
} else {
if (!ObjectUtils.equals(leftValue, rightValue)) return TriState.FALSE;
}
}

// If we get here, the namespace are equals
return TriState.TRUE;
return TriState.valueOf(
objectValueEquals(left, right, lefts, rights, leftValues, rightValues));
}

/** Do the comparison with another element. */
Expand All @@ -165,10 +105,10 @@ protected static TriState onOther(
}
}

/** Return the identity hash code for the given LKQL namespace. */
@ExportMessage
/** Get the identity hash code for the given namespace */
@CompilerDirectives.TruffleBoundary
static int identityHashCode(final LKQLNamespace receiver) {
@ExportMessage
public static int identityHashCode(LKQLNamespace receiver) {
return System.identityHashCode(receiver);
}

Expand Down Expand Up @@ -206,65 +146,4 @@ Object toDisplayString(
resultBuilder.append(")");
return resultBuilder.toString();
}

/** Tell the interop library that this value has members. */
@ExportMessage
boolean hasMembers() {
return true;
}

/**
* Get if the given member is in the receiver namespace. All members are readable but not
* modifiable.
*/
@ExportMessage
boolean isMemberReadable(
final String member, @CachedLibrary("this") DynamicObjectLibrary objectLibrary) {
return objectLibrary.containsKey(this, member);
}

/** Get the existing members for the receiver namespace. */
@ExportMessage
Object getMembers(
@SuppressWarnings("unused") final boolean includeInternal,
@CachedLibrary("this") DynamicObjectLibrary objectLibrary) {
return new LKQLList(objectLibrary.getKeyArray(this));
}

/** Get the value of the wanted member in the receiver namespace. */
@ExportMessage
Object readMember(
final String member, @CachedLibrary("this") DynamicObjectLibrary objectLibrary)
throws UnknownIdentifierException {
final Object result = objectLibrary.getOrDefault(this, member, null);
if (result == null) throw UnknownIdentifierException.create(member);
return result;
}

// ----- Override methods -----

@Override
public String toString() {
InteropLibrary interopLibrary = InteropLibrary.getUncached(this);
return (String) interopLibrary.toDisplayString(this);
}

@Override
public boolean equals(final Object o) {
if (o == this) return true;
if (!(o instanceof LKQLNamespace other)) return false;
InteropLibrary thisLibrary = InteropLibrary.getUncached(this);
InteropLibrary otherLibrary = InteropLibrary.getUncached(other);
return thisLibrary.isIdentical(this, other, otherLibrary);
}

@Override
public int hashCode() {
Object[] keys = this.keysUncached();
Object[] values = new Object[keys.length];
for (int i = 0; i < keys.length; i++) {
values[i] = this.getUncached(keys[i]);
}
return Arrays.hashCode(ArrayUtils.concat(keys, values));
}
}
Loading

0 comments on commit 8601955

Please sign in to comment.