stage0-specific changes
This commit is contained in:
11
LICENSE
11
LICENSE
@@ -1,3 +1,14 @@
|
|||||||
|
NOTICE TO PROSPECTIVE UPSTREAM CONTRIBUTORS of zig0/stage0
|
||||||
|
|
||||||
|
Zig0, the stage0 interpreter, was written with heavy assistance of an LLM.
|
||||||
|
|
||||||
|
Zig0 is licensed under the MIT License below. However, the author politely but
|
||||||
|
firmly requests that you do not submit this work, or any derivative thereof, to
|
||||||
|
the Zig project upstream unless you have obtained explicit written permission
|
||||||
|
from a Zig core team member authorizing the submission.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
The MIT License (Expat)
|
The MIT License (Expat)
|
||||||
|
|
||||||
Copyright (c) Zig contributors
|
Copyright (c) Zig contributors
|
||||||
|
|||||||
208
build.zig
208
build.zig
@@ -10,6 +10,29 @@ const assert = std.debug.assert;
|
|||||||
const DevEnv = @import("src/dev.zig").Env;
|
const DevEnv = @import("src/dev.zig").Env;
|
||||||
const ValueInterpretMode = enum { direct, by_name };
|
const ValueInterpretMode = enum { direct, by_name };
|
||||||
|
|
||||||
|
const zig0_headers = &[_][]const u8{ "common.h", "ast.h", "parser.h", "zir.h", "astgen.h" };
|
||||||
|
const zig0_c_lib_files = &[_][]const u8{ "tokenizer.c", "ast.c", "zig0.c", "parser.c", "zir.c", "astgen.c" };
|
||||||
|
const zig0_all_c_files = zig0_c_lib_files ++ &[_][]const u8{"main.c"};
|
||||||
|
const zig0_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",
|
||||||
|
};
|
||||||
|
const zig0_compilers = &[_][]const u8{ "zig", "clang", "gcc", "tcc" };
|
||||||
|
|
||||||
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 15, .patch = 1 };
|
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 15, .patch = 1 };
|
||||||
const stack_size = 46 * 1024 * 1024;
|
const stack_size = 46 * 1024 * 1024;
|
||||||
|
|
||||||
@@ -273,15 +296,15 @@ pub fn build(b: *std.Build) !void {
|
|||||||
2 => {
|
2 => {
|
||||||
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
|
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
|
||||||
var it = mem.splitScalar(u8, git_describe, '-');
|
var it = mem.splitScalar(u8, git_describe, '-');
|
||||||
const tagged_ancestor = it.first();
|
//const tagged_ancestor = it.first();
|
||||||
const commit_height = it.next().?;
|
const commit_height = it.next().?;
|
||||||
const commit_id = it.next().?;
|
const commit_id = it.next().?;
|
||||||
|
|
||||||
const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
|
//const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
|
||||||
if (zig_version.order(ancestor_ver) != .gt) {
|
//if (zig_version.order(ancestor_ver) != .gt) {
|
||||||
std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
|
// std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
|
||||||
std.process.exit(1);
|
// std.process.exit(1);
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Check that the commit hash is prefixed with a 'g' (a Git convention).
|
// Check that the commit hash is prefixed with a 'g' (a Git convention).
|
||||||
if (commit_id.len < 1 or commit_id[0] != 'g') {
|
if (commit_id.len < 1 or commit_id[0] != 'g') {
|
||||||
@@ -630,6 +653,79 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
|
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
|
||||||
try tests.addIncrementalTests(b, test_incremental_step);
|
try tests.addIncrementalTests(b, test_incremental_step);
|
||||||
test_step.dependOn(test_incremental_step);
|
test_step.dependOn(test_incremental_step);
|
||||||
|
|
||||||
|
// zig0 (C implementation) build steps
|
||||||
|
const zig0_cc = b.option([]const u8, "zig0-cc", "C compiler for zig0 tests") orelse "zig";
|
||||||
|
const zig0_no_exec = b.option(bool, "zig0-no-exec", "Compile zig0 test binary without running it") orelse false;
|
||||||
|
const zig0_test_timeout = b.option([]const u8, "zig0-test-timeout", "Test execution timeout for zig0 (default: 10s, none with valgrind)");
|
||||||
|
const zig0_valgrind = valgrind orelse false;
|
||||||
|
|
||||||
|
const zig0_target = blk: {
|
||||||
|
if (!zig0_valgrind) break :blk target;
|
||||||
|
var query = target.query;
|
||||||
|
//const arch = query.cpu_arch orelse @import("builtin").cpu.arch;
|
||||||
|
//if (arch == .x86_64) {
|
||||||
|
query.cpu_features_sub.addFeature(@intFromEnum(std.Target.x86.Feature.avx512f));
|
||||||
|
//}
|
||||||
|
break :blk b.resolveTargetQuery(query);
|
||||||
|
};
|
||||||
|
|
||||||
|
const test_zig0_step = b.step("test-zig0", "Run zig0 C implementation tests");
|
||||||
|
addZig0TestStep(b, test_zig0_step, zig0_target, optimize, zig0_cc, zig0_no_exec, zig0_valgrind, zig0_test_timeout);
|
||||||
|
|
||||||
|
const fmt_zig0 = b.step("fmt-zig0", "Format zig0 C code");
|
||||||
|
const clang_format = b.addSystemCommand(&.{ "clang-format", "-i" });
|
||||||
|
for (zig0_all_c_files ++ zig0_headers) |f| clang_format.addFileArg(b.path(b.fmt("stage0/{s}", .{f})));
|
||||||
|
fmt_zig0.dependOn(&clang_format.step);
|
||||||
|
|
||||||
|
const lint_zig0 = b.step("lint-zig0", "Run zig0 linters");
|
||||||
|
for (zig0_all_c_files) |cfile| {
|
||||||
|
const clang_analyze = b.addSystemCommand(&.{
|
||||||
|
"clang",
|
||||||
|
"--analyze",
|
||||||
|
"--analyzer-output",
|
||||||
|
"text",
|
||||||
|
"-Wno-unused-command-line-argument",
|
||||||
|
"-Werror",
|
||||||
|
"-Xclang",
|
||||||
|
"-analyzer-disable-checker",
|
||||||
|
"-Xclang",
|
||||||
|
"unix.Malloc",
|
||||||
|
});
|
||||||
|
clang_analyze.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
|
||||||
|
clang_analyze.step.name = b.fmt("clang --analyze ({s})", .{cfile});
|
||||||
|
clang_analyze.expectExitCode(0);
|
||||||
|
lint_zig0.dependOn(&clang_analyze.step);
|
||||||
|
|
||||||
|
const cppcheck = b.addSystemCommand(&.{
|
||||||
|
"cppcheck",
|
||||||
|
"--quiet",
|
||||||
|
"--error-exitcode=1",
|
||||||
|
"--check-level=exhaustive",
|
||||||
|
"--enable=all",
|
||||||
|
"--inline-suppr",
|
||||||
|
"--suppress=missingIncludeSystem",
|
||||||
|
"--suppress=checkersReport",
|
||||||
|
"--suppress=unusedFunction",
|
||||||
|
"--suppress=unusedStructMember",
|
||||||
|
"--suppress=unmatchedSuppression",
|
||||||
|
});
|
||||||
|
cppcheck.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
|
||||||
|
cppcheck.step.name = b.fmt("cppcheck ({s})", .{cfile});
|
||||||
|
cppcheck.expectExitCode(0);
|
||||||
|
lint_zig0.dependOn(&cppcheck.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
const all_zig0 = b.step("all-zig0", "Run zig0 fmt check, lint, and tests with all compilers");
|
||||||
|
// fmt check (dry-run)
|
||||||
|
const zig0_fmt_check = b.addSystemCommand(&.{ "clang-format", "--dry-run", "-Werror" });
|
||||||
|
for (zig0_all_c_files ++ zig0_headers) |f| zig0_fmt_check.addFileArg(b.path(b.fmt("stage0/{s}", .{f})));
|
||||||
|
zig0_fmt_check.expectExitCode(0);
|
||||||
|
all_zig0.dependOn(&zig0_fmt_check.step);
|
||||||
|
all_zig0.dependOn(lint_zig0);
|
||||||
|
for (zig0_compilers) |compiler| {
|
||||||
|
addZig0TestStep(b, all_zig0, zig0_target, optimize, compiler, false, zig0_valgrind, zig0_test_timeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
|
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
|
||||||
@@ -1484,3 +1580,103 @@ fn superHtmlCheck(b: *std.Build, html_file: std.Build.LazyPath) *std.Build.Step
|
|||||||
run_superhtml.expectExitCode(0);
|
run_superhtml.expectExitCode(0);
|
||||||
return &run_superhtml.step;
|
return &run_superhtml.step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addZig0TestStep(
|
||||||
|
b: *std.Build,
|
||||||
|
step: *std.Build.Step,
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
cc: []const u8,
|
||||||
|
no_exec: bool,
|
||||||
|
valgrind: bool,
|
||||||
|
test_timeout: ?[]const u8,
|
||||||
|
) void {
|
||||||
|
const bridge_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("stage0/zig0_bridge.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
bridge_mod.addIncludePath(b.path("stage0"));
|
||||||
|
|
||||||
|
// Parser + tokenizer tests (hooks into std's test files via zig0 bridge)
|
||||||
|
const test_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("lib/std/zig/zig0_test.zig"),
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
test_mod.addIncludePath(b.path("stage0"));
|
||||||
|
test_mod.addImport("zig0_bridge", bridge_mod);
|
||||||
|
|
||||||
|
// AstGen tests (standalone C-vs-Zig ZIR comparison)
|
||||||
|
const astgen_test_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("stage0/astgen_test.zig"),
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
astgen_test_mod.addIncludePath(b.path("stage0"));
|
||||||
|
|
||||||
|
const timeout: ?[]const u8 = test_timeout orelse if (valgrind) null else "10";
|
||||||
|
|
||||||
|
for ([_]struct { mod: *std.Build.Module, name: []const u8 }{
|
||||||
|
.{ .mod = test_mod, .name = "test" },
|
||||||
|
.{ .mod = astgen_test_mod, .name = "astgen_test" },
|
||||||
|
}) |entry| {
|
||||||
|
addZig0CSources(b, entry.mod, cc, optimize);
|
||||||
|
entry.mod.linkSystemLibrary("c", .{});
|
||||||
|
|
||||||
|
const test_exe = b.addTest(.{
|
||||||
|
.root_module = entry.mod,
|
||||||
|
.use_llvm = false,
|
||||||
|
.use_lld = false,
|
||||||
|
});
|
||||||
|
if (valgrind) {
|
||||||
|
test_exe.setExecCmd(&.{
|
||||||
|
"valgrind",
|
||||||
|
"--error-exitcode=2",
|
||||||
|
"--leak-check=full",
|
||||||
|
"--show-leak-kinds=all",
|
||||||
|
"--errors-for-leak-kinds=all",
|
||||||
|
"--track-fds=yes",
|
||||||
|
"--quiet",
|
||||||
|
null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
test_exe.setExecCmd(&.{ "timeout", timeout orelse "10", null });
|
||||||
|
}
|
||||||
|
if (no_exec) {
|
||||||
|
const install = b.addInstallArtifact(test_exe, .{});
|
||||||
|
step.dependOn(&install.step);
|
||||||
|
} else {
|
||||||
|
const run = b.addRunArtifact(test_exe);
|
||||||
|
run.step.name = b.fmt("{s} ({s})", .{ entry.name, cc });
|
||||||
|
step.dependOn(&run.step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addZig0CSources(
|
||||||
|
b: *std.Build,
|
||||||
|
mod: *std.Build.Module,
|
||||||
|
cc: []const u8,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
) void {
|
||||||
|
if (std.mem.eql(u8, cc, "zig")) {
|
||||||
|
mod.addCSourceFiles(.{
|
||||||
|
.root = b.path("stage0"),
|
||||||
|
.files = zig0_c_lib_files,
|
||||||
|
.flags = zig0_cflags,
|
||||||
|
});
|
||||||
|
} else for (zig0_c_lib_files) |cfile| {
|
||||||
|
const cc1 = b.addSystemCommand(&.{cc});
|
||||||
|
cc1.addArgs(zig0_cflags ++ .{"-g"});
|
||||||
|
cc1.addArg(switch (optimize) {
|
||||||
|
.Debug => "-O0",
|
||||||
|
.ReleaseFast, .ReleaseSafe => "-O3",
|
||||||
|
.ReleaseSmall => "-Os",
|
||||||
|
});
|
||||||
|
cc1.addArg("-c");
|
||||||
|
cc1.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile})));
|
||||||
|
cc1.addArg("-o");
|
||||||
|
mod.addObjectFile(cc1.addOutputFileArg(b.fmt("{s}.o", .{cfile[0 .. cfile.len - 2]})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ const print = std.debug.print;
|
|||||||
const io = std.io;
|
const io = std.io;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
|
|
||||||
|
const zig0 = if (@hasDecl(@import("root"), "zig0"))
|
||||||
|
@import("root").zig0
|
||||||
|
else
|
||||||
|
struct { pub const enabled = false; };
|
||||||
|
|
||||||
test "zig fmt: remove extra whitespace at start and end of file with comment between" {
|
test "zig fmt: remove extra whitespace at start and end of file with comment between" {
|
||||||
try testTransform(
|
try testTransform(
|
||||||
\\
|
\\
|
||||||
@@ -6386,6 +6391,17 @@ test "ampersand" {
|
|||||||
var fixed_buffer_mem: [100 * 1024]u8 = undefined;
|
var fixed_buffer_mem: [100 * 1024]u8 = undefined;
|
||||||
|
|
||||||
fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 {
|
fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 {
|
||||||
|
// Also test C parser if available
|
||||||
|
if (zig0.enabled) {
|
||||||
|
var c_tree = zig0.c.astParse(source.ptr, @intCast(source.len));
|
||||||
|
defer zig0.c.astDeinit(&c_tree);
|
||||||
|
var zig0_tree = try zig0.zigAst(allocator, c_tree);
|
||||||
|
defer zig0_tree.deinit(allocator);
|
||||||
|
var ref_tree = try std.zig.Ast.parse(allocator, source, .zig);
|
||||||
|
defer ref_tree.deinit(allocator);
|
||||||
|
try zig0.expectAstConsistent(zig0_tree, ref_tree, source);
|
||||||
|
}
|
||||||
|
|
||||||
var buffer: [64]u8 = undefined;
|
var buffer: [64]u8 = undefined;
|
||||||
const stderr = std.debug.lockStderrWriter(&buffer);
|
const stderr = std.debug.lockStderrWriter(&buffer);
|
||||||
defer std.debug.unlockStderrWriter();
|
defer std.debug.unlockStderrWriter();
|
||||||
@@ -6441,6 +6457,17 @@ fn testCanonical(source: [:0]const u8) !void {
|
|||||||
const Error = std.zig.Ast.Error.Tag;
|
const Error = std.zig.Ast.Error.Tag;
|
||||||
|
|
||||||
fn testError(source: [:0]const u8, expected_errors: []const Error) !void {
|
fn testError(source: [:0]const u8, expected_errors: []const Error) !void {
|
||||||
|
// Also test C parser error detection
|
||||||
|
if (zig0.enabled) {
|
||||||
|
var c_tree = zig0.c.astParse(source.ptr, @intCast(source.len));
|
||||||
|
defer zig0.c.astDeinit(&c_tree);
|
||||||
|
if (expected_errors.len == 0) {
|
||||||
|
try std.testing.expect(!c_tree.has_error);
|
||||||
|
} else {
|
||||||
|
try std.testing.expect(c_tree.has_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig);
|
var tree = try std.zig.Ast.parse(std.testing.allocator, source, .zig);
|
||||||
defer tree.deinit(std.testing.allocator);
|
defer tree.deinit(std.testing.allocator);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
const std = @import("../std.zig");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const zig0 = if (@hasDecl(@import("root"), "zig0"))
|
||||||
|
@import("root").zig0
|
||||||
|
else
|
||||||
|
struct { pub const enabled = false; };
|
||||||
|
|
||||||
pub const Token = struct {
|
pub const Token = struct {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
@@ -1707,6 +1712,17 @@ test "fuzzable properties upheld" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
|
fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
|
||||||
|
// Also test C tokenizer if available
|
||||||
|
if (zig0.enabled) {
|
||||||
|
var ctokenizer = zig0.c.tokenizerInit(source.ptr, @intCast(source.len));
|
||||||
|
for (expected_token_tags) |expected_token_tag| {
|
||||||
|
const token = zig0.c.tokenizerNext(&ctokenizer);
|
||||||
|
try std.testing.expectEqual(expected_token_tag, zig0.zigToken(token.tag));
|
||||||
|
}
|
||||||
|
const last_token = zig0.c.tokenizerNext(&ctokenizer);
|
||||||
|
try std.testing.expectEqual(Token.Tag.eof, zig0.zigToken(last_token.tag));
|
||||||
|
}
|
||||||
|
|
||||||
var tokenizer = Tokenizer.init(source);
|
var tokenizer = Tokenizer.init(source);
|
||||||
for (expected_token_tags) |expected_token_tag| {
|
for (expected_token_tags) |expected_token_tag| {
|
||||||
const token = tokenizer.next();
|
const token = tokenizer.next();
|
||||||
|
|||||||
6
lib/std/zig/zig0_test.zig
Normal file
6
lib/std/zig/zig0_test.zig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub const zig0 = @import("zig0_bridge");
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = @import("parser_test.zig");
|
||||||
|
_ = @import("tokenizer.zig");
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
NOTICE TO PROSPECTIVE UPSTREAM CONTRIBUTORS
|
|
||||||
|
|
||||||
This software is licensed under the MIT License below. However, the
|
|
||||||
author politely but firmly requests that you do not submit this work, or
|
|
||||||
any derivative thereof, to the Zig project upstream unless you have
|
|
||||||
obtained explicit written permission from a Zig core team member
|
|
||||||
authorizing the submission.
|
|
||||||
|
|
||||||
This notice is not a license restriction. The MIT License governs all
|
|
||||||
use of this software. This is a social contract: please honor it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
The MIT License (Expat)
|
|
||||||
|
|
||||||
Copyright (c) Motiejus Jakštys
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
@@ -18,18 +18,18 @@ This is written with help from LLM:
|
|||||||
|
|
||||||
Quick test:
|
Quick test:
|
||||||
|
|
||||||
zig build fmt test
|
zig build fmt-zig0 test-zig0
|
||||||
|
|
||||||
Full test and static analysis with all supported compilers and valgrind (run
|
Full test and static analysis with all supported compilers and valgrind (run
|
||||||
before commit, takes a while):
|
before commit, takes a while):
|
||||||
|
|
||||||
zig build -Dvalgrind
|
zig build all-zig0 -Dvalgrind
|
||||||
|
|
||||||
# Debugging tips
|
# Debugging tips
|
||||||
|
|
||||||
Test runs infinitely? Build the test program executable:
|
Test runs infinitely? Build the test program executable:
|
||||||
|
|
||||||
$ zig build test -Dno-exec
|
$ zig build test-zig0 -Dzig0-no-exec
|
||||||
|
|
||||||
And then run it, capturing the stack trace:
|
And then run it, capturing the stack trace:
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
1. implement @panic, write a test that does it.
|
|
||||||
2. local variables.
|
|
||||||
3. control flow.
|
|
||||||
4. functions.
|
|
||||||
5. imports until one can import stdlib.
|
|
||||||
706
stage0/zig0_bridge.zig
Normal file
706
stage0/zig0_bridge.zig
Normal file
@@ -0,0 +1,706 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Ast = std.zig.Ast;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Token = std.zig.Token;
|
||||||
|
|
||||||
|
pub const enabled = true;
|
||||||
|
|
||||||
|
pub const c = @cImport({
|
||||||
|
@cInclude("ast.h");
|
||||||
|
@cInclude("tokenizer.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn zigToken(token: c_uint) Token.Tag {
|
||||||
|
return switch (token) {
|
||||||
|
c.TOKEN_INVALID => .invalid,
|
||||||
|
c.TOKEN_INVALID_PERIODASTERISKS => .invalid_periodasterisks,
|
||||||
|
c.TOKEN_IDENTIFIER => .identifier,
|
||||||
|
c.TOKEN_STRING_LITERAL => .string_literal,
|
||||||
|
c.TOKEN_MULTILINE_STRING_LITERAL_LINE => .multiline_string_literal_line,
|
||||||
|
c.TOKEN_CHAR_LITERAL => .char_literal,
|
||||||
|
c.TOKEN_EOF => .eof,
|
||||||
|
c.TOKEN_BUILTIN => .builtin,
|
||||||
|
c.TOKEN_BANG => .bang,
|
||||||
|
c.TOKEN_PIPE => .pipe,
|
||||||
|
c.TOKEN_PIPE_PIPE => .pipe_pipe,
|
||||||
|
c.TOKEN_PIPE_EQUAL => .pipe_equal,
|
||||||
|
c.TOKEN_EQUAL => .equal,
|
||||||
|
c.TOKEN_EQUAL_EQUAL => .equal_equal,
|
||||||
|
c.TOKEN_EQUAL_ANGLE_BRACKET_RIGHT => .equal_angle_bracket_right,
|
||||||
|
c.TOKEN_BANG_EQUAL => .bang_equal,
|
||||||
|
c.TOKEN_L_PAREN => .l_paren,
|
||||||
|
c.TOKEN_R_PAREN => .r_paren,
|
||||||
|
c.TOKEN_SEMICOLON => .semicolon,
|
||||||
|
c.TOKEN_PERCENT => .percent,
|
||||||
|
c.TOKEN_PERCENT_EQUAL => .percent_equal,
|
||||||
|
c.TOKEN_L_BRACE => .l_brace,
|
||||||
|
c.TOKEN_R_BRACE => .r_brace,
|
||||||
|
c.TOKEN_L_BRACKET => .l_bracket,
|
||||||
|
c.TOKEN_R_BRACKET => .r_bracket,
|
||||||
|
c.TOKEN_PERIOD => .period,
|
||||||
|
c.TOKEN_PERIOD_ASTERISK => .period_asterisk,
|
||||||
|
c.TOKEN_ELLIPSIS2 => .ellipsis2,
|
||||||
|
c.TOKEN_ELLIPSIS3 => .ellipsis3,
|
||||||
|
c.TOKEN_CARET => .caret,
|
||||||
|
c.TOKEN_CARET_EQUAL => .caret_equal,
|
||||||
|
c.TOKEN_PLUS => .plus,
|
||||||
|
c.TOKEN_PLUS_PLUS => .plus_plus,
|
||||||
|
c.TOKEN_PLUS_EQUAL => .plus_equal,
|
||||||
|
c.TOKEN_PLUS_PERCENT => .plus_percent,
|
||||||
|
c.TOKEN_PLUS_PERCENT_EQUAL => .plus_percent_equal,
|
||||||
|
c.TOKEN_PLUS_PIPE => .plus_pipe,
|
||||||
|
c.TOKEN_PLUS_PIPE_EQUAL => .plus_pipe_equal,
|
||||||
|
c.TOKEN_MINUS => .minus,
|
||||||
|
c.TOKEN_MINUS_EQUAL => .minus_equal,
|
||||||
|
c.TOKEN_MINUS_PERCENT => .minus_percent,
|
||||||
|
c.TOKEN_MINUS_PERCENT_EQUAL => .minus_percent_equal,
|
||||||
|
c.TOKEN_MINUS_PIPE => .minus_pipe,
|
||||||
|
c.TOKEN_MINUS_PIPE_EQUAL => .minus_pipe_equal,
|
||||||
|
c.TOKEN_ASTERISK => .asterisk,
|
||||||
|
c.TOKEN_ASTERISK_EQUAL => .asterisk_equal,
|
||||||
|
c.TOKEN_ASTERISK_ASTERISK => .asterisk_asterisk,
|
||||||
|
c.TOKEN_ASTERISK_PERCENT => .asterisk_percent,
|
||||||
|
c.TOKEN_ASTERISK_PERCENT_EQUAL => .asterisk_percent_equal,
|
||||||
|
c.TOKEN_ASTERISK_PIPE => .asterisk_pipe,
|
||||||
|
c.TOKEN_ASTERISK_PIPE_EQUAL => .asterisk_pipe_equal,
|
||||||
|
c.TOKEN_ARROW => .arrow,
|
||||||
|
c.TOKEN_COLON => .colon,
|
||||||
|
c.TOKEN_SLASH => .slash,
|
||||||
|
c.TOKEN_SLASH_EQUAL => .slash_equal,
|
||||||
|
c.TOKEN_COMMA => .comma,
|
||||||
|
c.TOKEN_AMPERSAND => .ampersand,
|
||||||
|
c.TOKEN_AMPERSAND_EQUAL => .ampersand_equal,
|
||||||
|
c.TOKEN_QUESTION_MARK => .question_mark,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_LEFT => .angle_bracket_left,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_LEFT_EQUAL => .angle_bracket_left_equal,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT => .angle_bracket_angle_bracket_left,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_EQUAL => .angle_bracket_angle_bracket_left_equal,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE => .angle_bracket_angle_bracket_left_pipe,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_LEFT_PIPE_EQUAL => .angle_bracket_angle_bracket_left_pipe_equal,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_RIGHT => .angle_bracket_right,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_RIGHT_EQUAL => .angle_bracket_right_equal,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT => .angle_bracket_angle_bracket_right,
|
||||||
|
c.TOKEN_ANGLE_BRACKET_ANGLE_BRACKET_RIGHT_EQUAL => .angle_bracket_angle_bracket_right_equal,
|
||||||
|
c.TOKEN_TILDE => .tilde,
|
||||||
|
c.TOKEN_NUMBER_LITERAL => .number_literal,
|
||||||
|
c.TOKEN_DOC_COMMENT => .doc_comment,
|
||||||
|
c.TOKEN_CONTAINER_DOC_COMMENT => .container_doc_comment,
|
||||||
|
c.TOKEN_KEYWORD_ADDRSPACE => .keyword_addrspace,
|
||||||
|
c.TOKEN_KEYWORD_ALIGN => .keyword_align,
|
||||||
|
c.TOKEN_KEYWORD_ALLOWZERO => .keyword_allowzero,
|
||||||
|
c.TOKEN_KEYWORD_AND => .keyword_and,
|
||||||
|
c.TOKEN_KEYWORD_ANYFRAME => .keyword_anyframe,
|
||||||
|
c.TOKEN_KEYWORD_ANYTYPE => .keyword_anytype,
|
||||||
|
c.TOKEN_KEYWORD_ASM => .keyword_asm,
|
||||||
|
c.TOKEN_KEYWORD_BREAK => .keyword_break,
|
||||||
|
c.TOKEN_KEYWORD_CALLCONV => .keyword_callconv,
|
||||||
|
c.TOKEN_KEYWORD_CATCH => .keyword_catch,
|
||||||
|
c.TOKEN_KEYWORD_COMPTIME => .keyword_comptime,
|
||||||
|
c.TOKEN_KEYWORD_CONST => .keyword_const,
|
||||||
|
c.TOKEN_KEYWORD_CONTINUE => .keyword_continue,
|
||||||
|
c.TOKEN_KEYWORD_DEFER => .keyword_defer,
|
||||||
|
c.TOKEN_KEYWORD_ELSE => .keyword_else,
|
||||||
|
c.TOKEN_KEYWORD_ENUM => .keyword_enum,
|
||||||
|
c.TOKEN_KEYWORD_ERRDEFER => .keyword_errdefer,
|
||||||
|
c.TOKEN_KEYWORD_ERROR => .keyword_error,
|
||||||
|
c.TOKEN_KEYWORD_EXPORT => .keyword_export,
|
||||||
|
c.TOKEN_KEYWORD_EXTERN => .keyword_extern,
|
||||||
|
c.TOKEN_KEYWORD_FN => .keyword_fn,
|
||||||
|
c.TOKEN_KEYWORD_FOR => .keyword_for,
|
||||||
|
c.TOKEN_KEYWORD_IF => .keyword_if,
|
||||||
|
c.TOKEN_KEYWORD_INLINE => .keyword_inline,
|
||||||
|
c.TOKEN_KEYWORD_NOALIAS => .keyword_noalias,
|
||||||
|
c.TOKEN_KEYWORD_NOINLINE => .keyword_noinline,
|
||||||
|
c.TOKEN_KEYWORD_NOSUSPEND => .keyword_nosuspend,
|
||||||
|
c.TOKEN_KEYWORD_OPAQUE => .keyword_opaque,
|
||||||
|
c.TOKEN_KEYWORD_OR => .keyword_or,
|
||||||
|
c.TOKEN_KEYWORD_ORELSE => .keyword_orelse,
|
||||||
|
c.TOKEN_KEYWORD_PACKED => .keyword_packed,
|
||||||
|
c.TOKEN_KEYWORD_PUB => .keyword_pub,
|
||||||
|
c.TOKEN_KEYWORD_RESUME => .keyword_resume,
|
||||||
|
c.TOKEN_KEYWORD_RETURN => .keyword_return,
|
||||||
|
c.TOKEN_KEYWORD_LINKSECTION => .keyword_linksection,
|
||||||
|
c.TOKEN_KEYWORD_STRUCT => .keyword_struct,
|
||||||
|
c.TOKEN_KEYWORD_SUSPEND => .keyword_suspend,
|
||||||
|
c.TOKEN_KEYWORD_SWITCH => .keyword_switch,
|
||||||
|
c.TOKEN_KEYWORD_TEST => .keyword_test,
|
||||||
|
c.TOKEN_KEYWORD_THREADLOCAL => .keyword_threadlocal,
|
||||||
|
c.TOKEN_KEYWORD_TRY => .keyword_try,
|
||||||
|
c.TOKEN_KEYWORD_UNION => .keyword_union,
|
||||||
|
c.TOKEN_KEYWORD_UNREACHABLE => .keyword_unreachable,
|
||||||
|
c.TOKEN_KEYWORD_VAR => .keyword_var,
|
||||||
|
c.TOKEN_KEYWORD_VOLATILE => .keyword_volatile,
|
||||||
|
c.TOKEN_KEYWORD_WHILE => .keyword_while,
|
||||||
|
else => invalid_sentinel,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const invalid_sentinel = @as(Token.Tag, @enumFromInt(std.math.maxInt(@typeInfo(Token.Tag).@"enum".tag_type)));
|
||||||
|
|
||||||
|
pub fn zigNode(token: c_uint) Ast.Node.Tag {
|
||||||
|
return switch (token) {
|
||||||
|
c.AST_NODE_ROOT => .root,
|
||||||
|
c.AST_NODE_TEST_DECL => .test_decl,
|
||||||
|
c.AST_NODE_GLOBAL_VAR_DECL => .global_var_decl,
|
||||||
|
c.AST_NODE_LOCAL_VAR_DECL => .local_var_decl,
|
||||||
|
c.AST_NODE_SIMPLE_VAR_DECL => .simple_var_decl,
|
||||||
|
c.AST_NODE_ALIGNED_VAR_DECL => .aligned_var_decl,
|
||||||
|
c.AST_NODE_ERRDEFER => .@"errdefer",
|
||||||
|
c.AST_NODE_DEFER => .@"defer",
|
||||||
|
c.AST_NODE_CATCH => .@"catch",
|
||||||
|
c.AST_NODE_FIELD_ACCESS => .field_access,
|
||||||
|
c.AST_NODE_UNWRAP_OPTIONAL => .unwrap_optional,
|
||||||
|
c.AST_NODE_EQUAL_EQUAL => .equal_equal,
|
||||||
|
c.AST_NODE_BANG_EQUAL => .bang_equal,
|
||||||
|
c.AST_NODE_LESS_THAN => .less_than,
|
||||||
|
c.AST_NODE_GREATER_THAN => .greater_than,
|
||||||
|
c.AST_NODE_LESS_OR_EQUAL => .less_or_equal,
|
||||||
|
c.AST_NODE_GREATER_OR_EQUAL => .greater_or_equal,
|
||||||
|
c.AST_NODE_ASSIGN_MUL => .assign_mul,
|
||||||
|
c.AST_NODE_ASSIGN_DIV => .assign_div,
|
||||||
|
c.AST_NODE_ASSIGN_MOD => .assign_mod,
|
||||||
|
c.AST_NODE_ASSIGN_ADD => .assign_add,
|
||||||
|
c.AST_NODE_ASSIGN_SUB => .assign_sub,
|
||||||
|
c.AST_NODE_ASSIGN_SHL => .assign_shl,
|
||||||
|
c.AST_NODE_ASSIGN_SHL_SAT => .assign_shl_sat,
|
||||||
|
c.AST_NODE_ASSIGN_SHR => .assign_shr,
|
||||||
|
c.AST_NODE_ASSIGN_BIT_AND => .assign_bit_and,
|
||||||
|
c.AST_NODE_ASSIGN_BIT_XOR => .assign_bit_xor,
|
||||||
|
c.AST_NODE_ASSIGN_BIT_OR => .assign_bit_or,
|
||||||
|
c.AST_NODE_ASSIGN_MUL_WRAP => .assign_mul_wrap,
|
||||||
|
c.AST_NODE_ASSIGN_ADD_WRAP => .assign_add_wrap,
|
||||||
|
c.AST_NODE_ASSIGN_SUB_WRAP => .assign_sub_wrap,
|
||||||
|
c.AST_NODE_ASSIGN_MUL_SAT => .assign_mul_sat,
|
||||||
|
c.AST_NODE_ASSIGN_ADD_SAT => .assign_add_sat,
|
||||||
|
c.AST_NODE_ASSIGN_SUB_SAT => .assign_sub_sat,
|
||||||
|
c.AST_NODE_ASSIGN => .assign,
|
||||||
|
c.AST_NODE_ASSIGN_DESTRUCTURE => .assign_destructure,
|
||||||
|
c.AST_NODE_MERGE_ERROR_SETS => .merge_error_sets,
|
||||||
|
c.AST_NODE_MUL => .mul,
|
||||||
|
c.AST_NODE_DIV => .div,
|
||||||
|
c.AST_NODE_MOD => .mod,
|
||||||
|
c.AST_NODE_ARRAY_MULT => .array_mult,
|
||||||
|
c.AST_NODE_MUL_WRAP => .mul_wrap,
|
||||||
|
c.AST_NODE_MUL_SAT => .mul_sat,
|
||||||
|
c.AST_NODE_ADD => .add,
|
||||||
|
c.AST_NODE_SUB => .sub,
|
||||||
|
c.AST_NODE_ARRAY_CAT => .array_cat,
|
||||||
|
c.AST_NODE_ADD_WRAP => .add_wrap,
|
||||||
|
c.AST_NODE_SUB_WRAP => .sub_wrap,
|
||||||
|
c.AST_NODE_ADD_SAT => .add_sat,
|
||||||
|
c.AST_NODE_SUB_SAT => .sub_sat,
|
||||||
|
c.AST_NODE_SHL => .shl,
|
||||||
|
c.AST_NODE_SHL_SAT => .shl_sat,
|
||||||
|
c.AST_NODE_SHR => .shr,
|
||||||
|
c.AST_NODE_BIT_AND => .bit_and,
|
||||||
|
c.AST_NODE_BIT_XOR => .bit_xor,
|
||||||
|
c.AST_NODE_BIT_OR => .bit_or,
|
||||||
|
c.AST_NODE_ORELSE => .@"orelse",
|
||||||
|
c.AST_NODE_BOOL_AND => .bool_and,
|
||||||
|
c.AST_NODE_BOOL_OR => .bool_or,
|
||||||
|
c.AST_NODE_BOOL_NOT => .bool_not,
|
||||||
|
c.AST_NODE_NEGATION => .negation,
|
||||||
|
c.AST_NODE_BIT_NOT => .bit_not,
|
||||||
|
c.AST_NODE_NEGATION_WRAP => .negation_wrap,
|
||||||
|
c.AST_NODE_ADDRESS_OF => .address_of,
|
||||||
|
c.AST_NODE_TRY => .@"try",
|
||||||
|
c.AST_NODE_OPTIONAL_TYPE => .optional_type,
|
||||||
|
c.AST_NODE_ARRAY_TYPE => .array_type,
|
||||||
|
c.AST_NODE_ARRAY_TYPE_SENTINEL => .array_type_sentinel,
|
||||||
|
c.AST_NODE_PTR_TYPE_ALIGNED => .ptr_type_aligned,
|
||||||
|
c.AST_NODE_PTR_TYPE_SENTINEL => .ptr_type_sentinel,
|
||||||
|
c.AST_NODE_PTR_TYPE => .ptr_type,
|
||||||
|
c.AST_NODE_PTR_TYPE_BIT_RANGE => .ptr_type_bit_range,
|
||||||
|
c.AST_NODE_SLICE_OPEN => .slice_open,
|
||||||
|
c.AST_NODE_SLICE => .slice,
|
||||||
|
c.AST_NODE_SLICE_SENTINEL => .slice_sentinel,
|
||||||
|
c.AST_NODE_DEREF => .deref,
|
||||||
|
c.AST_NODE_ARRAY_ACCESS => .array_access,
|
||||||
|
c.AST_NODE_ARRAY_INIT_ONE => .array_init_one,
|
||||||
|
c.AST_NODE_ARRAY_INIT_ONE_COMMA => .array_init_one_comma,
|
||||||
|
c.AST_NODE_ARRAY_INIT_DOT_TWO => .array_init_dot_two,
|
||||||
|
c.AST_NODE_ARRAY_INIT_DOT_TWO_COMMA => .array_init_dot_two_comma,
|
||||||
|
c.AST_NODE_ARRAY_INIT_DOT => .array_init_dot,
|
||||||
|
c.AST_NODE_ARRAY_INIT_DOT_COMMA => .array_init_dot_comma,
|
||||||
|
c.AST_NODE_ARRAY_INIT => .array_init,
|
||||||
|
c.AST_NODE_ARRAY_INIT_COMMA => .array_init_comma,
|
||||||
|
c.AST_NODE_STRUCT_INIT_ONE => .struct_init_one,
|
||||||
|
c.AST_NODE_STRUCT_INIT_ONE_COMMA => .struct_init_one_comma,
|
||||||
|
c.AST_NODE_STRUCT_INIT_DOT_TWO => .struct_init_dot_two,
|
||||||
|
c.AST_NODE_STRUCT_INIT_DOT_TWO_COMMA => .struct_init_dot_two_comma,
|
||||||
|
c.AST_NODE_STRUCT_INIT_DOT => .struct_init_dot,
|
||||||
|
c.AST_NODE_STRUCT_INIT_DOT_COMMA => .struct_init_dot_comma,
|
||||||
|
c.AST_NODE_STRUCT_INIT => .struct_init,
|
||||||
|
c.AST_NODE_STRUCT_INIT_COMMA => .struct_init_comma,
|
||||||
|
c.AST_NODE_CALL_ONE => .call_one,
|
||||||
|
c.AST_NODE_CALL_ONE_COMMA => .call_one_comma,
|
||||||
|
c.AST_NODE_CALL => .call,
|
||||||
|
c.AST_NODE_CALL_COMMA => .call_comma,
|
||||||
|
c.AST_NODE_SWITCH => .@"switch",
|
||||||
|
c.AST_NODE_SWITCH_COMMA => .switch_comma,
|
||||||
|
c.AST_NODE_SWITCH_CASE_ONE => .switch_case_one,
|
||||||
|
c.AST_NODE_SWITCH_CASE_INLINE_ONE => .switch_case_inline_one,
|
||||||
|
c.AST_NODE_SWITCH_CASE => .switch_case,
|
||||||
|
c.AST_NODE_SWITCH_CASE_INLINE => .switch_case_inline,
|
||||||
|
c.AST_NODE_SWITCH_RANGE => .switch_range,
|
||||||
|
c.AST_NODE_WHILE_SIMPLE => .while_simple,
|
||||||
|
c.AST_NODE_WHILE_CONT => .while_cont,
|
||||||
|
c.AST_NODE_WHILE => .@"while",
|
||||||
|
c.AST_NODE_FOR_SIMPLE => .for_simple,
|
||||||
|
c.AST_NODE_FOR => .@"for",
|
||||||
|
c.AST_NODE_FOR_RANGE => .for_range,
|
||||||
|
c.AST_NODE_IF_SIMPLE => .if_simple,
|
||||||
|
c.AST_NODE_IF => .@"if",
|
||||||
|
c.AST_NODE_SUSPEND => .@"suspend",
|
||||||
|
c.AST_NODE_RESUME => .@"resume",
|
||||||
|
c.AST_NODE_CONTINUE => .@"continue",
|
||||||
|
c.AST_NODE_BREAK => .@"break",
|
||||||
|
c.AST_NODE_RETURN => .@"return",
|
||||||
|
c.AST_NODE_FN_PROTO_SIMPLE => .fn_proto_simple,
|
||||||
|
c.AST_NODE_FN_PROTO_MULTI => .fn_proto_multi,
|
||||||
|
c.AST_NODE_FN_PROTO_ONE => .fn_proto_one,
|
||||||
|
c.AST_NODE_FN_PROTO => .fn_proto,
|
||||||
|
c.AST_NODE_FN_DECL => .fn_decl,
|
||||||
|
c.AST_NODE_ANYFRAME_TYPE => .anyframe_type,
|
||||||
|
c.AST_NODE_ANYFRAME_LITERAL => .anyframe_literal,
|
||||||
|
c.AST_NODE_CHAR_LITERAL => .char_literal,
|
||||||
|
c.AST_NODE_NUMBER_LITERAL => .number_literal,
|
||||||
|
c.AST_NODE_UNREACHABLE_LITERAL => .unreachable_literal,
|
||||||
|
c.AST_NODE_IDENTIFIER => .identifier,
|
||||||
|
c.AST_NODE_ENUM_LITERAL => .enum_literal,
|
||||||
|
c.AST_NODE_STRING_LITERAL => .string_literal,
|
||||||
|
c.AST_NODE_MULTILINE_STRING_LITERAL => .multiline_string_literal,
|
||||||
|
c.AST_NODE_GROUPED_EXPRESSION => .grouped_expression,
|
||||||
|
c.AST_NODE_BUILTIN_CALL_TWO => .builtin_call_two,
|
||||||
|
c.AST_NODE_BUILTIN_CALL_TWO_COMMA => .builtin_call_two_comma,
|
||||||
|
c.AST_NODE_BUILTIN_CALL => .builtin_call,
|
||||||
|
c.AST_NODE_BUILTIN_CALL_COMMA => .builtin_call_comma,
|
||||||
|
c.AST_NODE_ERROR_SET_DECL => .error_set_decl,
|
||||||
|
c.AST_NODE_CONTAINER_DECL => .container_decl,
|
||||||
|
c.AST_NODE_CONTAINER_DECL_TRAILING => .container_decl_trailing,
|
||||||
|
c.AST_NODE_CONTAINER_DECL_TWO => .container_decl_two,
|
||||||
|
c.AST_NODE_CONTAINER_DECL_TWO_TRAILING => .container_decl_two_trailing,
|
||||||
|
c.AST_NODE_CONTAINER_DECL_ARG => .container_decl_arg,
|
||||||
|
c.AST_NODE_CONTAINER_DECL_ARG_TRAILING => .container_decl_arg_trailing,
|
||||||
|
c.AST_NODE_TAGGED_UNION => .tagged_union,
|
||||||
|
c.AST_NODE_TAGGED_UNION_TRAILING => .tagged_union_trailing,
|
||||||
|
c.AST_NODE_TAGGED_UNION_TWO => .tagged_union_two,
|
||||||
|
c.AST_NODE_TAGGED_UNION_TWO_TRAILING => .tagged_union_two_trailing,
|
||||||
|
c.AST_NODE_TAGGED_UNION_ENUM_TAG => .tagged_union_enum_tag,
|
||||||
|
c.AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING => .tagged_union_enum_tag_trailing,
|
||||||
|
c.AST_NODE_CONTAINER_FIELD_INIT => .container_field_init,
|
||||||
|
c.AST_NODE_CONTAINER_FIELD_ALIGN => .container_field_align,
|
||||||
|
c.AST_NODE_CONTAINER_FIELD => .container_field,
|
||||||
|
c.AST_NODE_COMPTIME => .@"comptime",
|
||||||
|
c.AST_NODE_NOSUSPEND => .@"nosuspend",
|
||||||
|
c.AST_NODE_BLOCK_TWO => .block_two,
|
||||||
|
c.AST_NODE_BLOCK_TWO_SEMICOLON => .block_two_semicolon,
|
||||||
|
c.AST_NODE_BLOCK => .block,
|
||||||
|
c.AST_NODE_BLOCK_SEMICOLON => .block_semicolon,
|
||||||
|
c.AST_NODE_ASM_SIMPLE => .asm_simple,
|
||||||
|
c.AST_NODE_ASM_LEGACY => .asm_legacy,
|
||||||
|
c.AST_NODE_ASM => .@"asm",
|
||||||
|
c.AST_NODE_ASM_OUTPUT => .asm_output,
|
||||||
|
c.AST_NODE_ASM_INPUT => .asm_input,
|
||||||
|
c.AST_NODE_ERROR_VALUE => .error_value,
|
||||||
|
c.AST_NODE_ERROR_UNION => .error_union,
|
||||||
|
else => @as(Ast.Node.Tag, @enumFromInt(std.math.maxInt(@typeInfo(Ast.Node.Tag).@"enum".tag_type))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toIndex(v: u32) Ast.Node.Index {
|
||||||
|
return @enumFromInt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toOptIndex(v: u32) Ast.Node.OptionalIndex {
|
||||||
|
return if (v == 0) .none else @enumFromInt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toExtraIndex(v: u32) Ast.ExtraIndex {
|
||||||
|
return @enumFromInt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toOptTokenIndex(v: u32) Ast.OptionalTokenIndex {
|
||||||
|
return @enumFromInt(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zigData(tag: Ast.Node.Tag, lhs: u32, rhs: u32) Ast.Node.Data {
|
||||||
|
return switch (tag) {
|
||||||
|
// data unused
|
||||||
|
.identifier,
|
||||||
|
.string_literal,
|
||||||
|
.char_literal,
|
||||||
|
.number_literal,
|
||||||
|
.unreachable_literal,
|
||||||
|
.anyframe_literal,
|
||||||
|
.enum_literal,
|
||||||
|
.error_value,
|
||||||
|
=> .{ .opt_node_and_opt_node = .{ toOptIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node (single node index)
|
||||||
|
.@"defer",
|
||||||
|
.@"comptime",
|
||||||
|
.@"nosuspend",
|
||||||
|
.@"suspend",
|
||||||
|
.@"resume",
|
||||||
|
.bool_not,
|
||||||
|
.negation,
|
||||||
|
.bit_not,
|
||||||
|
.negation_wrap,
|
||||||
|
.address_of,
|
||||||
|
.@"try",
|
||||||
|
.deref,
|
||||||
|
.optional_type,
|
||||||
|
=> .{ .node = toIndex(lhs) },
|
||||||
|
|
||||||
|
// .opt_node (single optional node)
|
||||||
|
.@"return",
|
||||||
|
=> .{ .opt_node = toOptIndex(lhs) },
|
||||||
|
|
||||||
|
// .node_and_node
|
||||||
|
.fn_decl,
|
||||||
|
.container_field_align,
|
||||||
|
.error_union,
|
||||||
|
.@"catch",
|
||||||
|
.equal_equal,
|
||||||
|
.bang_equal,
|
||||||
|
.less_than,
|
||||||
|
.greater_than,
|
||||||
|
.less_or_equal,
|
||||||
|
.greater_or_equal,
|
||||||
|
.assign_mul,
|
||||||
|
.assign_div,
|
||||||
|
.assign_mod,
|
||||||
|
.assign_add,
|
||||||
|
.assign_sub,
|
||||||
|
.assign_shl,
|
||||||
|
.assign_shl_sat,
|
||||||
|
.assign_shr,
|
||||||
|
.assign_bit_and,
|
||||||
|
.assign_bit_xor,
|
||||||
|
.assign_bit_or,
|
||||||
|
.assign_mul_wrap,
|
||||||
|
.assign_add_wrap,
|
||||||
|
.assign_sub_wrap,
|
||||||
|
.assign_mul_sat,
|
||||||
|
.assign_add_sat,
|
||||||
|
.assign_sub_sat,
|
||||||
|
.assign,
|
||||||
|
.merge_error_sets,
|
||||||
|
.mul,
|
||||||
|
.div,
|
||||||
|
.mod,
|
||||||
|
.array_mult,
|
||||||
|
.mul_wrap,
|
||||||
|
.mul_sat,
|
||||||
|
.add,
|
||||||
|
.sub,
|
||||||
|
.array_cat,
|
||||||
|
.add_wrap,
|
||||||
|
.sub_wrap,
|
||||||
|
.add_sat,
|
||||||
|
.sub_sat,
|
||||||
|
.shl,
|
||||||
|
.shl_sat,
|
||||||
|
.shr,
|
||||||
|
.bit_and,
|
||||||
|
.bit_xor,
|
||||||
|
.bit_or,
|
||||||
|
.@"orelse",
|
||||||
|
.bool_and,
|
||||||
|
.bool_or,
|
||||||
|
.array_type,
|
||||||
|
.array_access,
|
||||||
|
.switch_range,
|
||||||
|
=> .{ .node_and_node = .{ toIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .opt_node_and_opt_node
|
||||||
|
.fn_proto_simple,
|
||||||
|
.simple_var_decl,
|
||||||
|
.block_two,
|
||||||
|
.block_two_semicolon,
|
||||||
|
.builtin_call_two,
|
||||||
|
.builtin_call_two_comma,
|
||||||
|
.container_decl_two,
|
||||||
|
.container_decl_two_trailing,
|
||||||
|
.tagged_union_two,
|
||||||
|
.tagged_union_two_trailing,
|
||||||
|
.struct_init_dot_two,
|
||||||
|
.struct_init_dot_two_comma,
|
||||||
|
.array_init_dot_two,
|
||||||
|
.array_init_dot_two_comma,
|
||||||
|
=> .{ .opt_node_and_opt_node = .{ toOptIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node_and_opt_node
|
||||||
|
.call_one,
|
||||||
|
.call_one_comma,
|
||||||
|
.struct_init_one,
|
||||||
|
.struct_init_one_comma,
|
||||||
|
.container_field_init,
|
||||||
|
.aligned_var_decl,
|
||||||
|
=> .{ .node_and_opt_node = .{ toIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node_and_node (array_init_one uses node_and_node, not
|
||||||
|
// node_and_opt_node)
|
||||||
|
.array_init_one,
|
||||||
|
.array_init_one_comma,
|
||||||
|
=> .{ .node_and_node = .{ toIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .opt_node_and_node
|
||||||
|
.ptr_type_aligned,
|
||||||
|
.ptr_type_sentinel,
|
||||||
|
.switch_case_one,
|
||||||
|
.switch_case_inline_one,
|
||||||
|
=> .{ .opt_node_and_node = .{ toOptIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node_and_extra
|
||||||
|
.call,
|
||||||
|
.call_comma,
|
||||||
|
.container_field,
|
||||||
|
.array_type_sentinel,
|
||||||
|
.slice,
|
||||||
|
.slice_sentinel,
|
||||||
|
.array_init,
|
||||||
|
.array_init_comma,
|
||||||
|
.struct_init,
|
||||||
|
.struct_init_comma,
|
||||||
|
.@"switch",
|
||||||
|
.switch_comma,
|
||||||
|
.container_decl_arg,
|
||||||
|
.container_decl_arg_trailing,
|
||||||
|
.tagged_union_enum_tag,
|
||||||
|
.tagged_union_enum_tag_trailing,
|
||||||
|
.@"asm",
|
||||||
|
=> .{ .node_and_extra = .{ toIndex(lhs), toExtraIndex(rhs) } },
|
||||||
|
|
||||||
|
// .extra_and_node
|
||||||
|
.assign_destructure,
|
||||||
|
.switch_case,
|
||||||
|
.switch_case_inline,
|
||||||
|
.ptr_type,
|
||||||
|
.ptr_type_bit_range,
|
||||||
|
=> .{ .extra_and_node = .{ toExtraIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .extra_and_opt_node
|
||||||
|
.global_var_decl,
|
||||||
|
.local_var_decl,
|
||||||
|
.fn_proto_multi,
|
||||||
|
.fn_proto_one,
|
||||||
|
.fn_proto,
|
||||||
|
=> .{ .extra_and_opt_node = .{ toExtraIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
// .extra_range (SubRange)
|
||||||
|
.root,
|
||||||
|
.block,
|
||||||
|
.block_semicolon,
|
||||||
|
.builtin_call,
|
||||||
|
.builtin_call_comma,
|
||||||
|
.container_decl,
|
||||||
|
.container_decl_trailing,
|
||||||
|
.tagged_union,
|
||||||
|
.tagged_union_trailing,
|
||||||
|
.array_init_dot,
|
||||||
|
.array_init_dot_comma,
|
||||||
|
.struct_init_dot,
|
||||||
|
.struct_init_dot_comma,
|
||||||
|
=> .{ .extra_range = .{ .start = toExtraIndex(lhs), .end = toExtraIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node_and_token
|
||||||
|
.grouped_expression,
|
||||||
|
.asm_input,
|
||||||
|
.asm_simple,
|
||||||
|
.field_access,
|
||||||
|
.unwrap_optional,
|
||||||
|
=> .{ .node_and_token = .{ toIndex(lhs), rhs } },
|
||||||
|
|
||||||
|
// .opt_node_and_token
|
||||||
|
.asm_output,
|
||||||
|
=> .{ .opt_node_and_token = .{ toOptIndex(lhs), rhs } },
|
||||||
|
|
||||||
|
// .opt_token_and_node
|
||||||
|
.test_decl,
|
||||||
|
.@"errdefer",
|
||||||
|
=> .{ .opt_token_and_node = .{ toOptTokenIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .opt_token_and_opt_node
|
||||||
|
.@"break",
|
||||||
|
.@"continue",
|
||||||
|
=> .{ .opt_token_and_opt_node = .{ toOptTokenIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
// .token_and_token
|
||||||
|
.error_set_decl,
|
||||||
|
.multiline_string_literal,
|
||||||
|
=> .{ .token_and_token = .{ lhs, rhs } },
|
||||||
|
|
||||||
|
// .token_and_node
|
||||||
|
.anyframe_type,
|
||||||
|
=> .{ .token_and_node = .{ lhs, toIndex(rhs) } },
|
||||||
|
|
||||||
|
// .node_and_node for slice_open (lhs[rhs..])
|
||||||
|
.slice_open,
|
||||||
|
=> .{ .node_and_node = .{ toIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
.while_simple,
|
||||||
|
.for_simple,
|
||||||
|
.if_simple,
|
||||||
|
=> .{ .node_and_node = .{ toIndex(lhs), toIndex(rhs) } },
|
||||||
|
|
||||||
|
.while_cont,
|
||||||
|
.@"while",
|
||||||
|
.@"if",
|
||||||
|
=> .{ .node_and_extra = .{ toIndex(lhs), toExtraIndex(rhs) } },
|
||||||
|
|
||||||
|
.for_range,
|
||||||
|
=> .{ .node_and_opt_node = .{ toIndex(lhs), toOptIndex(rhs) } },
|
||||||
|
|
||||||
|
.@"for",
|
||||||
|
=> .{ .@"for" = .{ toExtraIndex(lhs), @bitCast(rhs) } },
|
||||||
|
|
||||||
|
.asm_legacy,
|
||||||
|
=> .{ .node_and_extra = .{ toIndex(lhs), toExtraIndex(rhs) } },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// zigAst converts a c.Ast to std.Zig.Ast. The resulting Ast should be freed with deinit().
|
||||||
|
pub fn zigAst(gpa: Allocator, c_ast: c.Ast) !Ast {
|
||||||
|
var tokens = Ast.TokenList{};
|
||||||
|
try tokens.resize(gpa, c_ast.tokens.len);
|
||||||
|
errdefer tokens.deinit(gpa);
|
||||||
|
|
||||||
|
for (0..c_ast.tokens.len) |i|
|
||||||
|
tokens.set(i, .{
|
||||||
|
.tag = zigToken(c_ast.tokens.tags[i]),
|
||||||
|
.start = c_ast.tokens.starts[i],
|
||||||
|
});
|
||||||
|
|
||||||
|
var nodes = Ast.NodeList{};
|
||||||
|
try nodes.resize(gpa, c_ast.nodes.len);
|
||||||
|
errdefer nodes.deinit(gpa);
|
||||||
|
|
||||||
|
for (0..c_ast.nodes.len) |i| {
|
||||||
|
const tag = zigNode(c_ast.nodes.tags[i]);
|
||||||
|
nodes.set(i, .{
|
||||||
|
.tag = tag,
|
||||||
|
.main_token = c_ast.nodes.main_tokens[i],
|
||||||
|
.data = zigData(tag, c_ast.nodes.datas[i].lhs, c_ast.nodes.datas[i].rhs),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const extra_data = try gpa.alloc(u32, c_ast.extra_data.len);
|
||||||
|
errdefer gpa.free(extra_data);
|
||||||
|
@memcpy(extra_data, c_ast.extra_data.arr[0..c_ast.extra_data.len]);
|
||||||
|
|
||||||
|
const errors = if (c_ast.has_error) blk: {
|
||||||
|
const errs = try gpa.alloc(Ast.Error, 1);
|
||||||
|
errs[0] = .{ .tag = .expected_token, .token = 0, .extra = .{ .none = {} } };
|
||||||
|
break :blk errs;
|
||||||
|
} else try gpa.alloc(Ast.Error, 0);
|
||||||
|
errdefer gpa.free(errors);
|
||||||
|
|
||||||
|
return Ast{
|
||||||
|
.source = c_ast.source[0..c_ast.source_len :0],
|
||||||
|
.mode = .zig,
|
||||||
|
.tokens = tokens.slice(),
|
||||||
|
.nodes = nodes.slice(),
|
||||||
|
.extra_data = extra_data,
|
||||||
|
.errors = errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of meaningful u32 fields in Node.Data for a given tag.
|
||||||
|
// 0 = data is undefined/unused, 1 = only first u32 is meaningful, 2 = both meaningful.
|
||||||
|
fn dataFieldCount(tag: Ast.Node.Tag) u2 {
|
||||||
|
return switch (tag) {
|
||||||
|
// data unused (undefined in Zig parser)
|
||||||
|
.identifier,
|
||||||
|
.string_literal,
|
||||||
|
.char_literal,
|
||||||
|
.number_literal,
|
||||||
|
.unreachable_literal,
|
||||||
|
.anyframe_literal,
|
||||||
|
.enum_literal,
|
||||||
|
.error_value,
|
||||||
|
=> 0,
|
||||||
|
|
||||||
|
// .node or .opt_node — only first u32
|
||||||
|
.@"defer",
|
||||||
|
.@"comptime",
|
||||||
|
.@"nosuspend",
|
||||||
|
.@"suspend",
|
||||||
|
.@"resume",
|
||||||
|
.bool_not,
|
||||||
|
.negation,
|
||||||
|
.bit_not,
|
||||||
|
.negation_wrap,
|
||||||
|
.address_of,
|
||||||
|
.@"try",
|
||||||
|
.deref,
|
||||||
|
.optional_type,
|
||||||
|
.@"return",
|
||||||
|
=> 1,
|
||||||
|
|
||||||
|
// everything else — both u32 fields
|
||||||
|
else => 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expectAstConsistent(c_tree: Ast, zig_tree: Ast, source: [:0]const u8) !void {
|
||||||
|
_ = source;
|
||||||
|
const print = std.debug.print;
|
||||||
|
|
||||||
|
if (c_tree.tokens.len != zig_tree.tokens.len) {
|
||||||
|
print("token count mismatch: c={d} zig={d}\n", .{ c_tree.tokens.len, zig_tree.tokens.len });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
for (0..c_tree.tokens.len) |i| {
|
||||||
|
if (c_tree.tokens.items(.start)[i] != zig_tree.tokens.items(.start)[i]) {
|
||||||
|
print("token[{d}] start mismatch: c={d} zig={d}\n", .{ i, c_tree.tokens.items(.start)[i], zig_tree.tokens.items(.start)[i] });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
if (c_tree.tokens.items(.tag)[i] != zig_tree.tokens.items(.tag)[i]) {
|
||||||
|
print("token[{d}] tag mismatch: c={s} zig={s}\n", .{ i, @tagName(c_tree.tokens.items(.tag)[i]), @tagName(zig_tree.tokens.items(.tag)[i]) });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_tree.nodes.len != zig_tree.nodes.len) {
|
||||||
|
print("node count mismatch: c={d} zig={d}\n", .{ c_tree.nodes.len, zig_tree.nodes.len });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
for (0..c_tree.nodes.len) |i| {
|
||||||
|
const c_tag = c_tree.nodes.items(.tag)[i];
|
||||||
|
const z_tag = zig_tree.nodes.items(.tag)[i];
|
||||||
|
if (c_tag != z_tag) {
|
||||||
|
print("node[{d}] tag mismatch: c={s} zig={s}\n", .{ i, @tagName(c_tag), @tagName(z_tag) });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
if (c_tree.nodes.items(.main_token)[i] != zig_tree.nodes.items(.main_token)[i]) {
|
||||||
|
print("node[{d}] main_token mismatch: c={d} zig={d}\n", .{ i, c_tree.nodes.items(.main_token)[i], zig_tree.nodes.items(.main_token)[i] });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
const field_count = dataFieldCount(c_tag);
|
||||||
|
if (field_count >= 1) {
|
||||||
|
const c_data: *const [2]u32 = @ptrCast(&c_tree.nodes.items(.data)[i]);
|
||||||
|
const z_data: *const [2]u32 = @ptrCast(&zig_tree.nodes.items(.data)[i]);
|
||||||
|
if (c_data[0] != z_data[0]) {
|
||||||
|
print("node[{d}] data[0] mismatch: c={d} zig={d}\n", .{ i, c_data[0], z_data[0] });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
if (field_count >= 2 and c_data[1] != z_data[1]) {
|
||||||
|
print("node[{d}] data[1] mismatch: c={d} zig={d}\n", .{ i, c_data[1], z_data[1] });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_tree.extra_data.len != zig_tree.extra_data.len) {
|
||||||
|
print("extra_data length mismatch: c={d} zig={d}\n", .{ c_tree.extra_data.len, zig_tree.extra_data.len });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
for (0..c_tree.extra_data.len) |i| {
|
||||||
|
if (c_tree.extra_data[i] != zig_tree.extra_data[i]) {
|
||||||
|
print("extra_data[{d}] mismatch: c={d} zig={d}\n", .{ i, c_tree.extra_data[i], zig_tree.extra_data[i] });
|
||||||
|
return error.TestExpectedEqual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user