agentlang-index · task medium

Read a count then that many u32 integers and write their sum, or error on any failure

016-parse-list-sum. Read line 1 as `N`, a decimal integer count in the range 0 to 1000

Prompt

This is the natural-language brief given to every model, verbatim. The harness prefixes a language-specific calling-convention block and suffixes a "return only the source code" instruction. Nothing else.

# 016-parse-list-sum

Read line 1 as `N`, a decimal integer count in the range 0 to 1000
inclusive. Then read `N` more lines, each a decimal unsigned integer
that fits in u32 (range 0 through 4294967295 inclusive). Sum all
`N` values. Write the sum as decimal followed by a single newline.

If any of the following hold, write `error\n` instead and exit:

1. Line 1 fails to parse as a u32 or exceeds 1000.
2. Fewer than `N` additional value lines are available.
3. Any value line fails to parse as a u32 (empty body, non-digit
   characters, leading `+`/`-` sign, or value exceeds u32 max).
4. The running sum overflows u32 (would exceed 4294967295).

Trailing whitespace on each line is tolerated and trimmed before
parsing. Leading zeros are accepted (`007` parses as 7). The empty
sum (`N=0`) writes `0\n`.

Output exactly one line followed by `\n`. Do not write to standard
error. Exit with status 0 in every case.

## Examples

Input (stdin):

```
3
1
2
3
```

Output: `6\n`

Input (stdin):

```
0
```

Output: `0\n`

Input (stdin):

```
2
1
abc
```

Output: `error\n` (non-digit mid-list)

Input (stdin):

```
2
4294967295
1
```

Output: `error\n` (running sum overflows u32)

## Zero input convention

Zero 0.1.2 has no exposed stdin capability. The Zero reference reads
`N` from `argv[1]` and the `N` values from `argv[2]`, `argv[3]`, etc.;
values are interpreted exactly as the corresponding stdin lines for
other languages.

Acceptance

A task counts as passed only when every public and hidden test case agrees on these fields. No fuzzy matching, no "off by one trailing newline is fine."

stdout (byte-exact, per case) true
stderr (exact bytes) ""
exit code 0
wall time max (ms) 5000
tags error-handling, parsing, loop, arithmetic, stdlib-breadth

Results

Each cell is one attempt. Pass means stdout matched byte-exact on every test case, stderr empty, exit zero. Hover a failure to see the captured first line of the diagnostic.

Model ZeroTypeScriptRustGoPython
gpt-4o compile wrong output
gpt-4o-mini compile wrong output
gpt-5 compile

Failure excerpts

5 of 15 attempts failed. Each card is one attempt, with the captured first line of the diagnostic.

  1. gpt-4o Zero compile
    ref.zero:6:8 PAR100: expected '{' before block
  2. gpt-4o Rust wrong output
    (no diagnostic captured)
  3. gpt-4o-mini Zero compile
    ref.zero:3:13 PAR100: expected '{' before block
  4. gpt-4o-mini Rust wrong output
    (no diagnostic captured)
  5. gpt-5 Zero compile
    ref.zero:1:1 IMP001: unknown package-local import 'std'

Reference implementations

The hand-written reference each language ships with. Every reference passes the same public and hidden test suite under the pinned toolchain before any model touches the task.

Click a language to expand

Zero 161 lines
// Parse-list-sum reference for AgentLang Index.
//
// Zero 0.1.2 has no exposed stdin, so N comes from argv[1] and the N
// values come from argv[2..N+1]. std.args.len() includes the program
// name at index 0. Three failure modes collapse to "error\n":
//   - N argv missing, malformed, or > 1000
//   - fewer than N value argv present
//   - any value argv non-digit / empty / > u32::MAX, OR running sum > u32::MAX
//
// std.parse.parseU* rejects runtime String inputs on the direct ELF64
// backend (CGEN004), so each parse is implemented inline with a u64
// digit-accumulator and a u32::MAX bounds check.
//
// main ends with an explicit `return` to dodge the trailing-write
// byte-count-as-exit-code codegen quirk.

