Setting up tree-sitter on macOS


tree-sitter logo

Tree-sitter is an incremental parsing library recently open sourced by GitHub. Incredible technology (highly suggest watching a talk, as the website does not do it justice). I ran into some problems setting it up (as of November 12th, 2019) and for others (especially future me) using macOS and wanting to play with this tech, here’s the solutions I found.

1. Install the system dependencies

brew install git and xcode-select --install are simple.

emscripten’s installation instructions are excellent.

2. Install the node packages

Unsurprisingly, I ran into my first problems with node. As of today, if you’re running latest node and try to npm install tree-sitter-javascript, you’ll get a node-gyp compile error. Instead, you’ll need to brew install node@10 and brew link node@10 to get this working.

3. Using the JavaScript grammar

The version of tree-sitter.js and tree-sitter.wasm linked in the web version’s README is version 9, which is incompatible if you follow the instruction the instructions to generate the .wasm files, which will build the latest (at the time of writing, it was version 10). To build the latest, clone down the tree-sitter repo and ./script/build-wasm and “[t]his will create the tree-sitter CLI executable in the target/release folder.”

  1. Basic <script> for an index.html.

I had some problems with await (it didn’t like that I was using it outside an async function). There’s probably a better way, but this snippet worked for me. I use the node http-server to serve up this index.html file.

<!DOCTYPE html>
<html>
<head>
<script src="/tree-sitter.js"></script>
</head>
<body>
<script>
const Parser = window.TreeSitter;
Parser.init().then(() => {
  const parser = new Parser;
  const promise = Parser.Language.load('/tree-sitter-javascript.wasm')
  promise.then(JavaScript => {
    parser.setLanguage(JavaScript);
    const sourceCode = 'let x = 1; console.log(x)';
    const tree = parser.parse(sourceCode);
    console.log(tree.rootNode.toString());
  })
});
</script>
</body>
</html>

Open up locahost:8080 and voilá!

(program (lexical_declaration (variable_declarator name: (identifier) value: (number))) (expression_statement (call_expression function: (member_expression object: (identifier) property: (property_identifier)) arguments: (arguments (identifier)))))