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

Fix the Array Visualisation #1588

Merged
merged 5 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
2 changes: 2 additions & 0 deletions distribution/std-lib/Standard/src/Base.enso
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Standard.Base.Data.Any.Extensions
import Standard.Base.Data.Array.Extensions
import Standard.Base.Data.Interval
import Standard.Base.Data.Json
import Standard.Base.Data.List
Expand Down Expand Up @@ -34,6 +35,7 @@ export Standard.Base.Meta
export Standard.Base.System.File

from Standard.Base.Data.Any.Extensions export all
from Standard.Base.Data.Array.Extensions export all
from Standard.Base.Data.List export Nil, Cons
from Standard.Base.Data.Number.Extensions export all hiding Math, String, Double
from Standard.Base.Data.Noise export all hiding Noise
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from Standard.Base import all

## Transform the array into text for displaying as part of its default
visualization.
Array.to_default_visualization_data : Text
Array.to_default_visualization_data =
Vector.Vector this |> .to_default_visualization_data
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved

13 changes: 13 additions & 0 deletions distribution/std-lib/Standard/src/Base/Data/Json.enso
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ type Json
Check the `message` field for detailed information on the specific failure.
type Parse_Error message

## Converts the error to a display representation.
Parse_Error.to_display_text : Text
Parse_Error.to_display_text = "Parse error in parsing JSON: " + this.message.to_text + "."

## Gets the value associated with the given key in this object. Returns
`Nothing` if the associated key is not defined.
Object.get : Text -> Json | Nothing
Expand Down Expand Up @@ -110,6 +114,15 @@ type Marshalling_Error
when the JSON does not contain all the fields required by the atom.
type Missing_Field_Error json field format

to_display_text : Text
to_display_text = case this of
Type_Mismatch_Error json format ->
json_text = Meta.display_type json
format_text = Meta.display_type format
"Type mismatch error: the json with type `" + json_text + "` did not match the format `" + format_text + "`."
Missing_Field_Error _ field _ ->
"Missing field in Json: the field `" + field.to_text "` was missing in the json."

## Generically converts an atom into a JSON object.

The input atom is converted into a JSON object, with a `"type"` field set to
Expand Down
7 changes: 7 additions & 0 deletions distribution/std-lib/Standard/src/Base/Data/Vector.enso
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,13 @@ type Vector

Vector new_vec_arr

## Transform the vector into text for displaying as part of its default
visualization.
to_default_visualization_data : Text
to_default_visualization_data =
json = this.take_start 100 |> .to_json
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
json.to_text

## A builder type for Enso vectors.

A vector builder is a mutable data structure, that allows to gather a
Expand Down
7 changes: 7 additions & 0 deletions distribution/std-lib/Standard/src/Base/Meta.enso
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,10 @@ is_same_object value_1 value_2 = Builtins.Meta.is_same_object value_1 value_2
get_source_location : Integer -> Text
get_source_location skip_frames =
Builtins.Meta.get_source_location skip_frames+1

## Displays the type of the provided value as text.

Arguments:
- value: The value for which to display the type.
display_type : Any -> Text
display_type value = Builtins.Meta.display_type value
2 changes: 1 addition & 1 deletion distribution/std-lib/Standard/src/Base/System/File.enso
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ new path = File (Prim_Io.get_file path)

> Example
Read the `data.csv` file in the project directory.
File.open (Enso_Project.data / "data.csv")
File.read (Enso_Project.data / "data.csv")
read : Text -> Text
read path = (here.new path).read

Expand Down
4 changes: 2 additions & 2 deletions distribution/std-lib/Standard/src/Test.enso
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ run_spec ~behavior =
case ex of
Failure _ -> ex
Finished_With_Error err stack_trace_text ->
Failure ("An unexpected error was returned: " + err.to_text + '\n' + stack_trace_text)
_ -> Failure ("An unexpected panic was thrown: " + ex.to_text + '\n' + maybeExc.get_stack_trace_text)
Failure ("An unexpected error was returned: " + err.to_display_text + '\n' + stack_trace_text)
_ -> Failure ("An unexpected panic was thrown: " + ex.to_display_text + '\n' + maybeExc.get_stack_trace_text)
result

## Creates a new test group, desribing properties of the object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ class Module(private val value: Value) {
* @param name the name of the method
* @return the runtime representation of the method
*/
def getMethod(constructor: Value, name: String): Function =
new Function(value.invokeMember(GET_METHOD, constructor, name))
def getMethod(constructor: Value, name: String): Option[Function] = {
val newVal = value.invokeMember(GET_METHOD, constructor, name);
if (newVal.isNull) { None } else {
Some(new Function(newVal))
}
}

