From 4296ca5088cffafae506522d6c1186fe011220d6 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 19 May 2017 14:10:16 -0400
Subject: [PATCH 16/31] FIXME: wire up the LSP server to the port

---
 gcc/http-server.c                |   2 +-
 gcc/http-server.h                |   4 +-
 gcc/json-rpc.c                   |  46 +++++-
 gcc/json-rpc.h                   |  19 +++
 gcc/lsp-main.c                   |  99 +++----------
 gcc/lsp-main.h                   |  25 ++++
 gcc/lsp.c                        | 312 +++++++++++++++++++--------------------
 gcc/lsp.h                        | 157 +++++++++++++++++++-
 gcc/testsuite/gcc.dg/lsp/test.py |  55 ++++++-
 gcc/toplev.c                     |   2 +-
 10 files changed, 479 insertions(+), 242 deletions(-)
 create mode 100644 gcc/lsp-main.h

diff --git a/gcc/http-server.c b/gcc/http-server.c
index ba5fc13..50b0c34 100644
--- a/gcc/http-server.c
+++ b/gcc/http-server.c
@@ -141,7 +141,7 @@ http::server::on_read (file_descriptor fd, size_t length, const char *buf)
       request req;
       req_start += req.parse_buffer (length, buf);
       http::response resp;
-      on_request (req, resp);
+      on_http_request (req, resp);
       char *resp_str = resp.to_str ();
       if (1)
 	inform (UNKNOWN_LOCATION, "sending http response: %qs",
diff --git a/gcc/http-server.h b/gcc/http-server.h
index 8a28ce8..48955cb 100644
--- a/gcc/http-server.h
+++ b/gcc/http-server.h
@@ -74,8 +74,8 @@ class server : public ::server
   void on_read (file_descriptor fd, size_t length,
 		const char *buf) OVERRIDE FINAL;
 
-  virtual void on_request (const http::request &request,
-			   http::response &response) = 0;
+  virtual void on_http_request (const http::request &request,
+				http::response &response) = 0;
 
  private:
   bool m_verbose;
diff --git a/gcc/json-rpc.c b/gcc/json-rpc.c
index a9bafbd..d81ee51 100644
--- a/gcc/json-rpc.c
+++ b/gcc/json-rpc.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "json.h"
+#include "http-server.h"
 #include "json-rpc.h"
 #include "selftest.h"
 
@@ -167,6 +168,30 @@ jsonrpc::server::handle_request_string (const char *utf8)
   return handle_request (strlen (utf8), utf8);
 }
 
+/* class ::jsonrpc::http_server : public ::http::server.  */
+
+jsonrpc::http_server::http_server (jsonrpc::server &json_handler)
+: ::http::server (true), m_json_handler (json_handler)
+{}
+
+/* Handle HTTP requests by parsing the content as JSON-RPC, and delegating
+   them to a ::jsonrpc::server.  */
+
+void
+jsonrpc::http_server::on_http_request (const http::request &http_request,
+				       http::response &http_response)
+{
+  size_t length = http_request.get_content_length ();
+  const char *buf = http_request.get_content ();
+  if (0)
+    fprintf (stderr, "got content: '%.*s'\n", (int)length, buf);
+  json::value *json_response = m_json_handler.handle_request (length, buf);
+  char *response_str = json_response->to_str ();
+  delete json_response;
+  http_response.set_content (strlen (response_str), response_str);
+  free (response_str);
+}
+
 #if CHECKING_P
 
 namespace selftest {
@@ -362,6 +387,25 @@ test_malformed_json ()
   delete response;
 }
 
