#include "ir_gen.h" #include #include #include namespace nix_irc { struct NameResolver::Impl { std::vector> scopes; std::vector> scope_names; Impl() { scopes.push_back({}); scope_names.push_back({}); } }; NameResolver::NameResolver() : pImpl(std::make_unique()) {} NameResolver::~NameResolver() = default; void NameResolver::enter_scope() { pImpl->scopes.push_back({}); pImpl->scope_names.push_back({}); } void NameResolver::exit_scope() { if (!pImpl->scopes.empty()) { pImpl->scopes.pop_back(); pImpl->scope_names.pop_back(); } } void NameResolver::bind(const std::string& name) { if (pImpl->scopes.empty()) return; uint32_t idx = pImpl->scope_names.back().size(); pImpl->scopes.back()[name] = idx; pImpl->scope_names.back().push_back(name); } uint32_t NameResolver::resolve(const std::string& name) { for (int i = (int) pImpl->scopes.size() - 1; i >= 0; --i) { auto it = pImpl->scopes[i].find(name); if (it != pImpl->scopes[i].end()) { uint32_t depth = pImpl->scopes.size() - 1 - i; uint32_t offset = it->second; return depth << 16 | offset; } } return 0xFFFFFFFF; } bool NameResolver::is_bound(const std::string& name) const { for (auto it = pImpl->scopes.rbegin(); it != pImpl->scopes.rend(); ++it) { if (it->count(name)) return true; } return false; } struct IRGenerator::Impl { std::unordered_map string_table; uint32_t next_string_id = 0; NameResolver name_resolver; Impl() {} uint32_t add_string(const std::string& str) { auto it = string_table.find(str); if (it != string_table.end()) { return it->second; } uint32_t id = next_string_id++; string_table[str] = id; return id; } std::shared_ptr convert(const std::shared_ptr& node_ptr) { if (!node_ptr) return std::make_shared(ConstNullNode{}); const Node& node = *node_ptr; if (auto* n = node.get_if()) { return std::make_shared(*n); } if (auto* n = node.get_if()) { return std::make_shared(*n); } if (auto* n = node.get_if()) { return std::make_shared(*n); } if (auto* n = node.get_if()) { return std::make_shared(*n); } if (auto* n = node.get_if()) { return std::make_shared(*n); } if (auto* n = node.get_if()) { uint32_t idx = name_resolver.resolve(n->name.value_or("")); VarNode converted(idx); converted.name = n->name; converted.line = n->line; return std::make_shared(converted); } if (auto* n = node.get_if()) { name_resolver.enter_scope(); if (n->param_name) { name_resolver.bind(*n->param_name); } auto body = convert(n->body); name_resolver.exit_scope(); LambdaNode lambda(n->arity, body, n->line); lambda.param_name = n->param_name; return std::make_shared(lambda); } if (auto* n = node.get_if()) { auto func = convert(n->func); auto arg = convert(n->arg); return std::make_shared(AppNode(func, arg, n->line)); } if (auto* n = node.get_if()) { AttrsetNode attrs(n->recursive, n->line); name_resolver.enter_scope(); for (const auto& [key, val] : n->attrs) { name_resolver.bind(key); } for (const auto& [key, val] : n->attrs) { attrs.attrs.push_back({key, convert(val)}); } name_resolver.exit_scope(); return std::make_shared(attrs); } if (auto* n = node.get_if()) { auto expr = convert(n->expr); auto attr = convert(n->attr); SelectNode select(expr, attr, n->line); if (n->default_expr) { select.default_expr = convert(*n->default_expr); } return std::make_shared(select); } if (auto* n = node.get_if()) { auto expr = convert(n->expr); auto attr = convert(n->attr); return std::make_shared(HasAttrNode(expr, attr, n->line)); } if (auto* n = node.get_if()) { auto attrs = convert(n->attrs); auto body = convert(n->body); return std::make_shared(WithNode(attrs, body, n->line)); } if (auto* n = node.get_if()) { auto cond = convert(n->cond); auto then_b = convert(n->then_branch); auto else_b = convert(n->else_branch); return std::make_shared(IfNode(cond, then_b, else_b, n->line)); } if (auto* n = node.get_if()) { name_resolver.enter_scope(); for (const auto& [key, val] : n->bindings) { name_resolver.bind(key); } std::vector>> new_bindings; new_bindings.reserve(n->bindings.size()); for (const auto& [key, val] : n->bindings) { new_bindings.push_back({key, convert(val)}); } auto body = convert(n->body); name_resolver.exit_scope(); LetNode let(body, n->line); let.bindings = std::move(new_bindings); return std::make_shared(let); } if (auto* n = node.get_if()) { name_resolver.enter_scope(); for (const auto& [key, val] : n->bindings) { name_resolver.bind(key); } std::vector>> new_bindings; new_bindings.reserve(n->bindings.size()); for (const auto& [key, val] : n->bindings) { new_bindings.push_back({key, convert(val)}); } auto body = convert(n->body); name_resolver.exit_scope(); LetRecNode letrec(body, n->line); letrec.bindings = std::move(new_bindings); return std::make_shared(letrec); } if (auto* n = node.get_if()) { auto cond = convert(n->cond); auto body = convert(n->body); return std::make_shared(AssertNode(cond, body, n->line)); } if (auto* n = node.get_if()) { auto left = convert(n->left); auto right = convert(n->right); return std::make_shared(BinaryOpNode(n->op, left, right, n->line)); } if (auto* n = node.get_if()) { auto operand = convert(n->operand); return std::make_shared(UnaryOpNode(n->op, operand, n->line)); } return std::make_shared(ConstNullNode{}); } }; IRGenerator::IRGenerator() : pImpl(std::make_unique()) {} IRGenerator::~IRGenerator() = default; void IRGenerator::set_string_table(const std::unordered_map& table) { pImpl->string_table = table; } uint32_t IRGenerator::add_string(const std::string& str) { return pImpl->add_string(str); } std::shared_ptr IRGenerator::generate(const std::shared_ptr& ast) { return pImpl->convert(ast); } } // namespace nix_irc