Shale is the tutorial for Shale. Shale is a programming language written entirely in zig, by agents and for agents.
Shale runs on 0.17, and the language itself was used for the upgrade to itself from 0.16. Shale has access to the zig tokenizer, and it’s optimized for file manipulation.
repo: GitHub - showell/shale · GitHub
Here is an example function:
function git_call(repo, args, opts, reading, stdin)
local shown = "`git " .. join(args, " ") .. "`"
local argv = {"git", "-C", git_real(repo, shown), "-c", "color.ui=never"}
if reading then push(argv, "--no-optional-locks") end
for a in args do push(argv, a) end
local o = {timeout_ms = 60000, env = {GIT_TERMINAL_PROMPT = "0"}}
if opts ~= nil and has_key(opts, "timeout_ms") then o.timeout_ms = opts.timeout_ms end
if reading then o.whole = 16777216 else
o.head = 10
o.tail = 10
end
if stdin ~= nil then o.stdin = stdin end
local r = run(argv, o)
if r.ended == "exit" and r.code == 0 then return r end
local said = lines(r.out)
local first = ""
if #said > 0 then first = ": " .. said[1] end
if not reading and r.out ~= "" then print(trim(r.out)) end
if r.ended == "exit" then fail(shown .. " exited " .. r.code .. first) end
if r.ended == "timeout" then fail(shown .. " timed out") end
fail(shown .. " was ended by a signal")
end
Here’s an example of a Zig builtin function for shale:
/// `re_find(s, pattern[, {nocase}])` returns the leftmost match of `pattern` in
/// `s`, the one a backtracking matcher would find first, as `{at, text}` with
/// `at` 1-based, or nil. When the pattern has a capture group, also `group`,
/// its text ("" where the match did not pass through it).
fn reFind(run: *Run, pos: ast.Pos, args: []const Value) Error!Value {
const s = try bi.stringArg(run, pos, .re_find, args[0], "its first argument");
const pattern = try bi.stringArg(run, pos, .re_find, args[1], "its pattern");
const found, const c = try searched(run, pos, .re_find, s, pattern, args);
const f = found orelse return .nil;
const a = run.alloc;
const m = try run.newTable(pos);
m.kind = .map;
m.map.put(a, "at", .{ .int = @intCast(f.start + 1) }) catch return run.oom(pos);
m.map.put(a, "text", .{ .string = s[f.start..f.end] }) catch return run.oom(pos);
if (c.program.group) m.map.put(a, "group", .{ .string = if (f.group) |g| s[g[0]..g[1]] else "" }) catch return run.oom(pos);
return .{ .table = m };
}
All the code for Shale was written by Claude. I’m the only human involved so far.