soma.cell

Run-length encoding — compress repeated characters

"aaabbc" -> "a3b2c1". Decoding walks the encoded string reading a letter followed by its digit-run count. Demonstrates per-char scanning, run counting, and reconstructing a string by repetition. Run: soma run run_length.cell --signal encode "aaabbbcccd"

A Soma program from the text part of the verified corpus: 66 lines, cells RunLength, RunLengthTest. It passes soma check with soma 3.2.4.

How it is built

The cell RunLength declares 2 signals in its face: encode(s: String) -> String and decode(s: String) -> String. Handlers: encode (line 17) and decode (line 35).

The file also holds 1 test cell (RunLengthTest) with 5 assertions, run by soma test.

Generated from soma describe on this file.

The source

run_length.cell

// ============================================================================
// Run-length encoding — compress repeated characters
// ============================================================================
//
// "aaabbc" -> "a3b2c1". Decoding walks the encoded string reading a letter
// followed by its digit-run count. Demonstrates per-char scanning, run
// counting, and reconstructing a string by repetition.
//
// Run: soma run run_length.cell --signal encode "aaabbbcccd"

cell RunLength {
    face {
        signal encode(s: String) -> String
        signal decode(s: String) -> String
    }

    on encode(s: String) {
        if len(s) == 0 { return "" }
        let out = ""
        let prev = s[0]
        let count = 1
        for i in range(1, len(s)) {
            let c = s[i]
            if c == prev {
                count = count + 1
            } else {
                out = out + prev + to_string(count)
                prev = c
                count = 1
            }
        }
        return out + prev + to_string(count)
    }

    on decode(s: String) {
        let out = ""
        let i = 0
        let n = len(s)
        while i < n {
            let ch = s[i]
            i = i + 1
            // read the digit run that follows
            let num = ""
            while i < n && s[i] >= "0" && s[i] <= "9" {
                num = num + s[i]
                i = i + 1
            }
            let reps = to_int(num)
            for j in range(0, reps) {
                out = out + ch
            }
        }
        return out
    }
}

cell test RunLengthTest {
    rules {
        assert encode("aaabbbcccd") == "a3b3c3d1"
        assert encode("") == ""
        assert encode("x") == "x1"
        assert decode("a3b3c3d1") == "aaabbbcccd"
        assert decode(encode("wwwwwwwwwwaa")) == "wwwwwwwwwwaa"
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check run_length.cell
warning: `num` grows by concatenation inside a loop — each step copies the whole value, so the loop is quadratic (8 MB took 32 s, a list + join() 30 ms): push the pieces to a List and `join(parts, "")` once
  --> run_length.cell:45:17
   |
45 |                 num = num + s[i]
   |                 ^
✓ 1 warning(s), no errors.
$ soma test run_length.cell
test RunLengthTest ...
  ✓ assert encode("aaabbbcccd") == "a3b3c3d1"
  ✓ assert encode("") == ""
  ✓ assert encode("x") == "x1"
  ✓ assert decode("a3b3c3d1") == "aaabbbcccd"
  ✓ assert decode(encode("wwwwwwwwwwaa")) == "wwwwwwwwwwaa"

5 tests: 5 passed, 0 failed
$ soma verify run_length.cell
Verifying run_length.cell...

RunLength/termination:

  ⚠ handler `decode`: while-loop without provable termination bound (write `while [loop_bound(N)] cond { … }`, or a for-loop over a bounded range)

0 passed, 1 warnings, 0 failures
Temporal: 0 passed, 0 failed
VERIFY OK

Builtins used

len, range, to_int, to_string

Source file: /corpus/text/run_length.cell · examples/corpus/text/run_length.cell