+static void
+test_http_server ()
+{
+  http::request req;
+  const char *in = ("POST /jsonrpc HTTP/1.1\r\n"
+		    "Content-Length: FIXME\r\n"
+		    "\r\n"
+		    "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\","
+		    " \"params\": [42, 23], \"id\": 1}");
+  req.parse_buffer (strlen (in), in);
+
+  test_server s (false);
+  http_server http_server (s);
+  http::response resp;
+  http_server.on_http_request (req, resp);
+  ASSERT_STREQ ("{\"jsonrpc\": \"2.0\", \"id\": 1, \"result\": 19}",
+		resp.get_content ()); // FIXME: length?
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -373,7 +417,7 @@ json_rpc_c_tests ()
   test_method_not_a_string ();
   test_method_not_found ();
   test_malformed_json ();
-  // TODO: bogus JSON
+  test_http_server ();
 }
 
 } // namespace selftest
diff --git a/gcc/json-rpc.h b/gcc/json-rpc.h
index 4b5fd4b..ef9ad2d 100644
--- a/gcc/json-rpc.h
+++ b/gcc/json-rpc.h
@@ -28,6 +28,7 @@ class server
  public:
   server (bool verbose) : m_verbose (verbose) {}
   virtual ~server () {}
+
   json::value *handle_request (json::value *);
   json::value *handle_request (size_t sz, const char *buf);
   json::value *handle_request_string (const char *utf8);
@@ -64,6 +65,24 @@ extern json::value *make_invalid_params (const json::value *id,
 
 extern json::value *make_success (const json::value *id, json::value *result);
 
+
+/* A subclass of ::http::server that handles HTTP requests
+   by parsing the content as JSON-RPC, and delegating them to
+   a ::jsonrpc::server.  */
+
+class http_server : public ::http::server
+{
+ public:
+  http_server (::jsonrpc::server &json_handler);
+
+  void on_http_request (const http::request &http_request,
+			http::response &http_response) OVERRIDE FINAL;
+
+ private:
+  ::jsonrpc::server &m_json_handler;
+};
+
+
 } // namespace jsonrpc
 
 #endif  /* GCC_JSON_RPC_H  */
diff --git a/gcc/lsp-main.c b/gcc/lsp-main.c
index 5b76d3c..a0d358f 100644
--- a/gcc/lsp-main.c
+++ b/gcc/lsp-main.c
@@ -23,96 +23,39 @@ along with GCC; see the file COPYING3.  If not see
 #include "http-server.h"
 #include "json.h"
 #include "json-rpc.h"
-#include "selftest.h"
+#include "lsp.h"
 
-class jsonrpc_server : public http::server
-{
- public:
-  jsonrpc_server (jsonrpc::server &json_handler)
-  : http::server (true), m_json_handler (json_handler) {}
-
-  void on_request (const http::request &http_request,
-		   http::response &http_response) OVERRIDE FINAL
-  {
-    size_t length = http_request.get_content_length ();
-    const char *buf = http_request.get_content ();
-    if (1)
-      fprintf (stderr, "got content: '%.*s'\n", (int)length, buf);
-    json::value *json_response = m_json_handler.handle_request (length, buf);
-    char *response_str = json_response->to_str ();
-    http_response.set_content (strlen (response_str), response_str);
-    free (response_str);
-  }
-
- private:
-  jsonrpc::server &m_json_handler;
-};
-
-// FIXME: copy of test server...
-
-using namespace jsonrpc;
+using namespace lsp;
 
