brewery
notashelf /
32f74c29fdcbe6362c2f8d5f29e38460fe2b8ec2

nixir

public

Import-resolving Nix IR plugin

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.git
src/plugin.cppCpp191 lines4.9 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
#include "nix/store/store-api.hh"
9
#include "nix/util/source-path.hh"
10
11
#include "irc/ir_gen.h"
12
#include "irc/parser.h"
13
#include "irc/resolver.h"
14
#include "irc/serializer.h"
15
#include "irc/types.h"
16
17
#include <fstream>
18
#include <iostream>
19
#include <memory>
20
#include <optional>
21
22
namespace nix_ir_plugin {
23
24
using namespace nix;
25
using namespace nix_irc;
26
27
/**
28
 * Load and evaluate a pre-compiled IR bundle
29
 * Usage: builtins.nixIR.loadIR "/path/to/file.nixir"
30
 */
31
static void prim_loadIR(EvalState &state, const PosIdx pos, Value **args,
32
                        Value &v) {
33
  auto path = state.forceStringNoCtx(
34
      *args[0], pos,
35
      "while evaluating the first argument to builtins.nixIR.loadIR");
36
37
  std::string pathStr(path);
38
39
  // Try to load the IR bundle
40
  std::ifstream file(pathStr, std::ios::binary | std::ios::ate);
41
  if (!file.is_open()) {
42
    state.error<EvalError>("cannot open IR bundle: %s", pathStr)
43
        .atPos(pos)
44
        .debugThrow();
45
  }
46
47
  // Read magic number to verify it's an IR file
48
  file.seekg(0);
49
  uint32_t magic = 0;
50
  file.read(reinterpret_cast<char *>(&magic), sizeof(magic));
51
52
  if (magic != IR_MAGIC) {
53
    state
54
        .error<EvalError>("not a valid IR bundle: %s (bad magic number)",
55
                          pathStr)
56
        .atPos(pos)
57
        .debugThrow();
58
  }
59
60
  // For now, just return a marker that this is an IR file
61
  // FIXME: complete full VM implementation
62
  auto bindings = state.buildBindings(2);
63
64
  Value *vType = state.allocValue();
65
  vType->mkString("ir-bundle");
66
  bindings.insert(state.symbols.create("type"), vType);
67
68
  Value *vPath = state.allocValue();
69
  vPath->mkString(pathStr);
70
  bindings.insert(state.symbols.create("path"), vPath);
71
72
  v.mkAttrs(bindings.finish());
73
}
74
75
/**
76
 * Compile Nix source to IR on-the-fly
77
 * Usage: builtins.nixIR.compile "{ x = 1; }"
78
 */
79
static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args,
80
                            Value &v) {
81
  auto source = state.forceStringNoCtx(
82
      *args[0], pos,
83
      "while evaluating the first argument to builtins.nixIR.compile");
84
85
  std::string sourceStr(source);
86
87
  try {
88
    // Parse the Nix source
89
    Parser parser;
90
    auto ast = parser.parse(sourceStr, "<inline>");
91
92
    if (!ast) {
93
      state.error<EvalError>("failed to parse Nix expression")
94
          .atPos(pos)
95
          .debugThrow();
96
    }
97
98
    // Generate IR
99
    IRGenerator ir_gen;
100
    auto ir = ir_gen.generate(ast);
101
102
    // For now, return a marker that compilation succeeded
103
    // FIXME: full evaluation
104
    auto bindings = state.buildBindings(2);
105
106
    Value *vType = state.allocValue();
107
    vType->mkString("ir-compiled");
108
    bindings.insert(state.symbols.create("type"), vType);
109
110
    Value *vSource = state.allocValue();
111
    vSource->mkString(sourceStr.substr(0, 50));
112
    bindings.insert(state.symbols.create("source"), vSource);
113
114
    v.mkAttrs(bindings.finish());
115
116
  } catch (const std::exception &e) {
117
    state.error<EvalError>("IR compilation failed: %s", e.what())
118
        .atPos(pos)
119
        .debugThrow();
120
  }
121
}
122
123
/**
124
 * Get information about the IR plugin
125
 * Usage: builtins.nixIR.info
126
 */
127
static void prim_info(EvalState &state, const PosIdx pos, Value **args,
128
                      Value &v) {
129
  auto bindings = state.buildBindings(4);
130
131
  Value *vName = state.allocValue();
132
  vName->mkString("nix-ir-plugin");
133
  bindings.insert(state.symbols.create("name"), vName);
134
135
  Value *vVersion = state.allocValue();
136
  vVersion->mkString("0.1.0-alpha");
137
  bindings.insert(state.symbols.create("version"), vVersion);
138
139
  Value *vPhase = state.allocValue();
140
  vPhase->mkString("phase-4");
141
  bindings.insert(state.symbols.create("phase"), vPhase);
142
143
  Value *vStatus = state.allocValue();
144
  vStatus->mkString("compiler-complete");
145
  bindings.insert(state.symbols.create("status"), vStatus);
146
147
  v.mkAttrs(bindings.finish());
148
}
149
150
// Register primops on plugin load
151
static RegisterPrimOp rp_loadIR({
152
    .name = "__nixIR_loadIR",
153
    .args = {"path"},
154
    .arity = 1,
155
    .doc = R"(
156
      Load a pre-compiled IR bundle from the given path.
157
      Returns an attrset with information about the loaded bundle.
158
159
    )",
160
    .fun = prim_loadIR,
161
});
162
163
static RegisterPrimOp rp_compileNix({
164
    .name = "__nixIR_compile",
165
    .args = {"source"},
166
    .arity = 1,
167
    .doc = R"(
168
      Compile Nix source code to IR on-the-fly.
169
      Returns an attrset with information about the compiled IR.
170
171
    )",
172
    .fun = prim_compileNix,
173
});
174
175
static RegisterPrimOp rp_info({
176
    .name = "__nixIR_info",
177
    .args = {},
178
    .arity = 0,
179
    .doc = R"(
180
      Get information about the IR plugin.
181
      Returns an attrset with plugin name, version, and status.
182
    )",
183
    .fun = prim_info,
184
});
185
186
} // namespace nix_ir_plugin
187
188
// Plugin initialization message
189
__attribute__((constructor)) static void init_plugin() {
190
  std::cerr << "nix-ir-plugin loaded" << std::endl;
191
}