Repository navigation
Releases: Cob-Software-Foundation/Cob
Release list
Cob v0.0.5
Cob Language v0.0.5
Overview
Three new capabilities for cob_interp, all opt-in and none of them
affecting the interpreter's original zero-dependency build:
- SQLite (
sql_open/sql_exec/sql_query/sql_close) and
_cobwindow, a native-window GUI backed by raylib
(window_open/window_label/window_wait/window_close) with
real, interactive raygui widgets (window_button/
window_slider/window_textbox), are now baked into
cob_interp_full-- the binary plainmakebuilds by default.
Both build with a plainMakefile, noconfigure/autoconf step for
either, so a cleanmakefrom a fresh checkout builds everything
itself in well under a minute. - Tcl/Tk (
tcl_eval/tk_eval) are still available, but no longer
part of the default build --make cob_interp_dbbuilds a separate
binary with them, for anyone who specifically wants that and is
willing to accept a much heavier, autoconf-based Tcl/Tk source build
(see "Fixed" below for what that build fights through on some
Windows toolchains). make cob_interpremains the original lightweight interpreter --
no SQLite, no_cobwindow, no Tcl/Tk, no vendor build at all.
Also new this release: a stress-test suite (tools/stress/), a
Dockerfile to run it in a reproducible container, and both a
ci.yml GitHub Actions workflow that runs it in Docker and natively,
and a build.yml workflow that now also round-trips the widget
keywords through the .strawberry cache.
Added
SQLite bindings
sql_open(<path>) -> handle (int, 0 on failure)
sql_exec(<handle>, <sql>) -> rc (int, 0 on success)
sql_query(<handle>, <sql>) -> string (first column of first row, "" if none)
sql_close(<handle>) -> 0
set h = sql_open("scores.db")
set rc = sql_exec(h, "CREATE TABLE IF NOT EXISTS t (name TEXT)")
set rc = sql_exec(h, "INSERT INTO t VALUES ('cob')")
set name = sql_query(h, "SELECT name FROM t LIMIT 1")
pop("got: " + name)
set rc = sql_close(h)
Builds via a single-file amalgamation (vendor/SQLite/sqlite3.c) --
no configure step, compiles the same way on every platform.
_cobwindow -- a native-window GUI backed by raylib, now with real widgets
window_open(<title>) -> handle (int, 0 on failure)
window_label(<handle>, <text>) -> 0 (sets/replaces the in-window text)
window_wait(<handle>, <seconds>) -> 0 (keeps the window responsive for ~<seconds>)
window_close(<handle>) -> 0
window_button(<h>, <label>) -> 1 if clicked since the last read of
that label, else 0
window_slider(<h>, <label>, <max>) -> current value, 0..<max>, as an int
window_textbox(<h>, <label>) -> current string contents of the box
shuck cobwindow
set h = window_open("Cob Window Demo")
set rc = window_label(h, "Hello from Cob!")
set clicked = window_button(h, "OK")
set volume = window_slider(h, "Volume", 100)
set name = window_textbox(h, "Name")
set rc = window_wait(h, 5)
set rc = window_close(h)
Backed by vendor/raylib (real 2D/3D graphics, proper anti-aliased
text rendering) instead of raw Win32/Xlib calls -- one build recipe
and one code path for every platform, rather than hand-maintained
separate Win32 and Xlib implementations. raylib's own build is a
plain Makefile: no configure, no autoconf, so none of the
busybox-ash/vendor-tree fragility documented under "Fixed" below
applies to it.
vendor/raygui (a header-only immediate-mode widget library that
draws on top of raylib) is now wired up to Cob syntax as
window_button/window_slider/window_textbox. Each widget is
identified by its own label text -- the first call with a new label
creates it, auto-stacked on screen below the window_label() text;
every later call with that same label (and kind -- a button and a
slider can share a label without colliding) reads or updates that
same widget. Declaring and reading happen in the same call, since Cob
has no separate "declare once, poll every frame" mechanism -- a
button's click flag resets on read, so a click is reported exactly
once; a slider re-ranges (and clamps) if called again with a
different <max>; a textbox is always in raygui's edit mode, since
Cob has no click-to-focus concept to hook a toggle to.
raylib only supports one native window per process (InitWindow()/
CloseWindow() are process-global, not per-handle) -- window_open()
called again before the first window is closed warns and returns 0,
same "0 means failure" convention every other handle-returning keyword
here uses. The close button ([X]) is intentionally swallowed -- Cob
has no callback mechanism to notify a running script that the user
clicked it, so the window keeps running until window_wait()'s timer
runs out or window_close() is called explicitly, the same
"explicit close only" model harvest()/trash() already use for
memory.
Verified for real, not just built: ran a .cob script against
cob_interp_window/cob_interp_full on a live (headless, via Xvfb)
X11 display and confirmed with actual screenshots that a real window
opened showing the label text, a button, a slider (with a readable
caption -- see "Fixed" below), and an editable text box with a
blinking cursor, all rendered with proper anti-aliased text.
cob_interp_full -- SQLite + _cobwindow, the new default
make (no target, i.e. make all) now builds cob_interp_full
instead of the lightweight cob_interp. It lists $(SQLITE_LIB) and
$(RAYLIB_LIB) as real Make prerequisites, so a single make builds
SQLite and raylib from vendor/ itself, with no separate build steps,
no configure/autoconf anywhere in the chain, and (confirmed) well
under a minute on a clean checkout.
make cob_interp still builds the original lightweight binary --
zero vendor dependency, builds in under a second -- for anyone who
wants that explicitly instead of the new default.
Kept as opt-in: cob_interp_db (SQLite + Tcl + Tk)
tcl_eval(<script>) -> string (Tcl's string result)
tk_eval(<script>) -> string (same interpreter as tcl_eval, plus Tk)
Still available via make cob_interp_db for anyone who specifically
wants tcl_eval()/tk_eval(). This needs a real Tcl/Tk source build
(make sqlite tcl tk, or cob_interp_db triggers it automatically
the same way cob_interp_full triggers SQLite/raylib) -- see "Fixed"
below for the autoconf/busybox-ash issues that build can hit on some
Windows toolchains, now resolved for the two specific failures
reported so far. _cobwindow is not part of this binary; use
cob_interp_full for that.
Stress-test suite, Dockerfile, ci.yml, and build.yml
tools/stress/run_stress.sh builds cob_interp_full and runs three
.cob scripts designed to catch regressions that only show up under
sustained load, not a single quick smoke test:
stress_arithmetic.cob-- 200,000-iteration loop (interpreter
overhead/stability)stress_sqlite.cob-- 2,000 sequentialINSERTs + a query (SQLite
under load)stress_window.cob-- 20 open/label/wait/close cycles (resource
leaks in the raylib backend would show up as the loop slowing down
or crashing, not just "does it open one window")
Dockerfile builds cob_interp_full in a clean Ubuntu 24.04
container with exactly the dependencies it needs (X11 + OpenGL dev
headers, Xvfb) and runs the stress suite as its entrypoint:
docker build -t cob-stress .
docker run --rm cob-stress # one pass
docker run --rm cob-stress --iterations 20 # repeat 20x
.github/workflows/ci.yml runs the same suite two ways -- once via
the Dockerfile (docker-stress job), once directly on the runner
(native-stress job) -- on push/PR to main, nightly on a schedule,
and on manual dispatch with a configurable iteration count.
.github/workflows/build.yml's test_extensions job now also opens
a real headless X11 window and round-trips window_button/
window_slider/window_textbox through the .strawberry cache --
write once, run again to force a cache hit, diff the two runs' output
-- specifically to catch a broken write_expr()/read_expr() pair
for the three new widget expression kinds (see "Fixed" below for why
this matters more than it might sound like).
Legal: raylib/raygui licenses
legal/license_raylib.terms and legal/license_raygui.terms added
(both zlib License). LICENSE.md's "THIRD-PARTY LICENSE NOTICE"
section was also out of date -- it only mentioned TinyCC, which isn't
even in this repo anymore -- rewritten to list every vendored
component actually present (miniz, SQLite, Tcl, Tk, raylib, raygui)
and where its license text lives.
cpi.cob.pixel-pulse.work.gd: fixed the "Package registry" 404 (separate repo)
docs/index.html's footer nav links "Package registry" to
.../download.html, which never existed on the cpi registry site
(Cob-Software-Foundation/cpi, a separate repo) -- only index.html
did, so the link 404'd. Added docs/download.html there: fetches
api/v1/packages/index.json and each manifest client-side, renders
them as cards matching the site's styling. This is a change to the
cpi repo, not this one -- shipped as its own small zip alongside
this release, not included in the main source zip.
Fixed
popcorn_comp: .strawberry magic constant was three format bumps stale
Repro: any plain .cob script, no SQL/window keywords required --
./cob smoke.cob then ./popcorn_comp smoke.strawberry -o smoke_native
failed with:
[popcorn_comp] error: 'smoke.strawberry' is not a valid .strawberry v3 file
Root cause: popcorn_comp.c keeps its own independent, byte-for-
byte-compatible copy of the .strawberry reader (documented in its
own header comment as deliberately duplicated from cob_interp.c),
including its own STRAWBERRY_MAGIC constant. cob_interp.c's magic
has mov...
Cob v0.0.3-bug-fix-1 (EOL)
⚠️ ARCHIVED / END OF LIFE (EOL)
NOTICE: This version is preserved strictly for historical reference. It will not receive future patches. Please migrate to the secure v0.0.3 bug fix 2 Release.
ℹ️ Hey There is a new version out v0.0.3 bug fix 2 available, we recommend upgrading to that version.
Cob Language v0.0.3-bug-fix-1
Fixed
popcorn_comp: Windows system() quoting bug in bundled-Zig auto-resolve
find_bundled_zig_cc() returns a pre-quoted compiler string ("path" cc).
cob_spawn_compile() then appends further quoted arguments (-o "out" "in"),
producing a command line with multiple separate quoted tokens that starts
with a quote.
On Windows, system() hands this to cmd.exe /c <string>. cmd.exe strips
only the first and last " of a command line that starts with a quote —
not matching pairs — which corrupts multi-token quoted strings like this
one. This meant auto-resolving a bundled zig/ folder next to the binary
failed with '...' is not recognized as an internal or external command,
even though the equivalent compiler invocation worked fine when passed
explicitly via --cc (which isn't pre-quoted).
Fix: on Windows, if the built command starts with a quote, wrap the whole
command in one more pair of quotes before calling system() — the standard
workaround for this cmd.exe behavior. --cc/$CobCC paths are untouched.
Only popcorn_comp (src/popcorn_comp.c) changed in this release; cob_interp
and farmer are unchanged from v0.0.3.
Not yet verified: on a real Windows machine with a genuine bundled Zig
folder. Verified so far: compiles clean, no regression to the --cc/$CobCC
explicit-compiler path, which was already unaffected by the bug.
Cob Language v0.0.3 — Project Obsidian Falcon
A corn-themed hybrid language with Python-style indentation, an interpreter, a native compiler, and a package manager.
What's new in v0.0.3
popcorn_comp: dropped embedded TCC, now spawns a real compiler
Earlier versions statically linked TCC's own compiler source (libtcc.c) directly into popcorn_comp. That's gone — popcorn_comp now transpiles a .strawberry file to plain C and spawns a real C compiler as a subprocess to produce the 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 a single install. That's what makesCobOS/CobArchcross-compiling a plain-targetflag instead of needing a separately installed cross-toolchain per platform. - Compiler resolution order:
--cc <path>→$CobCC→$CobOS/$CobArch(looked up in a table of Zig target triples) → plainzig cconPATHfor native builds. - Linux targets default to
musllibc, notglibc— produces fully static binaries with no runtime libc dependency. - Windows ARM32 is not supported (cut this cycle — it was also the target we were least confident Zig fully supports).
--emit-c <path.c>still works, for inspecting the generated C.
CobOS=windows CobArch=amd64 popcorn_comp prog.strawberry -o prog.exe
# -> spawns: zig cc -target x86_64-windows-gnu ...
farmer: real in-process zip extraction via miniz, plus zip-slip protection
farmer harvest used to shell out to unzip (Unix) or Expand-Archive (Windows) to extract downloaded packages. It now extracts in-process using the statically-linked miniz library instead — one less external tool required on the system.
- Every extracted archive entry's path is checked against zip-slip path traversal before anything is written to disk. A malicious
../../../../etc/whateverentry is rejected outright, with nothing written outside the destination directory. - Nested directories inside a package zip are now handled correctly regardless of whether the archive includes explicit directory entries.
- The package registry now lives in its own dedicated repo,
pixel-pulse-labs/cpi—farmer's default base URL was updated to match. Override anytime with$COB_FARMER_BASE_URL.
Documentation site
docs/index.html in this repo is now real language and tool reference documentation — every keyword (pop, set, while, shuck, harvest/trash, the _MakeCache directive) and all three CLI tools, each with usage and flags. The package-registry landing page that used to live here moved to the cpi repo, where it belongs.
Vendored libraries (not yet wired into Cob's language)
Added under vendor/ as embeddable/linkable libraries, per project decision. None of these have Cob-facing keywords yet — that's a separate design step.
- SQLite 3.53.4 — the single-file amalgamation build (
sqlite3.c/sqlite3.h). - Tcl 9.0.4 and Tk 9.0 — full source distributions, built via their own
configure/make(make tcl,make tktargets added to theMakefile). Tk requires real X11 development headers on the build machine. - miniz 3.1.1 — backs
farmer's zip extraction (see above).
CI
cob_interp,farmer, andpopcorn_compall build across the full 9-target matrix (Windows/Linux/macOS × amd64/386/arm64/arm as applicable — down from 10 after cutting Windows ARM32).- A real end-to-end smoke test now runs for
popcorn_compon native Linux amd64: compile a.cobprogram, run it throughpopcorn_comp, diff the output against the interpreter. - Fixed a bug in the TCC upstream-sync workflow where a
conftest.cfile./configuregenuinely needs was being silently dropped on every sync, because TCC's own vendored.gitignorehas aconftest*pattern that collaterally matched the tracked source file. (Now moot for this repo specifically, sincepopcorn_compno longer depends on TCC at all — but the underlying.gitignore-collision lesson is worth knowing if vendoring other C projects.)
Known gaps, stated plainly
- You need Zig installed for
popcorn_comp's default backend to work. This wasn't testable end-to-end in the environment these notes were written in (no network access toziglang.org) — the command-construction logic was verified against a stub, but real compiles need verification on an actual machine with Zig installed. - SQLite/Tcl/Tk are buildable, not usable from Cob yet. No
sqlopen, no Tclshuck-equivalent, no Tk widget keywords. Proving they build and link was this cycle's scope. popcorn_compisn't smoke-tested on the other 8 targets in CI — only native Linux amd64, since that's the only target whose output can actually execute on the CI runner without emulation.
Upgrading from v0.0.2
If you have scripts calling popcorn_comp and relying on the old CobOS/CobArch → cross-gcc-binary-name behavior, note that resolution now targets Zig triples instead. Install Zig, or pass --cc <path>/$CobCC to keep using a specific compiler directly.
Binaries are provided per-platform in this release. Verify downloads against checksums.txt.
Cob v0.0.4 (EOL)
Cob Language v0.0.4
Added
Strings — a real second value type
Cob variables were integers only, full stop, since the language's
first release. This adds a second kind of value: strings. This is a
new capability, not a bug fix, which is why it's versioned 0.0.4
rather than another 0.0.3-bug-fix-N.
What's new, concretely:
pop(<expr>)now accepts any expression, not just a string
literal.pop(x)prints an int variable's decimal value or a
string variable's contents. This was the single most-requested gap
in the language up to this point — there was previously no way to
print a computed value at all.setaccepts string literals:set name = "world". A
variable's "type" is just whatever it was lastsetto; Cob still
has no type declarations.- String concatenation via
+:"hello, " + name. If either
side of+is a string, the other side is stringified (an int
becomes its decimal digits) and the two are joined.-,*,/
still require two numbers, same as before, and now report a clear
warning (result treated as 0) rather than silently doing something
undefined if given a string. - String comparison in
while/conditions:==,!=,<,>,
<=,>=all work on two strings (strcmp-based ordering) exactly
as they already did on two numbers. Comparing a string to a number
is a warning, evaluating to false, rather than an implicit,
surprising conversion either direction. - Truthiness for a bare condition now applies to strings too: a
non-empty string is truthy, matching non-zero for numbers.
What did NOT change
harvest()/trash(), shuck, while loop semantics and the
10,000,000-iteration safety cap, and the --no-gc/--no-cache flags
are all unchanged and re-verified below.
popcorn_comp also compiles string-using programs now
Originally shipped as cob_interp-only in this same release, with
popcorn_comp support called out as follow-up work. That follow-up is
done: popcorn_comp now compiles .cob programs that use strings into
real, standalone native binaries too.
popcorn_comp has its own separate copy of the expression AST and its
own C code generator (it doesn't share code with cob_interp), so this
needed a real second implementation, not a shared fix. Every Cob
variable is now emitted as CobValue — a small tagged struct (int or
string) — instead of a plain long, and every operator becomes a
call into a small hand-written C runtime embedded at the top of the
generated file (cob_add, cob_eq, cob_pop, etc.) instead of a raw
C operator. That runtime deliberately mirrors cob_interp's
eval_expr/eval_cond logic, including the exact warning wording, so a
compiled program's behavior matches its interpreted behavior — same
results, same warnings, same fallback-to-0 on a type mismatch. The
one intentional difference: compiled-code warnings are tagged [cob]
rather than [cob_interp], since a compiled binary is its own
standalone program, not the interpreter.
popcorn_comp's own .strawberry reader was updated to the same v3
format (EXPR_STR, STMT_POP holding a general expression) so it
can read caches cob_interp now writes.
A real bug found and fixed before shipping this: the first
version of the string runtime used the platform's strdup(), which
isn't part of strict C99 — under -std=c99 it has no declaration, so
GCC implicitly assumed it returned int, truncating the returned
pointer and segfaulting on the very first string literal. Fixed by
hand-writing a small portable duplicate (cob_strdup_, malloc +
memcpy) instead of depending on a POSIX extension — the same pattern
cob_interp's own cob_strdup already used for exactly this reason.
A real leak found and fixed before shipping this: the first
version of the code generator never freed a variable's final string
value when the compiled program exited — cob_interp does this via
vars_free() at shutdown, but the generated C had no equivalent.
Fixed by emitting a cob_free() call for every declared variable
right before return 0 in generated main().
Also fixed in the same pass: pop(x) — printing a variable —
wasn't being scanned for variable names to declare in the generated
C, since the old codegen assumed pop() could only ever take a fixed
literal with no variables in it. A compiled program using pop(x)
would have referenced an undeclared C variable and failed to compile.
Verified this release, for popcorn_comp specifically:
- Every test used to verify cob_interp's string support was re-run
through the full pipeline —cob_interpproduces a.strawberry
cache,popcorn_compcompiles it, the resulting binary is run, and
its output is diffed againstcob_interp's own interpreted output
for the identical source. All matched exactly: the original
all-integer countdown example, string literals, concatenation
(string+string and string+int),pop()of both an int and a string
variable, string equality and ordering comparisons, both
type-mismatch warning paths,harvest()/trash()including a
dynamic (variable) byte count and a negative-size warning, the full
mathpackage (which exercisesshuck, six PASS assertions, and
the tally display), and the 2,000-iteration string-reassignment
stress test. - Every one of those, compiled and run, was also checked with
valgrind --leak-check=full— 0 leaks, 0 errors, including after
fixing the shutdown-cleanup leak above. gcc -std=c99 -Wall -Wextraonpopcorn_comp.citself: zero
warnings.
Known gap, pre-existing and not addressed in this pass: compiled
trash() has no double-free or invalid-handle detection at all — it
was already a direct, untracked free() call before strings existed,
and still is. cob_interp catches this and warns; a compiled binary
silently allows it, same as before this release. Worth its own
follow-up, unrelated to strings.
Known scope limit: cross-target string support is unverified
Everything verified above was compiled natively (Linux amd64 host,
Linux amd64 target, via plain gcc). The string runtime embedded in
generated C is written in portable C99 with no platform-specific
calls — it should cross-compile via Zig the same as any other
generated Cob program — but that hasn't actually been run and tested
on a genuine Windows or macOS target, or through the Zig backend
specifically, the way the native-gcc path in this release was. Treat
cross-compiled string support as "should work, not yet proven,"
consistent with how earlier releases have flagged untested
cross-platform paths.
The .strawberry cache format changed (v2 → v3)
The on-disk AST format changed shape to represent the new string
expression kind, so the cache's magic bytes were bumped from
COBSTRW2 to COBSTRW3. A cache written by this version is
correctly and safely rejected by anything still expecting v2 (falls
back to reparsing from source, the same as if no cache existed at
all) rather than being misread. This was verified directly: a
hand-corrupted file with the old magic and new-format bytes behind it
was confirmed to be rejected cleanly, with a fallback to reparsing,
not a crash or garbage output.
Verified this release
- Full rewrite of the value representation (
Var/VarTable,
eval_expr,eval_cond,execute()) from rawlongto a tagged
Value(int or string) — compiles clean with
gcc -std=c99 -Wall -Wextra, zero warnings. - Regression: the original all-integer countdown example and the
fullmathpackage test suite (factorial/gcd/power/abs/min/max/
tally, 6 assertions) both produce byte-identical output to before
this change. - New features, each actually run against the real interpreter:
string literals,pop()of an int variable,pop()of a string
variable, string+string concatenation, string+int concatenation,
string equality in a self-terminatingwhile, string ordering
comparison, and the type-mismatch warnings for-/*//on a
string and for comparing a string to a number. harvest()/trash()regression: allocate, free, double-free
warning, and the--no-gcgate all still behave identically now
that handles flow throughValueinstead of a barelong.- Memory correctness: every test above, plus a 2,000-iteration
loop reassigning a string each pass, run clean under
valgrind --leak-check=full— 0 leaks, 0 errors, allocations and
frees exactly balanced in every run. - Cache round-trip: a string-using program produces identical
output whether freshly parsed or loaded from its own.strawberry
v3 cache.
Not verified
- popcorn_comp's string support on a real Windows/macOS target, or
through a cross-compile (Zig) build rather than native gcc — see
above. - No testing on Windows or macOS for this change; verified on Linux
only, same as the source-level verification pattern in earlier
releases.
Cob Language v0.0.3-bug-fix-2
Changed
Project moved from pixel-pulse-labs to Cob-Software-Foundation on GitHub
All three repositories (Cob, cpi, and the new Cob-Docs) now live
under the Cob-Software-Foundation GitHub org instead of
pixel-pulse-labs. This release updates every reference that was
hardcoded to the old org:
include/common.h:COB_REPO_URLand the file header comment
now point tohttps://github.com/Cob-Software-Foundation/Cob.docs/index.htmlandRelease.txt: GitHub/license links
updated to the new org. (Historical mentions of the old
pixel-pulse-labs.github.io/cpiURL inside the bug-fix-2 changelog
entry above were left as-is deliberately — that's a factual record
of what the URL used to be, not a live link.)
COB_FARMER_DEFAULT_BASE_URL itself (`...
Cob v0.0.3-bug-fix-2 (EOL)
Cob Language v0.0.3-bug-fix-2
Changed
Project moved from pixel-pulse-labs to Cob-Software-Foundation on GitHub
All three repositories (Cob, cpi, and the new Cob-Docs) now live
under the Cob-Software-Foundation GitHub org instead of
pixel-pulse-labs. This release updates every reference that was
hardcoded to the old org:
include/common.h:COB_REPO_URLand the file header comment
now point tohttps://github.com/Cob-Software-Foundation/Cob.docs/index.htmlandRelease.txt: GitHub/license links
updated to the new org. (Historical mentions of the old
pixel-pulse-labs.github.io/cpiURL inside the bug-fix-2 changelog
entry above were left as-is deliberately — that's a factual record
of what the URL used to be, not a live link.)
COB_FARMER_DEFAULT_BASE_URL itself (cpi.cob.pixel-pulse.work.gd)
was already unaffected by the org rename, since it's a custom domain,
not a github.io URL — no change needed there, still correct from
bug-fix-2.
Also fixed while in there: cpi registry's zip_url fields were still on the old github.io URL
Separately from the org rename, cpi's own package metadata
(docs/api/v1/packages/*.json) had zip_url values pointing at
https://pixel-pulse-labs.github.io/cpi/packages/... — the raw
GitHub Pages URL from before the custom domain was set up in
bug-fix-2. farmer's own default base URL got updated to the custom
domain then, but the registry's self-referencing zip URLs were missed.
Updated both greeter.json and math.json to
https://cpi.cob.pixel-pulse.work.gd/packages/..., matching the
domain farmer actually resolves against by default.
Verified this release:
- Rebuilt
farmerfrom the patched source — compiles clean. - Re-ran the full local harvest test (local HTTP server standing in
for the registry, realfarmerbinary, real miniz extraction): metadata
fetch, sha256 verification, and extraction intocob_modules/math/
all passed against the correctedzip_url. - Grepped the full source tree, both doc sites, and both published
Cob packages (math,seed) for any remainingpixel-pulse-labs
reference — none left outside the deliberate historical changelog
mentions noted above.
Not verified: an actual farmer harvest against the live
cpi.cob.pixel-pulse.work.gd domain with the corrected zip_url from
a real machine — this environment's network doesn't reach that domain.
The local-server test above exercises the identical code path, but a
real end-to-end run on the live domain is still worth doing before
calling this fully verified.
Cob Language v0.0.3-bug-fix-2
Changed
farmer: default package registry URL updated to the custom domain
COB_FARMER_DEFAULT_BASE_URL (include/common.h) now points at
https://cpi.cob.pixel-pulse.work.gd instead of the previous
https://pixel-pulse-labs.github.io/cpi.
The cpi registry itself hasn't moved — it's still served from the
same GitHub Pages site (Cob-Software-Foundation/cpi, docs/ on main).
Only the domain in front of it changed, via a CNAME record on that
repo. This release just updates farmer's compiled-in default so a
plain farmer harvest <package> resolves against the new domain
without needing $COB_FARMER_BASE_URL set manually.
If you were already overriding the URL with
$COB_FARMER_BASE_URL=https://pixel-pulse-labs.github.io/cpi, that
still works — GitHub Pages doesn't stop serving the old
github.io URL just because a custom domain was added, it's just no
longer the default farmer uses.
No other change. cob_interp and popcorn_comp are unchanged from
v0.0.3-bug-fix-1.
Verified this release: grepped the full source tree for any other
reference to the old github.io URL — none found; common.h was the
only place it was hardcoded.
Not verified: an actual farmer harvest run against the live
cpi.cob.pixel-pulse.work.gd domain from a real machine outside this
environment (this environment's network egress doesn't reach that
domain to test directly). The URL was confirmed correct by inspection
of the compiled-in default, not by an end-to-end network fetch.
Cob Language v0.0.3-bug-fix-1
Fixed
popcorn_comp: Windows system() quoting bug in bundled-Zig auto-resolve
find_bundled_zig_cc() returns a pre-quoted compiler string ("path" cc).
cob_spawn_compile() then appends further quoted arguments (-o "out" "in"),
producing a command line with multiple separate quoted tokens that starts
with a quote.
On Windows, system() hands this to cmd.exe /c <string>. cmd.exe strips
only the first and last " of a command line that starts with a quote —
not matching pairs — which corrupts multi-token quoted strings like this
one. This meant auto-resolving a bundled zig/ folder next to the binary
failed with '...' is not recognized as an internal or external command,
even though the equivalent compiler invocation worked fine when passed
explicitly via --cc (which isn't pre-quoted).
Fix: on Windows, if the built command starts with a quote, wrap the whole
command in one more pair of quotes before calling system() — the standard
workaround for this cmd.exe behavior. --cc/$CobCC paths are untouched.
Only popcorn_comp (src/popcorn_comp.c) changed in this release; cob_interp
and farmer are unchanged from v0.0.3.
Not yet verified: on a real Windows machine with a genuine bundled Zig
folder. Verified so far: compiles clean, no regression to the --cc/$CobCC
explicit-compiler path, which was already unaffected by the bug.
Cob Language v0.0.3 — Project Obsidian Falcon
A corn-themed hybrid language with Python-style indentation, an interpreter, a native compiler, and a package manager.
What's new in v0.0.3
popcorn_comp: dropped embedded TCC, now spawns a real compiler
Earlier versions statically linked TCC's own compiler source (libtcc.c) directly into popcorn_comp. That's gone — popcorn_comp now transpiles a .strawberry file to plain C and spawns a real C compiler as a subprocess to produce the 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 a single install. That's what makesCobOS/CobArchcross-compiling a plain-targetflag instead of needing a separately installed cross-toolchain per platform. - Compiler resolution order:
--cc <path>→$CobCC→$CobOS/$CobArch(looked up in a table of Zig target triples) → plainzig cconPATHfor native builds. - Linux targets default to
musllibc, notglibc— produces fully static binaries with no runtime libc dependency. - Windows ARM32 is not supported (cut this cycle — it was also the target we were least confident Zig fully supports).
--emit-c <path.c>still works, for inspecting the generated C.
CobOS=windows CobArch=amd64 popcorn_comp prog.strawberry -o prog.exe
# -> spawns: zig cc -target x86_64-windows-gnu ...
farmer: real in-process zip extraction via miniz, plus zip-slip protection
farmer harvest used to shell out to unzip (Unix) or Expand-Archive (Windows) to extract downloaded packages. It now extracts in-process using the statically-linked miniz library instead — one less external tool required on the system.
- Every extracted archive entry's path is checked against zip-slip path traversal before anything is written to disk. A malicious
../../../../etc/whateverentry is rejected outright, with nothing written outside the destination directory. - Nested directories inside a package zip are now handled correctly regardless of whether the archive includes explicit directory entries.
- The package registry now lives in its own dedicated repo,
Cob-Software-Foundation/cpi—farmer's default base URL was updated to match. Override anytime with$COB_FARMER_BASE_URL.
Documentation site
docs/index.html in this repo is now real language and tool reference documentation — every keyword (pop, set, while, shuck, harvest/trash, the _MakeCache directive) and all three CLI tools, each with usage and flags. The package-registry landing page that used to live here moved to the cpi repo, where it belongs.
Vendored libraries (not yet wired into Cob's language)
Added under vendor/ as embeddable/linkable libraries, per project decision. None of these have Cob-facing keywords yet — that's a separate design step.
- SQLite 3.53.4 — the single-file amalgamation build (
sqlite3.c/sqlite3.h). - Tcl 9.0.4 and Tk 9.0 — full source distributions, built via their own
configure/make(make tcl,make tktargets added to theMakefile). Tk requires real X11 development headers on the build machine. - miniz 3.1.1 — backs
farmer's zip extraction (see above).
CI
cob_interp,farmer, andpopcorn_compall build across the full 9-target matrix (Windows/Linux/macOS × amd64/386/arm64/arm as applicable — down from 10 after cutting Windows ARM32).- A real end-to-end smoke test now runs for
popcorn_compon native Linux amd64: compile a.cobprogram, run it throughpopcorn_comp, diff the output against the interpreter. - Fixed a bug in the TCC upstream-sync workflow where a
conftest.cfile./configuregenuinely needs was being silently dropped on every sync, because TCC's own vendored.gitignorehas aconftest*pattern that collaterally matched the tracked source file. (Now moot for this repo specifically, sincepopcorn_compno longer depends on TCC at all — but the underlying.gitignore-collision lesson is worth knowing if vendoring other...
Cob v0.0.3 (EOL)
⚠️ ARCHIVED / END OF LIFE (EOL)
NOTICE: This version is preserved strictly for historical reference. It will not receive future patches. Please migrate to the secure v0.0.3 bug fix 1 Release.
ℹ️ Hey There is a new version out v0.0.3 bug fix 1 available, we recommend upgrading to that version.
Cob Language v0.0.3 — Project Obsidian Falcon
A corn-themed hybrid language with Python-style indentation, an interpreter, a native compiler, and a package manager.
What's new in v0.0.3
popcorn_comp: dropped embedded TCC, now spawns a real compiler
Earlier versions statically linked TCC's own compiler source (libtcc.c) directly into popcorn_comp. That's gone — popcorn_comp now transpiles a .strawberry file to plain C and spawns a real C compiler as a subprocess to produce the 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 a single install. That's what makesCobOS/CobArchcross-compiling a plain-targetflag instead of needing a separately installed cross-toolchain per platform. - Compiler resolution order:
--cc <path>→$CobCC→$CobOS/$CobArch(looked up in a table of Zig target triples) → plainzig cconPATHfor native builds. - Linux targets default to
musllibc, notglibc— produces fully static binaries with no runtime libc dependency. - Windows ARM32 is not supported (cut this cycle — it was also the target we were least confident Zig fully supports).
--emit-c <path.c>still works, for inspecting the generated C.
CobOS=windows CobArch=amd64 popcorn_comp prog.strawberry -o prog.exe
# -> spawns: zig cc -target x86_64-windows-gnu ...
farmer: real in-process zip extraction via miniz, plus zip-slip protection
farmer harvest used to shell out to unzip (Unix) or Expand-Archive (Windows) to extract downloaded packages. It now extracts in-process using the statically-linked miniz library instead — one less external tool required on the system.
- Every extracted archive entry's path is checked against zip-slip path traversal before anything is written to disk. A malicious
../../../../etc/whateverentry is rejected outright, with nothing written outside the destination directory. - Nested directories inside a package zip are now handled correctly regardless of whether the archive includes explicit directory entries.
- The package registry now lives in its own dedicated repo,
pixel-pulse-labs/cpi—farmer's default base URL was updated to match. Override anytime with$COB_FARMER_BASE_URL.
Documentation site
docs/index.html in this repo is now real language and tool reference documentation — every keyword (pop, set, while, shuck, harvest/trash, the _MakeCache directive) and all three CLI tools, each with usage and flags. The package-registry landing page that used to live here moved to the cpi repo, where it belongs.
Vendored libraries (not yet wired into Cob's language)
Added under vendor/ as embeddable/linkable libraries, per project decision. None of these have Cob-facing keywords yet — that's a separate design step.
- SQLite 3.53.4 — the single-file amalgamation build (
sqlite3.c/sqlite3.h). - Tcl 9.0.4 and Tk 9.0 — full source distributions, built via their own
configure/make(make tcl,make tktargets added to theMakefile). Tk requires real X11 development headers on the build machine. - miniz 3.1.1 — backs
farmer's zip extraction (see above).
CI
cob_interp,farmer, andpopcorn_compall build across the full 9-target matrix (Windows/Linux/macOS × amd64/386/arm64/arm as applicable — down from 10 after cutting Windows ARM32).- A real end-to-end smoke test now runs for
popcorn_compon native Linux amd64: compile a.cobprogram, run it throughpopcorn_comp, diff the output against the interpreter. - Fixed a bug in the TCC upstream-sync workflow where a
conftest.cfile./configuregenuinely needs was being silently dropped on every sync, because TCC's own vendored.gitignorehas aconftest*pattern that collaterally matched the tracked source file. (Now moot for this repo specifically, sincepopcorn_compno longer depends on TCC at all — but the underlying.gitignore-collision lesson is worth knowing if vendoring other C projects.)
Known gaps, stated plainly
- You need Zig installed for
popcorn_comp's default backend to work. This wasn't testable end-to-end in the environment these notes were written in (no network access toziglang.org) — the command-construction logic was verified against a stub, but real compiles need verification on an actual machine with Zig installed. - SQLite/Tcl/Tk are buildable, not usable from Cob yet. No
sqlopen, no Tclshuck-equivalent, no Tk widget keywords. Proving they build and link was this cycle's scope. popcorn_compisn't smoke-tested on the other 8 targets in CI — only native Linux amd64, since that's the only target whose output can actually execute on the CI runner without emulation.
Upgrading from v0.0.2
If you have scripts calling popcorn_comp and relying on the old CobOS/CobArch → cross-gcc-binary-name behavior, note that resolution now targets Zig triples instead. Install Zig, or pass --cc <path>/$CobCC to keep using a specific compiler directly.
Binaries are provided per-platform in this release. Verify downloads against checksums.txt.
Cob v0.0.2 (EOL)
⚠️ ARCHIVED / END OF LIFE (EOL)
NOTICE: This version is preserved strictly for historical reference. It will not receive future patches. Please migrate to the secure v0.0.3 Release.
ℹ️ Hey There is a new version out v0.0.3 available, we recommend upgrading to that version.
Cob Language v0.0.2 -- Project Obsidian Falcon
A corn-themed hybrid language with Python-style indentation, an
interpreter, a native compiler, and a package manager.
WHAT'S NEW IN v0.0.2
- while : now really loops, with real nested block bodies
and a safety cap against runaway/infinite loops. - set = supports integer variables and arithmetic
(+ - * /, with standard precedence) and comparisons
(== != < > <= >=). - shuck <library_name> loads <library_name>.cob (checking the current
directory, then cob_modules/<library_name>/<library_name>.cob -- the
layoutfarmer harvestinstalls into) and splices it into your
program. Circular and too-deep shucks are rejected with a clear
error instead of hanging or crashing. - harvest() / trash() are real now: harvest allocates
raw memory and returns an opaque handle, trash frees it. Both are
locked behind the --no-gc flag -- a program using them without it is
refused outright, not silently ignored. - A .cob file whose literal first line is
_MakeCache = False
(whitespace/case-insensitive) disables the .strawberry fast-boot
cache entirely for that file. - popcorn_comp is a real native compiler now. It reads a .strawberry
file, transpiles it to plain C, and compiles that to a standalone
native executable using TCC's own compiler source statically linked
directly into popcorn_comp -- no external compiler, no dynamic
linking to a system TCC install. CobOS/CobArch environment variables
are validated against what this specific popcorn_comp binary was
built for; cross-targeting a different OS/arch requires a
popcorn_comp built for that target (see .github/workflows/build.yml).
Currently built for native Linux amd64 in CI; other targets need a
matching TCC runtime (libtcc1.a) built for them first. - farmer is the package manager.
farmer harvest <package>fetches
metadata from a static JSON API (hosted free on GitHub Pages),
verifies the package name matches what was requested, downloads the
package zip, verifies its sha256 if one was provided, and unzips it
into cob_modules// -- ready forshuck <package>. All
values that reach a shell command line are validated and quoted
before use. - A real, working example package ("greeter") and static registry are
published under docs/ and served via GitHub Pages.
SCOPE NOTES
- popcorn_comp's cross-compilation story is honest, not aspirational:
a single statically-linked libtcc build only targets the one
platform it was compiled for. True cross-target support means
building separate popcorn_comp binaries per target, each with a
matching TCC runtime -- that's still a work in progress beyond
native Linux amd64. - cob_interp and farmer build for all 10 target platforms
(Windows/Linux/macOS x amd64/386/arm64/arm as applicable).
Binaries are provided per-platform in this release. Verify downloads
against checksums.txt. A popcorn_comp release also ships a runtime/
folder (libtcc1.a + TCC's bundled headers) alongside the binary --
keep them together, or point popcorn_comp at another copy via the
POPCORN_TCC_RUNTIME_DIR environment variable.
Cob v0.0.1 (EOL)
⚠️ ARCHIVED / END OF LIFE (EOL)
NOTICE: This version is preserved strictly for historical reference. It will not receive future patches. Please migrate to the secure v0.0.2 Release.
ℹ️ Hey There is a new version out v0.0.2 available, we recommend upgrading to that version.
Cob Language -- Project Obsidian Falcon
Corn-themed.
This release ships cob_interp, the v0.0.1 interpreter. Its scope is
intentionally narrow: pop("text") is the one fully working statement.
while, set, shuck, harvest, and trash are recognized by the
parser but not yet executed.
Binaries are provided for Windows, Linux, and macOS across
amd64/386/arm64/arm as applicable. Verify downloads against
checksums.txt in this release.
