# Difftastic: A Structural Diff Tool for Programming Languages

DevFeed: [Difftastic: A Structural Diff Tool for Programming Languages](<https://devfeed.tech/articles/difftastic-the-fantastic-diff-22024.md>)

Original publisher: [Read original article](<http://www.wilfred.me.uk/blog/2022/09/06/difftastic-the-fantastic-diff/>)

Author: Wilfred Hughes

Published: 2022-09-06T00:00:00Z

Content type: tutorial

Language: en

Sources: [Wilfred Hughes](<https://devfeed.tech/sources/wilfred-hughes.md>)

Topics: [Parsing](<https://devfeed.tech/topics/parsing.md>), [Tree-sitter](<https://devfeed.tech/topics/tree-sitter.md>), [Parser](<https://devfeed.tech/topics/parser.md>), [Code](<https://devfeed.tech/topics/code.md>), [Lisp](<https://devfeed.tech/topics/lisp.md>), [JavaScript](<https://devfeed.tech/topics/javascript.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [emacs](<https://devfeed.tech/tags/emacs.md>), [javascript](<https://devfeed.tech/tags/javascript.md>), [lisp](<https://devfeed.tech/tags/lisp.md>), [parsing](<https://devfeed.tech/tags/parsing.md>), [programming](<https://devfeed.tech/tags/programming.md>), [time](<https://devfeed.tech/tags/time.md>)

## AI overview

The article explains how difftastic implements structural diffs for programming languages. It describes parsing source code with tree-sitter, converting parse trees into a uniform s-expression representation, and calculating diffs as a shortest-path problem on a directed acyclic graph.

## Source excerpt

I've always wanted a structural diff tool, so I built difftastic. This has been the most fascinating, most frustrating, and most challenging program I've ever written. How Hard Could It Be? If you write Lisp code for a while, you start to see code like JSON. Everything is basically a list. json-diff example json-diff already exists, and it's pretty good. I wanted something similar for programming languages. After a huge amount of experimentation, I have something that works. In this post, I'll show you how it works. I won't show the many, many dead ends and failed designs along the way. We can pretend that I got it right first time. Parsing The Code If I want to compare two programs, I first need a parse tree for each program. I need an accurate lexer, a basic parser, and I need to preserve comments. tree-sitter was a great fit here. You define a grammar in JSON or JS, and it generates a C library that anyone can use. It's not 100% accurate (e.g. the C++ parser doesn't have preprocessor data) but it's more than good enough. list: ($) => seq("(", repeat($._sexp), ")"), vector: ($) => seq("[", repeat($._sexp), "]"), Here's an excerpt from my Emacs Lisp grammar. There's a ton of tree-sitter parsers available too. Difftastic now supports 44 different syntaxes, and adding new ones is so straightforward that my manual includes a worked example. Using difftastic with Emacs Lisp After parsing, difftastic converts the tree-sitter parse tree to an s-expression. Everything is a list or an atom. This uniform representation enables the diffing logic to work on any language that I can parse. For example, given a JavaScript program like this: foo(1, 2) tree-sitter parses it to this parse tree: expression_statement call_expression identifier "foo" arguments ( number "1" , number "2" ) difftastic then converts the tree to this s-expression representation: List { open_content: "", children: [ Atom "foo", List { open_content: "(", children: [ Atom "1", Atom ",", Atom "2", ], close_con