Search code examples
swiftclanglldbread-eval-print-loop

How can I grab the Swift REPL compiler errors in JSON format


I'm looking to grab Swift compiler errors from the Swift REPL in a readable format such as JSON or XML

The best I can do is read it in as a String via standard in/out pipes. I have tried nearly every argument/option with swiftc with no luck.

I read that I can write Python scripts that extend LLDB but I wouldn't know where to start.

Currently the format reads in as:

/Users/joeblow/Desktop/pre-compiled.swift:1:38: error: cannot convert value of type 'Int' to specified type 'String'
var age = 10; var name: String = 12;
                                 ^~

But I'm interested moreso in something like this:

{
  path: "/Users/joeblow/Desktop/compiled.swift",
  line: 1,
  position: 38,
  error: "cannot convert value of type 'Int' to specified type 'String'"
}

I do not want to use Regex/String manipulation.


Solution

  • The swift compiler accepts the -parseable-output flag, which produces a structured output including the errors. For instance, if wrong.swift has the contents of your example, I see:

     > swiftc -g -Onone -parseable-output wrong.swift
    1149
    {
      "kind": "began",
      "name": "compile",
      "command": "\/Applications\/Xcode.app\/Contents\/Developer\/Toolchains\/XcodeDefault.xctoolchain\/usr\/bin\/swift -frontend -c -primary-file wrong.swift -target x86_64-apple-macosx10.9 -enable-objc-interop -sdk \/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/MacOSX.platform\/Developer\/SDKs\/MacOSX10.13.sdk -g -emit-module-doc-path \/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.swiftdoc -color-diagnostics -Onone -module-name wrong -emit-module-path \/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.swiftmodule -o \/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.o",
      "inputs": [
        "wrong.swift"
      ],
      "outputs": [
        {
          "type": "object",
          "path": "\/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.o"
        },
        {
          "type": "swiftmodule",
          "path": "\/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.swiftmodule"
        },
        {
          "type": "swiftdoc",
          "path": "\/var\/folders\/zc\/dp8ptx_10pg8m6pnwpbnjms00000gp\/T\/wrong-bc5f07.swiftdoc"
        }
      ],
      "pid": 33440
    }
    306
    {
      "kind": "finished",
      "name": "compile",
      "pid": 33440,
      "output": "\u001B[1mwrong.swift:1:21: \u001B[0;1;31merror: \u001B[0m\u001B[1mcannot convert value of type 'Int' to specified type 'String'\n\u001B[0mvar name : String = 12\n\u001B[0;1;32m                    ^~\n\u001B[0m",
      "exit-status": 1
    }
    

    However, while the REPL uses a swift compiler instance for parsing your expressions, it doesn't have a way to accept and pass "extra flags" to that compiler, so at present I don't think there's any way to get the REPL to emit errors in this form.

    If you're interested in this capability then please file an enhancement request with the swift.org JIRA. If you are adventurous, you could even try adding it yourself. You would have to get the swift driver to pass this option to lldb, and then get lldb to parse and pass it to its compiler. Probably also have to extract only the errors from the output or it would be too noisy.