Thorn Protocol

The interface between Bramble and Thorn.

How Bramble communicates insight information to the Thorn insights platform.

Insights

The Thorn insights platform provides a first-class feature to give developers complete insight into everything Bramble does during compilation and why.

In order for Bramble to communicate with Thorn there is a communication protocol that defines how Bramble records every decision it makes. This is a set of JSON files that Bramble will generate when insight tracing is turned on.

Generating Insights

To generate the Thorn insights data, use the --json-trace flag on the Bramble compiler.

Thorn Protocol

Spans

The core value in the Thorn protocol is the span. This is a tuple that uniquely identifies a span of code in your project. Spans are unique across all the files in your project.

Source Map

In order to make sure that every file in your project can be assigned unique spans, each file must be assigned a span range from the global span space. Every span within a specific file will be contained within it’s span range in the Source Map file.

In theory, spans can cross files, but there are currently no cases where that would happen.

Example Source Map:

[
    {
        "source": "./main.br",
        "span": [0, 264]
    },
    {
        "source": "./second.br",
        "span": [264, 401]
    }
]

Trace File

The events themselves are recorded to trace.json. This file stores the trace of your source code through every stage of the compiler. It is consists of an array of compiler events. The compiler events represent decisions the compiler makes about different spans of your code. Each event consists of the span that caused the decision, the compiler stage, and information about the decision that was made.

Every event is given a unique integer ID. Some events have a parent ID, this means that the parent event triggered this event.

Event Results

Currently, an event can have one of two results: ok or err. Both of which have string values. ok means that the compiler successfully made a decision. err means that the compiler failed to make a decision and includes the error message detailing why the compiler failed.

Ref Spans

Some stages of compilation require context (for example, type resolution has to look up the declarations of functions). When a compiler decision needs to refer to another part of your code to make a decision, that reference is recorded with a ref span, which records the secondary span of your code that the compiler referred to.

Example Trace File

[{"id": 428, "parent_id": 427, "stage": "parser", "source": [393, 398], "ok": "Boolean Negate"},
{"id": 427, "parent_id": 426, "stage": "parser", "source": [393, 398]},
{"id": 426, "parent_id": 425, "stage": "parser", "source": [393, 398]},
{"id": 425, "parent_id": 424, "stage": "parser", "source": [393, 398]},
{"id": 424, "parent_id": 423, "stage": "parser", "source": [393, 398]},
{"id": 423, "parent_id": 422, "stage": "parser", "source": [393, 398]},
{"id": 422, "parent_id": 401, "stage": "parser", "source": [386, 398], "ok": "Return"},
{"id": 401, "parent_id": 321, "stage": "parser", "source": [353, 401], "ok": "Funtion Definition"},
{"id": 321, "stage": "parser", "source": [264, 401], "ok": "File Module"},
{"id": 437, "stage": "canonize-item-path", "source": [0, 401], "ok": "$basic::basic"},
{"id": 438, "stage": "canonize-item-path", "source": [0, 264], "ok": "$basic::main::main"},
{"id": 439, "stage": "canonize-item-path", "source": [0, 231], "ok": "$basic::main::my_main"},
{"id": 440, "stage": "canonize-item-path", "source": [233, 264], "ok": "$basic::main::MyStruct"},
{"id": 441, "stage": "canonize-item-path", "source": [255, 261], "ok": "$basic::main::f"},
{"id": 442, "stage": "canonize-item-path", "source": [264, 401], "ok": "$basic::second::second"},
{"id": 443, "stage": "canonize-item-path", "source": [264, 351], "ok": "$basic::second::my_bool"},
{"id": 444, "stage": "canonize-item-path", "source": [353, 401], "ok": "$basic::second::notter"},
{"id": 445, "stage": "canonize-item-path", "source": [363, 370], "ok": "$basic::second::b"},
{"id": 446, "stage": "canonize-type-ref", "source": [75, 89], "ok": "$basic::main::MyStruct"},
{"id": 447, "stage": "canonize-type-ref", "source": [153, 176], "ok": "$basic::second::my_bool"},
{"id": 448, "stage": "canonize-type-ref", "source": [305, 317], "ok": "$basic::second::notter"},
{"id": 449, "stage": "canonize-type-ref", "source": [321, 334], "ok": "$basic::second::notter"},
{"id": 453, "parent_id": 452, "stage": "type-resolver", "source": [39, 40], "ok": "i64"},
{"id": 455, "parent_id": 454, "stage": "type-resolver", "source": [44, 45], "ok": "i64"},
{"id": 454, "parent_id": 452, "stage": "type-resolver", "source": [43, 45], "ok": "i64"},
{"id": 452, "parent_id": 451, "stage": "type-resolver", "source": [39, 45], "ok": "i64"},
{"id": 451, "parent_id": 450, "stage": "type-resolver", "source": [26, 46], "ok": "i64"},
{"id": 459, "parent_id": 458, "stage": "type-resolver", "source": [87, 88], "ok": "i64"},
{"id": 458, "parent_id": 457, "stage": "type-resolver", "source": [75, 89], "ok": "$basic::main::MyStruct", "ref": [233, 264]}]

Last modified February 7, 2022: Add RFCs to the documentation site (5ab3587)