Stream: contributing

Topic: Adding a snapshot for the zig compiler


view this post on Zulip Luke Boswell (Mar 06 2025 at 08:58):

I thought I'd share this short summary in case it helps anyone interested in contributing to the new zig compiler. It's a small example working with the Parser and s-expressions with our snapshot tool.

I started by translating the old test_syntax snapshot from crates/compiler/test_syntax/tests/snapshots/pass/add_var_with_spaces.expr.roc to soemthing like the below at src/snapshots/if_then_else.txt

~~~META
description=Correct formatting for if-then-else statement
~~~SOURCE
module [foo]

foo =
    if
    h
    then
    A
    else &e
    s#
~~~FORMATTED
module [foo]

foo =
    if
        h
    then
        A
    else
        &e
    s #

However, running the snapshot tool zig build snapshot gave me an error ...

thread 2240469 panic: TODO: problem for no else UpperIdent@14
/Users/luke/Documents/GitHub/roc/src/check/parse/Parser.zig:868:32: 0x1007758c7 in parseExprWithBp (snapshot)

I expected to run into something like this. The issue here I think is that we've changed the syntax for if-then-else.

This snapshot is no longer relevant at least in it's current form.

So I modified it to use the new syntax taking inspiration from Anthony's "grab bag" unit test and used deliberately using sloppy formatting so I can validate the formatting also.

~~~META
description=Example if-then-else statement
~~~SOURCE
module [foo]

foo = if true A

    else {
    B
    }

However running it with zig build snapshot gave errors telling me I had unimplemented paths for generating a s-expression.

Following the compiler errors like a bouncing ball, I implemented those.

Here's what I wrote.

// (tag <tag>)
.tag => |tag| {
    var node = sexpr.Expr.init(env.gpa, "tag");
    node.appendStringChild(env.gpa, ir.resolve(tag.token));
    return node;
},

// (if_then_else <condition> <then> <else>)
.if_then_else => |stmt| {
    var node = sexpr.Expr.init(env.gpa, "if_then_else");

    var condition = ir.store.getExpr(stmt.condition).toSExpr(env, ir);
    var then = ir.store.getExpr(stmt.then).toSExpr(env, ir);
    var else_ = ir.store.getExpr(stmt.@"else").toSExpr(env, ir);

    node.appendNodeChild(env.gpa, &condition);
    node.appendNodeChild(env.gpa, &then);
    node.appendNodeChild(env.gpa, &else_);

    return node;
},

Finally running the snapshot tool gave me the following final golden output which I can commit to the repository. You can see it now includes the FORMATTED and PARSE sections which were generated from the SOURCE.

~~~META
description=Example if-then-else statement
~~~SOURCE
module [foo]

foo = if true A

    else {
    B
    }
~~~FORMATTED
module [foo]

foo = if true A else B
~~~PARSE
(file
    (header 'foo')
    (decl
        (ident 'foo')
        (if_then_else
            (ident '' 'true')
            (tag 'A')
            (block (tag 'B')))))

Relevant commit https://github.com/roc-lang/roc/pull/7669/commits/7d793aa6ee0e933a7d021f80df78fa554d7a5e9f


Last updated: Jul 06 2025 at 12:14 UTC