Overview

Cob is a corn-themed hybrid language with Python-style, indentation-and-colon block structure. A program is a sequence of statements; blocks (currently only while) are opened with a trailing : and their body is whatever's indented further than the header line.

set x = 5
while x > 0:
    pop("counting down")
    set x = x - 1
pop("liftoff")

Indentation is spaces only — tabs are a hard error.

The toolchain

ToolWhat it does
cob_interpInterprets a .cob file directly, with a fast-boot .strawberry bytecode cache.
popcorn_compCompiles a .strawberry file to a real, standalone native executable.
farmerThe package manager — installs .cob libraries from a static registry.

Language reference

pop("text")

Writes text to stdout followed by a newline.

pop("hello")          # hello
pop("line one\nline two")

Supported escapes inside the string literal: \\, \", \n, \t.

set <name> = <expr>

Assigns an integer to a variable, creating it if it doesn't exist yet. Expressions support + - * / with standard precedence (*// bind tighter than +/-), variable references, and integer literals.

set a = 2 + 3 * 4     # 14
set b = a - 1

while <condition>:

Loops while the condition is true. A bare expression is a truthiness test (nonzero); a comparison uses == != < > <= >=. Loops nest to any depth and are capped at 10,000,000 iterations as a safety net against runaway/infinite programs.

while a != 0:
    pop("tick")
    set a = a - 1

shuck <library_name>

Loads <library_name>.cob (checking the current directory first, then cob_modules/<library_name>/<library_name>.cob — the layout farmer harvest installs into) and splices its statements in at that point, like a textual include. Circular imports and excessive nesting depth are rejected with a clear error.

shuck greeter
pop("back in the main program")

harvest(<bytes>) / trash(<variable>)

Low-level manual memory: harvest(n) is an expression that allocates n bytes and returns an opaque integer handle; trash(v) frees the handle held in v. Both require the --no-gc flag — a program that uses either without it is refused outright by both cob_interp and popcorn_comp, not silently ignored.

set p = harvest(64)
trash(p)
Handles are plain integers, not real pointers — Cob code can't do pointer arithmetic with them, only pass them to trash(). Double-free and unknown-handle use are reported as warnings, not crashes.

_MakeCache = False

If the literal first line of a .cob file is _MakeCache = False (whitespace/case-insensitive), the .strawberry fast-boot cache is disabled entirely for that file — neither read nor written.

_MakeCache = False
pop("always reparsed fresh")

Tool reference

cob_interp

cob_interp <file.cob> [--no-cache] [--no-gc]
--no-cacheSkip reading/writing the .strawberry cache for this run.
--no-gcUnlock harvest()/trash().

popcorn_comp

popcorn_comp <file.strawberry> -o <output> [--no-gc] [--cc <compiler>] [--emit-c <path.c>]

Transpiles the bytecode to plain C, then spawns a real C compiler to produce a native executable. Default backend is Zig's zig cc — a Clang-based drop-in C compiler that bundles libc/CRT files for essentially every target in one install, which is what makes CobOS/CobArch cross-compiling a plain -target flag instead of needing a separately installed cross-toolchain per platform.

Compiler is resolved in this order:

--cc <path>Explicit override, always wins.
$CobCCEnvironment variable override.
$CobOS / $CobArchLooked up in a table of Zig target triples.
zig ccDefault: native compile, Zig auto-detects the host.
CobOS=windows CobArch=amd64 popcorn_comp prog.strawberry -o prog.exe
# -> spawns: zig cc -target x86_64-windows-gnu ...
Linux targets default to musl libc rather than glibc, producing fully static binaries with no runtime libc dependency.

farmer

farmer harvest <package>

Fetches {registry}/api/v1/packages/<package>.json, verifies the metadata's name field matches what was requested, downloads the package zip, verifies its sha256 if one was provided, and unzips it into cob_modules/<package>/ — ready for shuck <package>.

$COB_FARMER_BASE_URLOverride the registry base URL.

The registry itself lives at pixel-pulse-labs/cpi, served for free via GitHub Pages — no server, just static JSON files.