Skip to content

Commit

Permalink
Introducing Meta.Type (#5956)
Browse files Browse the repository at this point in the history
Fixing #5768 and #5765 and co. Introducing `Meta.Type` and giving it the desired methods.

# Important Notes
`Type` is no longer a `Meta.Atom`, but it has a dedicated `Meta.Type` representation.
  • Loading branch information
JaroslavTulach authored Mar 17, 2023
1 parent 75fda33 commit b46be10
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 18 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@
and renamed them to `match`, `find`, `find_all` (respectively).][5721]
- [Updated `rename_columns` to new API. Added `first_row`, `second_row` and
`last_row` to Table types][5719]
- [Introducing `Meta.Type`.][5768]
- [Remove many regex compile flags; separated `match` into `match` and
`match_all`.][5785]
- [Aligned names of columns created by column operations.][5850]
Expand Down Expand Up @@ -516,6 +517,7 @@
[4078]: https://github.com/enso-org/enso/pull/4078
[4085]: https://github.com/enso-org/enso/pull/4085
[4097]: https://github.com/enso-org/enso/pull/4097
[4115]: https://github.com/enso-org/enso/pull/4115
[4120]: https://github.com/enso-org/enso/pull/4120
[4050]: https://github.com/enso-org/enso/pull/4050
[4072]: https://github.com/enso-org/enso/pull/4072
Expand All @@ -529,7 +531,7 @@
[5719]: https://github.com/enso-org/enso/pull/5719
[5721]: https://github.com/enso-org/enso/pull/5721
[5757]: https://github.com/enso-org/enso/pull/5757
[4115]: https://github.com/enso-org/enso/pull/4115
[5768]: https://github.com/enso-org/enso/pull/5768
[5774]: https://github.com/enso-org/enso/pull/5774
[5779]: https://github.com/enso-org/enso/pull/5779
[5785]: https://github.com/enso-org/enso/pull/5785
Expand Down
59 changes: 57 additions & 2 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,36 @@ import project.Nothing.Nothing
import project.Polyglot.Java

import project.Error.Error as Base_Error
import project.Polyglot.Polyglot as Base_Polyglot
import project.Polyglot as Base_Polyglot

from project.Data.Boolean import Boolean, True, False

type Type
## UNSTABLE
ADVANCED

Type meta-representation.

Arguments:
- value: The value of the type in the meta representation.
Value value

## UNSTABLE
ADVANCED

Returns a vector of `Meta.Constructor` for this type
constructors : Vector
constructors self =
Vector.from_polyglot_array (get_type_constructors self.value Meta.Constructor.Value)

## UNSTABLE
ADVANCED

Returns a vector of `Meta.Constructor` for this type
methods : Vector
methods self =
Vector.from_polyglot_array (get_type_methods self.value)

type Atom
## UNSTABLE
ADVANCED
Expand Down Expand Up @@ -209,6 +235,25 @@ get_atom_constructor atom = @Builtin_Method "Meta.get_atom_constructor"
get_atom_fields : Atom -> Array
get_atom_fields atom = @Builtin_Method "Meta.get_atom_fields"

## PRIVATE

Get the constructors for the provided type.

Arguments:
- typ: The type to obtain the constructors for.
- factory: function to use to wrap constructors in
get_type_constructors : Atom -> (Any -> Any) -> Array
get_type_constructors typ factory = @Builtin_Method "Meta.get_type_constructors"

## PRIVATE

Get the methods for the provided type.

Arguments:
- typ: The type to obtain the methods for.
get_type_methods : Atom -> Array
get_type_methods typ = @Builtin_Method "Meta.get_type_methods"

## PRIVATE

Get a textual representation of the language from which an object comes.
Expand Down Expand Up @@ -298,7 +343,8 @@ meta value = if is_atom value then Atom.Value value else
if is_polyglot value then Polyglot.Value value else
if is_unresolved_symbol value then Unresolved_Symbol.Value value else
if is_error value then Error.Value value.catch else
Primitive.Value value
if is_type value then Type.Value value.catch else
Primitive.Value value

## UNSTABLE
ADVANCED
Expand Down Expand Up @@ -392,6 +438,15 @@ is_atom value = @Builtin_Method "Meta.is_atom"
is_error : Any -> Boolean
is_error value = @Builtin_Method "Meta.is_error"

## PRIVATE

Checks if the provided value is a type.

Arguments:
- value: The value to check.
is_type : Any -> Boolean
is_type value = @Builtin_Method "Meta.is_type"

## PRIVATE

Checks if the provided value is a polyglot value.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.enso.interpreter.node.expression.builtin.meta;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.Array;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.type.TypesGen;