-namespace {
+/* FIXME.  */
 
-class test_server : public jsonrpc::server
+class test_lsp_server : public lsp::noop_server
 {
- public:
-  test_server (bool verbose) : server (verbose) {}
-
-  json::value *
-  dispatch (const char *method, const json::value *params,
-	    const json::value *id) FINAL OVERRIDE
-  {
-    if (0 == strcmp (method, "echo"))
-      return do_echo (params, id);
-    if (0 == strcmp (method, "subtract"))
-      return do_subtract (params, id);
-    return make_method_not_found (id, method);
-  }
-
-  json::value *
-  do_echo (const json::value *params, const json::value *id)
-  {
-    const json::array *positional = params->as_array ();
-    if (!positional)
-      return make_invalid_params (id, "params was not an array");
-    if (positional->get_length () != 1)
-      return make_invalid_params (id, "length of params was not 1");
-    const json::value *arg0 = positional->get (0);
-    return make_success (id, arg0->clone ());
-  }
-
-  json::value *
-  do_subtract (const json::value *params, const json::value *id)
+  void
+  do_text_document_definition (const TextDocumentPositionParams &p,
+			       vec<Location> &out) OVERRIDE
   {
-    const json::array *positional = params->as_array ();
-    if (!positional)
-      return make_invalid_params (id, "params was not an array");
-    if (positional->get_length () != 2)
-      return make_invalid_params (id, "length of params was not 2");
-
-    const json::number *arg0 = positional->get (0)->as_number ();
-    if (!arg0)
-      return make_invalid_params (id, "param 0 was not a number");
-    const json::number *arg1 = positional->get (1)->as_number ();
-    if (!arg1)
-      return make_invalid_params (id, "param 1 was not a number");
-
-    double result = arg0->get () - arg1->get ();
-
-    return make_success (id, new json::number (result));
+    // FIXME: currently a hack
+    Location result;
+    result.uri = "test.c";
+    result.range.start.line = 20;
+    result.range.start.character = 10;
+    result.range.end.line = 20;
+    result.range.end.character = 15;
+    out.safe_push (result);
   }
 };
 
-} // anonymous namespace
-
 /* Serve LSP on PORT.  */
 
 void
 serve_lsp (int port)
 {
-  test_server ts (true);
-  jsonrpc_server s (ts);
+  // FIXME
+  test_lsp_server lsp_server;
+  lsp::jsonrpc_server json_lsp_server (true, lsp_server);
+  jsonrpc::http_server http_server (json_lsp_server);
+
   fprintf (stderr, "serving on port %i\n", port);
-  s.serve (port);
+  http_server.serve (port);
 }
diff --git a/gcc/lsp-main.h b/gcc/lsp-main.h
new file mode 100644
index 0000000..ec57201
--- /dev/null
+++ b/gcc/lsp-main.h
@@ -0,0 +1,25 @@
+/* Entrypoint to Language Server Protocol implementation.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_LSP_MAIN_H
+#define GCC_LSP_MAIN_H
+
+extern void serve_lsp (int port);
+
+#endif  /* GCC_LSP_MAIN_H  */
diff --git a/gcc/lsp.c b/gcc/lsp.c
index 682efcf..ff25d00 100644
--- a/gcc/lsp.c
+++ b/gcc/lsp.c
@@ -21,181 +21,179 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "json.h"
+#include "http-server.h"
 #include "json-rpc.h"
+#include "lsp.h"
 #include "selftest.h"
 
 using namespace jsonrpc;
+using namespace lsp;
 
-typedef const char *DocumentUri;
-
+// TODO: autogenerate the interface binding/marshalling/demarshalling code
+// from an interface description.
 
-/* Interfaces from the protocol specification (which uses camel case).  */
+TextDocumentItem
+TextDocumentItem::from_json (const json::value *params,
+				     json::value *&out_err)
+{
+  TextDocumentItem result;
+  const json::object *obj = params->as_object ();
+  if (!obj)
+    {
+      out_err = make_invalid_params (NULL, NULL);
+      return result;
+    }
+
+  result.uri = obj->get ("uri")->as_string ()->get_string ();
+  result.languageId = obj->get ("languageId")->as_string ()->get_string ();
+  result.version = obj->get ("version")->as_number ()->get ();
+  result.text = obj->get ("text")->as_string ()->get_string ();
+  return result;
+}
 
-// Exceptions would be nicer than passing around the out_err
+DidOpenTextDocumentParams
+DidOpenTextDocumentParams::from_json (const json::value *params,
+				      json::value *&out_err)
+{
+  DidOpenTextDocumentParams result;
+  const json::object *obj = params->as_object ();
+  if (!obj)
+    {
+      out_err = make_invalid_params (NULL, NULL);
+      return result;
+    }
+  // FIXME: error-handling
+  result.textDocument
+    = TextDocumentItem::from_json (obj->get ("textDocument"), out_err);
+  return result;
+}
 
