Skip to content
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
7 changes: 7 additions & 0 deletions src/aro/Pragma.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ const Compilation = @import("Compilation.zig");
const Diagnostics = @import("Diagnostics.zig");
const Parser = @import("Parser.zig");
const Preprocessor = @import("Preprocessor.zig");
const Source = @import("Source.zig");
const TokenIndex = @import("Tree.zig").TokenIndex;

pub const Error = Compilation.Error || error{ UnknownPragma, StopPreprocessing };

pub const BeforeIncludeError = Compilation.Error || error{SkipInclude};

const Pragma = @This();

/// A do-nothing pragma; useful for unwrapping an optional pragma into a pragma that does nothing in the null case.
Expand All @@ -29,6 +32,10 @@ afterParse: ?*const fn (*Pragma, *Compilation) void = null,
/// Called during Compilation.deinit
deinit: *const fn (*Pragma, *Compilation) void,

/// Called during Preprocessor.include. Return SkipInclude to skip the include
/// altogether (see once.zig).
beforeInclude: ?*const fn (*Pragma, *Preprocessor, Source) BeforeIncludeError!void = null,

/// Called whenever the preprocessor encounters this pragma. `start_idx` is the index
/// within `pp.tokens` of the pragma name token. The pragma end is indicated by a
/// .nl token (which may be generated if the source ends with a pragma with no newline)
Expand Down
31 changes: 31 additions & 0 deletions src/aro/Preprocessor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,9 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpans
}

_ = pp.defines.orderedRemove(macro_name);
if (pp.verbose) {
pp.verboseLog(directive, "macro {s} undefined", .{macro_name});
}
try pp.expectNl(&tokenizer);
},
.keyword_include => {
Expand Down Expand Up @@ -3550,6 +3553,34 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
if (pp.defines.contains(guard)) return;
}

// Run any beforeInclude pragma hooks.
//
// NOTE: This is currently the only deep-preprocessor hook other than the
// actual token handler itself. If more are added, an event hook system
// similar to the compilation-scoped one should be considered with a
// payload structure that can handle context-relevant event data (e.g.,
// here, the source file data is needed).
for (pp.comp.pragma_handlers.keys(), pp.comp.pragma_handlers.values()) |handler_pragma_name, handler_pragma| {
if (handler_pragma.beforeInclude) |func| {
func(handler_pragma, pp, new_source) catch |handler_err| {
switch (handler_err) {
error.SkipInclude => {
if (pp.verbose) {
pp.verboseLog(
first,
"skipping include file {s} under direction of \"{s}\" pragma",
.{ new_source.path, handler_pragma_name },
);
}

return;
},
else => |e| return e,
}
};
}
}

if (pp.dep_file) |dep| try dep.addDependency(gpa, new_source.path);
if (pp.verbose) {
pp.verboseLog(first, "include file {s}", .{new_source.path});
Expand Down
6 changes: 6 additions & 0 deletions src/aro/pragmas/once.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Once = @This();
pragma: Pragma = .{
.afterParse = afterParse,
.deinit = deinit,
.beforeInclude = beforeInclude,
.preprocessorHandler = preprocessorHandler,
.preserveTokens = preserveTokens,
},
Expand All @@ -37,6 +38,11 @@ fn deinit(pragma: *Pragma, comp: *Compilation) void {
comp.gpa.destroy(self);
}

fn beforeInclude(pragma: *Pragma, _: *Preprocessor, source: Source) Pragma.BeforeIncludeError!void {
var self: *Once = @fieldParentPtr("pragma", pragma);
if (self.pragma_once.contains(source.id)) return error.SkipInclude;
}

fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {
var self: *Once = @fieldParentPtr("pragma", pragma);
const name_tok = pp.tokens.get(start_idx);
Expand Down
2 changes: 2 additions & 0 deletions test/cases/include/pragma_once_not_at_start/a.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <b.h>
#include <c.h>
5 changes: 5 additions & 0 deletions test/cases/include/pragma_once_not_at_start/b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#define __B_INSIDE__

#include <c.h>

#undef __B_INSIDE__
5 changes: 5 additions & 0 deletions test/cases/include/pragma_once_not_at_start/c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#if !defined(__B_INSIDE__)
#error "expected test macros to be present"
#endif

#pragma once
6 changes: 6 additions & 0 deletions test/cases/pragma once not at start of file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <a.h> // include/pragma_once_not_at_start/a.h

/** manifest:
syntax
args = -I include/pragma_once_not_at_start
*/
Loading