Parser

A custom parser for counting certain letters, implemented with the roc-parser package.

Code

app [main!] {
	cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.21.0/4rAQg8kUYZ3Vksr4qMQHpaFYNiHSn9GgS7gVxghd1XYV.tar.zst",
	parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/1.0.2/FrnJ4RGDKpQyoDyESNoBwFNviY4ZGbMVLnUjW9tvSRjk.tar.zst",
	roc: "nightly-2026-08-12-606470f",
}

import cli.Stdout
import cli.Stderr
import cli.OsStr
import parser.Parser exposing [Parser, many, one_of, map]
import parser.String exposing [parse_str, codeunit, any_codeunit]

default_input_str = "ABRACADABRA"

main! : List(OsStr) => Try({}, [Exit(I32), ..])
main! = |args| {
	input_str = args.map(OsStr.display).get(1) ?? default_input_str

	match parse_str(many(letter_parser), input_str) {
		Ok(letters) => {
			count = count_letter_a(letters)
			msg = "I counted ${count} letter A's!"
			_ = Stdout.line!(msg)
			Ok({})
		}
		Err(err) => {
			_ = Stderr.line!("Parsing error: ${Str.inspect(err)}")
			Err(Exit(1))
		}
	}
}

Letter : [A, B, C, Other]

# Count the number of Letter A's
count_letter_a : List(Letter) -> Str
count_letter_a = |letters| {
	letters
		.count_if(|l| l == A)
		.to_str()
}

# Parser to convert utf8 input into Letter [tags](https://www.roc-lang.org/tutorial#tags)
letter_parser : Parser(List(U8), Letter)
letter_parser =
	one_of([
		codeunit('A').map(|_| A),
		codeunit('B').map(|_| B),
		codeunit('C').map(|_| C),
		any_codeunit.map(|_| Other),
	])

# Test parsing a single letter B
expect {
	input = "B"
	parser = letter_parser
	result = parse_str(parser, input)
	result == Ok(B)
}

# Test parsing a number of different letters
expect {
	input = "BCXA"
	parser = many(letter_parser)
	result = parse_str(parser, input)
	result == Ok([B, C, Other, A])
}

Output

Run this from the directory that has main.roc in it:

$ roc main.roc -- ABRACADABRA
I counted 5 letter A's!

Run unit tests with roc test main.roc