Demo of my Swift Interpreter that uses SwiftSyntax

Hey guys, I've been working on a Swift Interpreter for a while, and the results are starting to look good. It works by parsing the Swift code using SwiftSyntax then then traversing the AST tree. Here's a demo of it working!

Note: right now the repo is private. If you'd like to help or use it, message me and I can get you access.

21 Likes

Are you still working on this? I was curious to try it.

1 Like

I’m about to start an open source rewrite after discovering a good hack for initing generics. I’ll update the thread when it’s up.

3 Likes

Yes, I realize this is taking forever. (Who knew writing an interpreter would be hard? :wink:) Anyways, here's two updates on the rewrite.

1. My generics hack

Here's the repo. The most important feature is the ability to construct any generic you want at runtime. i.e. the following types can be constructed at runtime without being explicitly there at compile-time.

// compile time struct
struct MyStruct<T, U> {}
// ... later one at runtime the following can be constructed
MyStruct<Int, Double>
MyStruct<MyClass, SomeOtherType>

This generics hack is what is going to allow the interpreter to construct PATs, generic types, and call generic functions even when specific types of the values which the interpreter will create and pass around are not known at compile time. The demo video of the old interpreter in my OP has no real notion of types, and so it relied on type-eraser to handle generics.

2. A Swift bytecode compiler in the works

The rewrite is a bytecode interpreter, not just a simple AST-walker. Here's a screenshot of it going from source to bytecode.

There's still a lot to implement, but I will release it open source once I get it running simple Swift programs. No promises on when that will be.

11 Likes

This is honestly the coolest project.

Just a small update. I'm taking a break from this project for a little bit. I've learned a lot about compilers and interpreters in the last year though. Really fun. I'll update this thread if/when I return to the project.

6 Likes

This is a pretty cool project. Do you have any plans to release the current sources in case other contributors are able to / want to take a crack at it?

I would like to but the truth is that I’m unhappy with the current state. I’d rather the first public commit be something I’m sure others could meaningfully contribute to.

Maybe in the meantime the implementation could be discussed. There is a big design decision I’m struggling to make right now with the type system. That problem was actually part of the reason I needed to take a break.

1 Like

Good news. I'm on track to open sourcing my rewrite later this year. Keep on eye on this thread :)

7 Likes

This is super inspiring! Hope that the project is going well.

3 Likes

@Nicholas agreed! a Swift interpreter --> Swift as a scripting language --> :star_struck:

@sudoio hope you are doing well :grinning:

1 Like

Wow, that's awesome project!

Here's a very crude version of an alternative "low-tech" approach (running "/usr/bin/swift" from within the app)
import SwiftUI

// MARK: sandbox is disabled
// tried com.apple.security.temporary-exception.files.absolute-path.read-only /usr/bin/swift
// but that didn't work for some reason

// TODO: proper error checking and remove force unwrapping

struct ContentView: View {
    @State var source = #"print("Hello, World!")"#
    @State var output = ""
    @State var outcome = ""
    @State var executing = false
    
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Spacer()
                Button("run", action: run)
                    .disabled(executing)
                    .keyboardShortcut(.defaultAction)
            }
            TextEditor(text: $source)
                .monospaced()
                .font(.title2)
            TextEditor(text: $output)
                .disabled(true)
                .font(.title2)
                .foregroundColor(.secondary)
            Text(outcome)
                .font(.title2)
                .foregroundColor(.red)
        }
        .padding()
    }
    
    func run() {
        let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("foo.swift")
        let outputUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.txt")
        try! source.data(using: .utf8)!.write(to: fileUrl)
        try! "".data(using: .utf8)!.write(to: outputUrl)
        let task = try! NSUserUnixTask(url: URL(fileURLWithPath: "/usr/bin/swift"))
        let file = try! FileHandle(forWritingTo: outputUrl)
        task.standardOutput = file
        task.standardError = file
        output = ""
        outcome = ""
        executing = true
        task.execute(withArguments: [fileUrl.path]) { error in
            let data = try! Data(contentsOf: outputUrl)
            output = String(data: data, encoding: .utf8)!
            outcome = error?.localizedDescription ?? ""
            executing = false
            try? file.close()
        }
    }
}

// smart quotes workaround
extension NSTextView {
    open override var frame: CGRect {
        didSet {
            isAutomaticQuoteSubstitutionEnabled = false
        }
    }
}

@main struct macUApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Obviously this depends on "/usr/bin/swift" being available on the computer. Note that this was very quickly cooked and the code is littered with unsafe optional unwrapping and lacks proper error handling.

I had to disable sandbox as I wasn't able to talk macOS into using a provided temporary exception absolute file path readonly access. With sandbox enabled the app will refuse with: "The file "swift" couldn't be opened because you don't have permission to view it."

Example output

SwiftConsole

1 Like

Just wanted to add that this is really awesome! I've been looking for a nice embeddable language that has similar advantages to Swift. It would be awesome to see this grow!

1 Like