brewery
notashelf /
0a5920adaf7d2eed5d5936f8b350917fccb2ca59

nixir

public

Import-resolving Nix IR plugin

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.git
src/plugin.cppCpp158 lines4.1 KB
1
#ifdef unix
2
#undef unix
3
#endif
4
5
#include "nix/expr/eval.hh"
6
#include "nix/expr/primops.hh"
7
#include "nix/expr/value.hh"
8
9
#include "irc/evaluator.h"
10
#include "irc/ir_gen.h"
11
#include "irc/parser.h"
12
#include "irc/serializer.h"
13
#include "irc/types.h"
14
15
#include <chrono>
16
#include <iostream>
17
18
namespace nix_ir_plugin {
19
20
using namespace nix;
21
using namespace nix_irc;
22
23
/**
24
 * Load and evaluate a pre-compiled IR bundle
25
 * Usage: builtins.nixIR.loadIR "/path/to/file.nixir"
26
 */
27
static void prim_loadIR(EvalState& state, const PosIdx pos, Value** args, Value& v) {
28
  auto path = state.forceStringNoCtx(
29
      *args[0], pos, "while evaluating the first argument to builtins.nixIR.loadIR");
30
31
  std::string pathStr(path);
32
33
  auto t_start = std::chrono::high_resolution_clock::now();
34
35
  Deserializer deserializer;
36
  IRModule module;
37
38
  try {
39
    module = deserializer.deserialize(pathStr);
40
  } catch (const std::exception& e) {
41
    state.error<EvalError>("failed to deserialize IR bundle: %s", e.what()).atPos(pos).debugThrow();
42
  }
43
44
  auto t_deser = std::chrono::high_resolution_clock::now();
45
46
  if (!module.entry) {
47
    state.error<EvalError>("IR bundle has no entry point").atPos(pos).debugThrow();
48
  }
49
50
  try {
51
    Evaluator evaluator(state);
52
    evaluator.eval_to_nix(module.entry, v);
53
  } catch (const std::exception& e) {
54
    state.error<EvalError>("failed to evaluate IR: %s", e.what()).atPos(pos).debugThrow();
55
  }
56
57
  auto t_eval = std::chrono::high_resolution_clock::now();
58
59
  auto deser_us = std::chrono::duration_cast<std::chrono::microseconds>(t_deser - t_start).count();
60
  auto eval_us = std::chrono::duration_cast<std::chrono::microseconds>(t_eval - t_deser).count();
61
62
  std::cerr << "nixIR timing: deser=" << deser_us << "us eval=" << eval_us
63
            << "us total=" << (deser_us + eval_us) << "us" << std::endl;
64
}
65
66
/**
67
 * Compile Nix source to IR on-the-fly
68
 * Usage: builtins.nixIR.compile "{ x = 1; }"
69
 */
70
static void prim_compileNix(EvalState& state, const PosIdx pos, Value** args, Value& v) {
71
  auto source = state.forceStringNoCtx(
72
      *args[0], pos, "while evaluating the first argument to builtins.nixIR.compile");
73
74
  std::string sourceStr(source);
75
76
  try {
77
    Parser parser;
78
    auto ast = parser.parse(sourceStr, "<inline>");
79
80
    if (!ast) {
81
      state.error<EvalError>("failed to parse Nix expression").atPos(pos).debugThrow();
82
    }
83
84
    IRGenerator ir_gen;
85
    auto ir = ir_gen.generate(ast);
86
87
    Evaluator evaluator(state);
88
    evaluator.eval_to_nix(ir, v);
89
90
  } catch (const std::exception& e) {
91
    state.error<EvalError>("IR compilation failed: %s", e.what()).atPos(pos).debugThrow();
92
  }
93
}
94
95
/**
96
 * Get information about the IR plugin
97
 * Usage: builtins.nixIR.info
98
 */
99
static void prim_info(EvalState& state, const PosIdx pos, Value** args, Value& v) {
100
  auto bindings = state.buildBindings(3);
101
102
  Value* vName = state.allocValue();
103
  vName->mkString("nix-ir-plugin");
104
  bindings.insert(state.symbols.create("name"), vName);
105
106
  Value* vVersion = state.allocValue();
107
  vVersion->mkString("0.1.0");
108
  bindings.insert(state.symbols.create("version"), vVersion);
109
110
  Value* vStatus = state.allocValue();
111
  vStatus->mkString("runtime-active");
112
  bindings.insert(state.symbols.create("status"), vStatus);
113
114
  v.mkAttrs(bindings.finish());
115
}
116
117
// Register primops on plugin load
118
static RegisterPrimOp rp_loadIR({
119
    .name = "__nixIR_loadIR",
120
    .args = {"path"},
121
    .arity = 1,
122
    .doc = R"(
123
      Load a pre-compiled IR bundle from the given path.
124
      Returns an attrset with information about the loaded bundle.
125
126
    )",
127
    .fun = prim_loadIR,
128
});
129
130
static RegisterPrimOp rp_compileNix({
131
    .name = "__nixIR_compile",
132
    .args = {"source"},
133
    .arity = 1,
134
    .doc = R"(
135
      Compile Nix source code to IR on-the-fly.
136
      Returns an attrset with information about the compiled IR.
137
138
    )",
139
    .fun = prim_compileNix,
140
});
141
142
static RegisterPrimOp rp_info({
143
    .name = "__nixIR_info",
144
    .args = {},
145
    .arity = 0,
146
    .doc = R"(
147
      Get information about the IR plugin.
148
      Returns an attrset with plugin name, version, and status.
149
    )",
150
    .fun = prim_info,
151
});
152
153
} // namespace nix_ir_plugin
154
155
// Plugin initialization
156
__attribute__((constructor)) static void init_plugin() {
157
  // Plugin loads silently...
158
}