@BuiltinMethod(
type = "Meta",
name = "get_type_constructors",
description = "Gets the constructors of a type.",
autoRegister = false)
public abstract class GetTypeConstructorsNode extends Node {
static GetTypeConstructorsNode build() {
return GetTypeConstructorsNodeGen.create();
}

abstract Array execute(Object type, Object factory);

@Specialization
@CompilerDirectives.TruffleBoundary
Array allConstructors(Type type, AtomConstructor factory) {
var rawConstructors = type.getConstructors().values();
var rawResult = new Object[rawConstructors.size()];
int at = 0;
for (var cons : rawConstructors) {
var metaCons = factory.newInstance(cons);
rawResult[at++] = metaCons;
}
return new Array(rawResult);
}

@Fallback
@CompilerDirectives.TruffleBoundary
Array empty(Object type, Object factory) {
var ctx = EnsoContext.get(this);
var builtins = ctx.getBuiltins();
Atom payload;
if (TypesGen.isType(type)) {
payload = builtins.error().makeTypeError("AtomConstructor", factory, "factory");
} else {
payload = builtins.error().makeTypeError("Type", type, "type");
}
throw new PanicException(payload, this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.enso.interpreter.node.expression.builtin.meta;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.data.Array;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.PanicException;

@BuiltinMethod(
type = "Meta",
name = "get_type_methods",
description = "Gets the method names of a type.",
autoRegister = false)
public abstract class GetTypeMethodsNode extends Node {
static GetTypeMethodsNode build() {
return GetTypeMethodsNodeGen.create();
}

abstract Array execute(Object type);

@Specialization
@CompilerDirectives.TruffleBoundary
Array allMethods(Type type) {
var methodNames = type.getDefinitionScope().getMethods().get(type).keySet();
return new Array(methodNames.toArray());
}

@Fallback
@CompilerDirectives.TruffleBoundary
Array empty(Object type) {
var ctx = EnsoContext.get(this);
var builtins = ctx.getBuiltins();
Atom payload = builtins.error().makeTypeError("Type", type, "type");
throw new PanicException(payload, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.data.Type;

@BuiltinMethod(
type = "Meta",
Expand All @@ -13,6 +12,6 @@
autoRegister = false)
public class IsAtomNode extends Node {
boolean execute(@AcceptsError Object value) {
return value instanceof Atom || value instanceof Type;
return value instanceof Atom;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.enso.interpreter.node.expression.builtin.meta;

import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.data.Type;

@BuiltinMethod(
type = "Meta",
name = "is_type",
description = "Checks if the argument is a type",
autoRegister = false)
public class IsTypeNode extends Node {
boolean execute(@AcceptsError Object value) {
return value instanceof Type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
@ExportLibrary(TypesLibrary.class)
public class PanicException extends AbstractTruffleException {
final Object payload;
String cacheMessage;

/**
* Creates an instance of this class.
Expand All @@ -42,6 +43,12 @@ public PanicException(Object payload, Node location) {
throw new IllegalArgumentException("Only interop values are supported: " + payload);
}
this.payload = payload;
InteropLibrary library = InteropLibrary.getUncached();
try {
cacheMessage = library.asString(library.getExceptionMessage(this));
} catch (UnsupportedMessageException e) {
cacheMessage = TypeToDisplayTextNodeGen.getUncached().execute(payload);
}
}

/**
Expand All @@ -55,12 +62,7 @@ public Object getPayload() {

@Override
public String getMessage() {
InteropLibrary library = InteropLibrary.getUncached();
try {
return library.asString(library.getExceptionMessage(this));
} catch (UnsupportedMessageException e) {
return TypeToDisplayTextNodeGen.getUncached().execute(payload);
}
return cacheMessage;
}

@Override
Expand Down
43 changes: 36 additions & 7 deletions test/Tests/src/Semantic/Meta_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,46 @@ spec =
e_tpe . should_equal_type IOException
e_tpe . should_not_equal_type JException

Test.specify "fields of a Type" <|
Test.specify "constructors of Boolean" <|
typ = Boolean

Meta.is_atom typ . should_be_true
Meta.is_atom typ . should_be_false
meta_typ = Meta.meta typ
meta_typ . should_be_a Meta.Atom
fields = case meta_typ of
Meta.Atom.Value _ -> meta_typ.constructor.fields
_ -> Test.fail "Should be a Meta.Atom.Value: " + meta_typ.to_text
meta_typ . should_be_a Meta.Type
cons = case meta_typ of
Meta.Type.Value _ -> meta_typ.constructors
_ -> Test.fail "Should be a Meta.Type.Value: " + meta_typ.to_text

fields . should_equal []
cons.length . should_equal 2
cons.at 0 . should_be_a Meta.Constructor
cons.at 1 . should_be_a Meta.Constructor
cons . map (x -> x.name) . sort . should_equal [ "False", "True" ]

Test.specify "constructors of MyType" <|
typ = My_Type

Meta.is_atom typ . should_be_false
meta_typ = Meta.meta typ
meta_typ . should_be_a Meta.Type
cons = case meta_typ of
Meta.Type.Value _ -> meta_typ.constructors
_ -> Test.fail "Should be a Meta.Type.Value: " + meta_typ.to_text

cons.length . should_equal 1
cons.at 0 . should_be_a Meta.Constructor
cons . map (x -> x.name) . sort . should_equal [ "Value" ]

Test.specify "methods of MyType" <|
typ = My_Type

Meta.is_atom typ . should_be_false
meta_typ = Meta.meta typ
meta_typ . should_be_a Meta.Type
methods = case meta_typ of
_ : Meta.Type -> meta_typ.methods
_ -> Test.fail "Should be a Meta.Type: " + meta_typ.to_text

methods.sort . should_equal ['bar', 'baz', 'first_method', 'foo', 'my_method', 'other_method', 'second_method']

Test.specify "should correctly handle Java values" <|
java_meta = Meta.meta Random.new
Expand Down

0 comments on commit b46be10

Please sign in to comment.