A language server is an HTTP server which implements the LSP protocol. So you can run an embedded interpreter with access to sockets, then run code on the interpreter which starts the language server. Clients (IDEs) would connect to this server and send requests on the files being edited, which could be in the same language as the interpreter runs.
Although the interpreter runs code, it doesn’t handle editing code. The server could use eval and reflection to process LSP requests. For instance, editor requests available symbols -> interpreter sources the file (taking care to not run side effects, just load definitions) -> interpreter uses reflection to get available symbols -> interpreter responds to the editor.
However, the language server needs to read definitions from the file quickly and doing so shouldn’t cause any side effects, so interpreting the file may not actually be very beneficial. Typically a language server would be written in a language like C++ or Rust, which parses the source code and then uses special queries to extract information very quickly. See for example rust-analyzer and their blog posts, most recently on their incremental computation engine. Also, each feature and diagnostic listed in the manual has a link to the source code where said feature is implemented (ex: annotations).
What I do think is a good idea is having the interpreter implement the Debug Adapter Protocol. The interpreter, when run with a special flag, would start a debug server which IDEs can connect to. Then the IDE would send requests to evaluate specific programs and source code (see the DAP specification) as well as requests to add breakpoints etc.; since it’s already built to interpret code, the interpreter is already partway there to handling these requests.
I don’t even think it is necessarily required that the server is the interpreter frontend. All that matters is: Can they live in the same process (which is their host application) and many implications that arise.
Because that way, they could share known function signatures. In theory.
You can see here for info on VS Code’s DAP integration, and here for neovim. I think the IDE connects to the server when it loads a file of the server’s registered type. However in theory you can always have the server start the IDE (or connect to a running IDE process) and then make the IDE connect (by calling a function or opening a file and triggering whatever else is necessary).
Not 100% clear, but:
A language server is an HTTP server which implements the LSP protocol. So you can run an embedded interpreter with access to sockets, then run code on the interpreter which starts the language server. Clients (IDEs) would connect to this server and send requests on the files being edited, which could be in the same language as the interpreter runs.
Although the interpreter runs code, it doesn’t handle editing code. The server could use
eval
and reflection to process LSP requests. For instance, editor requests available symbols -> interpreter sources the file (taking care to not run side effects, just load definitions) -> interpreter uses reflection to get available symbols -> interpreter responds to the editor.However, the language server needs to read definitions from the file quickly and doing so shouldn’t cause any side effects, so interpreting the file may not actually be very beneficial. Typically a language server would be written in a language like C++ or Rust, which parses the source code and then uses special queries to extract information very quickly. See for example rust-analyzer and their blog posts, most recently on their incremental computation engine. Also, each feature and diagnostic listed in the manual has a link to the source code where said feature is implemented (ex: annotations).
What I do think is a good idea is having the interpreter implement the Debug Adapter Protocol. The interpreter, when run with a special flag, would start a debug server which IDEs can connect to. Then the IDE would send requests to evaluate specific programs and source code (see the DAP specification) as well as requests to add breakpoints etc.; since it’s already built to interpret code, the interpreter is already partway there to handling these requests.
Sorry, the title is somewhat misleading.
I don’t even think it is necessarily required that the server is the interpreter frontend. All that matters is: Can they live in the same process (which is their host application) and many implications that arise.
Because that way, they could share known function signatures. In theory.
I believe so, since you can host a client and server in the same process. You could use threads, co-routines, or polling to get the server to listen while the interpreter is running and vice versa
Do you know if it is possible for the server side to start the interaction? Or, when in doubt, an external application to pick the server instance?
You can see here for info on VS Code’s DAP integration, and here for neovim. I think the IDE connects to the server when it loads a file of the server’s registered type. However in theory you can always have the server start the IDE (or connect to a running IDE process) and then make the IDE connect (by calling a function or opening a file and triggering whatever else is necessary).
Thanks!