/** Evaluates an arbitrary expression as if it were placed in a function
* body inside this module.
Expand Down
19 changes: 13 additions & 6 deletions engine/runner/src/main/scala/org/enso/runner/Main.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package org.enso.runner

import java.io.File
import java.util.UUID

import akka.http.scaladsl.model.{IllegalUriException, Uri}
import cats.implicits._
import org.apache.commons.cli.{Option => CliOption, _}
Expand All @@ -12,8 +9,11 @@ import org.enso.loggingservice.LogLevel
import org.enso.pkg.{Contact, PackageManager, SemVerEnsoVersion}
import org.enso.polyglot.{LanguageInfo, Module, PolyglotContext}
import org.enso.version.VersionDescription
import org.graalvm.polyglot.{PolyglotException, Value}
import org.graalvm.polyglot.PolyglotException

import java.io.File
import java.util.UUID
import scala.Console.err
import scala.jdk.CollectionConverters._
import scala.util.Try

Expand Down Expand Up @@ -382,11 +382,18 @@ object Main {
mainModule: Module,
rootPkgPath: Option[File],
mainMethodName: String = "main"
): Value = {
): Unit = {
val mainCons = mainModule.getAssociatedConstructor
val mainFun = mainModule.getMethod(mainCons, mainMethodName)
try {
mainFun.execute(mainCons.newInstance())
mainFun match {
case Some(main) => main.execute(mainCons.newInstance())
case None =>
err.println(
"Your module does not contain a `main` function. It could not " +
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
"be run."
)
}
} catch {
case e: PolyglotException =>
printPolyglotException(e, rootPkgPath)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.enso.interpreter.node.expression.builtin.meta;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.text.util.TypeToDisplayTextNode;
import org.enso.interpreter.runtime.data.text.Text;

@BuiltinMethod(type = "Meta", name = "display_type", description = "Pretty prints a type.")
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
public class DisplayTypeNode extends Node {
@Child @CompilationFinal TypeToDisplayTextNode displayTypeNode = TypeToDisplayTextNode.build();

Text execute(Object _this, Object value) {
return Text.create(displayTypeNode.execute(value));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
public abstract class TypeToDisplayTextNode extends Node {
public abstract String execute(Object o);

/**
* Create a node that can display types as text.
*
* @return a new type display node
*/
public static TypeToDisplayTextNode build() {
return TypeToDisplayTextNodeGen.create();
}

