feature. See also
. The project being documented here (as the example) is the Zig library itself.
AstGen.globalVarDecl
fn globalVarDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
wip_decls: *WipDecls,
node: Ast.Node.Index,
var_decl: Ast.full.VarDecl,
) InnerError!void
File
Code
fn globalVarDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
wip_decls: *WipDecls,
node: Ast.Node.Index,
var_decl: Ast.full.VarDecl,
) InnerError!void {
const tree = astgen.tree;
const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher;
astgen.src_hasher = std.zig.SrcHasher.init(.{});
astgen.src_hasher.update(tree.getNodeSource(node));
astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
const is_mutable = tree.tokenTag(var_decl.ast.mut_token) == .keyword_var;
const name_token = var_decl.ast.mut_token + 1;
const is_pub = var_decl.visib_token != null;
const is_export = blk: {
const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
break :blk tree.tokenTag(maybe_export_token) == .keyword_export;
};
const is_extern = blk: {
const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
break :blk tree.tokenTag(maybe_extern_token) == .keyword_extern;
};
const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
if (!is_mutable) {
return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
}
break :blk true;
} else false;
const lib_name = if (var_decl.lib_name) |lib_name_token| blk: {
const lib_name_str = try astgen.strLitAsString(lib_name_token);
const lib_name_slice = astgen.string_bytes.items[@backingInt(lib_name_str.index)..][0..lib_name_str.len];
if (mem.findScalar(u8, lib_name_slice, 0) != null) {
return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{});
} else if (lib_name_str.len == 0) {
return astgen.failTok(lib_name_token, "library name cannot be empty", .{});
}
break :blk lib_name_str.index;
} else .empty;
astgen.advanceSourceCursorToNode(node);
const decl_column = astgen.source_column;
const decl_inst = try gz.makeDeclaration(node);
wip_decls.nextDecl(decl_inst);
if (var_decl.ast.init_node.unwrap()) |init_node| {
if (is_extern) {
return astgen.failNode(
init_node,
"extern variables have no initializers",
.{},
);
}
} else {
if (!is_extern) {
return astgen.failNode(node, "variables must be initialized", .{});
}
}
if (is_extern and var_decl.ast.type_node == .none) {
return astgen.failNode(node, "unable to infer variable type", .{});
}
assert(var_decl.comptime_token == null);
var type_gz: GenZir = .{
.parent = scope,
.decl_node_index = node,
.decl_line = astgen.source_line,
.astgen = astgen,
.is_comptime = true,
.instructions = gz.instructions,
.instructions_top = gz.instructions.items.len,
};
defer type_gz.unstack();
if (var_decl.ast.type_node.unwrap()) |type_node| {
const type_inst = try expr(&type_gz, &type_gz.base, coerced_type_ri, type_node);
_ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, node);
}
var align_gz = type_gz.makeSubBlock(scope);
defer align_gz.unstack();
if (var_decl.ast.align_node.unwrap()) |align_node| {
const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, align_node);
_ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
}
var linksection_gz = type_gz.makeSubBlock(scope);
defer linksection_gz.unstack();
if (var_decl.ast.section_node.unwrap()) |section_node| {
const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_node);
_ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
}
var addrspace_gz = type_gz.makeSubBlock(scope);
defer addrspace_gz.unstack();
if (var_decl.ast.addrspace_node.unwrap()) |addrspace_node| {
const addrspace_ty = try addrspace_gz.addStdLangValue(addrspace_node, .address_space);
const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, addrspace_node);
_ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
}
var init_gz = type_gz.makeSubBlock(scope);
defer init_gz.unstack();
if (var_decl.ast.init_node.unwrap()) |init_node| {
const init_ri: ResultInfo = if (var_decl.ast.type_node != .none) .{
.rl = .{ .coerced_ty = decl_inst.toRef() },
} else .{ .rl = .none };
const init_inst: Zir.Inst.Ref = try nameStratExpr(&init_gz, &init_gz.base, init_ri, init_node, .parent) orelse init: {
break :init try expr(&init_gz, &init_gz.base, init_ri, init_node);
};
_ = try init_gz.addBreakWithSrcNode(.break_inline, decl_inst, init_inst, node);
}
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
try setDeclaration(decl_inst, .{
.src_hash = hash,
.src_line = type_gz.decl_line,
.src_column = decl_column,
.kind = if (is_mutable) .@"var" else .@"const",
.name = try astgen.identAsString(name_token),
.is_pub = is_pub,
.is_threadlocal = is_threadlocal,
.linkage = if (is_extern) .@"extern" else if (is_export) .@"export" else .normal,
.lib_name = lib_name,
.type_gz = &type_gz,
.align_gz = &align_gz,
.linksection_gz = &linksection_gz,
.addrspace_gz = &addrspace_gz,
.value_gz = &init_gz,
});
}