-// TODO: autogenerate the interface binding/marshalling/demarshalling code
-// from an interface description.
+DidChangeTextDocumentParams
+DidChangeTextDocumentParams::from_json (const json::value *params,
+					json::value *&out_err)
+{
+  DidChangeTextDocumentParams result;
+  // FIXME
+  return result;
+}
 
-struct TextDocumentItem
+TextDocumentPositionParams
+TextDocumentPositionParams::from_json (const json::value *params,
+				       json::value *&out_err)
 {
-  static TextDocumentItem from_json (const json::value *params,
-				     json::value *&out_err)
-  {
-    TextDocumentItem result;
-    const json::object *obj = params->as_object ();
-    if (!obj)
-      {
-	out_err = make_invalid_params (NULL, NULL);
-	return result;
-      }
-
-    result.uri = obj->get ("uri")->as_string ()->get_string ();
-    result.languageId = obj->get ("languageId")->as_string ()->get_string ();
-    result.version = obj->get ("version")->as_number ()->get ();
-    result.text = obj->get ("text")->as_string ()->get_string ();
-    return result;
-  }
-
-  DocumentUri uri;
-  const char *languageId;
-  double version;
-  const char *text;
-};
-
-struct DidOpenTextDocumentParams
+  TextDocumentPositionParams result;
+  // FIXME
+  return result;
+}
+
+/* struct Position.  */
+
+json::value *
+Position::to_json () const
 {
-  static DidOpenTextDocumentParams from_json (const json::value *params,
-					      json::value *&out_err)
-  {
-    DidOpenTextDocumentParams result;
-    const json::object *obj = params->as_object ();
-    if (!obj)
-      {
-	out_err = make_invalid_params (NULL, NULL);
-	return result;
-      }
-    // FIXME: error-handling
-    result.textDocument
-      = TextDocumentItem::from_json (obj->get ("textDocument"), out_err);
-    return result;
-  }
-
-  TextDocumentItem textDocument;
-};
-
-struct DidChangeTextDocumentParams
+  json::object *result = new json::object ();
+  result->set ("line", new json::number (line));
+  result->set ("character", new json::number (character));
+  return result;
+}
+
+/* struct Range.  */
+
+json::value *
+Range::to_json () const
 {
- public:
-  static DidChangeTextDocumentParams from_json (const json::value *params,
-						json::value *&out_err)
-  {
-    DidChangeTextDocumentParams result;
-    // FIXME
-    return result;
-  }
-
- private:
-#if 0
-  VersionedTextDocumentIdentifier textDocument;
-  auto_vec<TextDocumentContentChangeEvent> contentChanges;
-#endif
-};
-
-/* An abstract base class for implementing the LSP as vfunc calls.  */
-
-class lsp_server
+  json::object *result = new json::object ();
+  result->set ("start", start.to_json ());
+  result->set ("end", end.to_json ());
+  return result;
+}
+
+/* struct Location.  */
+
+json::value *
+Location::to_json () const
 {
- public:
-  virtual ~lsp_server () {}
+  json::object *result = new json::object ();
+  result->set ("uri", new json::string (uri));
+  result->set ("range", range.to_json ());
+  return result;
+}
 
-  virtual void
-  do_text_document_did_open (const DidOpenTextDocumentParams &p) = 0;
+/* class lsp::jsonrpc_server : public ::jsonrpc::server.  */
 
