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: GitHub - 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.
duplicate declarations
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.
code completion
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: Completion limitations · Issue #113 · jpsim/SourceKitten · GitHub).
- 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.
Thanks!!