diff --git a/app/gui/controller/engine-protocol/src/language_server/tests.rs b/app/gui/controller/engine-protocol/src/language_server/tests.rs index 376032bddf..d6d20d0bdc 100644 --- a/app/gui/controller/engine-protocol/src/language_server/tests.rs +++ b/app/gui/controller/engine-protocol/src/language_server/tests.rs @@ -434,6 +434,7 @@ fn test_execution_context() { }; let positional_arguments_expressions = vec![1, 2, 3].iter().map(|x| x.to_string()).collect(); let visualization_config = VisualizationConfiguration { + visualization_module: "Foo.Bar.Baz".to_string(), execution_context_id: context_id, expression, positional_arguments_expressions, @@ -453,6 +454,7 @@ fn test_execution_context() { "definedOnType" : "[Foo.Bar.Baz]", "name" : "foo" }, + "visualizationModule" : "Foo.Bar.Baz", "positionalArgumentsExpressions" : ["1", "2", "3"] } }), @@ -479,6 +481,7 @@ fn test_execution_context() { }; let positional_arguments_expressions = vec!["foo"].iter().map(|x| x.to_string()).collect(); let visualization_config = VisualizationConfiguration { + visualization_module: "Foo.Bar.Baz".to_string(), execution_context_id: context_id, expression, positional_arguments_expressions, @@ -495,6 +498,7 @@ fn test_execution_context() { "definedOnType" : "[Foo.Bar.Baz]", "name" : "foo" }, + "visualizationModule" : "Foo.Bar.Baz", "positionalArgumentsExpressions" : ["foo"] } }), diff --git a/app/gui/controller/engine-protocol/src/language_server/types.rs b/app/gui/controller/engine-protocol/src/language_server/types.rs index e76d066002..92058e0252 100644 --- a/app/gui/controller/engine-protocol/src/language_server/types.rs +++ b/app/gui/controller/engine-protocol/src/language_server/types.rs @@ -713,6 +713,8 @@ pub type ExpressionId = Uuid; #[serde(rename_all = "camelCase")] #[allow(missing_docs)] pub struct VisualizationConfiguration { + /// Module to evaluate visualization in context of. + pub visualization_module: String, /// An execution context of the visualization. pub execution_context_id: ContextId, /// An enso function that will transform the data into expected format. diff --git a/app/gui/src/controller/graph/executed.rs b/app/gui/src/controller/graph/executed.rs index 473c3bcc5e..48c63c972b 100644 --- a/app/gui/src/controller/graph/executed.rs +++ b/app/gui/src/controller/graph/executed.rs @@ -403,10 +403,19 @@ impl Handle { } + /// Get a fully qualified name of the module in the [`graph`]. The name is obtained from the + /// module's path and the `project` name. + pub fn module_qualified_name_with_project( + &self, + project: &dyn model::project::API, + ) -> QualifiedName { + self.graph().module.path().qualified_module_name(project.qualified_name()) + } + /// Get a full qualified name of the module in the [`graph`]. The name is obtained from the /// module's path and the `project` name. - pub fn module_qualified_name(&self, project: &dyn model::project::API) -> QualifiedName { - self.graph().module.path().qualified_module_name(project.qualified_name()) + pub fn module_qualified_name(&self) -> QualifiedName { + self.graph().module.path().qualified_module_name(self.project.qualified_name()) } /// Returns information about all the connections between graph's nodes. diff --git a/app/gui/src/controller/graph/widget.rs b/app/gui/src/controller/graph/widget.rs index 6765b5dd9d..ce24058095 100644 --- a/app/gui/src/controller/graph/widget.rs +++ b/app/gui/src/controller/graph/widget.rs @@ -392,7 +392,7 @@ impl QueryData { /// Generate visualization metadata for this query. fn visualization_metadata(&self) -> Metadata { let arguments: Vec = vec![ - Self::escape_visualization_argument(&self.method_name).into(), + Self::as_unresolved_symbol(&self.method_name).into(), Self::arg_sequence(&self.arguments).into(), ]; @@ -410,6 +410,12 @@ impl QueryData { Ast::raw_text_literal(arg).repr() } + /// Creates unresolved symbol via ".name" syntax. Unresolved symbol contains name and also + /// module scope to resolve it properly. + fn as_unresolved_symbol(arg: &str) -> String { + format!(".{arg}") + } + /// Escape a list of strings to be used as a visualization argument. Transforms the strings into /// an enso expression with a list of string literals. fn arg_sequence(args: &[ImString]) -> String { diff --git a/app/gui/src/controller/searcher.rs b/app/gui/src/controller/searcher.rs index c9cd2d7b32..7c8dea2c83 100644 --- a/app/gui/src/controller/searcher.rs +++ b/app/gui/src/controller/searcher.rs @@ -574,7 +574,7 @@ impl Searcher { "Standard.Visualization.AI", "build_ai_prompt", )?; - let vis = Visualization::new(this.id, vis_ptr, vec![]); + let vis = Visualization::new(vis_ptr.module.to_owned(), this.id, vis_ptr, vec![]); let mut result = graph.attach_visualization(vis.clone()).await?; let next = result.next().await.ok_or(NoAIVisualizationDataReceived)?; let prompt = std::str::from_utf8(&next)?; @@ -1091,7 +1091,7 @@ impl Searcher { } fn module_qualified_name(&self) -> QualifiedName { - self.graph.module_qualified_name(&*self.project) + self.graph.module_qualified_name_with_project(&*self.project) } fn filter(&self) -> Filter { diff --git a/app/gui/src/controller/visualization/manager.rs b/app/gui/src/controller/visualization/manager.rs index 7441a85744..f32283d4d5 100644 --- a/app/gui/src/controller/visualization/manager.rs +++ b/app/gui/src/controller/visualization/manager.rs @@ -10,6 +10,7 @@ use crate::model::execution_context::VisualizationId; use crate::model::execution_context::VisualizationUpdateData; use crate::sync::Synchronized; +use double_representation::name::QualifiedName; use futures::channel::mpsc::UnboundedReceiver; use futures::future::ready; use ide_view::graph_editor::component::visualization::Metadata; @@ -158,6 +159,7 @@ impl Default for Status { #[allow(missing_docs)] #[derive(Clone, Debug, PartialEq, Eq)] pub struct Desired { + pub module: QualifiedName, pub visualization_id: VisualizationId, pub expression_id: ast::Id, pub metadata: Metadata, @@ -285,11 +287,15 @@ impl Manager { // Early return: requested to remove visualization that was already removed. return; }; + let prj = self.executed_graph.module_qualified_name(); + let graph = self.executed_graph.graph(); + let module = prj.new_child(graph.module.name()); let current_id = current.as_ref().and_then(|current| current.latest_id()); let new_desired = new_desired.map(|new_desired| Desired { - expression_id: target, + module, + expression_id: target, visualization_id: current_id.unwrap_or_else(VisualizationId::new_v4), - metadata: new_desired, + metadata: new_desired, }); self.write_new_desired(target, new_desired) } @@ -332,6 +338,7 @@ impl Manager { Ok(Visualization { id: desired.visualization_id, expression_id: desired.expression_id, + module: desired.module, method_pointer, arguments, }) @@ -556,13 +563,14 @@ mod tests { let qualified_module = inner.project.qualified_module_name(inner.module.path()); let method_pointer = QualifiedMethodPointer { module: qualified_module.clone(), - defined_on_type: qualified_module, + defined_on_type: qualified_module.clone(), name: Identifier::from_text("faux").unwrap(), }; let arguments = vec!["foo".to_owned()]; let faux_vis = Visualization { id: default(), expression_id: default(), + module: qualified_module, method_pointer, arguments, }; @@ -666,6 +674,7 @@ mod tests { // We don't attach it separately, as Manager identifies visualizations by their // expression ID rather than visualization ID. let desired_vis_3 = Desired { + module: QualifiedName::from_text("local.Widgets.Main").unwrap(), visualization_id: VisualizationId::from_u128(900), expression_id: node_id, metadata: desired_vis_1, diff --git a/app/gui/src/model/execution_context.rs b/app/gui/src/model/execution_context.rs index 6429e0570a..ed9d890273 100644 --- a/app/gui/src/model/execution_context.rs +++ b/app/gui/src/model/execution_context.rs @@ -323,6 +323,8 @@ pub struct Visualization { pub id: VisualizationId, /// Expression that is to be visualized. pub expression_id: ExpressionId, + /// Module to evaluate visualization in context of. + pub module: QualifiedName, /// A pointer to the enso method that will transform the data into expected format. pub method_pointer: QualifiedMethodPointer, /// Enso expressions for positional arguments @@ -333,12 +335,13 @@ impl Visualization { /// Creates a new visualization description. The visualization will get a randomly assigned /// identifier. pub fn new( + module: QualifiedName, expression_id: ExpressionId, method_pointer: QualifiedMethodPointer, arguments: Vec, ) -> Visualization { let id = VisualizationId::new_v4(); - Visualization { id, expression_id, method_pointer, arguments } + Visualization { id, expression_id, module, method_pointer, arguments } } /// Creates a `VisualizationConfiguration` that is used in communication with language server. @@ -346,6 +349,7 @@ impl Visualization { let expression = self.method_pointer.clone().into(); let positional_arguments_expressions = self.arguments.clone(); VisualizationConfiguration { + visualization_module: self.module.to_string_with_main_segment(), execution_context_id, expression, positional_arguments_expressions, diff --git a/app/gui/src/model/execution_context/synchronized.rs b/app/gui/src/model/execution_context/synchronized.rs index cc3865a95f..12e55c73cd 100644 --- a/app/gui/src/model/execution_context/synchronized.rs +++ b/app/gui/src/model/execution_context/synchronized.rs @@ -532,6 +532,7 @@ pub mod test { let arguments = vec![]; let vis = Visualization { id: model::execution_context::VisualizationId::new_v4(), + module: method_pointer.module.clone(), expression_id: model::execution_context::ExpressionId::new_v4(), method_pointer, arguments, @@ -581,6 +582,7 @@ pub mod test { let arguments = vec!["foo".to_owned()]; let vis = Visualization { id: model::execution_context::VisualizationId::new_v4(), + module: method_pointer.module.clone(), expression_id: model::execution_context::ExpressionId::new_v4(), method_pointer, arguments, @@ -618,6 +620,7 @@ pub mod test { let arguments = vec!["bar".to_owned()]; let vis = Visualization { id: model::execution_context::VisualizationId::new_v4(), + module: method_pointer.module.clone(), expression_id: model::execution_context::ExpressionId::new_v4(), method_pointer, arguments: arguments.clone(), @@ -634,6 +637,7 @@ pub mod test { let expected_config = language_server::types::VisualizationConfiguration { execution_context_id: data.context_id, + visualization_module: MockData::new().module_qualified_name().to_string(), expression: new_expression.clone().into(), positional_arguments_expressions: arguments.clone(), }; diff --git a/app/gui/tests/language_server.rs b/app/gui/tests/language_server.rs index 8fb037db05..d0110c73a0 100644 --- a/app/gui/tests/language_server.rs +++ b/app/gui/tests/language_server.rs @@ -140,6 +140,7 @@ async fn ls_text_protocol_test() { execution_context_id, expression, positional_arguments_expressions, + visualization_module: visualization_module.to_string(), }; let response = client.attach_visualization(&visualization_id, &expression_id, &visualization_config); @@ -157,6 +158,7 @@ async fn ls_text_protocol_test() { execution_context_id, expression, positional_arguments_expressions, + visualization_module: visualization_module.to_string(), }; let response = client.modify_visualization(&visualization_id, &visualization_config).await; response.expect("Couldn't modify visualization."); @@ -375,7 +377,8 @@ async fn binary_visualization_updates_test_hlp() { module_qualified_name, Identifier::from_text("quux").unwrap(), ); - let visualization = Visualization::new(the_node.id(), method_pointer, vec![]); + let visualization = + Visualization::new(method_pointer.module.clone(), the_node.id(), method_pointer, vec![]); let stream = graph_executed.attach_visualization(visualization.clone()).await.unwrap(); info!("Attached the visualization {}", visualization.id); let mut stream = stream.boxed_local(); diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso index 3f224cedc8..e9067a0b79 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso @@ -419,10 +419,10 @@ type_of value = @Builtin_Method "Meta.type_of" Arguments: - target: The value or type to get the attribute from. - - method_name: The name of the method or constructor to get the attribute for. + - method: The symbol representing method or constructor to get the attribute for. - parameter_name: The name of the parameter to get the attribute for. -get_annotation : Any -> Text -> Text -> Any | Nothing -get_annotation target method_name parameter_name = @Builtin_Method "Meta.get_annotation" +get_annotation : Any -> Any -> Text -> Any | Nothing +get_annotation target method parameter_name = @Builtin_Method "Meta.get_annotation" ## PRIVATE Represents a polyglot language. diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Widgets.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Widgets.enso index 01ce017d3a..1644ce0e98 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Widgets.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Widgets.enso @@ -4,7 +4,7 @@ from Standard.Base import all Basic preprocessor for widgets metadata visualization. Returns full annotation data for all requested arguments. -get_widget_json : Any -> Text -> Vector Text -> Text +get_widget_json : Any -> Any -> Vector Text -> Text get_widget_json value call_name argument_names = read_annotation argument = annotation = Warning.clear <| Meta.get_annotation value call_name argument diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index 91aa5394ce..82aeaaba5b 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -453,10 +453,9 @@ interface VisualizationConfiguration { executionContextId: UUID; /** - * A qualified name of the module containing the expression which creates - * visualization. + * A qualified name of the module to be used to evaluate the arguments for the visualization expression. */ - visualizationModule?: String; + visualizationModule: String; /** An expression that creates a visualization. */ expression: String | MethodPointer; diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/VisualizationConfiguration.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/VisualizationConfiguration.scala index 1200937f00..2e780f9a62 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/VisualizationConfiguration.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/VisualizationConfiguration.scala @@ -12,16 +12,16 @@ import java.util.UUID * * @param executionContextId an execution context of the visualization * @param expression an expression that creates a visualization + * @param visualizationModule the name of a module to execute expression at + * @param executionContextId an execution context of the visualization + * @param expression an expression that creates a visualization */ case class VisualizationConfiguration( executionContextId: UUID, - expression: VisualizationExpression + expression: VisualizationExpression, + visualizationModule: String ) extends ToLogString { - /** A qualified module name containing the expression. */ - def visualizationModule: String = - expression.module - /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = s"VisualizationConfiguration(" + @@ -31,8 +31,9 @@ case class VisualizationConfiguration( /** Convert to corresponding [[Api]] message. */ def toApi: Api.VisualizationConfiguration = Api.VisualizationConfiguration( - executionContextId = executionContextId, - expression = expression.toApi + executionContextId = executionContextId, + expression = expression.toApi, + visualizationModule = visualizationModule ) } @@ -52,7 +53,8 @@ object VisualizationConfiguration { ): VisualizationConfiguration = new VisualizationConfiguration( contextId, - VisualizationExpression.Text(module, expression) + VisualizationExpression.Text(module, expression), + module ) /** Create a visualization configuration. @@ -65,6 +67,7 @@ object VisualizationConfiguration { */ def apply( contextId: UUID, + module: String, expression: MethodPointer, positionalArgumentsExpressions: Vector[String] ): VisualizationConfiguration = @@ -73,7 +76,8 @@ object VisualizationConfiguration { VisualizationExpression.ModuleMethod( expression, positionalArgumentsExpressions - ) + ), + module ) private object CodecField { @@ -99,11 +103,15 @@ object VisualizationConfiguration { expression <- cursor .downField(CodecField.Expression) .as[MethodPointer] + visualizationModule <- cursor + .downField(CodecField.VisualizationModule) + .as[String] arguments <- cursor .downField(CodecField.Arguments) .as[Option[Vector[String]]] } yield VisualizationConfiguration( contextId, + visualizationModule, expression, arguments.getOrElse(Vector()) ) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ExecutionContextJsonMessages.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ExecutionContextJsonMessages.scala index f3e2a4ee17..b9197a5be2 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ExecutionContextJsonMessages.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ExecutionContextJsonMessages.scala @@ -204,6 +204,7 @@ object ExecutionContextJsonMessages { "expressionId": $expressionId, "visualizationConfig": { "executionContextId": ${configuration.executionContextId}, + "visualizationModule": ${configuration.visualizationModule}, "expression": { "module": ${methodPointer.module}, "definedOnType": ${methodPointer.definedOnType}, @@ -223,6 +224,7 @@ object ExecutionContextJsonMessages { "expressionId": $expressionId, "visualizationConfig": { "executionContextId": ${configuration.executionContextId}, + "visualizationModule": ${methodPointer.module}, "expression": { "module": ${methodPointer.module}, "definedOnType": ${methodPointer.definedOnType}, diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala index 0ba794f803..044648f9c2 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala @@ -66,6 +66,7 @@ class VisualizationOperationsTest extends BaseServerTest { val visualizationConfig = VisualizationConfiguration( contextId, + visualizationModule, MethodPointer( visualizationModule, visualizationModule, @@ -120,6 +121,7 @@ class VisualizationOperationsTest extends BaseServerTest { val visualizationConfig = VisualizationConfiguration( contextId, + visualizationModule, MethodPointer( visualizationModule, visualizationModule, diff --git a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala index a5670bcf99..984b19284a 100644 --- a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala +++ b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala @@ -615,21 +615,20 @@ object Runtime { * * @param executionContextId an execution context of the visualization * @param expression the expression that creates a visualization + * @param visualizationModule module to evaluate arguments for visualization at */ case class VisualizationConfiguration( executionContextId: ContextId, - expression: VisualizationExpression + expression: VisualizationExpression, + visualizationModule: String ) extends ToLogString { - /** A qualified module name containing the expression. */ - def visualizationModule: String = - expression.module - /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = s"VisualizationConfiguration(" + s"executionContextId=$executionContextId," + - s"expression=${expression.toLogString(shouldMask)})" + s"expression=${expression.toLogString(shouldMask)})" + + s"visualizationModule=${visualizationModule})" } /** An operation applied to the suggestion argument. */ diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala index c3075a272a..1d87cdc93e 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala @@ -59,6 +59,7 @@ class UpsertVisualizationJob( try { val maybeCallable = UpsertVisualizationJob.evaluateVisualizationExpression( + config.visualizationModule, config.expression ) @@ -180,7 +181,10 @@ object UpsertVisualizationJob { val expressionId = visualization.expressionId val visualizationId = visualization.id val maybeCallable = - evaluateVisualizationExpression(visualization.config.expression) + evaluateVisualizationExpression( + visualizationConfig.visualizationModule, + visualizationConfig.expression + ) maybeCallable.foreach { result => updateVisualization( @@ -215,8 +219,9 @@ object UpsertVisualizationJob { /** Evaluate the visualization expression in a given module. * - * @param module the module where to evaluate the expression + * @param module the module where to evaluate arguments for the expression * @param expression the visualization expression + * @param expressionModule the module where to evaluate the expression * @param retryCount the number of attempted retries * @param ctx the runtime context * @return either the evaluation result or an evaluation failure @@ -224,6 +229,7 @@ object UpsertVisualizationJob { private def evaluateModuleExpression( module: Module, expression: Api.VisualizationExpression, + expressionModule: Module, retryCount: Int = 0 )(implicit ctx: RuntimeContext @@ -233,7 +239,7 @@ object UpsertVisualizationJob { val (callback, arguments) = expression match { case Api.VisualizationExpression.Text(_, expression) => val callback = ctx.executionService.evaluateExpression( - module, + expressionModule, expression ) val arguments = Vector() @@ -243,7 +249,7 @@ object UpsertVisualizationJob { argumentExpressions ) => val callback = ctx.executionService.prepareFunctionCall( - module, + expressionModule, QualifiedName.fromString(definedOnType).item, name ) @@ -261,7 +267,12 @@ object UpsertVisualizationJob { Level.FINE, s"Evaluation of visualization was interrupted. Retrying [${retryCount + 1}]." ) - evaluateModuleExpression(module, expression, retryCount + 1) + evaluateModuleExpression( + module, + expression, + expressionModule, + retryCount + 1 + ) case error: ThreadInterruptedException => val message = @@ -297,18 +308,25 @@ object UpsertVisualizationJob { /** Evaluate the visualization expression. * + * @param module module to evaluate the expression arguments at * @param expression the visualization expression to evaluate * @param ctx the runtime context * @return either the evaluation result or an evaluation error */ private def evaluateVisualizationExpression( + module: String, expression: Api.VisualizationExpression )(implicit ctx: RuntimeContext ): Either[EvaluationFailure, EvaluationResult] = { for { - module <- findModule(expression.module) - expression <- evaluateModuleExpression(module, expression) + module <- findModule(module) + expressionModule <- findModule(expression.module) + expression <- evaluateModuleExpression( + module, + expression, + expressionModule + ) } yield expression } diff --git a/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala b/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala index 964930a168..e7bbb6b259 100644 --- a/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala +++ b/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala @@ -358,7 +358,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -476,7 +477,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -611,7 +613,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -739,7 +742,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "encode" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -867,7 +871,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "encode" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -919,7 +924,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "encode" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1085,7 +1091,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1123,7 +1130,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> incAndEncode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1192,7 +1200,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1356,7 +1365,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "encode" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1468,7 +1478,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> encode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1506,7 +1517,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "x -> incAndEncode x" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -1600,7 +1612,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Test.Undefined", "x -> x" - ) + ), + "Test.Undefined" ) ) ) @@ -1666,7 +1679,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Standard.Visualization.Main", "x -> x.default_visualization.to_text" - ) + ), + "Standard.Visualization.Main" ) ) ) @@ -1762,7 +1776,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Main", "Main.does_not_exist" - ) + ), + "Enso_Test.Test.Main" ) ) ) @@ -1843,7 +1858,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( moduleName, "x -> x.visualise_me" - ) + ), + moduleName ) ) ) @@ -1955,7 +1971,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Visualization", "inc_and_encode" - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -2071,7 +2088,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( moduleName, "x -> x.catch_primitive _.to_text" - ) + ), + moduleName ) ) ) @@ -2170,7 +2188,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( moduleName, "x -> Panic.catch_primitive x caught_panic-> caught_panic.payload.to_text" - ) + ), + moduleName ) ) ) @@ -2302,7 +2321,8 @@ class RuntimeVisualizationsTest visualizationFunction ), Vector() - ) + ), + visualizationModule ) ) ) @@ -2403,7 +2423,8 @@ class RuntimeVisualizationsTest visualizationFunction ), Vector() - ) + ), + visualizationModule ) ) ) @@ -2500,7 +2521,8 @@ class RuntimeVisualizationsTest "incAndEncode" ), Vector() - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -2628,7 +2650,8 @@ class RuntimeVisualizationsTest "incAndEncode" ), Vector("2", "3") - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -2698,7 +2721,8 @@ class RuntimeVisualizationsTest "incAndEncode" ), Vector("2", "4") - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -2801,7 +2825,8 @@ class RuntimeVisualizationsTest "incAndEncode" ), Vector() - ) + ), + "Enso_Test.Test.Visualization" ) ) ) @@ -2963,7 +2988,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Main", "x -> x.to_text" - ) + ), + "Enso_Test.Test.Main" ) ) ) @@ -3063,7 +3089,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Main", "x -> x.to_text" - ) + ), + "Enso_Test.Test.Main" ) ) ) @@ -3191,7 +3218,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( "Enso_Test.Test.Main", "x -> x.to_text" - ) + ), + "Enso_Test.Test.Main" ) ) ) @@ -3308,7 +3336,8 @@ class RuntimeVisualizationsTest Api.VisualizationExpression.Text( moduleName, "x -> x.to_text" - ) + ), + moduleName ) ) ) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java index 7c410f16c0..01ba9cbcdc 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java @@ -1,24 +1,23 @@ package org.enso.interpreter.node.expression.builtin.meta; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.callable.Annotation; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.error.DataflowError; -import org.enso.interpreter.runtime.scope.ModuleScope; +import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.state.State; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; - @BuiltinMethod( type = "Meta", name = "get_annotation", @@ -39,16 +38,22 @@ public abstract class GetAnnotationNode extends BaseNode { @Cached ThunkExecutorNode thunkExecutorNode, @Cached ExpectStringNode expectStringNode, @Cached TypeOfNode typeOfNode) { - String methodName = expectStringNode.execute(method); - Object targetTypeResult = typeOfNode.execute(target); if (targetTypeResult instanceof DataflowError error) { return error; } if (targetTypeResult instanceof Type targetType) { - ModuleScope scope = targetType.getDefinitionScope(); - Function methodFunction = scope.lookupMethodDefinition(targetType, methodName); + Function methodFunction; + if (method instanceof UnresolvedSymbol symbol) { + methodFunction = symbol.resolveFor(targetType); + } else { + CompilerDirectives.transferToInterpreter(); + var ctx = EnsoContext.get(this); + var err = ctx.getBuiltins().error(); + var payload = err.makeUnsupportedArgumentsError(new Object[] { method }, "Use .name to specify name of function"); + throw new PanicException(payload, this); + } if (methodFunction != null) { String parameterName = expectStringNode.execute(parameter); Annotation annotation = methodFunction.getSchema().getAnnotation(parameterName); @@ -59,6 +64,7 @@ public abstract class GetAnnotationNode extends BaseNode { } } if (target instanceof Type type) { + String methodName = ((UnresolvedSymbol) symbol).getName(); AtomConstructor constructor = getAtomConstructor(type, methodName); if (constructor != null) { Function constructorFunction = constructor.getConstructorFunction(); diff --git a/test/Tests/src/Semantic/Meta_Spec.enso b/test/Tests/src/Semantic/Meta_Spec.enso index 1519b793db..0e0be36c39 100644 --- a/test/Tests/src/Semantic/Meta_Spec.enso +++ b/test/Tests/src/Semantic/Meta_Spec.enso @@ -282,32 +282,32 @@ spec = (Test_Type.Value a)==(Test_Type.Value c) . should_be_false Test.specify "get annotations" <| - Meta.get_annotation Meta_Spec "test_method" "a" . should_equal 7 - Meta.get_annotation Meta_Spec "test_method" "b" . should_equal (Test_Type.Value 49) - Meta.get_annotation Meta_Spec "test_method" "c" . should_fail_with Text - Meta.get_annotation Meta_Spec "test_method" "c" . catch . should_equal "Error Value" - Meta.get_annotation Meta_Spec "test_method" "x" . should_equal Nothing + Meta.get_annotation Meta_Spec .test_method "a" . should_equal 7 + Meta.get_annotation Meta_Spec .test_method "b" . should_equal (Test_Type.Value 49) + Meta.get_annotation Meta_Spec .test_method "c" . should_fail_with Text + Meta.get_annotation Meta_Spec .test_method "c" . catch . should_equal "Error Value" + Meta.get_annotation Meta_Spec .test_method "x" . should_equal Nothing value = My_Type.Value 99 "bar" True - Meta.get_annotation value "first_method" "param" . should_equal 11 - Meta.get_annotation value "second_method" "param" . should_equal Nothing - Meta.get_annotation value "third_method" "param" . should_equal Nothing - Meta.get_annotation value "other_method" "a" 7 . should_equal 12 - Meta.get_annotation value "other_method" "b" value . should_equal 99 - Meta.get_annotation value "other_method" "c" . should_equal Nothing + Meta.get_annotation value .first_method "param" . should_equal 11 + Meta.get_annotation value .second_method "param" . should_equal Nothing + Meta.get_annotation value .third_method "param" . should_equal Nothing + Meta.get_annotation value .other_method "a" 7 . should_equal 12 + Meta.get_annotation value .other_method "b" value . should_equal 99 + Meta.get_annotation value .other_method "c" . should_equal Nothing - Meta.get_annotation value "my_method" "self" . should_equal "self" + Meta.get_annotation value .my_method "self" . should_equal "self" Test.specify "no constructor annotations on value" <| value = My_Type.Value 99 "bar" True - Meta.get_annotation value "Value" "foo" . should_equal Nothing - Meta.get_annotation value "Value" "bar" . should_equal Nothing - Meta.get_annotation value "Value" "baz" . should_equal Nothing + Meta.get_annotation value .Value "foo" . should_equal Nothing + Meta.get_annotation value .Value "bar" . should_equal Nothing + Meta.get_annotation value .Value "baz" . should_equal Nothing Test.specify "get annotations on constructor" <| - Meta.get_annotation My_Type "Value" "foo" 7 8 . should_equal 15 - Meta.get_annotation My_Type "Value" "bar" . should_equal Nothing - Meta.get_annotation My_Type "Value" "baz" . should_equal (My_Type.Value 1 2 3) + Meta.get_annotation My_Type .Value "foo" 7 8 . should_equal 15 + Meta.get_annotation My_Type .Value "bar" . should_equal Nothing + Meta.get_annotation My_Type .Value "baz" . should_equal (My_Type.Value 1 2 3) Test.group "Check Nothing and NaN" <| Test.specify "Nothing.is_a Nothing" <| diff --git a/test/Visualization_Tests/src/Widgets/Database_Widgets_Spec.enso b/test/Visualization_Tests/src/Widgets/Database_Widgets_Spec.enso index c14a5c57d9..a3cecaaf1c 100644 --- a/test/Visualization_Tests/src/Widgets/Database_Widgets_Spec.enso +++ b/test/Visualization_Tests/src/Widgets/Database_Widgets_Spec.enso @@ -21,7 +21,7 @@ spec = Test.group "Widgets for In-Database Connection with table types" <| Test.specify "works for `tables`" <| - result = Widgets.get_widget_json connection "tables" ["types"] + result = Widgets.get_widget_json connection .tables ["types"] result.should_contain "'TABLE'" result.should_contain "'VIEW'" @@ -29,8 +29,8 @@ spec = Test.specify "works for `query` and `read`" <| choices = ['a_table', 'another', 'mock_table'] . map n-> Choice.Option n n.pretty expect = [["query", Widget.Single_Choice choices Nothing Display.Always]] . to_json - Widgets.get_widget_json connection "query" ["query"] . should_equal expect - Widgets.get_widget_json connection "read" ["query"] . should_equal expect + Widgets.get_widget_json connection .query ["query"] . should_equal expect + Widgets.get_widget_json connection .read ["query"] . should_equal expect Test.group "Widgets for In-Database Table with column name sets" <| mock_table = connection.query "mock_table" @@ -38,17 +38,17 @@ spec = Test.specify "works for `get` and `at`" <| choices = mock_table.column_names . map n-> Choice.Option n n.pretty expect = [["selector", Widget.Single_Choice choices Nothing Display.Always]] . to_json - Widgets.get_widget_json mock_table "get" ["selector"] . should_equal expect - Widgets.get_widget_json mock_table "at" ["selector"] . should_equal expect + Widgets.get_widget_json mock_table .get ["selector"] . should_equal expect + Widgets.get_widget_json mock_table .at ["selector"] . should_equal expect Test.specify "works for `filter`" <| choices = mock_table.column_names . map n-> Choice.Option n n.pretty expect = [["column", Widget.Single_Choice choices Nothing Display.Always]] . to_json - Widgets.get_widget_json mock_table "filter" ["column"] . should_equal expect + Widgets.get_widget_json mock_table .filter ["column"] . should_equal expect Test.group "Widgets for Database" <| Test.specify "works for `connect`" <| - result = Widgets.get_widget_json Database "connect" ["details"] + result = Widgets.get_widget_json Database .connect ["details"] result.should_contain "SQLite" result.should_contain "Postgres" result.should_contain "Redshift" diff --git a/test/Visualization_Tests/src/Widgets/Table_Widgets_Spec.enso b/test/Visualization_Tests/src/Widgets/Table_Widgets_Spec.enso index bd49093326..2a2ecc4f36 100644 --- a/test/Visualization_Tests/src/Widgets/Table_Widgets_Spec.enso +++ b/test/Visualization_Tests/src/Widgets/Table_Widgets_Spec.enso @@ -18,12 +18,12 @@ spec = Test.specify "works for `get` and `at`" <| choices = mock_table.column_names . map n-> Choice.Option n n.pretty expect = [["selector", Widget.Single_Choice choices Nothing Display.Always]] . to_json - Widgets.get_widget_json mock_table "get" ["selector"] . should_equal expect - Widgets.get_widget_json mock_table "at" ["selector"] . should_equal expect + Widgets.get_widget_json mock_table .get ["selector"] . should_equal expect + Widgets.get_widget_json mock_table .at ["selector"] . should_equal expect Test.specify "works for `filter`" <| choices = mock_table.column_names . map n-> Choice.Option n n.pretty expect = [["column", Widget.Single_Choice choices Nothing Display.Always]] . to_json - Widgets.get_widget_json mock_table "filter" ["column"] . should_equal expect + Widgets.get_widget_json mock_table .filter ["column"] . should_equal expect main = Test_Suite.run_main spec diff --git a/test/Visualization_Tests/src/Widgets/Text_Widgets_Spec.enso b/test/Visualization_Tests/src/Widgets/Text_Widgets_Spec.enso index 071068fe93..a9a91edcce 100644 --- a/test/Visualization_Tests/src/Widgets/Text_Widgets_Spec.enso +++ b/test/Visualization_Tests/src/Widgets/Text_Widgets_Spec.enso @@ -16,9 +16,9 @@ spec = mock_text = "abc def" default_widget = Text_Sub_Range.default_widget expect = [["range", default_widget]] . to_json - json = Widgets.get_widget_json mock_text "take" ["range"] + json = Widgets.get_widget_json mock_text .take ["range"] json . should_equal expect - Widgets.get_widget_json mock_text "drop" ["range"] . should_equal expect + Widgets.get_widget_json mock_text .drop ["range"] . should_equal expect obj = json.parse_json widget = obj.first.second options = widget . at "values"