-  virtual void
-  do_text_document_did_change (const DidChangeTextDocumentParams &p) = 0;
-};
+json::value *
+lsp::jsonrpc_server::dispatch (const char *method, const json::value *params,
+			       const json::value *id)
+{
+  if (0 == strcmp (method, "initialize"))
+    return do_initialize (id, params);
+  if (0 == strcmp (method, "textDocument/didOpen"))
+    return do_text_document_did_open (params);
+  if (0 == strcmp (method, "textDocument/didChange"))
+    return do_text_document_did_change (params);
+  if (0 == strcmp (method, "textDocument/definition"))
+    return do_text_document_definition (params);
+  return make_method_not_found (id, method);
+}
 
-/* A concrete subclass of lsp_server that implements everything as a no-op.  */
+json::value *
+lsp::jsonrpc_server::do_initialize (const json::value *id,
+				    const json::value *params)
+{
+  // FIXME: for now, ignore params
 
-class noop_lsp_server : public lsp_server
+  json::object *server_caps = new json::object ();
+  json::object *result = new json::object ();
+  result->set ("capabilities", server_caps);
+  return make_success (id, result);
+}
+
+json::value *
+lsp::jsonrpc_server::do_text_document_did_open (const json::value *params)
 {
-  void
-  do_text_document_did_open (const DidOpenTextDocumentParams &p) OVERRIDE
-  {
-    // no-op
-  }
-
-  void
-  do_text_document_did_change (const DidChangeTextDocumentParams &p) OVERRIDE
-  {
-    // no-op
-  }
-};
-
-/* A jsonrpc::server subclass that decodes incoming JSON-RPC requests
-   and dispatches them to an lsp_server instance as vfunc calls.  */
-
-class json_lsp_server : public jsonrpc::server
+  json::value *err = NULL;
+  DidOpenTextDocumentParams p
+    = DidOpenTextDocumentParams::from_json (params, err);
+  if (err)
+    return err; // though we ought not to return non-NULL for a notification
+
+  m_inner.do_text_document_did_open (p);
+  return NULL; // notification, so no response
+}
+
+json::value *
+lsp::jsonrpc_server::do_text_document_did_change (const json::value *params)
 {
- public:
-  json_lsp_server (bool verbose, lsp_server &inner)
-  : server (verbose), m_inner (inner) {}
-
-  json::value *
-  dispatch (const char *method, const json::value *params,
-	    const json::value *id) FINAL OVERRIDE
-  {
-    if (0 == strcmp (method, "initialize"))
-      return do_initialize (id, params);
-    if (0 == strcmp (method, "textDocument/didOpen"))
-      return do_text_document_did_open (params);
-    if (0 == strcmp (method, "textDocument/didChange"))
-      return do_text_document_did_change (params);
-    return make_method_not_found (id, method);
-  }
-
-  json::value *
-  do_initialize (const json::value *id, const json::value *params)
-  {
-    // FIXME: for now, ignore params
-
-    json::object *server_caps = new json::object ();
-    json::object *result = new json::object ();
-    result->set ("capabilities", server_caps);
-    return make_success (id, result);
-  }
-
-  json::value *
-  do_text_document_did_open (const json::value *params)
-  {
-    json::value *err = NULL;
-    DidOpenTextDocumentParams p
-      = DidOpenTextDocumentParams::from_json (params, err);
-    if (err)
-      return err; // though we ought not to return non-NULL for a notification
-
-    m_inner.do_text_document_did_open (p);
-    return NULL; // notification, so no response
-  }
-
-  json::value *
-  do_text_document_did_change (const json::value *params)
-  {
-    json::value *err = NULL;
-    DidChangeTextDocumentParams p
-      = DidChangeTextDocumentParams::from_json (params, err);
-    if (err)
-      return err; // though we ought not to return non-NULL for a notification
-
-    m_inner.do_text_document_did_change (p);
-
-    return NULL; // notification, so no response
-  }
-
- private:
-  lsp_server &m_inner;
-};
+  json::value *err = NULL;
+  DidChangeTextDocumentParams p
+    = DidChangeTextDocumentParams::from_json (params, err);
+  if (err)
+    return err; // though we ought not to return non-NULL for a notification
+
+  m_inner.do_text_document_did_change (p);
 