pub fun main(world: World) -> Void raises {
    let maybe_n = std.args.get(1)
    if maybe_n.has == false {
        check world.out.write("error\n")
        return
    }
    let n_in = std.mem.span(maybe_n.value)

    // ---- Parse N as u32, reject > 1000 ----
    let n_len = std.mem.len(n_in)
    let mut n_acc: u64 = 0_u64
    let mut n_have: Bool = false
    let mut n_ok: Bool = true
    let mut n_i: usize = 0
    while n_i < n_len {
        let c = n_in[n_i]
        if c >= 48_u8 {
            if c <= 57_u8 {
                let d: u64 = (c - 48_u8) as u64
                n_acc = n_acc * 10_u64 + d
                n_have = true
                n_i = n_i + 1
            } else {
                n_ok = false
                n_i = n_len
            }
        } else {
            n_ok = false
            n_i = n_len
        }
    }
    if n_ok == false {
        check world.out.write("error\n")
        return
    }
    if n_have == false {
        check world.out.write("error\n")
        return
    }
    if n_acc > 1000_u64 {
        check world.out.write("error\n")
        return
    }
    let n_val: u32 = n_acc as u32

    // ---- Verify std.args.len() >= n_val + 2 (program + N-arg + N values) ----
    let argc = std.args.len()
    let needed: usize = (n_val as usize) + 2_usize
    if argc < needed {
        check world.out.write("error\n")
        return
    }

    // ---- Loop N times: parse argv[i+1] (i in 1..=N), accumulate in u64 ----
    let mut total: u64 = 0_u64
    let mut idx: u32 = 0_u32
    let mut loop_ok: Bool = true
    while idx < n_val {
        let arg_pos: usize = (idx as usize) + 2_usize
        let maybe_v = std.args.get(arg_pos)
        if maybe_v.has == false {
            loop_ok = false
            idx = n_val
        } else {
            let v_in = std.mem.span(maybe_v.value)
            let v_len = std.mem.len(v_in)
            let mut v_acc: u64 = 0_u64
            let mut v_have: Bool = false
            let mut v_ok: Bool = true
            let mut v_i: usize = 0
            while v_i < v_len {
                let c = v_in[v_i]
                if c >= 48_u8 {
                    if c <= 57_u8 {
                        let d: u64 = (c - 48_u8) as u64
                        v_acc = v_acc * 10_u64 + d
                        v_have = true
                        v_i = v_i + 1
                    } else {
                        v_ok = false
                        v_i = v_len
                    }
                } else {
                    v_ok = false
                    v_i = v_len
                }
            }
            if v_ok == false {
                loop_ok = false
                idx = n_val
            } else {
                if v_have == false {
                    loop_ok = false
                    idx = n_val
                } else {
                    if v_acc > 4294967295_u64 {
                        loop_ok = false
                        idx = n_val
                    } else {
                        total = total + v_acc
                        if total > 4294967295_u64 {
                            loop_ok = false
                            idx = n_val
                        } else {
                            idx = idx + 1_u32
                        }
                    }
                }
            }
        }
    }
    if loop_ok == false {
        check world.out.write("error\n")
        return
    }

    // ---- Render total (u64, but constrained to u32 range) as decimal + newline ----
    let mut out: [16]u8 = [0_u8; 16]
    let mut out_n: usize = 0
    if total == 0_u64 {
        out[out_n] = 48_u8
        out_n = out_n + 1
    } else {
        let mut tmp: [16]u8 = [0_u8; 16]
        let mut tn: usize = 0
        let mut v: u64 = total
        while v > 0_u64 {
            let digit_u64: u64 = 48_u64 + (v % 10_u64)
            tmp[tn] = digit_u64 as u8
            tn = tn + 1
            v = v / 10_u64
        }
        let mut wj: usize = 0
        while wj < tn {
            out[out_n] = tmp[tn - 1 - wj]
            out_n = out_n + 1
            wj = wj + 1
        }
    }
    out[out_n] = 10_u8
    out_n = out_n + 1
    check world.out.write(out[0..out_n])
    return
}
TypeScript 62 lines
const U32_MAX = 4294967295n;
const N_MAX = 1000n;

