Skip to content

Inner Workings of RagConnect

Please see API documentation for more details.

ragconnect-process

RagConnect uses the relast-preprocessor to parse .relast grammar files. This results in an ASTNode of type Program. It further uses a dedicated parser for .connect files containing port-, mapping-, and dependency-definitions. This results in an ASTNode of type RagConnect. The goal is to generate an aspect file containing setters and getters of tokens referred to by port-definitions We use mustache (currently its Java version) making use of partials to separate concerns. The .mustache files are located in ragconnect.base/src/main/resources. The generation process uses intermediates NTAs (whose types are defined in Intermediate.relast) to ease the definition of two main generation "problems". Those problems are differentiation on both kinds of a port (send/receive and type/token/list), and attributes depending on position in n-ary relations.

There are aspect files for Navigation (mainly isX/asX attributes), Analysis (static analysis attributes), Printing, Mappings (default mappings). One of the main aspects is Intermediate containing all attributes consumed by mustache and other attributes the former depend on. The other main aspect (which is currently not really used) is IntermediateToYAML containing the transformation from a RagConnect subtree to a Document subtree defined by Mustache.relast (located in relast-preprocessor submodule). This is used to generate a YAML file containing the data used by mustache. It can be used by the default mustache implementation together with the templates.

Implementation Details

In the following, details for special implementation topics are discussed.

Forwarding

When a nonterminal is used in a send ports, it needs an implicit forwarding attribute to work, because only computed elements can be sent. Since the nonterminal itself should be sent, the generated attribute simply returns this nonterminal.

However, changing any token within the whole subtree or changing the structure of the subtree must trigger a new message, upon computation of the forwarding attribute, all tokens are "touched" (their getter is called). This way, the dependency tracking registers a dependency between structure and tokens to the attribute.

The attribute (as well as any other generated element) is prefixed with _ragconnect_ to avoid potential name conflicts with user-specified elements.

Implementation Hints

Debugging Tests and Finding Bugs

To help with finding errors/bugs when tests fail, there are several things to find the correct spot.

  • Look closely. Analyze the error message closely, and possible any previous error message(s) that could have caused the test to fail.
  • Focus on single error
    • To only inspect one test, mark them with @Tag("New") and use the gradle task "newTests".
    • Use Assumptions.assumeTrue(false); to abort unneeded test cases early.
    • When editing RagConnect itself and force recreating source for the affected test, e.g., compileForwardingIncremental.outputs.upToDateWhen { false }
    • Remember to undo all changes, once the bug is fixed.
  • Activate logs. Activate logging in the ragconnect specification of the compile-task of the affected test:
    • Remember to remove those lines, once the bug is fixed.
task compile(type: RagConnectTest) {
    ragconnect {
        // ... other parameters ...
        logReads = true
        logWrites = true
        logIncremental = true
    }
    // ... other tools ...
}
  • Trace incremental events. Add a receiver right after creation of the root node (named model here)
    • This will output every event fired by the incremental evaluation engine.
    • Remember to remove this line, once the bug is fixed.
model.trace().setReceiver(TestUtils::logEvent);
  • Add log statements. As there will be quite some log output, add some identifying log statement (i.e., using logger.fatal("---")) right before the suspicious statement to inspect only the relevant log message after that.

Last update: November 22, 2022 14:25:18