Browse Source

Support REPL expressions through DAP `evaluate` request

Ricardo Subtil 10 months ago
parent
commit
0d098d3cca

+ 20 - 7
editor/debugger/debug_adapter/debug_adapter_parser.cpp

@@ -30,6 +30,8 @@
 
 
 #include "debug_adapter_parser.h"
 #include "debug_adapter_parser.h"
 
 
+#include "core/variant/variant.h"
+#include "editor/debugger/debug_adapter/debug_adapter_types.h"
 #include "editor/debugger/editor_debugger_node.h"
 #include "editor/debugger/editor_debugger_node.h"
 #include "editor/debugger/script_editor_debugger.h"
 #include "editor/debugger/script_editor_debugger.h"
 #include "editor/export/editor_export_platform.h"
 #include "editor/export/editor_export_platform.h"
@@ -487,16 +489,27 @@ Dictionary DebugAdapterParser::req_stepIn(const Dictionary &p_params) const {
 }
 }
 
 
 Dictionary DebugAdapterParser::req_evaluate(const Dictionary &p_params) const {
 Dictionary DebugAdapterParser::req_evaluate(const Dictionary &p_params) const {
-	Dictionary response = prepare_success_response(p_params), body;
-	response["body"] = body;
-
 	Dictionary args = p_params["arguments"];
 	Dictionary args = p_params["arguments"];
+	String expression = args["expression"];
+	int frame_id = args.has("frameId") ? static_cast<int>(args["frameId"]) : DebugAdapterProtocol::get_singleton()->_current_frame;
 
 
-	String value = EditorDebuggerNode::get_singleton()->get_var_value(args["expression"]);
-	body["result"] = value;
-	body["variablesReference"] = 0;
+	if (HashMap<String, DAP::Variable>::Iterator E = DebugAdapterProtocol::get_singleton()->eval_list.find(expression); E) {
+		Dictionary response = prepare_success_response(p_params);
+		Dictionary body;
+		response["body"] = body;
 
 
-	return response;
+		DAP::Variable var = E->value;
+
+		body["result"] = var.value;
+		body["variablesReference"] = var.variablesReference;
+
+		// Since an evaluation can alter the state of the debuggee, they are volatile, and should only be used once
+		DebugAdapterProtocol::get_singleton()->eval_list.erase(E->key);
+		return response;
+	} else {
+		DebugAdapterProtocol::get_singleton()->request_remote_evaluate(expression, frame_id);
+	}
+	return Dictionary();
 }
 }
 
 
 Dictionary DebugAdapterParser::req_godot_put_msg(const Dictionary &p_params) const {
 Dictionary DebugAdapterParser::req_godot_put_msg(const Dictionary &p_params) const {

+ 34 - 0
editor/debugger/debug_adapter/debug_adapter_protocol.cpp

@@ -799,6 +799,22 @@ void DebugAdapterProtocol::parse_object(SceneDebuggerObject &p_obj) {
 	variable_list.insert(object_list[object_id], properties);
 	variable_list.insert(object_list[object_id], properties);
 }
 }
 
 
+void DebugAdapterProtocol::parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var) {
+	// If the eval is not on the pending list, we weren't expecting it. Ignore it.
+	String eval = p_var.name;
+	if (!eval_pending_list.erase(eval)) {
+		return;
+	}
+
+	DAP::Variable variable;
+	variable.name = p_var.name;
+	variable.value = p_var.value;
+	variable.type = Variant::get_type_name(p_var.value.get_type());
+	variable.variablesReference = parse_variant(p_var.value);
+
+	eval_list.insert(variable.name, variable);
+}
+
 const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) {
 const Variant DebugAdapterProtocol::parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property) {
 	const PropertyInfo &info = p_property.first;
 	const PropertyInfo &info = p_property.first;
 	const Variant &value = p_property.second;
 	const Variant &value = p_property.second;
@@ -833,6 +849,18 @@ bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {
 	return true;
 	return true;
 }
 }
 
 
+bool DebugAdapterProtocol::request_remote_evaluate(const String &p_eval, int p_stack_frame) {
+	// If the eval is already on the pending list, we don't need to request it again
+	if (eval_pending_list.has(p_eval)) {
+		return false;
+	}
+
+	EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_evaluate(p_eval, p_stack_frame);
+	eval_pending_list.insert(p_eval);
+
+	return true;
+}
+
 bool DebugAdapterProtocol::process_message(const String &p_text) {
 bool DebugAdapterProtocol::process_message(const String &p_text) {
 	JSON json;
 	JSON json;
 	ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
 	ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
@@ -1148,6 +1176,12 @@ void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_dat
 		remote_obj.deserialize(p_data);
 		remote_obj.deserialize(p_data);
 
 
 		parse_object(remote_obj);
 		parse_object(remote_obj);
+	} else if (p_msg == "evaluation_return") {
+		// An evaluation was requested from the debuggee; parse it.
+		DebuggerMarshalls::ScriptStackVariable remote_evaluation;
+		remote_evaluation.deserialize(p_data);
+
+		parse_evaluation(remote_evaluation);
 	}
 	}
 
 
 	notify_custom_data(p_msg, p_data);
 	notify_custom_data(p_msg, p_data);

