andreamazza89 / jq-exercises

Learn jq with incremental exercises
4 stars 0 forks source link

Jq-exercises

This is a learning project, with the following high-level goals:

Short term Goals

Medium term Goals

Long term Goals

To run it locally

You need to have NodeJS installed (version 16 or above).

Architecture

There are two phases: compiling and interpreting.

The compile phase takes jq source code and turns it into an abstract representation (Expression).

The interpreter step takes the Expression, along with input json and returns json.

.. compile   ('.foo') -> Select "foo"
String -> Either ParseError AST

.. interpret {"foo": 32} -> (Select "foo") -> 32
JSON -> Expression -> Array JSON

Questions

Things I've learned

Left recursion

When I started adding support for Pipe (|), I ran into the left recursion problem, which took me a while to even realise what the problem was. This page describes the issue really well and helped me climb out of that hole!

The page above mentions this page, which is a mathematical explanation of how the problem is solved. I'd love to be able to understand the math version.

Associative Property

I ran into this when looking up the associativity of the , and | operators. Intuitively, the | operator seems to be left associative (see my thinking in the questions section), however the language specification says it's right associative (see here).

It turns out that the pipe operator will give the same result, regardless of how it's associated. This property is called associative property and described in this wiki like so:

Within an expression containing two or more occurrences in a row of the same associative operator, the order in which the operations are performed does not matter as long as the sequence of the operands is not changed.

Addition is an example of this property, where it doesn't matter how you parenthesise, it will always yield the same result.

Pratt Parsers and operator precedence

Adding a second infix operator (,), raised the issue of operator precedence. This is fully described in this issue including how I decided to implement a Pratt Parser to solve the problem.

JQ is an iceberg!

I had no idea how 'big' a language JQ could be, including functions, variables and modules.

I would love to see real-world examples where all these features are used for some very complex transformation, but I personally feel like perhaps some of the more esoteric features are born from wanting to stretch the language rather than a need coming from its users; this is just a hunch and I'd love to be wrong and see examples.