+  return NULL; // notification, so no response
+}
+
+json::value *
+lsp::jsonrpc_server::do_text_document_definition (const json::value *params)
+{
+  json::value *err = NULL;
+  TextDocumentPositionParams p
+    = TextDocumentPositionParams::from_json (params, err);
+  if (err)
+    return err;
+
+  auto_vec<Location> out;
+  m_inner.do_text_document_definition (p, out);
+
+  json::array *result = new json::array ();
+  unsigned i;
+  Location *loc;
+  FOR_EACH_VEC_ELT (out, i, loc)
+    result->append (loc->to_json ());
+  return result;
+}
 
 #if CHECKING_P
 
@@ -206,8 +204,8 @@ namespace selftest {
 static void
 test_simple ()
 {
-  noop_lsp_server noop;
-  json_lsp_server js (true, noop);
+  noop_server noop;
+  lsp::jsonrpc_server js (true, noop);
   const char *init_request
     = ("{\"jsonrpc\": \"2.0\", \"method\": \"initialize\","
        " \"params\": [42, 23], \"id\": 1}"); // FIXME
diff --git a/gcc/lsp.h b/gcc/lsp.h
index 6b04025..f44e278 100644
--- a/gcc/lsp.h
+++ b/gcc/lsp.h
@@ -20,7 +20,162 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_LSP_H
 #define GCC_LSP_H
 
-extern void serve_lsp (int port);
+namespace lsp {
+
+typedef const char *DocumentUri;
+
+/* Interfaces from the protocol specification (which uses camel case).  */
+
+struct Position
+{
+  json::value *to_json () const;
+
+  int line;
+  int character;
+};
+
+struct Range
+{
+  json::value *to_json () const;
+
+  Position start;
+  Position end;
+};
+
+struct Location
+{
+  json::value *to_json () const;
+
+  DocumentUri uri;
+  Range range;
+};
+
+// Exceptions would be nicer than passing around the out_err
+
+// TODO: autogenerate the interface binding/marshalling/demarshalling code
+// from an interface description.
+
+struct TextDocumentIdentifier
+{
+  DocumentUri uri;
+};
+
+struct TextDocumentItem
+{
+  static TextDocumentItem from_json (const json::value *params,
+				     json::value *&out_err);
+
+  DocumentUri uri;
+  const char *languageId;
+  double version;
+  const char *text;
+};
+
+struct DidOpenTextDocumentParams
+{
+  static DidOpenTextDocumentParams from_json (const json::value *params,
+					      json::value *&out_err);
+
+  TextDocumentItem textDocument;
+};
+
+struct DidChangeTextDocumentParams
+{
+ public:
+  static DidChangeTextDocumentParams from_json (const json::value *params,
+						json::value *&out_err);
+
+ private:
+#if 0
+  VersionedTextDocumentIdentifier textDocument;
+  auto_vec<TextDocumentContentChangeEvent> contentChanges;
+#endif
+};
+
+struct TextDocumentPositionParams
+{
+  static TextDocumentPositionParams from_json (const json::value *params,
+					       json::value *&out_err);
+
+  TextDocumentIdentifier textDocument;
+  Position position;
+};
+
+/* An abstract base class for implementing the LSP as vfunc calls,
+   avoiding dealing with JSON.  */
+
+class server
+{
+ public:
+  virtual ~server () {}
+
+  virtual void
+  do_text_document_did_open (const DidOpenTextDocumentParams &p) = 0;
+
+  virtual void
+  do_text_document_did_change (const DidChangeTextDocumentParams &p) = 0;
+
+  virtual void
+  do_text_document_definition (const TextDocumentPositionParams &p,
+			       vec<Location> &out) = 0;
+};
+
+/* A concrete subclass of lsp::server that implements everything as a no-op.  */
+
+class noop_server : public server
+{
+  void
+  do_text_document_did_open (const DidOpenTextDocumentParams &p) OVERRIDE
+  {
+    // no-op
+  }
+
+  void
+  do_text_document_did_change (const DidChangeTextDocumentParams &p) OVERRIDE
+  {
+    // no-op
+  }
+
+  void
+  do_text_document_definition (const TextDocumentPositionParams &p,
+			       vec<Location> &out) OVERRIDE
+  {
+    // no-op
+  }
+};
+
+/* A jsonrpc::server subclass that decodes incoming JSON-RPC requests
+   and dispatches them to an lsp_server instance as vfunc calls,
+   marshalling the inputs/outputs to/from JSON objects.  */
+
+class jsonrpc_server : public ::jsonrpc::server
+{
+ public:
+  jsonrpc_server (bool verbose, ::lsp::server &inner)
+  : server (verbose), m_inner (inner) {}
+
+  json::value *
+  dispatch (const char *method, const json::value *params,
+	    const json::value *id) FINAL OVERRIDE;
+
+ private:
+  json::value *
+  do_initialize (const json::value *id, const json::value *params);
+
+  json::value *
+  do_text_document_did_open (const json::value *params);
+
+  json::value *
+  do_text_document_did_change (const json::value *params);
+
+  json::value *
+  do_text_document_definition (const json::value *params);
+
+ private:
+  ::lsp::server &m_inner;
+};
+
+} // namespace lsp
 
 #endif  /* GCC_LSP_H  */
 
diff --git a/gcc/testsuite/gcc.dg/lsp/test.py b/gcc/testsuite/gcc.dg/lsp/test.py
index 5acae6b..a793745 100644
--- a/gcc/testsuite/gcc.dg/lsp/test.py
+++ b/gcc/testsuite/gcc.dg/lsp/test.py
@@ -6,11 +6,61 @@ def test():
 import requests
 import json
 
+class Position:
+    def __init__(self, line, column):
+        self.line = line
+        self.column = column
+
+    def to_json(self):
+        return {'line': self.line, 'column': self.column}
+
+class TextDocumentIdentifier:
+    def __init__(self, uri):
+        self.uri = uri
+
+    def to_json(self):
+        return {'uri': self.uri}
+
+class TextDocumentPositionParams:
+    def __init__(self, textDocument, position):
+        self.textDocument = textDocument
+        self.position = position
+
+
+class LspProxy:
+    def __init__(self, url):
+        self.url = url
+        self.next_id = 0
+
+    def make_request(self, method, params):
+        json_req = {"method": method,
+                    "params": params,
+                    "jsonrpc": "2.0",
+                    "id": self.next_id}
+        self.next_id += 1
+        return json_req
+
+    def post_request(self, method, params):
+        payload = self.make_request(method, params)
+        headers = {'content-type': 'application/json'}
+        response = requests.post(
+            self.url, data=json.dumps(payload), headers=headers)
+        print('response: %r' % response)
+        print('response.json(): %r' % response.json())
+        return response.json()
+
+    def goto_definition(self, textDocument, position):
+        json_resp = self.post_request('textDocument/definition',
+                                      {"textDocument" : textDocument.to_json(),
+                                       "position" : position.to_json()})
+        print(json_resp)
+        
 
 def main():
     url = "http://localhost:4000/jsonrpc"
     headers = {'content-type': 'application/json'}
 
+    """
     # Example echo method
     payload = {
         "method": "echo",
@@ -27,7 +77,10 @@ def main():
     assert response["result"] == "echome!"
     assert response["jsonrpc"]
     assert response["id"] == 0
+    """
+
+    proxy = LspProxy(url)
+    print(proxy.goto_definition(TextDocumentIdentifier('test.c'), Position(9, 17)))
 
 if __name__ == "__main__":
     main()
-
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 681bda8..9532106 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -79,7 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "omp-offload.h"
 #include "hsa-common.h"
 #include "edit-context.h"
-#include "lsp.h"
+#include "lsp-main.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
 #include "dbxout.h"
-- 
1.8.5.3