function parseU32(s: string): bigint | null {
    const t = s.trim();
    if (t.length === 0) return null;
    for (let i = 0; i < t.length; i++) {
        const c = t.charCodeAt(i);
        if (c < 48 || c > 57) return null;
    }
    try {
        const v = BigInt(t);
        if (v > U32_MAX) return null;
        return v;
    } catch {
        return null;
    }
}

async function readAll(): Promise<string> {
    const chunks: Buffer[] = [];
    for await (const chunk of process.stdin) {
        chunks.push(chunk as Buffer);
    }
    return Buffer.concat(chunks).toString("utf8");
}

async function main(): Promise<void> {
    const data = await readAll();
    const lines = data.split("\n");
    if (lines.length < 1) {
        process.stdout.write("error\n");
        return;
    }
    const n = parseU32(lines[0]);
    if (n === null || n > N_MAX) {
        process.stdout.write("error\n");
        return;
    }
    const count = Number(n);
    if (lines.length < count + 1) {
        process.stdout.write("error\n");
        return;
    }
    let total = 0n;
    for (let i = 1; i <= count; i++) {
        const v = parseU32(lines[i]);
        if (v === null) {
            process.stdout.write("error\n");
            return;
        }
        total += v;
        if (total > U32_MAX) {
            process.stdout.write("error\n");
            return;
        }
    }
    process.stdout.write(`${total}\n`);
}

main();
Rust 52 lines
use std::io::{self, Read, Write};

const U32_MAX_U64: u64 = 4294967295;
const N_MAX: u32 = 1000;

fn parse_u32(s: &str) -> Option<u32> {
    let t = s.trim();
    if t.is_empty() {
        return None;
    }
    for b in t.bytes() {
        if !(b'0'..=b'9').contains(&b) {
            return None;
        }
    }
    t.parse::<u32>().ok()
}

fn run() -> Option<u64> {
    let mut input = String::new();
    io::stdin().read_to_string(&mut input).ok()?;
    let mut lines = input.split('\n');
    let n_line = lines.next()?;
    let n = parse_u32(n_line)?;
    if n > N_MAX {
        return None;
    }
    let mut total: u64 = 0;
    for _ in 0..n {
        let line = lines.next()?;
        let v = parse_u32(line)? as u64;
        total += v;
        if total > U32_MAX_U64 {
            return None;
        }
    }
    Some(total)
}

fn main() {
    let stdout = io::stdout();
    let mut out = stdout.lock();
    match run() {
        Some(total) => {
            let _ = writeln!(out, "{}", total);
        }
        None => {
            let _ = out.write_all(b"error\n");
        }
    }
}
Go 83 lines
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

const u32MaxU64 uint64 = 4294967295
const nMax uint32 = 1000

func parseU32(s string) (uint32, bool) {
	t := strings.TrimSpace(s)
	if t == "" {
		return 0, false
	}
	for _, c := range t {
		if c < '0' || c > '9' {
			return 0, false
		}
	}
	v, err := strconv.ParseUint(t, 10, 32)
	if err != nil {
		return 0, false
	}
	return uint32(v), true
}

func readAll(r *bufio.Reader) string {
	var sb strings.Builder
	buf := make([]byte, 4096)
	for {
		n, err := r.Read(buf)
		if n > 0 {
			sb.Write(buf[:n])
		}
		if err != nil {
			break
		}
	}
	return sb.String()
}

func run(data string) (uint64, bool) {
	lines := strings.Split(data, "\n")
	if len(lines) < 1 {
		return 0, false
	}
	n, ok := parseU32(lines[0])
	if !ok || n > nMax {
		return 0, false
	}
	if uint32(len(lines)) < n+1 {
		return 0, false
	}
	var total uint64 = 0
	for i := uint32(1); i <= n; i++ {
		v, ok := parseU32(lines[i])
		if !ok {
			return 0, false
		}
		total += uint64(v)
		if total > u32MaxU64 {
			return 0, false
		}
	}
	return total, true
}

func main() {
	w := bufio.NewWriter(os.Stdout)
	defer w.Flush()
	data := readAll(bufio.NewReader(os.Stdin))
	total, ok := run(data)
	if !ok {
		fmt.Fprint(w, "error\n")
		return
	}
	fmt.Fprintf(w, "%d\n", total)
}
Python 52 lines
#!/usr/bin/env python3
import sys

