astgen: handle extern variables and full declaration layout
Rewrite globalVarDecl to properly handle extern/export/pub/threadlocal variables with type/align/linksection/addrspace bodies. Port the full Declaration extra data layout from upstream AstGen.zig:13883, including lib_name, type_body, and special bodies fields. Add extractVarDecl to decode all VarDecl node types (global, local, simple, aligned) and computeVarDeclId to select the correct Declaration.Flags.Id. Fix firstToken to scan backwards for modifier tokens (extern, export, pub, threadlocal, comptime) on var decl nodes, matching upstream Ast.zig:634-643. Test added: extern var. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
507
astgen.c
507
astgen.c
@@ -552,6 +552,37 @@ static uint32_t firstToken(const Ast* tree, uint32_t node) {
|
||||
case AST_NODE_ARRAY_ACCESS:
|
||||
n = tree->nodes.datas[n].lhs;
|
||||
continue;
|
||||
// Var decls: scan backwards for modifiers (Ast.zig:634-643).
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
case AST_NODE_SIMPLE_VAR_DECL:
|
||||
case AST_NODE_ALIGNED_VAR_DECL: {
|
||||
uint32_t mt = tree->nodes.main_tokens[n];
|
||||
uint32_t i = mt;
|
||||
while (i > 0) {
|
||||
TokenizerTag tt = tree->tokens.tags[i - 1];
|
||||
if (tt == TOKEN_KEYWORD_EXTERN || tt == TOKEN_KEYWORD_EXPORT
|
||||
|| tt == TOKEN_KEYWORD_PUB
|
||||
|| tt == TOKEN_KEYWORD_THREADLOCAL
|
||||
|| tt == TOKEN_KEYWORD_COMPTIME
|
||||
|| tt == TOKEN_STRING_LITERAL) {
|
||||
i--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
// Container fields: check for preceding comptime (Ast.zig:646-648).
|
||||
case AST_NODE_CONTAINER_FIELD_INIT:
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
case AST_NODE_CONTAINER_FIELD: {
|
||||
uint32_t mt = tree->nodes.main_tokens[n];
|
||||
if (mt > 0
|
||||
&& tree->tokens.tags[mt - 1] == TOKEN_KEYWORD_COMPTIME)
|
||||
return mt - 1;
|
||||
return mt;
|
||||
}
|
||||
// Everything else: main_token (Ast.zig:602-643).
|
||||
default:
|
||||
return tree->nodes.main_tokens[n];
|
||||
@@ -890,6 +921,38 @@ static bool declIdHasName(DeclFlagsId id) {
|
||||
return id != DECL_ID_UNNAMED_TEST && id != DECL_ID_COMPTIME;
|
||||
}
|
||||
|
||||
// Does this Declaration.Flags.Id have a lib name? (Zir.zig:2771)
|
||||
static bool declIdHasLibName(DeclFlagsId id) {
|
||||
switch (id) {
|
||||
case DECL_ID_EXTERN_CONST:
|
||||
case DECL_ID_PUB_EXTERN_CONST:
|
||||
case DECL_ID_EXTERN_VAR:
|
||||
case DECL_ID_EXTERN_VAR_THREADLOCAL:
|
||||
case DECL_ID_PUB_EXTERN_VAR:
|
||||
case DECL_ID_PUB_EXTERN_VAR_THREADLOCAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Does this Declaration.Flags.Id have a type body? (Zir.zig:2783)
|
||||
static bool declIdHasTypeBody(DeclFlagsId id) {
|
||||
switch (id) {
|
||||
case DECL_ID_UNNAMED_TEST:
|
||||
case DECL_ID_TEST:
|
||||
case DECL_ID_DECLTEST:
|
||||
case DECL_ID_COMPTIME:
|
||||
case DECL_ID_CONST_SIMPLE:
|
||||
case DECL_ID_PUB_CONST_SIMPLE:
|
||||
case DECL_ID_VAR_SIMPLE:
|
||||
case DECL_ID_PUB_VAR_SIMPLE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Does this Declaration.Flags.Id have a value body? (Zir.zig:2800)
|
||||
static bool declIdHasValueBody(DeclFlagsId id) {
|
||||
switch (id) {
|
||||
@@ -907,20 +970,79 @@ static bool declIdHasValueBody(DeclFlagsId id) {
|
||||
}
|
||||
}
|
||||
|
||||
// Mirrors setDeclaration (AstGen.zig:13883).
|
||||
// Simplified: no type/align/linksection/addrspace bodies.
|
||||
static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst,
|
||||
uint32_t src_line, uint32_t src_column, DeclFlagsId id,
|
||||
uint32_t name_string_index, const uint32_t* value_body,
|
||||
uint32_t value_body_len) {
|
||||
bool has_name = declIdHasName(id);
|
||||
bool has_value_body = declIdHasValueBody(id);
|
||||
// Does this Declaration.Flags.Id have special bodies? (Zir.zig:2815)
|
||||
static bool declIdHasSpecialBodies(DeclFlagsId id) {
|
||||
switch (id) {
|
||||
case DECL_ID_UNNAMED_TEST:
|
||||
case DECL_ID_TEST:
|
||||
case DECL_ID_DECLTEST:
|
||||
case DECL_ID_COMPTIME:
|
||||
case DECL_ID_CONST_SIMPLE:
|
||||
case DECL_ID_CONST_TYPED:
|
||||
case DECL_ID_PUB_CONST_SIMPLE:
|
||||
case DECL_ID_PUB_CONST_TYPED:
|
||||
case DECL_ID_EXTERN_CONST_SIMPLE:
|
||||
case DECL_ID_PUB_EXTERN_CONST_SIMPLE:
|
||||
case DECL_ID_VAR_SIMPLE:
|
||||
case DECL_ID_PUB_VAR_SIMPLE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t need = 6; // Declaration struct: src_hash[4] + flags[2]
|
||||
// Mirrors setDeclaration (AstGen.zig:13883).
|
||||
// Full version with type/align/linksection/addrspace/value bodies.
|
||||
typedef struct {
|
||||
uint32_t src_line;
|
||||
uint32_t src_column;
|
||||
DeclFlagsId id;
|
||||
uint32_t name; // NullTerminatedString index
|
||||
uint32_t lib_name; // NullTerminatedString index (UINT32_MAX=none)
|
||||
const uint32_t* type_body;
|
||||
uint32_t type_body_len;
|
||||
const uint32_t* align_body;
|
||||
uint32_t align_body_len;
|
||||
const uint32_t* linksection_body;
|
||||
uint32_t linksection_body_len;
|
||||
const uint32_t* addrspace_body;
|
||||
uint32_t addrspace_body_len;
|
||||
const uint32_t* value_body;
|
||||
uint32_t value_body_len;
|
||||
} SetDeclArgs;
|
||||
|
||||
static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst,
|
||||
SetDeclArgs args) {
|
||||
DeclFlagsId id = args.id;
|
||||
bool has_name = declIdHasName(id);
|
||||
bool has_lib_name = declIdHasLibName(id);
|
||||
bool has_type_body_field = declIdHasTypeBody(id);
|
||||
bool has_special_bodies = declIdHasSpecialBodies(id);
|
||||
bool has_value_body_field = declIdHasValueBody(id);
|
||||
|
||||
uint32_t type_len
|
||||
= countBodyLenAfterFixups(ag, args.type_body, args.type_body_len);
|
||||
uint32_t align_len
|
||||
= countBodyLenAfterFixups(ag, args.align_body, args.align_body_len);
|
||||
uint32_t linksection_len = countBodyLenAfterFixups(
|
||||
ag, args.linksection_body, args.linksection_body_len);
|
||||
uint32_t addrspace_len = countBodyLenAfterFixups(
|
||||
ag, args.addrspace_body, args.addrspace_body_len);
|
||||
uint32_t value_len
|
||||
= countBodyLenAfterFixups(ag, args.value_body, args.value_body_len);
|
||||
|
||||
uint32_t need = 6; // src_hash[4] + flags[2]
|
||||
if (has_name)
|
||||
need++;
|
||||
if (has_value_body)
|
||||
need += 1 + value_body_len;
|
||||
if (has_lib_name)
|
||||
need++;
|
||||
if (has_type_body_field)
|
||||
need++;
|
||||
if (has_special_bodies)
|
||||
need += 3;
|
||||
if (has_value_body_field)
|
||||
need++;
|
||||
need += type_len + align_len + linksection_len + addrspace_len + value_len;
|
||||
ensureExtraCapacity(ag, need);
|
||||
|
||||
uint32_t payload_start = ag->extra_len;
|
||||
@@ -934,24 +1056,39 @@ static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst,
|
||||
// Declaration.Flags: packed struct(u64) { src_line: u30, src_column: u29,
|
||||
// id: u5 } (Zir.zig:2719)
|
||||
uint64_t flags = 0;
|
||||
flags |= (uint64_t)(src_line & 0x3FFFFFFFu);
|
||||
flags |= (uint64_t)(src_column & 0x1FFFFFFFu) << 30;
|
||||
flags |= (uint64_t)(args.src_line & 0x3FFFFFFFu);
|
||||
flags |= (uint64_t)(args.src_column & 0x1FFFFFFFu) << 30;
|
||||
flags |= (uint64_t)((uint32_t)id & 0x1Fu) << 59;
|
||||
ag->extra[ag->extra_len++] = (uint32_t)(flags & 0xFFFFFFFFu);
|
||||
ag->extra[ag->extra_len++] = (uint32_t)(flags >> 32);
|
||||
|
||||
if (has_name) {
|
||||
ag->extra[ag->extra_len++] = name_string_index;
|
||||
if (has_name)
|
||||
ag->extra[ag->extra_len++] = args.name;
|
||||
if (has_lib_name) {
|
||||
ag->extra[ag->extra_len++]
|
||||
= (args.lib_name != UINT32_MAX) ? args.lib_name : 0;
|
||||
}
|
||||
|
||||
if (has_value_body) {
|
||||
ag->extra[ag->extra_len++] = value_body_len;
|
||||
for (uint32_t i = 0; i < value_body_len; i++) {
|
||||
ag->extra[ag->extra_len++] = value_body[i];
|
||||
}
|
||||
if (has_type_body_field)
|
||||
ag->extra[ag->extra_len++] = type_len;
|
||||
if (has_special_bodies) {
|
||||
ag->extra[ag->extra_len++] = align_len;
|
||||
ag->extra[ag->extra_len++] = linksection_len;
|
||||
ag->extra[ag->extra_len++] = addrspace_len;
|
||||
}
|
||||
if (has_value_body_field)
|
||||
ag->extra[ag->extra_len++] = value_len;
|
||||
|
||||
for (uint32_t i = 0; i < args.type_body_len; i++)
|
||||
appendPossiblyRefdBodyInst(ag, args.type_body[i]);
|
||||
for (uint32_t i = 0; i < args.align_body_len; i++)
|
||||
appendPossiblyRefdBodyInst(ag, args.align_body[i]);
|
||||
for (uint32_t i = 0; i < args.linksection_body_len; i++)
|
||||
appendPossiblyRefdBodyInst(ag, args.linksection_body[i]);
|
||||
for (uint32_t i = 0; i < args.addrspace_body_len; i++)
|
||||
appendPossiblyRefdBodyInst(ag, args.addrspace_body[i]);
|
||||
for (uint32_t i = 0; i < args.value_body_len; i++)
|
||||
appendPossiblyRefdBodyInst(ag, args.value_body[i]);
|
||||
|
||||
// Set the declaration instruction's payload_index.
|
||||
ag->inst_datas[decl_inst].declaration.payload_index = payload_start;
|
||||
}
|
||||
|
||||
@@ -6673,8 +6810,11 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
makeBreakInline(&decl_block, decl_inst, func_ref, AST_NODE_OFFSET_NONE);
|
||||
|
||||
// setDeclaration (AstGen.zig:4903-4923).
|
||||
setDeclaration(ag, decl_inst, decl_line, decl_column, decl_id, test_name,
|
||||
gzInstructionsSlice(&decl_block), gzInstructionsLen(&decl_block));
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = decl_id, .name = test_name, .lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&decl_block),
|
||||
.value_body_len = gzInstructionsLen(&decl_block) });
|
||||
gzUnstack(&decl_block);
|
||||
|
||||
(void)gz;
|
||||
@@ -7037,8 +7177,11 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
DeclFlagsId decl_id
|
||||
= is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE;
|
||||
uint32_t name_str = identAsString(ag, fn_name_token);
|
||||
setDeclaration(ag, decl_inst, decl_line, decl_column, decl_id, name_str,
|
||||
gzInstructionsSlice(&decl_gz), gzInstructionsLen(&decl_gz));
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = decl_id, .name = name_str, .lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&decl_gz),
|
||||
.value_body_len = gzInstructionsLen(&decl_gz) });
|
||||
gzUnstack(&decl_gz);
|
||||
|
||||
(void)gz;
|
||||
@@ -7075,8 +7218,11 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
makeBreakInline(
|
||||
&value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
|
||||
|
||||
setDeclaration(ag, decl_inst, decl_line, decl_column, DECL_ID_COMPTIME, 0,
|
||||
gzInstructionsSlice(&value_gz), gzInstructionsLen(&value_gz));
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line, .src_column = decl_column,
|
||||
.id = DECL_ID_COMPTIME, .name = 0, .lib_name = UINT32_MAX,
|
||||
.value_body = gzInstructionsSlice(&value_gz),
|
||||
.value_body_len = gzInstructionsLen(&value_gz) });
|
||||
gzUnstack(&value_gz);
|
||||
|
||||
(void)gz;
|
||||
@@ -7084,10 +7230,158 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
|
||||
// --- globalVarDecl (AstGen.zig:4498) ---
|
||||
|
||||
// Extract VarDecl fields from an AST node (Ast.zig:1326-1380).
|
||||
typedef struct {
|
||||
uint32_t mut_token;
|
||||
uint32_t type_node; // 0 = none
|
||||
uint32_t align_node; // 0 = none
|
||||
uint32_t addrspace_node; // 0 = none
|
||||
uint32_t section_node; // 0 = none
|
||||
uint32_t init_node; // UINT32_MAX = none
|
||||
bool is_pub;
|
||||
bool is_extern;
|
||||
bool is_export;
|
||||
bool is_mutable;
|
||||
bool is_threadlocal;
|
||||
uint32_t lib_name_token; // UINT32_MAX = none
|
||||
} VarDeclInfo;
|
||||
|
||||
static VarDeclInfo extractVarDecl(const Ast* tree, uint32_t node) {
|
||||
AstNodeTag tag = tree->nodes.tags[node];
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
uint32_t mut_token = tree->nodes.main_tokens[node];
|
||||
VarDeclInfo info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.mut_token = mut_token;
|
||||
info.init_node = UINT32_MAX;
|
||||
info.lib_name_token = UINT32_MAX;
|
||||
|
||||
switch (tag) {
|
||||
case AST_NODE_SIMPLE_VAR_DECL:
|
||||
// lhs = type_node (optional), rhs = init_node (optional)
|
||||
info.type_node = nd.lhs;
|
||||
info.init_node = nd.rhs;
|
||||
break;
|
||||
case AST_NODE_ALIGNED_VAR_DECL:
|
||||
// lhs = align_node, rhs = init_node (optional)
|
||||
info.align_node = nd.lhs;
|
||||
info.init_node = nd.rhs;
|
||||
break;
|
||||
case AST_NODE_GLOBAL_VAR_DECL: {
|
||||
// lhs = extra_data index, rhs = init_node (optional)
|
||||
uint32_t ei = nd.lhs;
|
||||
info.type_node = tree->extra_data.arr[ei + 0];
|
||||
info.align_node = tree->extra_data.arr[ei + 1];
|
||||
info.addrspace_node = tree->extra_data.arr[ei + 2];
|
||||
info.section_node = tree->extra_data.arr[ei + 3];
|
||||
info.init_node = nd.rhs;
|
||||
break;
|
||||
}
|
||||
case AST_NODE_LOCAL_VAR_DECL: {
|
||||
// lhs = extra_data index, rhs = init_node (optional)
|
||||
uint32_t ei = nd.lhs;
|
||||
info.type_node = tree->extra_data.arr[ei + 0];
|
||||
info.align_node = tree->extra_data.arr[ei + 1];
|
||||
info.init_node = nd.rhs;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Scan backwards from mut_token to find modifiers (Ast.zig:2003-2025).
|
||||
info.is_mutable
|
||||
= (tree->tokens.tags[mut_token] == TOKEN_KEYWORD_VAR);
|
||||
for (uint32_t i = mut_token; i > 0;) {
|
||||
i--;
|
||||
TokenizerTag ttag = tree->tokens.tags[i];
|
||||
if (ttag == TOKEN_KEYWORD_EXTERN)
|
||||
info.is_extern = true;
|
||||
else if (ttag == TOKEN_KEYWORD_EXPORT)
|
||||
info.is_export = true;
|
||||
else if (ttag == TOKEN_KEYWORD_PUB)
|
||||
info.is_pub = true;
|
||||
else if (ttag == TOKEN_KEYWORD_THREADLOCAL)
|
||||
info.is_threadlocal = true;
|
||||
else if (ttag == TOKEN_STRING_LITERAL)
|
||||
info.lib_name_token = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// Compute DeclFlagsId from VarDecl properties (AstGen.zig:13916-13972).
|
||||
static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub,
|
||||
bool is_extern, bool is_export, bool is_threadlocal, bool has_type_body,
|
||||
bool has_special_body, bool has_lib_name) {
|
||||
if (!is_mutable) {
|
||||
// const
|
||||
if (is_extern) {
|
||||
if (is_pub) {
|
||||
if (has_lib_name || has_special_body)
|
||||
return DECL_ID_PUB_EXTERN_CONST;
|
||||
return DECL_ID_PUB_EXTERN_CONST_SIMPLE;
|
||||
}
|
||||
if (has_lib_name || has_special_body)
|
||||
return DECL_ID_EXTERN_CONST;
|
||||
return DECL_ID_EXTERN_CONST_SIMPLE;
|
||||
}
|
||||
if (is_export)
|
||||
return is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST;
|
||||
if (is_pub) {
|
||||
if (has_special_body)
|
||||
return DECL_ID_PUB_CONST;
|
||||
if (has_type_body)
|
||||
return DECL_ID_PUB_CONST_TYPED;
|
||||
return DECL_ID_PUB_CONST_SIMPLE;
|
||||
}
|
||||
if (has_special_body)
|
||||
return DECL_ID_CONST;
|
||||
if (has_type_body)
|
||||
return DECL_ID_CONST_TYPED;
|
||||
return DECL_ID_CONST_SIMPLE;
|
||||
}
|
||||
// var
|
||||
if (is_extern) {
|
||||
if (is_pub) {
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_PUB_EXTERN_VAR_THREADLOCAL;
|
||||
return DECL_ID_PUB_EXTERN_VAR;
|
||||
}
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_EXTERN_VAR_THREADLOCAL;
|
||||
return DECL_ID_EXTERN_VAR;
|
||||
}
|
||||
if (is_export) {
|
||||
if (is_pub) {
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_PUB_EXPORT_VAR_THREADLOCAL;
|
||||
return DECL_ID_PUB_EXPORT_VAR;
|
||||
}
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_EXPORT_VAR_THREADLOCAL;
|
||||
return DECL_ID_EXPORT_VAR;
|
||||
}
|
||||
if (is_pub) {
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_PUB_VAR_THREADLOCAL;
|
||||
if (has_special_body || has_type_body)
|
||||
return DECL_ID_PUB_VAR;
|
||||
return DECL_ID_PUB_VAR_SIMPLE;
|
||||
}
|
||||
if (is_threadlocal)
|
||||
return DECL_ID_VAR_THREADLOCAL;
|
||||
if (has_special_body || has_type_body)
|
||||
return DECL_ID_VAR;
|
||||
return DECL_ID_VAR_SIMPLE;
|
||||
}
|
||||
|
||||
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
uint32_t mut_token = ag->tree->nodes.main_tokens[node];
|
||||
uint32_t name_token = mut_token + 1;
|
||||
const Ast* tree = ag->tree;
|
||||
VarDeclInfo vd = extractVarDecl(tree, node);
|
||||
uint32_t name_token = vd.mut_token + 1;
|
||||
|
||||
// advanceSourceCursorToNode before makeDeclaration (AstGen.zig:4542-4546).
|
||||
advanceSourceCursorToNode(ag, node);
|
||||
@@ -7097,42 +7391,135 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
wip_decl_insts[*decl_idx] = decl_inst;
|
||||
(*decl_idx)++;
|
||||
|
||||
// Set up init sub-block (AstGen.zig:4610).
|
||||
GenZir init_gz;
|
||||
memset(&init_gz, 0, sizeof(init_gz));
|
||||
init_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
init_gz.parent = NULL;
|
||||
init_gz.astgen = ag;
|
||||
init_gz.decl_node_index = node;
|
||||
init_gz.instructions_top = ag->scratch_inst_len;
|
||||
init_gz.decl_line = ag->source_line;
|
||||
init_gz.is_comptime = true;
|
||||
// Set up type sub-block (AstGen.zig:4574-4582).
|
||||
GenZir type_gz;
|
||||
memset(&type_gz, 0, sizeof(type_gz));
|
||||
type_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
type_gz.astgen = ag;
|
||||
type_gz.decl_node_index = node;
|
||||
type_gz.instructions_top = ag->scratch_inst_len;
|
||||
type_gz.decl_line = ag->source_line;
|
||||
type_gz.is_comptime = true;
|
||||
|
||||
// Evaluate init expression.
|
||||
// For simple_var_decl: data.rhs = init_node (optional).
|
||||
AstData data = ag->tree->nodes.datas[node];
|
||||
uint32_t init_node = data.rhs;
|
||||
uint32_t init_ref;
|
||||
|
||||
if (init_node != UINT32_MAX) {
|
||||
init_ref = expr(&init_gz, &init_gz.base, init_node);
|
||||
} else {
|
||||
// extern variable: no init. Not handled yet.
|
||||
SET_ERROR(ag);
|
||||
init_ref = ZIR_REF_VOID_VALUE;
|
||||
if (vd.type_node != 0) {
|
||||
uint32_t type_inst = typeExpr(&type_gz, &type_gz.base, vd.type_node);
|
||||
makeBreakInline(&type_gz, decl_inst, type_inst, 0);
|
||||
}
|
||||
|
||||
// addBreakWithSrcNode(.break_inline, decl_inst, init_inst, node)
|
||||
// nodeIndexToRelative: decl_node_index == node, so offset = 0.
|
||||
// (AstGen.zig:4620)
|
||||
makeBreakInline(&init_gz, decl_inst, init_ref, 0);
|
||||
// Record type_gz boundary for slicing.
|
||||
uint32_t type_top = ag->scratch_inst_len;
|
||||
|
||||
// Align sub-block (AstGen.zig:4592-4596).
|
||||
GenZir align_gz;
|
||||
memset(&align_gz, 0, sizeof(align_gz));
|
||||
align_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
align_gz.astgen = ag;
|
||||
align_gz.decl_node_index = node;
|
||||
align_gz.instructions_top = type_top;
|
||||
align_gz.decl_line = ag->source_line;
|
||||
align_gz.is_comptime = true;
|
||||
|
||||
if (vd.align_node != 0) {
|
||||
uint32_t align_inst
|
||||
= expr(&align_gz, &align_gz.base, vd.align_node);
|
||||
makeBreakInline(&align_gz, decl_inst, align_inst, 0);
|
||||
}
|
||||
|
||||
uint32_t align_top = ag->scratch_inst_len;
|
||||
|
||||
// Linksection sub-block (AstGen.zig:4598-4602).
|
||||
GenZir linksection_gz;
|
||||
memset(&linksection_gz, 0, sizeof(linksection_gz));
|
||||
linksection_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
linksection_gz.astgen = ag;
|
||||
linksection_gz.decl_node_index = node;
|
||||
linksection_gz.instructions_top = align_top;
|
||||
linksection_gz.decl_line = ag->source_line;
|
||||
linksection_gz.is_comptime = true;
|
||||
|
||||
if (vd.section_node != 0) {
|
||||
uint32_t ls_inst
|
||||
= expr(&linksection_gz, &linksection_gz.base, vd.section_node);
|
||||
makeBreakInline(&linksection_gz, decl_inst, ls_inst, 0);
|
||||
}
|
||||
|
||||
uint32_t linksection_top = ag->scratch_inst_len;
|
||||
|
||||
// Addrspace sub-block (AstGen.zig:4604-4608).
|
||||
GenZir addrspace_gz;
|
||||
memset(&addrspace_gz, 0, sizeof(addrspace_gz));
|
||||
addrspace_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
addrspace_gz.astgen = ag;
|
||||
addrspace_gz.decl_node_index = node;
|
||||
addrspace_gz.instructions_top = linksection_top;
|
||||
addrspace_gz.decl_line = ag->source_line;
|
||||
addrspace_gz.is_comptime = true;
|
||||
|
||||
if (vd.addrspace_node != 0) {
|
||||
uint32_t as_inst
|
||||
= expr(&addrspace_gz, &addrspace_gz.base, vd.addrspace_node);
|
||||
makeBreakInline(&addrspace_gz, decl_inst, as_inst, 0);
|
||||
}
|
||||
|
||||
uint32_t addrspace_top = ag->scratch_inst_len;
|
||||
|
||||
// Value sub-block (AstGen.zig:4610-4620).
|
||||
GenZir value_gz;
|
||||
memset(&value_gz, 0, sizeof(value_gz));
|
||||
value_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
value_gz.astgen = ag;
|
||||
value_gz.decl_node_index = node;
|
||||
value_gz.instructions_top = addrspace_top;
|
||||
value_gz.decl_line = ag->source_line;
|
||||
value_gz.is_comptime = true;
|
||||
|
||||
if (vd.init_node != UINT32_MAX && vd.init_node != 0) {
|
||||
uint32_t init_ref = expr(&value_gz, &value_gz.base, vd.init_node);
|
||||
makeBreakInline(&value_gz, decl_inst, init_ref, 0);
|
||||
}
|
||||
|
||||
// Compute body slices (instructionsSliceUpto).
|
||||
const uint32_t* type_body = ag->scratch_instructions + type_gz.instructions_top;
|
||||
uint32_t type_body_len = type_top - type_gz.instructions_top;
|
||||
const uint32_t* align_body = ag->scratch_instructions + align_gz.instructions_top;
|
||||
uint32_t align_body_len = align_top - align_gz.instructions_top;
|
||||
const uint32_t* ls_body = ag->scratch_instructions + linksection_gz.instructions_top;
|
||||
uint32_t ls_body_len = linksection_top - linksection_gz.instructions_top;
|
||||
const uint32_t* as_body = ag->scratch_instructions + addrspace_gz.instructions_top;
|
||||
uint32_t as_body_len = addrspace_top - addrspace_gz.instructions_top;
|
||||
const uint32_t* val_body = gzInstructionsSlice(&value_gz);
|
||||
uint32_t val_body_len = gzInstructionsLen(&value_gz);
|
||||
|
||||
bool has_type_body = (type_body_len > 0);
|
||||
bool has_special_body
|
||||
= (align_body_len > 0 || ls_body_len > 0 || as_body_len > 0);
|
||||
bool has_lib_name = (vd.lib_name_token != UINT32_MAX);
|
||||
|
||||
uint32_t name_str = identAsString(ag, name_token);
|
||||
|
||||
setDeclaration(ag, decl_inst, ag->source_line, decl_column,
|
||||
DECL_ID_CONST_SIMPLE, name_str, gzInstructionsSlice(&init_gz),
|
||||
gzInstructionsLen(&init_gz));
|
||||
gzUnstack(&init_gz);
|
||||
DeclFlagsId decl_id = computeVarDeclId(vd.is_mutable, vd.is_pub,
|
||||
vd.is_extern, vd.is_export, vd.is_threadlocal, has_type_body,
|
||||
has_special_body, has_lib_name);
|
||||
|
||||
// Compute lib_name string index.
|
||||
uint32_t lib_name = UINT32_MAX;
|
||||
if (has_lib_name) {
|
||||
uint32_t li, ll;
|
||||
strLitAsString(ag, vd.lib_name_token, &li, &ll);
|
||||
lib_name = li;
|
||||
}
|
||||
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = ag->source_line,
|
||||
.src_column = decl_column, .id = decl_id, .name = name_str,
|
||||
.lib_name = lib_name, .type_body = type_body,
|
||||
.type_body_len = type_body_len, .align_body = align_body,
|
||||
.align_body_len = align_body_len, .linksection_body = ls_body,
|
||||
.linksection_body_len = ls_body_len, .addrspace_body = as_body,
|
||||
.addrspace_body_len = as_body_len, .value_body = val_body,
|
||||
.value_body_len = val_body_len });
|
||||
|
||||
gzUnstack(&value_gz);
|
||||
|
||||
(void)gz;
|
||||
}
|
||||
|
||||
@@ -934,6 +934,18 @@ test "astgen: error set with members" {
|
||||
try expectEqualZir(gpa, ref_zir, c_zir);
|
||||
}
|
||||
|
||||
test "astgen: extern var" {
|
||||
const gpa = std.testing.allocator;
|
||||
const source: [:0]const u8 = "extern var x: u32;";
|
||||
var ref_zir = try refZir(gpa, source);
|
||||
defer ref_zir.deinit(gpa);
|
||||
var c_ast = c.astParse(source.ptr, @intCast(source.len));
|
||||
defer c.astDeinit(&c_ast);
|
||||
var c_zir = c.astGen(&c_ast);
|
||||
defer c.zirDeinit(&c_zir);
|
||||
try expectEqualZir(gpa, ref_zir, c_zir);
|
||||
}
|
||||
|
||||
test "astgen: corpus test_all.zig" {
|
||||
const gpa = std.testing.allocator;
|
||||
try corpusCheck(gpa, "test_all.zig", @embedFile("test_all.zig"));
|
||||
|
||||
Reference in New Issue
Block a user