astgen: implement namespace scopes, identifier resolution across scope boundaries
Add ScopeNamespace struct with per-namespace declaration tables and capture storage, replacing the flat decl_table on AstGenCtx. Implement tunnelThroughClosure for cross-namespace captures (closure_get ZIR instruction). Modify identifierExpr to walk past namespace scopes, checking namespace decls and tracking num_namespaces_out for proper closure tunneling. Key changes: - ScopeNamespace with decl_names/decl_nodes, capture_keys/capture_vals - scanContainer populates per-namespace decls instead of flat table - structDeclInner/enumDeclInner create namespace scopes, write captures - globalVarDecl/fnDecl/testDecl/comptimeDecl receive scope parameter - localVarRef properly tunnels through namespace boundaries - scopeParent helper for generic scope chain walking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
574
stage0/astgen.c
574
stage0/astgen.c
@@ -79,12 +79,6 @@ typedef struct {
|
||||
ImportEntry* imports;
|
||||
uint32_t imports_len;
|
||||
uint32_t imports_cap;
|
||||
// Namespace decl table: maps string indices to node indices.
|
||||
// Populated by scanContainer, used by identifier resolution.
|
||||
uint32_t* decl_names; // string indices
|
||||
uint32_t* decl_nodes; // node indices
|
||||
uint32_t decl_table_len;
|
||||
uint32_t decl_table_cap;
|
||||
// Shared dynamic array for GenZir instructions (AstGen.zig:11796).
|
||||
// Sub-blocks share this array and track their slice via
|
||||
// instructions_top.
|
||||
@@ -304,6 +298,126 @@ typedef struct {
|
||||
uint32_t block_inst; // instruction index (not ref)
|
||||
} ScopeLabel;
|
||||
|
||||
// Scope.Namespace (AstGen.zig:11737-11762) — represents a type declaration
|
||||
// scope (struct, enum, union, opaque) that has declarations in it.
|
||||
typedef struct {
|
||||
Scope base; // tag = SCOPE_NAMESPACE
|
||||
Scope* parent;
|
||||
uint32_t node; // AST node of the container decl
|
||||
uint32_t inst; // instruction index of the container decl
|
||||
GenZir* declaring_gz; // the GenZir containing this namespace
|
||||
bool maybe_generic; // true if inside a function (astgen.within_fn)
|
||||
// Per-namespace declaration table (maps name string index → node index).
|
||||
uint32_t* decl_names;
|
||||
uint32_t* decl_nodes;
|
||||
uint32_t decl_len;
|
||||
uint32_t decl_cap;
|
||||
// Captures (populated by tunnelThroughClosure).
|
||||
// Keys are packed Capture u32 values, values are NullTerminatedString.
|
||||
uint32_t* capture_keys;
|
||||
uint32_t* capture_vals;
|
||||
uint32_t captures_len;
|
||||
uint32_t captures_cap;
|
||||
} ScopeNamespace;
|
||||
|
||||
// Initialize a ScopeNamespace on the stack.
|
||||
static void scopeNamespaceInit(ScopeNamespace* ns, Scope* parent,
|
||||
uint32_t node, uint32_t inst, GenZir* declaring_gz, bool maybe_generic) {
|
||||
memset(ns, 0, sizeof(*ns));
|
||||
ns->base.tag = SCOPE_NAMESPACE;
|
||||
ns->parent = parent;
|
||||
ns->node = node;
|
||||
ns->inst = inst;
|
||||
ns->declaring_gz = declaring_gz;
|
||||
ns->maybe_generic = maybe_generic;
|
||||
}
|
||||
|
||||
// Free dynamic arrays in a ScopeNamespace.
|
||||
static void scopeNamespaceDeinit(ScopeNamespace* ns) {
|
||||
free(ns->decl_names);
|
||||
free(ns->decl_nodes);
|
||||
free(ns->capture_keys);
|
||||
free(ns->capture_vals);
|
||||
}
|
||||
|
||||
// Add a declaration to a namespace's decl table.
|
||||
static void scopeNamespaceAddDecl(
|
||||
ScopeNamespace* ns, uint32_t name_str, uint32_t decl_node) {
|
||||
if (ns->decl_len >= ns->decl_cap) {
|
||||
uint32_t new_cap = ns->decl_cap > 0 ? ns->decl_cap * 2 : 8;
|
||||
uint32_t* n = realloc(ns->decl_names, new_cap * sizeof(uint32_t));
|
||||
uint32_t* d = realloc(ns->decl_nodes, new_cap * sizeof(uint32_t));
|
||||
if (!n || !d)
|
||||
exit(1);
|
||||
ns->decl_names = n;
|
||||
ns->decl_nodes = d;
|
||||
ns->decl_cap = new_cap;
|
||||
}
|
||||
ns->decl_names[ns->decl_len] = name_str;
|
||||
ns->decl_nodes[ns->decl_len] = decl_node;
|
||||
ns->decl_len++;
|
||||
}
|
||||
|
||||
// Look up a name in a namespace's decl table. Returns the node index,
|
||||
// or UINT32_MAX if not found.
|
||||
static uint32_t scopeNamespaceFindDecl(
|
||||
const ScopeNamespace* ns, uint32_t name_str) {
|
||||
for (uint32_t i = 0; i < ns->decl_len; i++) {
|
||||
if (ns->decl_names[i] == name_str)
|
||||
return ns->decl_nodes[i];
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
// Add a capture to a namespace. Returns the capture index (position).
|
||||
// If the capture already exists, returns the existing index.
|
||||
// key is a packed Capture u32 (3-bit tag | 29-bit data).
|
||||
static uint32_t scopeNamespaceAddCapture(
|
||||
ScopeNamespace* ns, uint32_t key, uint32_t name_str) {
|
||||
// Check for existing capture with same key.
|
||||
for (uint32_t i = 0; i < ns->captures_len; i++) {
|
||||
if (ns->capture_keys[i] == key)
|
||||
return i;
|
||||
}
|
||||
if (ns->captures_len >= ns->captures_cap) {
|
||||
uint32_t new_cap = ns->captures_cap > 0 ? ns->captures_cap * 2 : 4;
|
||||
uint32_t* k = realloc(ns->capture_keys, new_cap * sizeof(uint32_t));
|
||||
uint32_t* v = realloc(ns->capture_vals, new_cap * sizeof(uint32_t));
|
||||
if (!k || !v)
|
||||
exit(1);
|
||||
ns->capture_keys = k;
|
||||
ns->capture_vals = v;
|
||||
ns->captures_cap = new_cap;
|
||||
}
|
||||
uint32_t idx = ns->captures_len;
|
||||
ns->capture_keys[idx] = key;
|
||||
ns->capture_vals[idx] = name_str;
|
||||
ns->captures_len++;
|
||||
return idx;
|
||||
}
|
||||
|
||||
// Walk to a scope's parent. Returns NULL if there is no parent.
|
||||
static Scope* scopeParent(Scope* s) {
|
||||
switch (s->tag) {
|
||||
case SCOPE_GEN_ZIR:
|
||||
return ((GenZir*)s)->parent;
|
||||
case SCOPE_LOCAL_VAL:
|
||||
return ((ScopeLocalVal*)s)->parent;
|
||||
case SCOPE_LOCAL_PTR:
|
||||
return ((ScopeLocalPtr*)s)->parent;
|
||||
case SCOPE_DEFER_NORMAL:
|
||||
case SCOPE_DEFER_ERROR:
|
||||
return ((ScopeDefer*)s)->parent;
|
||||
case SCOPE_NAMESPACE:
|
||||
return ((ScopeNamespace*)s)->parent;
|
||||
case SCOPE_LABEL:
|
||||
return ((ScopeLabel*)s)->parent;
|
||||
case SCOPE_TOP:
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --- GenZir instruction helpers (AstGen.zig:11830-11850) ---
|
||||
|
||||
// Returns the number of instructions in this scope.
|
||||
@@ -612,6 +726,25 @@ static uint32_t addNodeExtended(
|
||||
return idx + ZIR_REF_START_INDEX;
|
||||
}
|
||||
|
||||
// Mirrors GenZir.addExtendedNodeSmall (AstGen.zig:12479-12499).
|
||||
// Creates an extended instruction with operand = node offset and custom small.
|
||||
static uint32_t addNodeExtendedSmall(
|
||||
GenZir* gz, uint16_t opcode, uint32_t src_node, uint16_t small) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
ensureInstCapacity(ag, 1);
|
||||
uint32_t idx = ag->inst_len;
|
||||
ag->inst_tags[idx] = ZIR_INST_EXTENDED;
|
||||
ZirInstData data;
|
||||
data.extended.opcode = opcode;
|
||||
data.extended.small = small;
|
||||
data.extended.operand
|
||||
= (uint32_t)((int32_t)src_node - (int32_t)gz->decl_node_index);
|
||||
ag->inst_datas[idx] = data;
|
||||
ag->inst_len++;
|
||||
gzAppendInstruction(gz, idx);
|
||||
return idx + ZIR_REF_START_INDEX;
|
||||
}
|
||||
|
||||
// Mirrors GenZir.addExtendedPayload (AstGen.zig:12781).
|
||||
// Creates an extended instruction with given payload_index and small=0.
|
||||
static uint32_t addExtendedPayload(
|
||||
@@ -1873,28 +2006,10 @@ static void setStruct(AstGenCtx* ag, uint32_t inst, uint32_t src_node,
|
||||
|
||||
// --- scanContainer (AstGen.zig:13384) ---
|
||||
|
||||
// Add a name→node entry to the decl table.
|
||||
static void addDeclToTable(
|
||||
AstGenCtx* ag, uint32_t name_str_index, uint32_t node) {
|
||||
if (ag->decl_table_len >= ag->decl_table_cap) {
|
||||
uint32_t new_cap = ag->decl_table_cap > 0 ? ag->decl_table_cap * 2 : 8;
|
||||
uint32_t* n = realloc(ag->decl_names, new_cap * sizeof(uint32_t));
|
||||
uint32_t* d = realloc(ag->decl_nodes, new_cap * sizeof(uint32_t));
|
||||
if (!n || !d)
|
||||
exit(1);
|
||||
ag->decl_names = n;
|
||||
ag->decl_nodes = d;
|
||||
ag->decl_table_cap = new_cap;
|
||||
}
|
||||
ag->decl_names[ag->decl_table_len] = name_str_index;
|
||||
ag->decl_nodes[ag->decl_table_len] = node;
|
||||
ag->decl_table_len++;
|
||||
}
|
||||
|
||||
// Mirrors scanContainer (AstGen.zig:13384).
|
||||
// Also populates the decl table (namespace.decls) for identifier resolution.
|
||||
static uint32_t scanContainer(
|
||||
AstGenCtx* ag, const uint32_t* members, uint32_t member_count) {
|
||||
// Populates the namespace's decl table for identifier resolution.
|
||||
static uint32_t scanContainer(AstGenCtx* ag, ScopeNamespace* ns,
|
||||
const uint32_t* members, uint32_t member_count) {
|
||||
const Ast* tree = ag->tree;
|
||||
uint32_t decl_count = 0;
|
||||
for (uint32_t i = 0; i < member_count; i++) {
|
||||
@@ -1908,7 +2023,7 @@ static uint32_t scanContainer(
|
||||
decl_count++;
|
||||
uint32_t name_token = tree->nodes.main_tokens[member] + 1;
|
||||
uint32_t name_str = identAsString(ag, name_token);
|
||||
addDeclToTable(ag, name_str, member);
|
||||
scopeNamespaceAddDecl(ns, name_str, member);
|
||||
break;
|
||||
}
|
||||
case AST_NODE_FN_PROTO_SIMPLE:
|
||||
@@ -1919,7 +2034,7 @@ static uint32_t scanContainer(
|
||||
decl_count++;
|
||||
uint32_t name_token = tree->nodes.main_tokens[member] + 1;
|
||||
uint32_t name_str = identAsString(ag, name_token);
|
||||
addDeclToTable(ag, name_str, member);
|
||||
scopeNamespaceAddDecl(ns, name_str, member);
|
||||
break;
|
||||
}
|
||||
// Container fields: add field name to string table for ordering
|
||||
@@ -3525,6 +3640,234 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node) {
|
||||
return ZIR_REF_NONE;
|
||||
}
|
||||
|
||||
// Capture tag values for packed Capture u32 (Zir.zig:3391-3435).
|
||||
#define CAPTURE_TAG_NESTED 0
|
||||
#define CAPTURE_TAG_INSTRUCTION 1
|
||||
#define CAPTURE_TAG_INSTRUCTION_LOAD 2
|
||||
#define CAPTURE_TAG_DECL_VAL 3
|
||||
#define CAPTURE_TAG_DECL_REF 4
|
||||
|
||||
static uint32_t packCapture(uint32_t tag, uint32_t data) {
|
||||
return (tag & 0x7u) | (data << 3);
|
||||
}
|
||||
|
||||
// Mirrors tunnelThroughClosure (AstGen.zig:8526-8624).
|
||||
// Access a ZIR instruction/decl through closure. May tunnel through
|
||||
// arbitrarily many namespaces, adding closure captures as required.
|
||||
// Returns the ref of the closure_get instruction added to gz.
|
||||
//
|
||||
// capture_tag: one of CAPTURE_TAG_* constants.
|
||||
// capture_data: the instruction index or NullTerminatedString index.
|
||||
static uint32_t tunnelThroughClosure(GenZir* gz, uint32_t inner_ref_node,
|
||||
uint32_t num_tunnels, uint32_t capture_tag, uint32_t capture_data,
|
||||
uint32_t name_str_index) {
|
||||
// For trivial refs (instruction tag with data mapping to a non-index ref),
|
||||
// no tunnel is needed. In the upstream, this checks if
|
||||
// ref.toIndex()==null. A ref with index < ZIR_REF_START_INDEX is
|
||||
// non-indexed (e.g. void, true).
|
||||
if (capture_tag == CAPTURE_TAG_INSTRUCTION
|
||||
&& capture_data + ZIR_REF_START_INDEX < ZIR_REF_START_INDEX) {
|
||||
return capture_data + ZIR_REF_START_INDEX;
|
||||
}
|
||||
|
||||
// Walk gz->parent to find the namespace scopes we're tunneling through.
|
||||
// The root namespace is the outermost (first found when counting
|
||||
// num_tunnels-1 intermediate tunnels from the inside).
|
||||
// Allocate on the stack for typical small counts.
|
||||
ScopeNamespace* intermediates[16];
|
||||
ScopeNamespace** inter = intermediates;
|
||||
ScopeNamespace** inter_heap = NULL;
|
||||
if (num_tunnels > 17) {
|
||||
inter_heap = malloc((num_tunnels - 1) * sizeof(ScopeNamespace*));
|
||||
if (!inter_heap)
|
||||
exit(1);
|
||||
inter = inter_heap;
|
||||
}
|
||||
|
||||
// Find the root namespace and intermediate tunnels (AstGen.zig:8568-8582).
|
||||
ScopeNamespace* root_ns = NULL;
|
||||
{
|
||||
uint32_t remaining = num_tunnels - 1;
|
||||
Scope* s = gz->parent;
|
||||
while (s != NULL && remaining > 0) {
|
||||
if (s->tag == SCOPE_NAMESPACE) {
|
||||
remaining--;
|
||||
inter[remaining] = (ScopeNamespace*)s;
|
||||
}
|
||||
s = scopeParent(s);
|
||||
}
|
||||
// Find the root namespace.
|
||||
while (s != NULL) {
|
||||
if (s->tag == SCOPE_NAMESPACE) {
|
||||
root_ns = (ScopeNamespace*)s;
|
||||
break;
|
||||
}
|
||||
s = scopeParent(s);
|
||||
}
|
||||
}
|
||||
|
||||
// root_ns must have been found — we are tunneling through at least one
|
||||
// namespace, so there must be a root namespace in the scope chain.
|
||||
if (root_ns == NULL) {
|
||||
free(inter_heap);
|
||||
SET_ERROR(gz->astgen);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
|
||||
// Add the root capture (AstGen.zig:8584-8594).
|
||||
uint32_t root_capture = packCapture(capture_tag, capture_data);
|
||||
uint32_t cur_capture_index
|
||||
= scopeNamespaceAddCapture(root_ns, root_capture, name_str_index);
|
||||
|
||||
// Chain through intermediate namespaces (AstGen.zig:8596-8616).
|
||||
for (uint32_t i = 0; i < num_tunnels - 1; i++) {
|
||||
uint32_t nested_capture
|
||||
= packCapture(CAPTURE_TAG_NESTED, cur_capture_index);
|
||||
cur_capture_index = scopeNamespaceAddCapture(
|
||||
inter[i], nested_capture, name_str_index);
|
||||
}
|
||||
|
||||
free(inter_heap);
|
||||
|
||||
// Add closure_get instruction (AstGen.zig:8622-8623).
|
||||
return addNodeExtendedSmall(gz, (uint16_t)ZIR_EXT_CLOSURE_GET,
|
||||
inner_ref_node, (uint16_t)cur_capture_index);
|
||||
}
|
||||
|
||||
// Mirrors localVarRef (AstGen.zig:8367-8521).
|
||||
static uint32_t localVarRef(GenZir* gz, Scope* scope, ResultLoc rl,
|
||||
uint32_t node, uint32_t ident_token, uint32_t name_str) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
uint32_t found_already = UINT32_MAX; // node index if found
|
||||
bool found_needs_tunnel = false;
|
||||
uint32_t found_namespaces_out = 0;
|
||||
uint32_t num_namespaces_out = 0;
|
||||
ScopeNamespace* capturing_namespace = NULL;
|
||||
|
||||
for (Scope* s = scope; s != NULL;) {
|
||||
switch (s->tag) {
|
||||
case SCOPE_LOCAL_VAL: {
|
||||
ScopeLocalVal* lv = (ScopeLocalVal*)s;
|
||||
if (lv->name == name_str) {
|
||||
// Locals cannot shadow, no ambiguity check needed.
|
||||
uint32_t value_inst;
|
||||
if (num_namespaces_out != 0) {
|
||||
value_inst = tunnelThroughClosure(gz, node,
|
||||
num_namespaces_out, CAPTURE_TAG_INSTRUCTION,
|
||||
lv->inst - ZIR_REF_START_INDEX, name_str);
|
||||
} else {
|
||||
value_inst = lv->inst;
|
||||
}
|
||||
return rvalueNoCoercePreRef(gz, rl, value_inst, node);
|
||||
}
|
||||
s = lv->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_LOCAL_PTR: {
|
||||
ScopeLocalPtr* lp = (ScopeLocalPtr*)s;
|
||||
if (lp->name == name_str) {
|
||||
// Can't close over a runtime variable
|
||||
// (AstGen.zig:8424-8432).
|
||||
if (num_namespaces_out != 0 && !lp->maybe_comptime
|
||||
&& !gz->is_typeof) {
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
if (RL_IS_REF(rl)) {
|
||||
uint32_t ptr_inst;
|
||||
if (num_namespaces_out != 0) {
|
||||
ptr_inst = tunnelThroughClosure(gz, node,
|
||||
num_namespaces_out, CAPTURE_TAG_INSTRUCTION,
|
||||
lp->ptr - ZIR_REF_START_INDEX, name_str);
|
||||
} else {
|
||||
ptr_inst = lp->ptr;
|
||||
}
|
||||
return ptr_inst;
|
||||
} else {
|
||||
uint32_t val_inst;
|
||||
if (num_namespaces_out != 0) {
|
||||
val_inst = tunnelThroughClosure(gz, node,
|
||||
num_namespaces_out, CAPTURE_TAG_INSTRUCTION_LOAD,
|
||||
lp->ptr - ZIR_REF_START_INDEX, name_str);
|
||||
} else {
|
||||
val_inst = addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
|
||||
}
|
||||
return rvalueNoCoercePreRef(gz, rl, val_inst, node);
|
||||
}
|
||||
}
|
||||
s = lp->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_GEN_ZIR: {
|
||||
s = ((GenZir*)s)->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_DEFER_NORMAL:
|
||||
case SCOPE_DEFER_ERROR: {
|
||||
s = ((ScopeDefer*)s)->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_LABEL: {
|
||||
s = ((ScopeLabel*)s)->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_NAMESPACE: {
|
||||
// Check namespace decls, then continue walking
|
||||
// (AstGen.zig:8455-8472).
|
||||
ScopeNamespace* ns = (ScopeNamespace*)s;
|
||||
uint32_t decl_node = scopeNamespaceFindDecl(ns, name_str);
|
||||
if (decl_node != UINT32_MAX) {
|
||||
if (found_already != UINT32_MAX) {
|
||||
// Ambiguous reference (AstGen.zig:8458-8462).
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
found_already = decl_node;
|
||||
found_needs_tunnel = ns->maybe_generic;
|
||||
found_namespaces_out = num_namespaces_out;
|
||||
}
|
||||
num_namespaces_out++;
|
||||
capturing_namespace = ns;
|
||||
s = ns->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_TOP:
|
||||
goto done_walk;
|
||||
}
|
||||
}
|
||||
done_walk:
|
||||
(void)capturing_namespace;
|
||||
|
||||
if (found_already == UINT32_MAX) {
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
}
|
||||
|
||||
// Decl references (AstGen.zig:8484-8520).
|
||||
if (found_namespaces_out > 0 && found_needs_tunnel) {
|
||||
if (RL_IS_REF(rl)) {
|
||||
return tunnelThroughClosure(gz, node, found_namespaces_out,
|
||||
CAPTURE_TAG_DECL_REF, name_str, name_str);
|
||||
} else {
|
||||
uint32_t result
|
||||
= tunnelThroughClosure(gz, node, found_namespaces_out,
|
||||
CAPTURE_TAG_DECL_VAL, name_str, name_str);
|
||||
return rvalueNoCoercePreRef(gz, rl, result, node);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple decl reference (AstGen.zig:8512-8520).
|
||||
ZirInstData data;
|
||||
data.str_tok.start = name_str;
|
||||
data.str_tok.src_tok = tokenIndexToRelative(gz, ident_token);
|
||||
if (RL_IS_REF(rl)) {
|
||||
return addInstruction(gz, ZIR_INST_DECL_REF, data);
|
||||
} else {
|
||||
uint32_t result = addInstruction(gz, ZIR_INST_DECL_VAL, data);
|
||||
return rvalueNoCoercePreRef(gz, rl, result, node);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t identifierExpr(
|
||||
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
||||
AstGenCtx* ag = gz->astgen;
|
||||
@@ -3535,68 +3878,10 @@ static uint32_t identifierExpr(
|
||||
if (prim != ZIR_REF_NONE)
|
||||
return rvalue(gz, rl, prim, node);
|
||||
|
||||
// Scope chain walk (AstGen.zig:8340-8461).
|
||||
uint32_t name_str = identAsString(ag, ident_token);
|
||||
for (Scope* s = scope; s != NULL;) {
|
||||
switch (s->tag) {
|
||||
case SCOPE_LOCAL_VAL: {
|
||||
ScopeLocalVal* lv = (ScopeLocalVal*)s;
|
||||
if (lv->name == name_str)
|
||||
return rvalueNoCoercePreRef(gz, rl, lv->inst, node);
|
||||
s = lv->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_LOCAL_PTR: {
|
||||
ScopeLocalPtr* lp = (ScopeLocalPtr*)s;
|
||||
if (lp->name == name_str) {
|
||||
if (RL_IS_REF(rl))
|
||||
return lp->ptr;
|
||||
uint32_t val = addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
|
||||
return rvalueNoCoercePreRef(gz, rl, val, node);
|
||||
}
|
||||
s = lp->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_GEN_ZIR: {
|
||||
GenZir* gzs = (GenZir*)s;
|
||||
s = gzs->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_DEFER_NORMAL:
|
||||
case SCOPE_DEFER_ERROR: {
|
||||
ScopeDefer* sd = (ScopeDefer*)s;
|
||||
s = sd->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_LABEL: {
|
||||
ScopeLabel* sl = (ScopeLabel*)s;
|
||||
s = sl->parent;
|
||||
continue;
|
||||
}
|
||||
case SCOPE_NAMESPACE:
|
||||
case SCOPE_TOP:
|
||||
goto decl_table;
|
||||
}
|
||||
}
|
||||
decl_table:
|
||||
|
||||
// Decl table lookup (AstGen.zig:8462-8520).
|
||||
for (uint32_t i = 0; i < ag->decl_table_len; i++) {
|
||||
if (ag->decl_names[i] == name_str) {
|
||||
ZirInstData data;
|
||||
data.str_tok.start = name_str;
|
||||
data.str_tok.src_tok = tokenIndexToRelative(gz, ident_token);
|
||||
if (RL_IS_REF(rl)) {
|
||||
return addInstruction(gz, ZIR_INST_DECL_REF, data);
|
||||
} else {
|
||||
uint32_t result = addInstruction(gz, ZIR_INST_DECL_VAL, data);
|
||||
return rvalueNoCoercePreRef(gz, rl, result, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SET_ERROR(ag);
|
||||
return ZIR_REF_VOID_VALUE;
|
||||
// Local variables and container-level declarations
|
||||
// (AstGen.zig:8340-8365).
|
||||
return localVarRef(
|
||||
gz, scope, rl, node, ident_token, identAsString(ag, ident_token));
|
||||
}
|
||||
|
||||
// --- fieldAccess (AstGen.zig:6154) ---
|
||||
@@ -10598,8 +10883,8 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
|
||||
|
||||
// --- testDecl (AstGen.zig:4708) ---
|
||||
|
||||
static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
static void testDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
|
||||
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
|
||||
const Ast* tree = ag->tree;
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
uint32_t body_node = nd.rhs;
|
||||
@@ -10640,7 +10925,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir decl_block;
|
||||
memset(&decl_block, 0, sizeof(decl_block));
|
||||
decl_block.base.tag = SCOPE_GEN_ZIR;
|
||||
decl_block.parent = NULL;
|
||||
decl_block.parent = scope;
|
||||
decl_block.astgen = ag;
|
||||
decl_block.decl_node_index = node;
|
||||
decl_block.decl_line = decl_line;
|
||||
@@ -10739,8 +11024,8 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
// Handles function declarations with bodies (fn_decl) and
|
||||
// function prototypes without bodies (fn_proto*).
|
||||
|
||||
static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
|
||||
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
|
||||
const Ast* tree = ag->tree;
|
||||
AstNodeTag node_tag = tree->nodes.tags[node];
|
||||
AstData nd = tree->nodes.datas[node];
|
||||
@@ -10873,7 +11158,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir decl_gz;
|
||||
memset(&decl_gz, 0, sizeof(decl_gz));
|
||||
decl_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
decl_gz.parent = NULL;
|
||||
decl_gz.parent = scope;
|
||||
decl_gz.astgen = ag;
|
||||
decl_gz.decl_node_index = proto_node;
|
||||
decl_gz.decl_line = decl_line;
|
||||
@@ -11321,8 +11606,8 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
|
||||
// --- comptimeDecl (AstGen.zig:4645) ---
|
||||
|
||||
static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
static void comptimeDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
|
||||
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
|
||||
// makeDeclaration before advanceSourceCursorToNode (AstGen.zig:4663-4665).
|
||||
uint32_t decl_inst = makeDeclaration(ag, node);
|
||||
wip_decl_insts[*decl_idx] = decl_inst;
|
||||
@@ -11337,7 +11622,7 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir value_gz;
|
||||
memset(&value_gz, 0, sizeof(value_gz));
|
||||
value_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
value_gz.parent = NULL;
|
||||
value_gz.parent = scope;
|
||||
value_gz.astgen = ag;
|
||||
value_gz.decl_node_index = node;
|
||||
value_gz.decl_line = decl_line;
|
||||
@@ -11545,8 +11830,8 @@ static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
|
||||
}
|
||||
}
|
||||
|
||||
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
|
||||
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
|
||||
const Ast* tree = ag->tree;
|
||||
VarDeclInfo vd = extractVarDecl(tree, node);
|
||||
uint32_t name_token = vd.mut_token + 1;
|
||||
@@ -11607,6 +11892,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir type_gz;
|
||||
memset(&type_gz, 0, sizeof(type_gz));
|
||||
type_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
type_gz.parent = scope;
|
||||
type_gz.astgen = ag;
|
||||
type_gz.decl_node_index = node;
|
||||
type_gz.instructions_top = ag->scratch_inst_len;
|
||||
@@ -11626,6 +11912,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir align_gz;
|
||||
memset(&align_gz, 0, sizeof(align_gz));
|
||||
align_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
align_gz.parent = scope;
|
||||
align_gz.astgen = ag;
|
||||
align_gz.decl_node_index = node;
|
||||
align_gz.instructions_top = type_top;
|
||||
@@ -11651,6 +11938,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir linksection_gz;
|
||||
memset(&linksection_gz, 0, sizeof(linksection_gz));
|
||||
linksection_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
linksection_gz.parent = scope;
|
||||
linksection_gz.astgen = ag;
|
||||
linksection_gz.decl_node_index = node;
|
||||
linksection_gz.instructions_top = align_top;
|
||||
@@ -11676,6 +11964,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir addrspace_gz;
|
||||
memset(&addrspace_gz, 0, sizeof(addrspace_gz));
|
||||
addrspace_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
addrspace_gz.parent = scope;
|
||||
addrspace_gz.astgen = ag;
|
||||
addrspace_gz.decl_node_index = node;
|
||||
addrspace_gz.instructions_top = linksection_top;
|
||||
@@ -11703,6 +11992,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir value_gz;
|
||||
memset(&value_gz, 0, sizeof(value_gz));
|
||||
value_gz.base.tag = SCOPE_GEN_ZIR;
|
||||
value_gz.parent = scope;
|
||||
value_gz.astgen = ag;
|
||||
value_gz.decl_node_index = node;
|
||||
value_gz.instructions_top = addrspace_top;
|
||||
@@ -12334,16 +12624,21 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
uint32_t decl_inst = reserveInstructionIndex(ag);
|
||||
gzAppendInstruction(gz, decl_inst);
|
||||
|
||||
// Create namespace scope (AstGen.zig:5618-5623).
|
||||
ScopeNamespace namespace;
|
||||
scopeNamespaceInit(
|
||||
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
|
||||
|
||||
advanceSourceCursorToNode(ag, node);
|
||||
|
||||
// scanContainer to register names in string table (AstGen.zig:5635).
|
||||
scanContainer(ag, members, members_len);
|
||||
scanContainer(ag, &namespace, members, members_len);
|
||||
|
||||
// Set up block_scope for tag value expressions (AstGen.zig:5624-5632).
|
||||
GenZir block_scope;
|
||||
memset(&block_scope, 0, sizeof(block_scope));
|
||||
block_scope.base.tag = SCOPE_GEN_ZIR;
|
||||
block_scope.parent = NULL;
|
||||
block_scope.parent = &namespace.base;
|
||||
block_scope.astgen = ag;
|
||||
block_scope.decl_node_index = node;
|
||||
block_scope.decl_line = ag->source_line;
|
||||
@@ -12368,19 +12663,23 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
AstNodeTag mtag = tree->nodes.tags[member_node];
|
||||
switch (mtag) {
|
||||
case AST_NODE_COMPTIME:
|
||||
comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
comptimeDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_SIMPLE_VAR_DECL:
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
case AST_NODE_ALIGNED_VAR_DECL:
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_FN_DECL:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_TEST_DECL:
|
||||
testDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
testDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_CONTAINER_FIELD_INIT:
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
@@ -12432,19 +12731,26 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len);
|
||||
|
||||
// setEnum (AstGen.zig:5705-5715).
|
||||
setEnum(ag, decl_inst, node, arg_inst, 0 /* captures_len */, body_len,
|
||||
setEnum(ag, decl_inst, node, arg_inst, namespace.captures_len, body_len,
|
||||
total_fields, decl_count, nonexhaustive, name_strategy);
|
||||
|
||||
wipMembersFinishBitsEnum(&wm);
|
||||
|
||||
// Append trailing data (AstGen.zig:5718-5725):
|
||||
// captures (none), decls, body, fields.
|
||||
// captures, decls, body, fields.
|
||||
uint32_t decls_len_out;
|
||||
const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len_out);
|
||||
uint32_t fields_len_out;
|
||||
const uint32_t* fields_slice = wipMembersFieldsSlice(&wm, &fields_len_out);
|
||||
|
||||
ensureExtraCapacity(ag, decls_len_out + body_len + fields_len_out);
|
||||
ensureExtraCapacity(ag,
|
||||
namespace.captures_len * 2 + decls_len_out + body_len
|
||||
+ fields_len_out);
|
||||
// Captures (AstGen.zig:5721-5722).
|
||||
for (uint32_t i = 0; i < namespace.captures_len; i++)
|
||||
ag->extra[ag->extra_len++] = namespace.capture_keys[i];
|
||||
for (uint32_t i = 0; i < namespace.captures_len; i++)
|
||||
ag->extra[ag->extra_len++] = namespace.capture_vals[i];
|
||||
for (uint32_t i = 0; i < decls_len_out; i++)
|
||||
ag->extra[ag->extra_len++] = decls_slice[i];
|
||||
// Body instructions with fixups (AstGen.zig:5724).
|
||||
@@ -12456,6 +12762,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
|
||||
gzUnstack(&block_scope);
|
||||
wipMembersDeinit(&wm);
|
||||
scopeNamespaceDeinit(&namespace);
|
||||
return decl_inst;
|
||||
}
|
||||
|
||||
@@ -12669,9 +12976,15 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
}
|
||||
|
||||
// Non-empty container (AstGen.zig:4973-5189).
|
||||
|
||||
// Create namespace scope (AstGen.zig:4973-4979).
|
||||
ScopeNamespace namespace;
|
||||
scopeNamespaceInit(
|
||||
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
|
||||
|
||||
advanceSourceCursorToNode(ag, node);
|
||||
|
||||
uint32_t decl_count = scanContainer(ag, members, members_len);
|
||||
uint32_t decl_count = scanContainer(ag, &namespace, members, members_len);
|
||||
uint32_t field_count = members_len - decl_count;
|
||||
|
||||
WipMembers wm = wipMembersInit(decl_count, field_count);
|
||||
@@ -12681,7 +12994,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
GenZir block_scope;
|
||||
memset(&block_scope, 0, sizeof(block_scope));
|
||||
block_scope.base.tag = SCOPE_GEN_ZIR;
|
||||
block_scope.parent = NULL;
|
||||
block_scope.parent = &namespace.base;
|
||||
block_scope.astgen = ag;
|
||||
block_scope.decl_node_index = node;
|
||||
block_scope.decl_line = gz->decl_line; // Fix #7: use gz->decl_line
|
||||
@@ -12730,29 +13043,35 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
AstNodeTag mtag = tree->nodes.tags[member_node];
|
||||
switch (mtag) {
|
||||
case AST_NODE_COMPTIME:
|
||||
comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
comptimeDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_SIMPLE_VAR_DECL:
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_TEST_DECL:
|
||||
testDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
testDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_FN_DECL:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
// fn_proto* dispatch (AstGen.zig:5809-5813, issue #9).
|
||||
case AST_NODE_FN_PROTO_SIMPLE:
|
||||
case AST_NODE_FN_PROTO_MULTI:
|
||||
case AST_NODE_FN_PROTO_ONE:
|
||||
case AST_NODE_FN_PROTO:
|
||||
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_USINGNAMESPACE:
|
||||
case AST_NODE_GLOBAL_VAR_DECL:
|
||||
case AST_NODE_LOCAL_VAR_DECL:
|
||||
case AST_NODE_ALIGNED_VAR_DECL:
|
||||
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
|
||||
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
|
||||
member_node);
|
||||
break;
|
||||
case AST_NODE_CONTAINER_FIELD_INIT:
|
||||
case AST_NODE_CONTAINER_FIELD_ALIGN:
|
||||
@@ -12929,6 +13248,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
// setStruct (AstGen.zig:5152-5166).
|
||||
StructDeclSmall small;
|
||||
memset(&small, 0, sizeof(small));
|
||||
small.has_captures_len = (namespace.captures_len > 0);
|
||||
small.has_decls_len = (decl_count > 0);
|
||||
small.has_fields_len = (field_count > 0);
|
||||
small.has_backing_int = (backing_int_ref != ZIR_REF_NONE);
|
||||
@@ -12939,9 +13259,10 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
small.any_aligned_fields = any_aligned_fields;
|
||||
small.layout = layout;
|
||||
small.name_strategy = name_strategy;
|
||||
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
|
||||
setStruct(ag, decl_inst, node, small, namespace.captures_len, field_count,
|
||||
decl_count);
|
||||
|
||||
// Append: captures (none), backing_int, decls, fields, bodies
|
||||
// Append: captures, backing_int, decls, fields, bodies
|
||||
// (AstGen.zig:5172-5186).
|
||||
uint32_t decls_len;
|
||||
const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len);
|
||||
@@ -12955,8 +13276,14 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
ag, backing_int_body_raw, backing_int_body_raw_len);
|
||||
}
|
||||
ensureExtraCapacity(ag,
|
||||
(backing_int_ref != ZIR_REF_NONE ? backing_int_body_len + 2 : 0)
|
||||
namespace.captures_len * 2
|
||||
+ (backing_int_ref != ZIR_REF_NONE ? backing_int_body_len + 2 : 0)
|
||||
+ decls_len + fields_len + wm.bodies_len);
|
||||
// Captures (AstGen.zig:5174-5175).
|
||||
for (uint32_t i = 0; i < namespace.captures_len; i++)
|
||||
ag->extra[ag->extra_len++] = namespace.capture_keys[i];
|
||||
for (uint32_t i = 0; i < namespace.captures_len; i++)
|
||||
ag->extra[ag->extra_len++] = namespace.capture_vals[i];
|
||||
// backing_int (AstGen.zig:5176-5183).
|
||||
if (backing_int_ref != ZIR_REF_NONE) {
|
||||
ag->extra[ag->extra_len++] = backing_int_body_len;
|
||||
@@ -12977,6 +13304,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
|
||||
gzUnstack(&block_scope);
|
||||
wipMembersDeinit(&wm);
|
||||
scopeNamespaceDeinit(&namespace);
|
||||
return decl_inst;
|
||||
}
|
||||
|
||||
@@ -14254,8 +14582,6 @@ Zir astGen(const Ast* ast) {
|
||||
zir.has_compile_errors = ag.has_compile_errors;
|
||||
|
||||
free(ag.imports);
|
||||
free(ag.decl_names);
|
||||
free(ag.decl_nodes);
|
||||
free(ag.scratch_instructions);
|
||||
free(ag.scratch_extra);
|
||||
free(ag.ref_table_keys);
|
||||
|
||||
Reference in New Issue
Block a user