U32_MAX = 4294967295
N_MAX = 1000


def parse_u32(s: str):
    s = s.strip()
    if not s:
        return None
    for ch in s:
        if not ('0' <= ch <= '9'):
            return None
    try:
        v = int(s)
    except ValueError:
        return None
    if v > U32_MAX:
        return None
    return v


def main() -> None:
    data = sys.stdin.read()
    lines = data.split("\n")
    if len(lines) < 1:
        sys.stdout.write("error\n")
        return
    n = parse_u32(lines[0])
    if n is None or n > N_MAX:
        sys.stdout.write("error\n")
        return
    if len(lines) < n + 1:
        sys.stdout.write("error\n")
        return
    total = 0
    for i in range(1, n + 1):
        v = parse_u32(lines[i])
        if v is None:
            sys.stdout.write("error\n")
            return
        total += v
        if total > U32_MAX:
            sys.stdout.write("error\n")
            return
    sys.stdout.write(f"{total}\n")


if __name__ == "__main__":
    main()

Design notes

Algorithm, failure modes, cross-language parity, and where Zero needed a workaround. From corpus/016-parse-list-sum/notes.md.

Algorithm

Read a count N (u32, capped at 1000) from line 1. Then read N more lines, each a u32. Sum them and write the sum as decimal + \n. Three failure-mode classes collapse to error\n:

  1. Line 1 fails to parse, exceeds 1000, or is missing.
  2. Fewer than N value lines are available.
  3. Any value line fails to parse, OR the running sum overflows u32.

The running sum is accumulated in u64 so the overflow check is a single > 4294967295_u64 comparison after each addition.

Loop-with-mid-iteration-failure shape

This is the structural distinction from task 015. Where 015 had three independent flat failure modes that short-circuit at gate checks before the work, 016 has a counted loop where ANY iteration can fail and must terminate the loop cleanly with an error signal. Each language threads this differently:

  • Python / TypeScript: early return from main inside the loop.
  • Rust: ? on Option<u32> inside a helper run that returns Option<u64>; main matches once at the end.
  • Go: explicit (uint64, bool) return from a helper; loop checks !ok and short-circuits.
  • Zero: loop_ok: Bool flag plus idx = n_val to break the outer loop (no break in 0.1.2). The post-loop branch reads the flag.

The Zero pattern is the same flag-then-set-counter-to-end trick used in tasks 008, 011 for inner scans — the loop-with-mid-iteration shape isn't new but this is the first task where it gates the whole output decision rather than just an inner-loop short-circuit.

Cross-implementation parity

All five share the same dispatch:

  1. parse N
  2. validate N <= 1000
  3. validate enough lines/argv remain
  4. loop N times: parse value, check value <= u32::MAX, add to u64 running sum, check sum <= u32::MAX
  5. emit sum + \n

Byte-exact agreement on every case.

Zero-specific notes

  • argv[1] is N; argv[2..N+1] are the values. std.args.len() includes the program name at index 0, so argc >= N + 2 checks that enough argv slots exist.
  • The parse helper is inlined twice (once for N, once per value iteration) per the seventh quirk forbidding Span-taking user functions on direct ELF64. The two parse blocks are byte-identical apart from the local-variable prefix (n_* vs v_*).
  • std.parse.parseU32 is still unusable for runtime data per the eighth quirk (CGEN004 on direct ELF64 for non-literal input).
  • main ends with an explicit return to dodge the trailing-write byte-count-as-exit-code codegen quirk.
  • Sum is rendered from u64 (after the u32::MAX bounds check), not u32, because the rendering loop reuses the same u64 path that was used in the accumulator. The final value is always <= u32::MAX.

No new codegen quirks surfaced during 016 — the eighth quirk from 015 was already in scope, and the rest of the program follows patterns established in 013-015.


Cost

Model Prompt tokens Completion tokens API ms
gpt-4o 3,345 1,595 12,519
gpt-4o-mini 3,345 1,492 24,693
gpt-5 3,340 26,635 233,567

Tokens and API ms are summed across the five languages this model attempted for this task.


Compare

Model deep-dives: gpt-4o · gpt-4o-mini · gpt-5 . Back to the leaderboard and methodology.