diff --git a/distribution/std-lib/Base/src/Error/Extensions.enso b/distribution/std-lib/Base/src/Error/Extensions.enso index 9acad84e319..6ccd31c2a30 100644 --- a/distribution/std-lib/Base/src/Error/Extensions.enso +++ b/distribution/std-lib/Base/src/Error/Extensions.enso @@ -3,4 +3,4 @@ from Base import all ## Returns the method name of the method that could not be found. No_Such_Method_Error.method_name : Text No_Such_Method_Error.method_name = - Meta.get_unresolved_symbol_name this.symbol + Meta.meta this.symbol . name diff --git a/distribution/std-lib/Base/src/Main.enso b/distribution/std-lib/Base/src/Main.enso index 13b1ef40c9f..d6d81eca426 100644 --- a/distribution/std-lib/Base/src/Main.enso +++ b/distribution/std-lib/Base/src/Main.enso @@ -4,11 +4,13 @@ import Base.Number.Extensions import Base.Text.Extensions import Base.System.File import Base.Meta.Enso_Project +import Base.Meta.Meta import Base.Error.Extensions import Base.Polyglot.Java -from Builtins import Unit, Number, Integer, Any, True, False +from Builtins import Unit, Number, Integer, Any, True, False, Cons -from Builtins export all +export Base.Meta.Meta +from Builtins export all hiding Meta from Base.Meta.Enso_Project export all from Base.List export Nil, Cons @@ -68,3 +70,26 @@ type Math to its diameter. Math.pi : Decimal Math.pi = 3.141592653589793 + +## Generic equality of arbitrary values. +Any.== : Any -> Boolean +Any.== that = if Meta.is_same_object this that then True else + this_meta = Meta.meta this + that_meta = Meta.meta that + case Cons this_meta that_meta of + Cons (Meta.Atom _) (Meta.Atom _) -> + c_1 = this_meta.constructor + c_2 = that_meta.constructor + if not (Meta.is_same_object c_1 c_2) then False else + f_1 = this_meta.fields + f_2 = that_meta.fields + 0.upto f_1.length . every i-> (f_1.at i) == (f_2.at i) + Cons (Meta.Error _) (Meta.Error _) -> this_meta.payload == that_meta.payload + Cons (Meta.Polyglot o_1) (Meta.Polyglot o_2) -> + langs_match = this_meta.language == Meta.Java && that_meta.language == Meta.Java + if not langs_match then False else o_1.equals [o_2] + ## Constructor comparison is covered by the identity equality. + Primitive objects should define their own equality. + Therefore, there is no more cases to handle in this method. + _ -> False + diff --git a/distribution/std-lib/Base/src/Meta/Meta.enso b/distribution/std-lib/Base/src/Meta/Meta.enso new file mode 100644 index 00000000000..843e24edba9 --- /dev/null +++ b/distribution/std-lib/Base/src/Meta/Meta.enso @@ -0,0 +1,88 @@ +from Base import all +import Builtins + +## Represents a polyglot language. +type Language + ## The Java laguage. + type Java + ## Unknown language. + type Unknown + +## A meta-representation of a runtime value. + + ! Warning + The functionality contained in this module exposes certain implementation + details of the language. As such, the API has no stability guarantees and + is subject to change as the Enso interpreter evolves. +type Meta + ## An Atom meta-representation. + type Atom value + ## A constructor meta-representation. + type Constructor value + ## A primitive value meta-prepresentation. + type Primitive value + ## An unresolved symbol meta-representation. + type Unresolved_Symbol value + ## An error meta-representation. + type Error value + ## A polyglot value meta-representation. + type Polyglot value + +## Returns a vector of field values of the given atom. +Atom.fields : Vector +Atom.fields = Vector (Builtins.Meta.get_atom_fields this.value) + +## Returns a constructor value of the given atom. +Atom.constructor : Any +Atom.constructor = Builtins.Meta.get_atom_constructor this.value + +## Returns a new unresolved symbol with its name changed to the provided + argument. +Unresolved_Symbol.rename : Text -> Any +Unresolved_Symbol.rename new_name = + Builtins.Meta.create_unresolved_symbol new_name this.scope + +## Returns the name of an unresolved symbol. +Unresolved_Symbol.name : Text +Unresolved_Symbol.name = Builtins.Meta.get_unresolved_symbol_name this.value + +## Returns the definition scope of an unresolved symbol. +Unresolved_Symbol.scope : Any +Unresolved_Symbol.scope = Builtins.Meta.get_unresolved_symbol_scope this.value + +## Returns the payload carried by an error value. +Error.payload : Any +Error.payload = this.value.catch e->e + +## Returns a vector of field names defined by a constructor. +Constructor.fields : Vector +Constructor.fields = Vector (Builtins.Meta.get_constructor_fields this.value) + +## Returns the name of a constructor. +Constructor.name : Text +Constructor.name = Builtins.Meta.get_constructor_name this.value + +## Creates a new atom of the given constructor, with field values provided + in the `fields` vector. +Constructor.new : Vector -> Any +Constructor.new fields = Builtins.Meta.new_atom this.value fields.to_array + +## Returns the language of a polyglot value. +Polyglot.get_language : Language +Polyglot.get_language = + lang_str = Builtins.Meta.get_polyglot_language + if lang_str == "java" then Java else Unknown + +## Returns a meta-representation of a given runtime entity. +meta : Any -> Meta +meta value = if Builtins.Meta.is_atom value then Atom value else + if Builtins.Meta.is_constructor value then Constructor value else + if Builtins.Meta.is_polyglot value then Polyglot value else + if Builtins.Meta.is_unresolved_symbol value then Unresolved_Symbol value else + if Builtins.Meta.is_error value then Error value else + Primitive value + +## Checks whether two objects are represented by the same underlying reference. + This is a power-user feature, that is only useful for certain optimizations. +is_same_object : Any -> Any -> Boolean +is_same_object value_1 value_2 = Builtins.Meta.is_same_object value_1 value_2 diff --git a/distribution/std-lib/Base/src/Number/Extensions.enso b/distribution/std-lib/Base/src/Number/Extensions.enso index b8073482392..d0f310316b5 100644 --- a/distribution/std-lib/Base/src/Number/Extensions.enso +++ b/distribution/std-lib/Base/src/Number/Extensions.enso @@ -83,3 +83,11 @@ Integer.upto n = Range this n Returns `True` when `this` and `that` are at most `epsilon` apart. Number.equals : Number -> Number -> Boolean Number.equals that epsilon=0.0 = (this - that).abs <= epsilon + +## Returns the smaller value of `this` and `that`. +Number.min : Number -> Number +Number.min that = if this < that then this else that + +## Returns the larger value of `this` and `that`. +Number.max : Number -> Number +Number.max that = if this > that then this else that diff --git a/distribution/std-lib/Base/src/Vector.enso b/distribution/std-lib/Base/src/Vector.enso index 4ffa7b2be9c..2b4c6cb857c 100644 --- a/distribution/std-lib/Base/src/Vector.enso +++ b/distribution/std-lib/Base/src/Vector.enso @@ -197,6 +197,22 @@ type Vector take_right count = if count >= this.length then this else this.drop (this.length - count) + ## Performs a pair-wise operation passed in `function` on consecutive + elements of `this` and `that`. + The result of this function is a vector of length being the shorter of + `this` and `that`, containing results of calling `function`. + > Example + To pairwise-sum two vectors: + zip [1, 2, 3] [4, 5, 6] (+) == [5, 7, 9] + When the `function` is not provided, it defaults to creating a pair + of both elements: + zip [1, 2, 3] [4, 5, 6] == [[1, 4], [2, 5], [3, 6]] + zip : Vector -> (Any -> Any -> Any) -> Vector + zip that function=[_,_] = + len = min this.length that.length + Vector.new len i-> function (this.at i) (that.at i) + + ## A builder type for Enso vectors. A vector builder is a mutable data structure, that allows to gather a diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java index 36291696649..af733699512 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java @@ -434,6 +434,8 @@ public abstract class MethodResolverNode extends Node { return context.getBuiltins().polyglot().getPolyglotToTextFunction(); } else if (symbol.getName().equals("catch")) { return symbol.resolveFor(context.getBuiltins().any()); + } else if (symbol.getName().equals("==")) { + return symbol.resolveFor(context.getBuiltins().any()); } else { return context.getBuiltins().polyglot().buildPolyglotMethodDispatch(symbol); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomConstructorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomConstructorNode.java new file mode 100644 index 00000000000..d022755818e --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomConstructorNode.java @@ -0,0 +1,17 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.callable.atom.Atom; +import org.enso.interpreter.runtime.callable.atom.AtomConstructor; +import org.enso.interpreter.runtime.data.Array; + +@BuiltinMethod( + type = "Meta", + name = "get_atom_constructor", + description = "Gets the constructor of an atom.") +public class GetAtomConstructorNode extends Node { + AtomConstructor execute(Object _this, Atom atom) { + return atom.getConstructor(); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomFieldsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomFieldsNode.java new file mode 100644 index 00000000000..38c304f232a --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAtomFieldsNode.java @@ -0,0 +1,18 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; +import org.enso.interpreter.runtime.callable.atom.Atom; +import org.enso.interpreter.runtime.data.Array; +import org.enso.interpreter.runtime.scope.ModuleScope; + +@BuiltinMethod( + type = "Meta", + name = "get_atom_fields", + description = "Gets the fields of an unresolved atom.") +public class GetAtomFieldsNode extends Node { + Array execute(Object _this, Atom atom) { + return new Array(atom.getFields()); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorFieldNamesNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorFieldNamesNode.java new file mode 100644 index 00000000000..3f90049852b --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorFieldNamesNode.java @@ -0,0 +1,24 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; +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.text.Text; + +@BuiltinMethod( + type = "Meta", + name = "get_constructor_fields", + description = "Gets the field names of a constructor.") +public class GetConstructorFieldNamesNode extends Node { + Array execute(Object _this, AtomConstructor atom_constructor) { + ArgumentDefinition[] fields = atom_constructor.getFields(); + Object[] result = new Object[fields.length]; + for (int i = 0; i < fields.length; i++) { + result[i] = Text.create(fields[i].getName()); + } + return new Array(result); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorNameNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorNameNode.java new file mode 100644 index 00000000000..8127d2d29d5 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetConstructorNameNode.java @@ -0,0 +1,17 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.callable.atom.Atom; +import org.enso.interpreter.runtime.callable.atom.AtomConstructor; +import org.enso.interpreter.runtime.data.text.Text; + +@BuiltinMethod( + type = "Meta", + name = "get_constructor_name", + description = "Gets the name of a constructor.") +public class GetConstructorNameNode extends Node { + Text execute(Object _this, AtomConstructor atom_constructor) { + return Text.create(atom_constructor.getName()); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetPolyglotLanguageNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetPolyglotLanguageNode.java new file mode 100644 index 00000000000..74a07566e3b --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetPolyglotLanguageNode.java @@ -0,0 +1,34 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.CachedContext; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.Language; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.data.text.Text; + +@BuiltinMethod( + type = "Meta", + name = "get_polyglot_language", + description = "Returns a text representation of a language of origin of a given value.") +public abstract class GetPolyglotLanguageNode extends Node { + static GetPolyglotLanguageNode build() { + return GetPolyglotLanguageNodeGen.create(); + } + + private final Text java = Text.create("java"); + private final Text unknown = Text.create("unknown"); + + abstract Text execute(Object _this, Object value); + + @Specialization + Text doExecute(Object _this, Object value, @CachedContext(Language.class) Context context) { + if (context.getEnvironment().isHostObject(value)) { + return java; + } else { + return unknown; + } + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomConstructorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomConstructorNode.java new file mode 100644 index 00000000000..d9aee13010e --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomConstructorNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "is_atom_constructor", + description = "Checks if the argument is a constructor.") +public class IsAtomConstructorNode extends Node { + boolean execute(Object _this, Object value) { + return TypesGen.isAtomConstructor(value); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomNode.java new file mode 100644 index 00000000000..4d9f1025cb7 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsAtomNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "is_atom", + description = "Checks if the argument is an atom") +public class IsAtomNode extends Node { + boolean execute(Object _this, Object value) { + return TypesGen.isAtom(value); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsErrorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsErrorNode.java new file mode 100644 index 00000000000..50065bf543e --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsErrorNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "is_error", + description = "Checks if the argument is an error.") +public class IsErrorNode extends Node { + boolean execute(Object _this, Object value) { + return TypesGen.isRuntimeError(value); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsPolyglotNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsPolyglotNode.java new file mode 100644 index 00000000000..90d96b908c8 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsPolyglotNode.java @@ -0,0 +1,23 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.dsl.CachedContext; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.Language; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod(type = "Meta", name = "is_polyglot", description = "Checks if the argument is a polyglot value.") +public abstract class IsPolyglotNode extends Node { + static IsPolyglotNode build() { + return IsPolyglotNodeGen.create(); + } + + abstract boolean execute(Object _this, Object value); + + @Specialization + boolean doExecute(Object _this, Object value, @CachedContext(Language.class) Context context) { + return context.getEnvironment().isHostObject(value); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsSameObjectNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsSameObjectNode.java new file mode 100644 index 00000000000..f4c048b75a8 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsSameObjectNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "is_same_object", + description = "Checks if the two arguments share an underlying reference.") +public class IsSameObjectNode extends Node { + boolean execute(Object _this, Object value_1, Object value_2) { + return value_1 == value_2; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsUnresolvedSymbolNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsUnresolvedSymbolNode.java new file mode 100644 index 00000000000..c4275eb8566 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsUnresolvedSymbolNode.java @@ -0,0 +1,15 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "is_unresolved_symbol", + description = "Checks if the argument is an unresolved symbol.") +public class IsUnresolvedSymbolNode extends Node { + boolean execute(Object _this, Object value) { + return TypesGen.isUnresolvedSymbol(value); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java new file mode 100644 index 00000000000..b1d42bd2a21 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/NewAtomInstanceNode.java @@ -0,0 +1,18 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +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.type.TypesGen; + +@BuiltinMethod( + type = "Meta", + name = "new_atom", + description = "Creates a new atom with given constructor and fields.") +public class NewAtomInstanceNode extends Node { + Atom execute(Object _this, AtomConstructor constructor, Array fields) { + return constructor.newInstance(fields.getItems()); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Meta.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Meta.java index 7abdcb8e00a..130d807e3c3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Meta.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Meta.java @@ -1,9 +1,7 @@ package org.enso.interpreter.runtime.builtin; import org.enso.interpreter.Language; -import org.enso.interpreter.node.expression.builtin.meta.CreateUnresolvedSymbolMethodGen; -import org.enso.interpreter.node.expression.builtin.meta.GetUnresolvedSymbolNameMethodGen; -import org.enso.interpreter.node.expression.builtin.meta.GetUnresolvedSymbolScopeMethodGen; +import org.enso.interpreter.node.expression.builtin.meta.*; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.scope.ModuleScope; @@ -20,6 +18,9 @@ public class Meta { AtomConstructor meta = new AtomConstructor("Meta", scope).initializeFields(); scope.registerConstructor(meta); + + scope.registerMethod( + meta, "is_unresolved_symbol", IsUnresolvedSymbolMethodGen.makeFunction(language)); scope.registerMethod( meta, "get_unresolved_symbol_name", @@ -30,5 +31,25 @@ public class Meta { GetUnresolvedSymbolScopeMethodGen.makeFunction(language)); scope.registerMethod( meta, "create_unresolved_symbol", CreateUnresolvedSymbolMethodGen.makeFunction(language)); + + scope.registerMethod(meta, "is_constructor", IsAtomConstructorMethodGen.makeFunction(language)); + scope.registerMethod( + meta, "get_constructor_name", GetConstructorNameMethodGen.makeFunction(language)); + scope.registerMethod( + meta, "get_constructor_fields", GetConstructorFieldNamesMethodGen.makeFunction(language)); + scope.registerMethod(meta, "new_atom", NewAtomInstanceMethodGen.makeFunction(language)); + + + scope.registerMethod(meta, "is_atom", IsAtomMethodGen.makeFunction(language)); + scope.registerMethod(meta, "get_atom_fields", GetAtomFieldsMethodGen.makeFunction(language)); + scope.registerMethod( + meta, "get_atom_constructor", GetAtomConstructorMethodGen.makeFunction(language)); + + scope.registerMethod(meta, "is_error", IsErrorMethodGen.makeFunction(language)); + + scope.registerMethod(meta, "is_polyglot", IsPolyglotMethodGen.makeFunction(language)); + scope.registerMethod(meta, "get_polyglot_language", GetPolyglotLanguageMethodGen.makeFunction(language)); + + scope.registerMethod(meta, "is_same_object", IsSameObjectMethodGen.makeFunction(language)); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/AtomConstructor.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/AtomConstructor.java index 21cb6fc4b0a..2ec114be9f3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/AtomConstructor.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/atom/AtomConstructor.java @@ -196,8 +196,18 @@ public class AtomConstructor implements TruffleObject { return newInstance(arguments); } + @ExportMessage + String toDisplayString(boolean allowSideEffects) { + return "Constructor<" + name + ">"; + } + /** @return the fully qualified name of this constructor. */ public QualifiedName getQualifiedName() { return definitionScope.getModule().getName().createChild(getName()); } + + /** @return the fields defined by this constructor. */ + public ArgumentDefinition[] getFields() { + return constructorFunction.getSchema().getArgumentInfos(); + } } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/lint/ShadowedPatternFields.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/lint/ShadowedPatternFields.scala index df9510e8951..eb245b5d939 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/lint/ShadowedPatternFields.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/lint/ShadowedPatternFields.scala @@ -148,10 +148,12 @@ case object ShadowedPatternFields extends IRPass { name = IR.Name.Blank(location = name.location) ) .addDiagnostic(warning) - } else { + } else if (!name.isInstanceOf[IR.Name.Blank]) { lastSeen(name.name) = named seenNames += name.name named + } else { + named } case cons @ Pattern.Constructor(_, fields, _, _, _) => val newFields = fields.reverse.map(go(_, seenNames)).reverse diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala index bbcd76efe29..470a2a0fb97 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala @@ -152,6 +152,10 @@ case object LambdaConsolidate extends IRPass { val (processedArgList, newBody) = computeReplacedExpressions(newArgNames, lastBody, usageIdsForShadowed) + val consolidatedArgs = processedArgList.map( + _.mapExpressions(runExpression(_, inlineContext)) + ) + val newLocation = chainedLambdas.head.location match { case Some(location) => Some( @@ -167,7 +171,7 @@ case object LambdaConsolidate extends IRPass { } lam.copy( - arguments = processedArgList, + arguments = consolidatedArgs, body = runExpression(newBody, inlineContext), location = newLocation, canBeTCO = chainedLambdas.last.canBeTCO diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/optimise/LambdaConsolidateTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/optimise/LambdaConsolidateTest.scala index f06f30239ca..0307df26681 100644 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/pass/optimise/LambdaConsolidateTest.scala +++ b/engine/runtime/src/test/scala/org/enso/compiler/test/pass/optimise/LambdaConsolidateTest.scala @@ -198,6 +198,17 @@ class LambdaConsolidateTest extends CompilerTest { .suspended shouldEqual true } + "work properly with arguments defaulted to lambdas" in { + implicit val inlineContext: InlineContext = mkContext + val ir = """ + |x -> (y = x->y->z) -> y x + |""".stripMargin.preprocessExpression.get.optimise.asInstanceOf[IR.Function.Lambda] + ir.arguments.length shouldEqual 2 + val defaultExpr = ir.arguments(1).defaultValue.get + defaultExpr shouldBe a[IR.Function.Lambda] + defaultExpr.asInstanceOf[IR.Function.Lambda].arguments.length shouldEqual 2 + } + "collapse lambdas with multiple parameters" in { implicit val inlineContext: InlineContext = mkContext diff --git a/test/Benchmarks/src/Collections.enso b/test/Benchmarks/src/Collections.enso index 11c85f29685..a501e4ec8d2 100644 --- a/test/Benchmarks/src/Collections.enso +++ b/test/Benchmarks/src/Collections.enso @@ -1,4 +1,5 @@ from Base import all +import Builtins import Base.Bench_Utils gen_list len = 0.upto len . fold Nil (l -> i -> Cons i+1 l) @@ -11,11 +12,22 @@ sum_vec vec = res = sumator 0 0 res +sum_list_meta list = + nil_cons = Meta.meta Nil . constructor + folder acc list = + meta_list = Meta.meta list + if meta_list.constructor == nil_cons then acc else + fs = meta_list.fields + folder (acc + fs.at 0) (fs.at 1) + res = folder 0 list + res + main = mil = 1000000 list = here.gen_list mil vec = Vector.new mil (ix -> ix + 1) vec_decimal = Vector.new mil (ix -> ix + 0.0) - Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 + Bench_Utils.measure (here.sum_list_meta list) "list meta-fold" 1000 10 Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10 + Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 Bench_Utils.measure (vec_decimal.fold 0 (+)) "vector decimal fold" 1000 10 diff --git a/test/Test/src/Main.enso b/test/Test/src/Main.enso index 560fc49363a..0293722b6cf 100644 --- a/test/Test/src/Main.enso +++ b/test/Test/src/Main.enso @@ -5,6 +5,7 @@ import Test.Semantic.Deep_Export.Spec as Deep_Export_Spec import Test.Semantic.Java_Interop_Spec import Test.Semantic.Error_Spec import Test.Semantic.Names_Spec +import Test.Semantic.Meta_Spec import Test.List_Spec import Test.Number_Spec @@ -29,3 +30,4 @@ main = Test.Suite.runMain <| Text_Spec.spec Time_Spec.spec File_Spec.spec + Meta_Spec.spec diff --git a/test/Test/src/Semantic/Meta_Spec.enso b/test/Test/src/Semantic/Meta_Spec.enso new file mode 100644 index 00000000000..9e880610d4b --- /dev/null +++ b/test/Test/src/Semantic/Meta_Spec.enso @@ -0,0 +1,24 @@ +from Base import all +import Base.Test + +type My_Type foo bar baz + +My_Type.my_method = this.foo + this.bar + this.baz + +spec = describe "Meta-Value Manipulation" <| + it "should allow manipulating unresolved symbols" <| + sym = does_not_exist + meta_sym = Meta.meta sym + meta_sym.name.should equal "does_not_exist" + new_sym = meta_sym . rename "my_method" + object = My_Type 1 2 3 + new_sym object . should equal 6 + it "should allow manipulating atoms" <| + atom = My_Type 1 "foo" Unit + meta_atom = Meta.meta atom + meta_atom.constructor.should equal My_Type + meta_atom.fields.should equal [1, "foo", Unit] + Meta.meta (meta_atom.constructor) . new [1, "foo", Unit] . should equal atom + it "should correctly return representations of different classes of objects" <| + Meta.meta 1 . should equal (Meta.Primitive 1) + Meta.meta "foo" . should equal (Meta.Primitive "foo")