Files
zig/build.zig
Motiejus Jakštys 37ae8b01d1 parser: implement for loops, port for/while loop test
Implement in parser.c:
- forPrefix: parse for input expressions and capture variables
- parseForExpr: for_simple and for AST nodes with optional else
- Handle for and while in parsePrimaryTypeExpr for top-level usage

Remove stale cppcheck knownConditionTrueFalse suppression.

Port test "top-level for/while loop".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-11 14:40:18 +00:00

188 lines
5.6 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const headers = &[_][]const u8{
"common.h",
"ast.h",
"parser.h",
};
const c_lib_files = &[_][]const u8{
"tokenizer.c",
"ast.c",
"zig0.c",
"parser.c",
};
const all_c_files = c_lib_files ++ &[_][]const u8{"main.c"};
const cflags = &[_][]const u8{
"-std=c11",
"-Wall",
"-Wvla",
"-Wextra",
"-Werror",
"-Wshadow",
"-Wswitch",
"-Walloca",
"-Wformat=2",
"-fno-common",
"-Wconversion",
"-Wuninitialized",
"-Wdouble-promotion",
"-fstack-protector-all",
"-Wimplicit-fallthrough",
"-Wno-unused-function", // TODO remove once refactoring is done
//"-D_FORTIFY_SOURCE=2", // consider when optimization flags are enabled
};
const compilers = &[_][]const u8{ "zig", "clang", "gcc", "tcc" };
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const cc = b.option([]const u8, "cc", "C compiler") orelse "zig";
const no_exec = b.option(bool, "no-exec", "Compile test binary without running it") orelse false;
const test_step = b.step("test", "Run unit tests");
addTestStep(b, test_step, target, optimize, cc, no_exec);
const fmt_step = b.step("fmt", "clang-format");
const clang_format = b.addSystemCommand(&.{ "clang-format", "-i" });
for (all_c_files ++ headers) |f| clang_format.addFileArg(b.path(f));
fmt_step.dependOn(&clang_format.step);
const lint_step = b.step("lint", "Run linters");
const clang_analyze = b.addSystemCommand(&.{
"clang",
"--analyze",
"--analyzer-output",
"text",
"-Wno-unused-command-line-argument",
"-Werror",
});
for (all_c_files) |cfile| clang_analyze.addFileArg(b.path(cfile));
clang_analyze.expectExitCode(0);
lint_step.dependOn(&clang_analyze.step);
const gcc_analyze = b.addSystemCommand(&.{
"gcc",
"--analyzer",
"-Werror",
"-o",
"/dev/null",
});
for (all_c_files) |cfile| gcc_analyze.addFileArg(b.path(cfile));
gcc_analyze.expectExitCode(0);
lint_step.dependOn(&gcc_analyze.step);
const cppcheck = b.addSystemCommand(&.{
"cppcheck",
"--quiet",
"--error-exitcode=1",
"--check-level=exhaustive",
"--enable=all",
"--suppress=missingIncludeSystem",
"--suppress=checkersReport",
"--suppress=unusedFunction", // TODO remove after plumbing is done
"--suppress=unusedStructMember", // TODO remove after plumbing is done
});
for (all_c_files) |cfile| cppcheck.addFileArg(b.path(cfile));
cppcheck.expectExitCode(0);
lint_step.dependOn(&cppcheck.step);
const all_step = b.step("all", "Run fmt check, lint, and tests with all compilers");
all_step.dependOn(lint_step);
const fmt_check = b.addSystemCommand(&.{ "clang-format", "--dry-run", "-Werror" });
for (all_c_files ++ headers) |f| fmt_check.addFileArg(b.path(f));
fmt_check.expectExitCode(0);
all_step.dependOn(&fmt_check.step);
for (compilers) |compiler| {
addTestStep(b, all_step, target, optimize, compiler, false);
}
b.default_step = all_step;
}
fn addTestStep(
b: *std.Build,
step: *std.Build.Step,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
cc: []const u8,
no_exec: bool,
) void {
const test_mod = b.createModule(.{
.root_source_file = b.path("test_all.zig"),
.optimize = optimize,
.target = target,
});
test_mod.addIncludePath(b.path("."));
// TODO(zig 0.16+): remove this if block entirely; keep only the addLibrary branch.
// Also delete addCObjectsDirectly.
// Zig 0.15's ELF archive parser fails on archives containing odd-sized objects
// (off-by-one after 2-byte alignment). This is fixed on zig master/0.16.
if (comptime builtin.zig_version.order(.{ .major = 0, .minor = 16, .patch = 0 }) == .lt) {
addCObjectsDirectly(b, test_mod, cc, optimize);
} else {
const lib_mod = b.createModule(.{
.optimize = optimize,
.target = target,
.link_libc = true,
});
const lib = b.addLibrary(.{
.name = b.fmt("zig0-{s}", .{cc}),
.root_module = lib_mod,
});
addCSources(b, lib.root_module, cc, optimize);
test_mod.linkLibrary(lib);
}
const test_exe = b.addTest(.{ .root_module = test_mod });
if (no_exec) {
const install = b.addInstallArtifact(test_exe, .{});
step.dependOn(&install.step);
} else {
step.dependOn(&b.addRunArtifact(test_exe).step);
}
}
fn addCSources(
b: *std.Build,
mod: *std.Build.Module,
cc: []const u8,
optimize: std.builtin.OptimizeMode,
) void {
if (std.mem.eql(u8, cc, "zig")) {
mod.addCSourceFiles(.{ .files = c_lib_files, .flags = cflags });
} else for (c_lib_files) |cfile| {
const cc1 = b.addSystemCommand(&.{cc});
cc1.addArgs(cflags ++ .{"-g"});
cc1.addArg(switch (optimize) {
.Debug => "-O0",
.ReleaseFast, .ReleaseSafe => "-O3",
.ReleaseSmall => "-Os",
});
cc1.addArg("-c");
cc1.addFileArg(b.path(cfile));
cc1.addArg("-o");
mod.addObjectFile(cc1.addOutputFileArg(b.fmt("{s}.o", .{cfile[0 .. cfile.len - 2]})));
}
}
// TODO(zig 0.16+): delete this function.
fn addCObjectsDirectly(
b: *std.Build,
mod: *std.Build.Module,
cc: []const u8,
optimize: std.builtin.OptimizeMode,
) void {
addCSources(b, mod, cc, optimize);
mod.linkSystemLibrary("c", .{});
}