Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement #elifdef and #elifndef #467

Merged
merged 4 commits into from
Apr 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn build(b: *Build) !void {
if (link_libc) {
exe.linkLibC();
}
exe.install();
b.installArtifact(exe);

const tests_step = b.step("test", "Run all tests");
tests_step.dependOn(&exe.step);
Expand All @@ -112,7 +112,7 @@ pub fn build(b: *Build) !void {
integration_tests.addOptions("build_options", test_runner_options);
test_runner_options.addOption(bool, "test_all_allocation_failures", test_all_allocation_failures);

const integration_test_runner = integration_tests.run();
const integration_test_runner = b.addRunArtifact(integration_tests);
integration_test_runner.addArg(b.pathFromRoot("test/cases"));
integration_test_runner.addArg(b.zig_exe);

Expand All @@ -121,7 +121,7 @@ pub fn build(b: *Build) !void {
.root_source_file = .{ .path = "test/record_runner.zig" },
});
record_tests.addModule("aro", aro_module);
const record_tests_runner = record_tests.run();
const record_tests_runner = b.addRunArtifact(record_tests);
record_tests_runner.addArg(b.pathFromRoot("test/records"));
record_tests_runner.addArg(b.zig_exe);

Expand Down
1 change: 1 addition & 0 deletions deps/zig/type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ pub const CType = enum {
.renderscript32,
.ve,
.spu_2,
.xtensa,
=> 4,

.aarch64_32,
Expand Down
24 changes: 14 additions & 10 deletions src/Attribute.zig
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ fn getArguments(comptime descriptor: type) []const ZigType.StructField {
/// number of required arguments
pub fn requiredArgCount(attr: Tag) u32 {
switch (attr) {
inline else => |tag| comptime {
var needed = 0;
const fields = getArguments(@field(attributes, @tagName(tag)));
for (fields) |arg_field| {
if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .Optional) needed += 1;
inline else => |tag| {
comptime var needed = 0;
comptime {
const fields = getArguments(@field(attributes, @tagName(tag)));
for (fields) |arg_field| {
if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .Optional) needed += 1;
}
}
return needed;
},
Expand All @@ -107,11 +109,13 @@ pub fn requiredArgCount(attr: Tag) u32 {
/// maximum number of args that can be passed
pub fn maxArgCount(attr: Tag) u32 {
switch (attr) {
inline else => |tag| comptime {
const fields = getArguments(@field(attributes, @tagName(tag)));
var max = 0;
for (fields) |arg_field| {
if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1;
inline else => |tag| {
comptime var max = 0;
comptime {
const fields = getArguments(@field(attributes, @tagName(tag)));
for (fields) |arg_field| {
if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1;
}
}
return max;
},
Expand Down
16 changes: 16 additions & 0 deletions src/Diagnostics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ const messages = struct {
const msg = "#elif after #else";
const kind = .@"error";
};
const elifdef_without_if = struct {
const msg = "#elifdef without #if";
const kind = .@"error";
};
const elifdef_after_else = struct {
const msg = "#elifdef after #else";
const kind = .@"error";
};
const elifndef_without_if = struct {
const msg = "#elifndef without #if";
const kind = .@"error";
};
const elifndef_after_else = struct {
const msg = "#elifndef after #else";
const kind = .@"error";
};
const else_without_if = struct {
const msg = "#else without #if";
const kind = .@"error";
Expand Down
102 changes: 102 additions & 0 deletions src/Preprocessor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,88 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
else => unreachable,
}
},
.keyword_elifdef => {
if (if_level == 0) {
try pp.err(directive, .elifdef_without_if);
if_level += 1;
if_kind.set(if_level, until_else);
} else if (if_level == 1) {
guard_name = null;
}
switch (if_kind.get(if_level)) {
until_else => {
const macro_name = try pp.expectMacroName(&tokenizer);
if (macro_name == null) {
if_kind.set(if_level, until_else);
try pp.skip(&tokenizer, .until_else);
if (pp.verbose) {
pp.verboseLog(directive, "entering else branch of #elifdef", .{});
}
} else {
try pp.expectNl(&tokenizer);
if (pp.defines.get(macro_name.?) != null) {
if_kind.set(if_level, until_endif);
if (pp.verbose) {
pp.verboseLog(directive, "entering then branch of #elifdef", .{});
}
} else {
if_kind.set(if_level, until_else);
try pp.skip(&tokenizer, .until_else);
if (pp.verbose) {
pp.verboseLog(directive, "entering else branch of #elifdef", .{});
}
}
}
},
until_endif => try pp.skip(&tokenizer, .until_endif),
until_endif_seen_else => {
try pp.err(directive, .elifdef_after_else);
skipToNl(&tokenizer);
},
else => unreachable,
}
},
.keyword_elifndef => {
if (if_level == 0) {
try pp.err(directive, .elifdef_without_if);
if_level += 1;
if_kind.set(if_level, until_else);
} else if (if_level == 1) {
guard_name = null;
}
switch (if_kind.get(if_level)) {
until_else => {
const macro_name = try pp.expectMacroName(&tokenizer);
if (macro_name == null) {
if_kind.set(if_level, until_else);
try pp.skip(&tokenizer, .until_else);
if (pp.verbose) {
pp.verboseLog(directive, "entering else branch of #elifndef", .{});
}
} else {
try pp.expectNl(&tokenizer);
if (pp.defines.get(macro_name.?) == null) {
if_kind.set(if_level, until_endif);
if (pp.verbose) {
pp.verboseLog(directive, "entering then branch of #elifndef", .{});
}
} else {
if_kind.set(if_level, until_else);
try pp.skip(&tokenizer, .until_else);
if (pp.verbose) {
pp.verboseLog(directive, "entering else branch of #elifndef", .{});
}
}
}
},
until_endif => try pp.skip(&tokenizer, .until_endif),
until_endif_seen_else => {
try pp.err(directive, .elifdef_after_else);
skipToNl(&tokenizer);
},
else => unreachable,
}
},
.keyword_else => {
try pp.expectNl(&tokenizer);
if (if_level == 0) {
Expand Down Expand Up @@ -812,6 +894,24 @@ fn skip(
tokenizer.* = saved_tokenizer;
return;
},
.keyword_elifdef => {
if (ifs_seen != 0 or cont == .until_endif) continue;
if (cont == .until_endif_seen_else) {
try pp.err(directive, .elifdef_after_else);
continue;
}
tokenizer.* = saved_tokenizer;
return;
},
.keyword_elifndef => {
if (ifs_seen != 0 or cont == .until_endif) continue;
if (cont == .until_endif_seen_else) {
try pp.err(directive, .elifndef_after_else);
continue;
}
tokenizer.* = saved_tokenizer;
return;
},
.keyword_endif => {
if (ifs_seen == 0) {
tokenizer.* = saved_tokenizer;
Expand Down Expand Up @@ -2452,6 +2552,8 @@ test "Include guards" {
fn pairsWithIfndef(tok_id: RawToken.Id) bool {
return switch (tok_id) {
.keyword_elif,
.keyword_elifdef,
.keyword_elifndef,
.keyword_else,
=> true,

Expand Down
12 changes: 12 additions & 0 deletions src/Tokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ pub const Token = struct {
keyword_ifdef,
keyword_ifndef,
keyword_elif,
keyword_elifdef,
keyword_elifndef,
keyword_endif,
keyword_error,
keyword_warning,
Expand Down Expand Up @@ -292,6 +294,8 @@ pub const Token = struct {
.keyword_ifdef,
.keyword_ifndef,
.keyword_elif,
.keyword_elifdef,
.keyword_elifndef,
.keyword_endif,
.keyword_error,
.keyword_warning,
Expand Down Expand Up @@ -422,6 +426,8 @@ pub const Token = struct {
.keyword_ifdef,
.keyword_ifndef,
.keyword_elif,
.keyword_elifdef,
.keyword_elifndef,
.keyword_endif,
.keyword_error,
.keyword_warning,
Expand Down Expand Up @@ -601,6 +607,8 @@ pub const Token = struct {
.keyword_ifdef => "ifdef",
.keyword_ifndef => "ifndef",
.keyword_elif => "elif",
.keyword_elifdef => "elifdef",
.keyword_elifndef => "elifndef",
.keyword_endif => "endif",
.keyword_error => "error",
.keyword_warning => "warning",
Expand Down Expand Up @@ -759,6 +767,8 @@ pub const Token = struct {
.keyword_true,
.keyword_false,
.keyword_nullptr,
.keyword_elifdef,
.keyword_elifndef,
=> if (standard.atLeast(.c2x)) kw else .identifier,

.keyword_int64,
Expand Down Expand Up @@ -871,6 +881,8 @@ pub const Token = struct {
.{ "ifdef", .keyword_ifdef },
.{ "ifndef", .keyword_ifndef },
.{ "elif", .keyword_elif },
.{ "elifdef", .keyword_elifdef },
.{ "elifndef", .keyword_elifndef },
.{ "endif", .keyword_endif },
.{ "error", .keyword_error },
.{ "warning", .keyword_warning },
Expand Down
17 changes: 17 additions & 0 deletions test/cases/#elifdef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//aro-args -E
#ifdef FOO
long long
#elifdef FOO
long
#elifndef FOO
int
#endif

#define BAR
#ifdef FOO
long long
#elifdef BAR
long
#elifndef FOO
int
#endif
17 changes: 17 additions & 0 deletions test/cases/#elifdefc2x.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//aro-args -std=c2x -E
#ifdef FOO
long long
#elifdef FOO
long
#elifndef FOO
int
#endif

#define BAR
#ifdef FOO
long long
#elifdef BAR
long
#elifndef FOO
int
#endif
20 changes: 20 additions & 0 deletions test/cases/#elifdefc2x_error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//aro-args -E -std=c2x
#define EXPECTED_ERRORS \
"#elifdefc2x_error.c:8:9: error: macro name missing" \
"#elifdefc2x_error.c:17:10: error: macro name missing"
#ifdef FOO
long long
#elifdef
long
#else
int
#endif

#define BAR
#ifdef FOO
long long
#elifndef
long
#else
int
#endif
2 changes: 2 additions & 0 deletions test/cases/expanded/#elifdef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@


4 changes: 4 additions & 0 deletions test/cases/expanded/#elifdefc2x.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

int

long
4 changes: 4 additions & 0 deletions test/cases/expanded/#elifdefc2x_error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

int

int
2 changes: 1 addition & 1 deletion test/record_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn main() !void {
const alloc = fixed_alloc.allocator();
defer {
gpa.free(fixed_buffer);
if (general_purpose_allocator.deinit()) std.process.exit(1);
if (general_purpose_allocator.deinit() == .leak) std.process.exit(1);
}

var args = try std.process.argsAlloc(gpa);
Expand Down
2 changes: 1 addition & 1 deletion test/runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ fn testAllAllocationFailures(cases: [][]const u8) !void {

pub fn main() !void {
const gpa = general_purpose_allocator.allocator();
defer if (general_purpose_allocator.deinit()) std.process.exit(1);
defer if (general_purpose_allocator.deinit() == .leak) std.process.exit(1);

var args = try std.process.argsAlloc(gpa);
defer std.process.argsFree(gpa, args);
Expand Down