tiny.chant.driver
Defined in tiny.chant.
API (8)
Actions
Public operations.
Types and contracts
Public types and contracts.
Source
Source: lib/chant/src/driver.zig
zig
const std = @import("std");const choir = @import("choir");const sys = @import("sys");const lexer = @import("lexer/root.zig");const parse = @import("parse/root.zig");const preprocess_mod = @import("preprocess/root.zig");const lower = @import("lower/root.zig");pub const Error = preprocess_mod.Error || lexer.Error || lexer.CapacityError || lexer.Exhaustion || lexer.Storage.InitError || parse.Error || parse.CapacityError || parse.Exhaustion || parse.Storage.InitError || lower.Error;pub const Diagnostic = preprocess_mod.Diagnostic;pub const Options = preprocess_mod.Options;pub fn preprocess( arena: std.mem.Allocator, environ: std.process.Environ, source_path: []const u8, options: Options, diagnostic: ?*Diagnostic,) Error![]const u8 { return preprocess_mod.run(arena, environ, source_path, options, diagnostic);}pub const Compiled = struct { unit: lower.Unit, diagnostic: parse.Diagnostic = .{},};pub fn compileSource( gpa: std.mem.Allocator, arena: std.mem.Allocator, ctx: *choir.Context, source: []const u8, file: []const u8, diagnostic: ?*parse.Diagnostic,) Error!Compiled { const token_survey = try lexer.survey(source, file); const token_capacity = try lexer.Capacity.derive(token_survey.limits); const token_bytes = try arena.alignedAlloc( u8, .fromByteUnits(lexer.Storage.storage_alignment), token_capacity.storage_bytes, ); var token_storage = try lexer.Storage.init(token_bytes, token_survey.limits); token_storage.activate(); defer _ = token_storage.deinit(); const tokens = try token_storage.fill(token_survey, source, file); const node_survey = parse.survey(tokens); const node_capacity = try parse.Capacity.derive(node_survey.limits); const node_bytes = try arena.alignedAlloc( u8, .fromByteUnits(parse.Storage.storage_alignment), node_capacity.storage_bytes, ); var node_storage = try parse.Storage.init(node_bytes, node_survey.limits); node_storage.activate(); defer _ = node_storage.deinit(); var parser = try parse.init(arena, &node_storage, node_survey, tokens); const tree = parse.parseTranslationUnit(&parser) catch |err| { if (diagnostic) |out| out.* = parser.diagnostic; return err; }; const unit = try lower.lowerUnit(gpa, arena, ctx, tree); return .{ .unit = unit };}pub fn compileFile( gpa: std.mem.Allocator, arena: std.mem.Allocator, ctx: *choir.Context, environ: std.process.Environ, source_path: []const u8, options: Options, diagnostic: ?*Diagnostic,) Error!Compiled { const source = try preprocess(arena, environ, source_path, options, diagnostic); return compileSource(gpa, arena, ctx, source, source_path, diagnostic);}test "compileSource drives the full pipeline" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void scale(int n, double a, double *x) { \\ int i; \\ for (i = 0; i < n; i++) \\ x[i] = x[i] * a; \\} , "scale.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("scale", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 bool and separated constants" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void c23(int n, double *x) { \\ bool enabled = true; \\ int stride = 0b10'00; \\ double scale = 1.5'0; \\ for (int i = 0; i < n; i++) \\ if (enabled) \\ x[i] = x[i] + scale * stride; \\} , "c23.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 parser syntax" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\static_assert(alignof(double) == 8, "lp64"); \\[[maybe_unused]] thread_local alignas(16) int global [[maybe_unused]] = {}; \\void c23_syntax(int n, double *x) { \\start: \\ int i = {}; \\ for (i = 0; i < n; i++) { \\ body: \\ x[i] = x[i] + 1.0; \\ end: \\ } \\} , "c23-syntax.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_syntax", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 inferred scalar syntax" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\typedef typeof(nullptr) nullptr_t; \\static_assert(!nullptr); \\static_assert(sizeof(typeof(int *)) == 8); \\constexpr int lanes = 4; \\static_assert(lanes == 4); \\alignas(lanes) int aligned_lanes = 0; \\void c23_types(int n, double *x) { \\ constexpr auto stride = 2; \\ static_assert(stride == 2); \\ unsigned _BitInt(stride + 1) mask = 3uwb; \\ typeof_unqual(*x) scale = 1.0; \\ for (typeof(n) i = 0; i < n; i++) \\ x[i] = x[i] + scale * stride + mask; \\} , "c23-types.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_types", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 bit precise integers" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void c23_bitint(int n, double *x) { \\ _BitInt(17) offset = 3wb; \\ unsigned _BitInt(6) mask = 0b101010uwb; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + offset + (_BitInt(17))mask; \\} , "c23-bitint.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_bitint", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 decimal floating syntax" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void c23_decimal(int n, double *x) { \\ _Decimal32 step = 1.25df; \\ _Decimal64 scale = 2.5DD; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + step + scale; \\} , "c23-decimal.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_decimal", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 fixed underlying enums" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\enum Color : unsigned int { RED = 1, GREEN, BLUE = RED + 4 }; \\enum Forward : unsigned short; \\enum Forward : unsigned short { SMALL = 3, SMALL_NEXT }; \\enum Wide { WIDE = 2147483648L, WIDE_NEXT }; \\static_assert(BLUE == 5); \\static_assert(SMALL_NEXT == 4); \\static_assert(WIDE_NEXT == 2147483649L); \\void c23_enum(int n, double *x) { \\ enum Color c = BLUE; \\ enum Forward small = SMALL_NEXT; \\ typeof(WIDE) w = WIDE_NEXT; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + c + GREEN + small + w; \\} , "c23-enum.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_enum", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 aggregate initializers" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void c23_init(int n, double *x) { \\ int empty[3] = {}; \\ int values[3] = {1, 2, 3,}; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + empty[0] + values[2]; \\} , "c23-init.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_init", compiled.unit.lowered.items[0]);}test "compileSource accepts c23 deeper array initializers" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); const compiled = try compileSource(std.testing.allocator, arena, &ctx, \\void c23_init_deep(int n, double *x) { \\ char word[] = "az"; \\ int inferred[] = {1, 2, [4] = 5}; \\ int nested[2][3] = {{1, 2}, [1][2] = 6}; \\ int flat[][2] = {1, 2, 3, 4}; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + word[1] + inferred[4] + nested[1][2] + flat[1][1]; \\} , "c23-init-deep.c", null); try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_init_deep", compiled.unit.lowered.items[0]);}test "compileFile accepts c23 standard header surface" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "header-compile.c" }); try sys.fs.writeFile(source_path, \\#include <stdbit.h> \\#include <stdckdint.h> \\#include <uchar.h> \\void c23_headers(int n, double *x) { \\ unsigned int stride = stdc_count_ones(15u); \\ unsigned int width = stdc_bit_width(stride); \\ unsigned int floor = stdc_bit_floor(stride); \\ unsigned int zeros = stdc_count_zeros(stride); \\ unsigned int single = stdc_has_single_bit(width); \\ unsigned int leading = stdc_leading_zeros(width); \\ unsigned int trailing = stdc_trailing_zeros(floor); \\ unsigned int first = stdc_first_trailing_one(floor); \\ unsigned int ceil = stdc_bit_ceil(stride); \\ unsigned int checked = 0; \\ unsigned int overflow = ckd_add(&checked, stride, width); \\ overflow += ckd_sub(&checked, checked, floor); \\ overflow += ckd_mul(&checked, checked, 2u); \\ char8_t marker = u8'a'; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + stride + width + floor + zeros + single + leading + trailing + first + ceil + checked + overflow + marker; \\} \\ ); const include_dir = try includeDir(arena); const environ = sys.env.current(); const compiled = compileFile(std.testing.allocator, arena, &ctx, environ, source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_headers", compiled.unit.lowered.items[0]);}test "compileFile accepts c23 string and time header surface" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "lib-header-compile.c" }); try sys.fs.writeFile(source_path, \\#include <string.h> \\#include <time.h> \\static_assert(__STDC_VERSION_STRING_H__ == 202311L); \\static_assert(__STDC_VERSION_TIME_H__ == 202311L); \\void c23_lib_headers(int n, char *dst, char *src, time_t *timer, double *x) { \\ size_t len = strlen(src); \\ int same = strcmp(dst, src); \\ int prefix = strncmp(dst, src, len); \\ int bytes = memcmp(dst, src, len); \\ time_t now = time(timer); \\ double diff = difftime(now, 0); \\ clock_t ticks = clock(); \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + len + same + prefix + bytes + now + diff + ticks; \\} \\ ); const include_dir = try includeDir(arena); const environ = sys.env.current(); const compiled = compileFile(std.testing.allocator, arena, &ctx, environ, source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_lib_headers", compiled.unit.lowered.items[0]);}test "compileFile accepts c23 stdlib header surface" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "stdlib-header-compile.c" }); try sys.fs.writeFile(source_path, \\#include <stdlib.h> \\static_assert(__STDC_VERSION_STDLIB_H__ == 202311L); \\void c23_stdlib(int n, char *text, char *buffer, double *x) { \\ int as_int = atoi(text); \\ double as_double = atof(text); \\ long as_long = atol(text); \\ long as_wide = atoll(text); \\ int magnitude = abs(as_int); \\ long wide = labs(as_long) + llabs(as_wide); \\ size_t alignment = memalignment(buffer); \\ free_sized(buffer, alignment); \\ free_aligned_sized(buffer, alignment, alignment); \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + as_int + as_double + magnitude + wide + alignment + EXIT_SUCCESS + EXIT_FAILURE; \\} \\ ); const include_dir = try includeDir(arena); const environ = sys.env.current(); const compiled = compileFile(std.testing.allocator, arena, &ctx, environ, source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_stdlib", compiled.unit.lowered.items[0]);}test "compileFile accepts c23 math header surface" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "math-header-compile.c" }); try sys.fs.writeFile(source_path, \\#include <math.h> \\static_assert(__STDC_VERSION_MATH_H__ == 202311L); \\void c23_math(int n, double *x) { \\ for (int i = 0; i < n; i++) { \\ double expo = exp10(x[i]) + exp10m1(x[i]) + exp2m1(x[i]); \\ double logs = logp1(x[i]) + log2p1(x[i]) + log10p1(x[i]); \\ double trig = acospi(0.25) + asinpi(0.25) + atanpi(x[i]) + atan2pi(x[i], 1.0); \\ trig += sinpi(x[i]) + cospi(x[i]) + tanpi(x[i]); \\ double powers = compoundn(x[i], 2) + pown(x[i], 2) + powr(2.0, x[i]) + rootn(x[i], 2) + rsqrt(x[i]); \\ double rounded = roundeven(x[i]) + fromfp(x[i], FP_INT_TONEAREST, 32) + ufromfp(x[i], FP_INT_TOWARDZERO, 32); \\ rounded += fromfpx(x[i], FP_INT_UPWARD, 32) + ufromfpx(x[i], FP_INT_DOWNWARD, 32); \\ double adjacent = nextup(x[i]) + nextdown(x[i]); \\ double extrema = fmaximum(x[i], 1.0) + fminimum(x[i], 1.0) + fmaximum_mag(x[i], -1.0) + fminimum_mag(x[i], -1.0); \\ extrema += fmaximum_num(x[i], 1.0) + fminimum_num(x[i], 1.0) + fmaximum_mag_num(x[i], -1.0) + fminimum_mag_num(x[i], -1.0); \\ long exponent = llogb(x[i]); \\ x[i] = x[i] + expo + logs + trig + powers + rounded + adjacent + extrema + exponent; \\ } \\} \\ ); const include_dir = try includeDir(arena); const environ = sys.env.current(); const compiled = compileFile(std.testing.allocator, arena, &ctx, environ, source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_math", compiled.unit.lowered.items[0]);}test "preprocess delegates to the system compiler when present" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "driver.c" }); try sys.fs.writeFile(source_path, "#define N 4\nint values[N];\n"); const environ = sys.env.current(); const output = preprocess(arena, environ, source_path, .{}, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expect(std.mem.indexOf(u8, output, "int values[4];") != null);}test "preprocess accepts c23 standard headers" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "header-preprocess.c" }); try sys.fs.writeFile(source_path, \\#include <limits.h> \\#include <math.h> \\#include <stdbool.h> \\#include <stdbit.h> \\#include <stdckdint.h> \\#include <stdlib.h> \\#include <string.h> \\#include <time.h> \\#include <uchar.h> \\#if __STDC_VERSION_LIMITS_H__ != 202311L \\#error bad limits version \\#endif \\#if BITINT_MAXWIDTH != ULLONG_WIDTH \\#error bad bitint max width \\#endif \\#if __STDC_VERSION_MATH_H__ != 202311L \\#error bad math version \\#endif \\#if __STDC_VERSION_STDBIT_H__ != 202311L \\#error bad stdbit version \\#endif \\#if __STDC_VERSION_STDCKDINT_H__ != 202311L \\#error bad stdckdint version \\#endif \\#if __STDC_VERSION_STDLIB_H__ != 202311L \\#error bad stdlib version \\#endif \\#if __STDC_VERSION_STRING_H__ != 202311L \\#error bad string version \\#endif \\#if __STDC_VERSION_TIME_H__ != 202311L \\#error bad time version \\#endif \\#if __STDC_VERSION_UCHAR_H__ != 202311L \\#error bad uchar version \\#endif \\#if __STDC_ENDIAN_NATIVE__ != __STDC_ENDIAN_LITTLE__ && __STDC_ENDIAN_NATIVE__ != __STDC_ENDIAN_BIG__ \\#error bad endian value \\#endif \\int checked(int a, int b) { \\ int out; \\ bool overflow = ckd_add(&out, a, b); \\ char8_t byte = u8'a'; \\ return overflow || stdc_count_ones((unsigned int)byte) == 0; \\} \\double math_probe(double x) { \\ return roundeven(x) + nextup(x) + logp1(x); \\} \\ ); const include_dir = try includeDir(arena); const environ = sys.env.current(); const output = preprocess(arena, environ, source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expect(std.mem.indexOf(u8, output, "__builtin_add_overflow") != null); try std.testing.expect(std.mem.indexOf(u8, output, "char8_t byte") != null); try std.testing.expect(std.mem.indexOf(u8, output, "stdc_count_ones_ull") != null); try std.testing.expect(std.mem.indexOf(u8, output, "[[unsequenced]]") != null); try std.testing.expect(std.mem.indexOf(u8, output, "free_sized") != null); try std.testing.expect(std.mem.indexOf(u8, output, "memalignment") != null); try std.testing.expect(std.mem.indexOf(u8, output, "memset_explicit") != null); try std.testing.expect(std.mem.indexOf(u8, output, "timespec_getres") != null); try std.testing.expect(std.mem.indexOf(u8, output, "roundeven") != null);}test "preprocess accepts c23 preprocessor additions" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "preprocessor.c" }); const data_path = try std.fs.path.join(arena, &.{ tmp_path, "resource.bin" }); const empty_path = try std.fs.path.join(arena, &.{ tmp_path, "empty.bin" }); try sys.fs.writeFile(data_path, &.{ 11, 12, 13 }); try sys.fs.writeFile(empty_path, ""); try sys.fs.writeFile(source_path, \\#include <stddef.h> \\#warning chant c23 warning smoke \\#if !__has_include(<stddef.h>) \\#error missing has_include \\#endif \\#if !__has_c_attribute(maybe_unused) \\#error missing has_c_attribute \\#endif \\#if __has_embed("resource.bin") != __STDC_EMBED_FOUND__ \\#error missing has_embed \\#endif \\#if __has_embed("empty.bin") != __STDC_EMBED_EMPTY__ \\#error missing empty has_embed \\#endif \\#if 0 \\#error bad elifdef branch \\#elifdef __has_embed \\int elifdef_has_embed = 1; \\#else \\#error missing elifdef \\#endif \\#if 0 \\#error bad elifndef branch \\#elifndef __has_embed \\#error has_embed should be defined \\#else \\int elifndef_has_embed = 1; \\#endif \\#define C23_VA(base, ...) base __VA_OPT__(+) __VA_ARGS__ \\int va_empty = C23_VA(5); \\int va_full = C23_VA(5, 7); \\unsigned char bytes[] = { \\#embed "resource.bin" limit(2) prefix(1,) suffix(, 2) \\}; \\int empty_value = \\#embed "empty.bin" if_empty(9) \\; \\ ); const include_dir = try includeDir(arena); const output = preprocess(arena, sys.env.current(), source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expect(std.mem.indexOf(u8, output, "int elifdef_has_embed = 1;") != null); try std.testing.expect(std.mem.indexOf(u8, output, "int elifndef_has_embed = 1;") != null); try std.testing.expect(std.mem.indexOf(u8, output, "int va_empty = 5 ;") != null); try std.testing.expect(std.mem.indexOf(u8, output, "int va_full = 5 + 7;") != null); try std.testing.expect(std.mem.indexOf(u8, output, "1,11,12, 2") != null); try std.testing.expect(std.mem.indexOf(u8, output, "int empty_value =\n9") != null);}test "compileFile accepts c23 embed output" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "embed-compile.c" }); const data_path = try std.fs.path.join(arena, &.{ tmp_path, "resource.bin" }); try sys.fs.writeFile(data_path, &.{5}); try sys.fs.writeFile(source_path, \\#if __has_embed("resource.bin") != __STDC_EMBED_FOUND__ \\#error missing embed resource \\#endif \\void c23_embed(int n, double *x) { \\ int add = \\#embed "resource.bin" \\ ; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + add; \\} \\ ); const compiled = compileFile(std.testing.allocator, arena, &ctx, sys.env.current(), source_path, .{}, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_embed", compiled.unit.lowered.items[0]);}test "compileFile accepts c23 embed inside included headers" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); var ctx = try choir.Context.init(arena, choir.Context.Limits.testing); defer ctx.deinit(arena); try choir.dialects.registerAllDialects(&ctx); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const tmp_path = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], arena); const include_dir = try std.fs.path.join(arena, &.{ tmp_path, "include" }); try sys.fs.createDirPath(include_dir); const source_path = try std.fs.path.join(arena, &.{ tmp_path, "header-embed-main.c" }); const header_path = try std.fs.path.join(arena, &.{ include_dir, "header_embed.h" }); const data_path = try std.fs.path.join(arena, &.{ include_dir, "payload.bin" }); try sys.fs.writeFile(data_path, &.{ 17, 18 }); try sys.fs.writeFile(header_path, \\#define HEADER_RESOURCE "payload.bin" \\#define HEADER_LIMIT limit(1) \\void c23_header_embed(int n, double *x) { \\ int add = \\#embed HEADER_RESOURCE HEADER_LIMIT \\ ; \\ for (int i = 0; i < n; i++) \\ x[i] = x[i] + add; \\} \\ ); try sys.fs.writeFile(source_path, \\#include <header_embed.h> \\ ); const compiled = compileFile(std.testing.allocator, arena, &ctx, sys.env.current(), source_path, .{ .include_dirs = &.{include_dir}, }, null) catch |err| switch (err) { error.PreprocessorUnavailable => return error.SkipZigTest, else => return err, }; try std.testing.expectEqual(@as(usize, 1), compiled.unit.lowered.items.len); try std.testing.expectEqualStrings("c23_header_embed", compiled.unit.lowered.items[0]);}pub fn includeDir(arena: std.mem.Allocator) ![]const u8 { if (directoryExists("include")) return std.fs.path.resolve(arena, &.{"include"}); return std.fs.path.resolve(arena, &.{ "lib", "chant", "include" });}fn directoryExists(path: []const u8) bool { sys.fs.cwd().access(sys.fs.debugIo(), path, .{}) catch return false; return true;}Source: lib/chant/src/root.zig:65
zig
pub const driver = @import("driver.zig");Complete caller list for driver.compileSource
10 direct callers.
tiny.chant.driver.compileFile[function] atlib/chant/src/driver.zig:70lib.chant.src.driver.test_compileSource_accepts_c23_aggregate_initializers[function] — test source atlib/chant/src/driver.zig:252in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_bit_precise_integers[function] — test source atlib/chant/src/driver.zig:181in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_bool_and_separated_constants[function] — test source atlib/chant/src/driver.zig:103in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_decimal_floating_syntax[function] — test source atlib/chant/src/driver.zig:202in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_deeper_array_initializers[function] — test source atlib/chant/src/driver.zig:273in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_fixed_underlying_enums[function] — test source atlib/chant/src/driver.zig:223in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_inferred_scalar_syntax[function] — test source atlib/chant/src/driver.zig:152in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_accepts_c23_parser_syntax[function] — test source atlib/chant/src/driver.zig:126in nearest public ownertiny.chant.driverlib.chant.src.driver.test_compileSource_drives_the_full_pipeline[function] — test source atlib/chant/src/driver.zig:83in nearest public ownertiny.chant.driver
Audit
| Definitions | 7 |
|---|---|
| Public names | 7 |
| Members | 2 |
| Version | 26.7.0 |
| Revision | daab053ee433 |