@Specialization
@CompilerDirectives.TruffleBoundary
String doDisplay(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.File;
import java.io.IOException;

import java.util.Map;
import org.enso.compiler.core.IR;
import org.enso.compiler.phase.StubIrBuilder;
import org.enso.interpreter.Language;
Expand Down Expand Up @@ -405,7 +406,11 @@ static Object doInvoke(
ModuleScope scope = module.compileScope(context);
switch (member) {
case MethodNames.Module.GET_METHOD:
return getMethod(scope, arguments);
var result = getMethod(scope, arguments);
if (result == null) {
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
return context.getBuiltins().nothing().newInstance();
}
return result;
case MethodNames.Module.GET_CONSTRUCTOR:
return getConstructor(scope, arguments);
case MethodNames.Module.REPARSE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public Meta(Language language, ModuleScope scope) {
AtomConstructor meta = new AtomConstructor("Meta", scope).initializeFields();
scope.registerConstructor(meta);

scope.registerMethod(meta, "display_type", DisplayTypeMethodGen.makeFunction(language));
scope.registerMethod(
meta, "is_unresolved_symbol", IsUnresolvedSymbolMethodGen.makeFunction(language));
scope.registerMethod(
Expand Down
14 changes: 11 additions & 3 deletions engine/runtime/src/main/resources/Builtins.enso
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ type Error
catch_primitive : (Error -> Any) -> Any
catch_primitive handler = @Builtin_Method "Any.catch"

## PRIVATE
## PRIVATE
UNSTABLE

Returns a textual representation of the stack trace attached to an error.
Expand Down Expand Up @@ -728,8 +728,16 @@ type Meta
Arguments:
- frames_to_skip: how many frames on the stack to skip. Called with 0
will return exact location of the call.
get_source_location : Integer -> Text
get_source_location frames_to_skip = @Builtin_Method "Meta.get_source_location"
get_source_location : Integer -> Text
get_source_location frames_to_skip = @Builtin_Method "Meta.get_source_location"

## Pretty-prints the type of the provided value using the interpreter's
internal logic for printing types.

Arguments:
- value: The value whose type should be printed.
display_type : Any -> Text
display_type value = @Builtin_Method "Meta.display_type"

## Utilities for working with primitive arrays.
type Array
Expand Down
10 changes: 6 additions & 4 deletions engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package org.enso.compiler.core

import java.util.UUID

import org.enso.compiler.core.IR.{Expression, IdentifiedLocation}
import org.enso.compiler.core.ir.{DiagnosticStorage, MetadataStorage}
import org.enso.compiler.core.ir.MetadataStorage.MetadataPair
import org.enso.compiler.core.ir.{DiagnosticStorage, MetadataStorage}
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.IRPass
import org.enso.interpreter.epb.EpbParser
import org.enso.syntax.text.{AST, Debug, Location}

import java.util.UUID
import scala.annotation.unused

/** [[IR]] is a temporary and fairly unsophisticated internal representation
Expand Down Expand Up @@ -5337,7 +5336,10 @@ object IR {
// === Errors ===============================================================

/** A trait for all errors in Enso's IR. */
sealed trait Error extends Expression with Diagnostic {
sealed trait Error
extends Expression
with IR.Module.Scope.Definition
with Diagnostic {
override def mapExpressions(fn: Expression => Expression): Error
override def setLocation(location: Option[IdentifiedLocation]): Error
override def duplicate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ case object ComplexType extends IRPass {
matchSignaturesAndGenerate(name, binding)
case funSugar @ IR.Function.Binding(name, _, _, _, _, _, _) =>
matchSignaturesAndGenerate(name, funSugar)
case err: IR.Error => Seq(err)
case _ =>
throw new CompilerError("Unexpected IR node in complex type body.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,42 @@ class ComplexTypeTest extends CompilerTest {
.name shouldEqual "bad_trailing_sig"
}
}

"Invalid complex types" should {
implicit val ctx: ModuleContext = mkModuleContext

val ir =
"""
|type Foo
| Bar
| type Baz
|
| g a = this + a
|
| f a =
|""".stripMargin.preprocessModule.desugar

"have their types translated untouched" in {
ir.bindings.head shouldBe a[Definition.Atom]
val atom = ir.bindings.head.asInstanceOf[Definition.Atom]
atom.name.name shouldEqual "Baz"
}

"have their errors translated untouched" in {
ir.bindings.last shouldBe an[IR.Error.Syntax]
val err = ir.bindings.last.asInstanceOf[IR.Error.Syntax]
err.reason shouldBe an[IR.Error.Syntax.UnexpectedDeclarationInType.type]
}

"have their valid methods desugared" in {
ir.bindings(1) shouldBe a[Definition.Method.Binding]
ir.bindings(2) shouldBe a[Definition.Method.Binding]
val methodOnBar = ir.bindings(1).asInstanceOf[Definition.Method.Binding]
val methodOnBaz = ir.bindings(2).asInstanceOf[Definition.Method.Binding]
methodOnBar.typeName.name shouldEqual "Bar"
methodOnBar.methodName.name shouldEqual "g"
methodOnBaz.typeName.name shouldEqual "Baz"
methodOnBaz.methodName.name shouldEqual "g"
}
}
}
12 changes: 12 additions & 0 deletions test/Tests/src/Data/Array_Spec.enso
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from Standard.Base import all

import Standard.Test

spec = Test.group "Arrays" <|
Test.specify "should be able to be converted to a visualization rep" <|
arr = Vector.fill 1000 0 |> .to_array
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
text = arr.to_default_visualization_data
json = Json.parse text
as_vec = json.into (Vector.Vector Number)
as_vec.should_equal <| Vector.fill 100 0

7 changes: 7 additions & 0 deletions test/Tests/src/Data/Vector_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,10 @@ spec = Test.group "Vectors" <|
fail a = Error.throw <| My_Error a
[fail 1].map (x -> x.catch (x -> x.a)) . should_equal [1]
[1].map fail . map .catch . should_equal [My_Error 1]
Test.specify "should be able to be efficiently converted to a visualisation" <|
vec = Vector.fill 1000 0
text = vec.to_default_visualization_data
json = Json.parse text
as_vec = json.into (Vector.Vector Number)
as_vec.should_equal <| Vector.fill 100 0

2 changes: 2 additions & 0 deletions test/Tests/src/Main.enso
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Tests.Semantic.Js_Interop_Spec
import Tests.Semantic.Python_Interop_Spec
import Tests.Semantic.R_Interop_Spec

import Tests.Data.Array_Spec
import Tests.Data.Interval_Spec
import Tests.Data.Json_Spec
import Tests.Data.List_Spec
Expand All @@ -40,6 +41,7 @@ import Tests.System.Process_Spec

main = Test.Suite.runMain <|
Any_Spec.spec
Array_Spec.spec
Case_Spec.spec
Deep_Export_Spec.spec
Error_Spec.spec
Expand Down