I've started experimenting with a Jupyter kernel for Swift that works by calling LLDB's APIs to evaluate code. (If you're not familiar with Jupyter, it's like a REPL but with big boxes that make it easy to enter large multiline snippets of code to execute all at once. It also has a few other features like graphics output that make it really popular in machine learning and data science communities.) You can see it here: https://github.com/google/swift-jupyter
I have one general question: Does calling LLDB's APIs (specifically,
SBTarget.EvaluateExpression) to evaluate code sound like a sensible approach for implementing a Jupyter kernel?
And I have a few specific questions that have arisen from my experimentation.
When you declare something twice in the Swift REPL, the second declaration replaces the first one:
1> let x = 1 x: Int = 1 2> let x = 2 x: Int = 2 3> x $R0: Int = 2
However, if you use your declaration in the same line where you re-declare it, the REPL gives you an error:
1> let x = 1; print(x) 1 x: Int = 1 2> let x = 2; print(x) error: repl.swift:2:18: error: ambiguous use of 'x' let x = 2; print(x) ^ repl.swift:2:5: note: found this candidate let x = 2; print(x) ^
Is this something that can and should be fixed? I think that line 2 should succeed and print 2.
People using Jupyter will run into this a lot, because it's very common to write "cells" (single blocks of code that get executed all at once) that declare and use variables.
I'm happy to work on a fix if this is indeed something that can and should be fixed.
The Swift REPL has some nice code completion behavior that is not exposed through the LLDB API. I would love to be able to use this in the Jupyter kernel. Would it be reasonable for me to expose the code completion through the LLDB API somewhere?
I nearly have basic code completion working using the SourceKit API, but I think using the Swift REPL's implementation would be better in the long term because:
- The Swift REPL provides completions in more contexts. For example, if you type half a function name, the Swift REPL will complete it but SourceKit won't. (I found a previous discussion of this here: https://github.com/jpsim/SourceKitten/issues/113).
- I need to pass the code-completer a "history" of all the code that has already been executed, so that it knows how to complete things that the user has declared in previously-executed code. The Swift REPL completion seems to be happy to accept duplicate declarations in the history. SourceKit errors out when there is a duplicate declaration in the history.
- Overall, SourceKit seems intended for operating on files rather than interactive REPL sessions.