+ 7 - 0
editor/debugger/debug_adapter/debug_adapter_protocol.h

@@ -31,9 +31,11 @@
 #ifndef DEBUG_ADAPTER_PROTOCOL_H
 #ifndef DEBUG_ADAPTER_PROTOCOL_H
 #define DEBUG_ADAPTER_PROTOCOL_H
 #define DEBUG_ADAPTER_PROTOCOL_H
 
 
+#include "core/debugger/debugger_marshalls.h"
 #include "core/io/stream_peer_tcp.h"
 #include "core/io/stream_peer_tcp.h"
 #include "core/io/tcp_server.h"
 #include "core/io/tcp_server.h"
 
 
+#include "core/object/object_id.h"
 #include "debug_adapter_parser.h"
 #include "debug_adapter_parser.h"
 #include "debug_adapter_types.h"
 #include "debug_adapter_types.h"
 #include "scene/debugger/scene_debugger.h"
 #include "scene/debugger/scene_debugger.h"
@@ -103,9 +105,11 @@ private:
 	int parse_variant(const Variant &p_var);
 	int parse_variant(const Variant &p_var);
 	void parse_object(SceneDebuggerObject &p_obj);
 	void parse_object(SceneDebuggerObject &p_obj);
 	const Variant parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property);
 	const Variant parse_object_variable(const SceneDebuggerObject::SceneDebuggerProperty &p_property);
+	void parse_evaluation(DebuggerMarshalls::ScriptStackVariable &p_var);
 
 
 	ObjectID search_object_id(DAPVarID p_var_id);
 	ObjectID search_object_id(DAPVarID p_var_id);
 	bool request_remote_object(const ObjectID &p_object_id);
 	bool request_remote_object(const ObjectID &p_object_id);
+	bool request_remote_evaluate(const String &p_eval, int p_stack_frame);
 
 
 	bool _initialized = false;
 	bool _initialized = false;
 	bool _processing_breakpoint = false;
 	bool _processing_breakpoint = false;
@@ -129,6 +133,9 @@ private:
 	HashMap<ObjectID, DAPVarID> object_list;
 	HashMap<ObjectID, DAPVarID> object_list;
 	HashSet<ObjectID> object_pending_set;
 	HashSet<ObjectID> object_pending_set;
 
 
+	HashMap<String, DAP::Variable> eval_list;
+	HashSet<String> eval_pending_list;
+
 public:
 public:
 	friend class DebugAdapterServer;
 	friend class DebugAdapterServer;
 
 

+ 1 - 4
editor/debugger/editor_expression_evaluator.cpp

@@ -64,10 +64,7 @@ void EditorExpressionEvaluator::_evaluate() {
 		return;
 		return;
 	}
 	}
 
 
-	Array expr_data;
-	expr_data.push_back(expression);
-	expr_data.push_back(editor_debugger->get_stack_script_frame());
-	editor_debugger->send_message("evaluate", expr_data);
+	editor_debugger->request_remote_evaluate(expression, editor_debugger->get_stack_script_frame());
 
 
 	expression_input->clear();
 	expression_input->clear();
 }
 }

+ 7 - 0
editor/debugger/script_editor_debugger.cpp

@@ -253,6 +253,13 @@ const SceneDebuggerTree *ScriptEditorDebugger::get_remote_tree() {
 	return scene_tree;
 	return scene_tree;
 }
 }
 
 
+void ScriptEditorDebugger::request_remote_evaluate(const String &p_expression, int p_stack_frame) {
+	Array msg;
+	msg.push_back(p_expression);
+	msg.push_back(p_stack_frame);
+	_put_msg("evaluate", msg);
+}
+
 void ScriptEditorDebugger::update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value) {
 void ScriptEditorDebugger::update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value) {
 	Array msg;
 	Array msg;
 	msg.push_back(p_obj_id);
 	msg.push_back(p_obj_id);

+ 2 - 0
editor/debugger/script_editor_debugger.h

@@ -254,6 +254,8 @@ public:
 	void request_remote_tree();
 	void request_remote_tree();
 	const SceneDebuggerTree *get_remote_tree();
 	const SceneDebuggerTree *get_remote_tree();
 
 
+	void request_remote_evaluate(const String &p_expression, int p_stack_frame);
+
 	void start(Ref<RemoteDebuggerPeer> p_peer);
 	void start(Ref<RemoteDebuggerPeer> p_peer);
 	void stop();
 	void stop();