As I started getting into symbol compilation, I’ve found that I have many layers of “context” now: there’s the context of the source module, the actual names defined in it; there’s the context of the resolve file, the snapshot of external hashes; and the context of the library, the locally stored symbols. When resolving identifiers, we need all three of these (context for local names, resolver for imported names, library for hashes). This makes things a little confusing, but I feel like writing it out like this makes it easier to reason about.
---
When we build the context, we’re trying to resolve all names to hashes to build up our collection of source code for assembly. When compiling symbols, we actually want the opposite: we want to resolve all names to hashes. Although, routines still need to expand macros, so we also still need to get all macro source. Maybe this isn’t the way to think about it.
When we assemble, we’re trying to get every name reference into some assemble-able byteco. A name can resolve to local source or a linked library symbol. A hash can resolve to a linked library symbol (because in the assembly path we’re not bothering to compile local source into symbols). When we encounter a hash, we check the linked symbols, and then the library at large. When we encounter a name,
shower thoughts: if we drop the relative only requirements, we could just always funnel everything into “symbol” buckets once they’ve been rendered. this would simplify things, and allow everything to reference other things directly by hash.