Files
zig/deps/aro/pragmas/pack.zig
Veikka Tuominen 5792570197 add Aro sources as a dependency
ref: 5688dbccfb58216468267a0f46b96bed7013715a
2023-10-01 23:51:54 +03:00

165 lines
5.5 KiB
Zig
Vendored

const std = @import("std");
const mem = std.mem;
const Compilation = @import("../Compilation.zig");
const Pragma = @import("../Pragma.zig");
const Diagnostics = @import("../Diagnostics.zig");
const Preprocessor = @import("../Preprocessor.zig");
const Parser = @import("../Parser.zig");
const Tree = @import("../Tree.zig");
const TokenIndex = Tree.TokenIndex;
const Pack = @This();
pragma: Pragma = .{
.deinit = deinit,
.parserHandler = parserHandler,
.preserveTokens = preserveTokens,
},
stack: std.ArrayListUnmanaged(struct { label: []const u8, val: u8 }) = .{},
pub fn init(allocator: mem.Allocator) !*Pragma {
var pack = try allocator.create(Pack);
pack.* = .{};
return &pack.pragma;
}
fn deinit(pragma: *Pragma, comp: *Compilation) void {
var self = @fieldParentPtr(Pack, "pragma", pragma);
self.stack.deinit(comp.gpa);
comp.gpa.destroy(self);
}
fn parserHandler(pragma: *Pragma, p: *Parser, start_idx: TokenIndex) Compilation.Error!void {
var pack = @fieldParentPtr(Pack, "pragma", pragma);
var idx = start_idx + 1;
const l_paren = p.pp.tokens.get(idx);
if (l_paren.id != .l_paren) {
return p.pp.comp.diag.add(.{
.tag = .pragma_pack_lparen,
.loc = l_paren.loc,
}, l_paren.expansionSlice());
}
idx += 1;
// TODO -fapple-pragma-pack -fxl-pragma-pack
const apple_or_xl = false;
const tok_ids = p.pp.tokens.items(.id);
const arg = idx;
switch (tok_ids[arg]) {
.identifier => {
idx += 1;
const Action = enum {
show,
push,
pop,
};
const action = std.meta.stringToEnum(Action, p.tokSlice(arg)) orelse {
return p.errTok(.pragma_pack_unknown_action, arg);
};
switch (action) {
.show => {
try p.errExtra(.pragma_pack_show, arg, .{ .unsigned = p.pragma_pack orelse 8 });
},
.push, .pop => {
var new_val: ?u8 = null;
var label: ?[]const u8 = null;
if (tok_ids[idx] == .comma) {
idx += 1;
const next = idx;
idx += 1;
switch (tok_ids[next]) {
.pp_num => new_val = (try packInt(p, next)) orelse return,
.identifier => {
label = p.tokSlice(next);
if (tok_ids[idx] == .comma) {
idx += 1;
const int = idx;
idx += 1;
if (tok_ids[int] != .pp_num) return p.errTok(.pragma_pack_int_ident, int);
new_val = (try packInt(p, int)) orelse return;
}
},
else => return p.errTok(.pragma_pack_int_ident, next),
}
}
if (action == .push) {
try pack.stack.append(p.pp.comp.gpa, .{ .label = label orelse "", .val = p.pragma_pack orelse 8 });
} else {
pack.pop(p, label);
if (new_val != null) {
try p.errTok(.pragma_pack_undefined_pop, arg);
} else if (pack.stack.items.len == 0) {
try p.errTok(.pragma_pack_empty_stack, arg);
}
}
if (new_val) |some| {
p.pragma_pack = some;
}
},
}
},
.r_paren => if (apple_or_xl) {
pack.pop(p, null);
} else {
p.pragma_pack = null;
},
.pp_num => {
const new_val = (try packInt(p, arg)) orelse return;
idx += 1;
if (apple_or_xl) {
try pack.stack.append(p.pp.comp.gpa, .{ .label = "", .val = p.pragma_pack });
}
p.pragma_pack = new_val;
},
else => {},
}
if (tok_ids[idx] != .r_paren) {
return p.errTok(.pragma_pack_rparen, idx);
}
}
fn packInt(p: *Parser, tok_i: TokenIndex) Compilation.Error!?u8 {
const res = p.parseNumberToken(tok_i) catch |err| switch (err) {
error.ParsingFailed => {
try p.errTok(.pragma_pack_int, tok_i);
return null;
},
else => |e| return e,
};
const int = if (res.val.tag == .int) res.val.getInt(u64) else 99;
switch (int) {
1, 2, 4, 8, 16 => return @intCast(int),
else => {
try p.errTok(.pragma_pack_int, tok_i);
return null;
},
}
}
fn pop(pack: *Pack, p: *Parser, maybe_label: ?[]const u8) void {
if (maybe_label) |label| {
var i = pack.stack.items.len;
while (i > 0) {
i -= 1;
if (std.mem.eql(u8, pack.stack.items[i].label, label)) {
const prev = pack.stack.orderedRemove(i);
p.pragma_pack = prev.val;
return;
}
}
} else {
const prev = pack.stack.popOrNull() orelse {
p.pragma_pack = 2;
return;
};
p.pragma_pack = prev.val;
}
}
fn preserveTokens(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) bool {
_ = pp;
_ = start_idx;
return true;
}