brewery
notashelf /
feb247f64a93c65c93a80df2d9c810bc72c71386

nixir

public

Import-resolving Nix IR plugin

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.git
src/irc/types.hC372 lines9.2 KB
1
#ifndef NIX_IRC_TYPES_H
2
#define NIX_IRC_TYPES_H
3
4
#include <cstdint>
5
#include <memory>
6
#include <optional>
7
#include <string>
8
#include <unordered_map>
9
#include <utility>
10
#include <variant>
11
#include <vector>
12
13
namespace nix_irc {
14
15
constexpr uint32_t IR_MAGIC = 0x4E495258;
16
constexpr uint32_t IR_VERSION = 3;
17
18
enum class NodeType : uint8_t {
19
  CONST_INT = 0x01,
20
  CONST_FLOAT = 0x06,
21
  CONST_STRING = 0x02,
22
  CONST_PATH = 0x03,
23
  CONST_BOOL = 0x04,
24
  CONST_NULL = 0x05,
25
  CONST_URI = 0x07,
26
  CONST_LOOKUP_PATH = 0x08,
27
  VAR = 0x10,
28
  LAMBDA = 0x20,
29
  APP = 0x21,
30
  BINARY_OP = 0x22,
31
  UNARY_OP = 0x23,
32
  IMPORT = 0x24,
33
  ATTRSET = 0x30,
34
  SELECT = 0x31,
35
  HAS_ATTR = 0x34,
36
  WITH = 0x32,
37
  LIST = 0x33,
38
  IF = 0x40,
39
  LET = 0x50,
40
  LETREC = 0x51,
41
  ASSERT = 0x52,
42
  THUNK = 0x60,
43
  FORCE = 0x61,
44
  LAMBDA_PATTERN = 0x70,
45
  INHERIT = 0x71,
46
  INHERIT_FROM = 0x72,
47
  STRING_INTERPOLATION = 0x73,
48
  BUILTIN_CALL = 0x74,
49
  ERROR = 0xFF
50
};
51
52
enum class BinaryOp : uint8_t {
53
  ADD,
54
  SUB,
55
  MUL,
56
  DIV,
57
  CONCAT,
58
  EQ,
59
  NE,
60
  LT,
61
  GT,
62
  LE,
63
  GE,
64
  AND,
65
  OR,
66
  IMPL,
67
  MERGE
68
};
69
70
enum class UnaryOp : uint8_t { NEG, NOT };
71
72
// Forward declare Node for use in shared_ptr
73
class Node;
74
75
struct ConstIntNode {
76
  int64_t value;
77
  uint32_t line = 0;
78
  ConstIntNode(int64_t v = 0, uint32_t l = 0) : value(v), line(l) {}
79
};
80
81
struct ConstStringNode {
82
  std::string value;
83
  uint32_t line = 0;
84
  ConstStringNode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {}
85
};
86
87
struct ConstPathNode {
88
  std::string value;
89
  uint32_t line = 0;
90
  ConstPathNode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {}
91
};
92
93
struct ConstBoolNode {
94
  bool value;
95
  uint32_t line = 0;
96
  ConstBoolNode(bool v = false, uint32_t l = 0) : value(v), line(l) {}
97
};
98
99
struct ConstNullNode {
100
  uint32_t line = 0;
101
  ConstNullNode(uint32_t l = 0) : line(l) {}
102
};
103
104
struct ConstFloatNode {
105
  double value;
106
  uint32_t line = 0;
107
  ConstFloatNode(double v = 0.0, uint32_t l = 0) : value(v), line(l) {}
108
};
109
110
struct ConstURINode {
111
  std::string value;
112
  uint32_t line = 0;
113
  ConstURINode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {}
114
};
115
116
struct ConstLookupPathNode {
117
  std::string value; // e.g., "nixpkgs" or "nixpkgs/lib"
118
  uint32_t line = 0;
119
  ConstLookupPathNode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {}
120
};
121
122
struct VarNode {
123
  uint32_t index = 0;
124
  std::optional<std::string> name;
125
  uint32_t line = 0;
126
  VarNode(uint32_t idx = 0, std::string n = "", uint32_t l = 0)
127
      : index(idx), name(n.empty() ? std::nullopt : std::optional<std::string>(n)), line(l) {}
128
};
129
130
struct LambdaNode {
131
  uint32_t arity = 1;
132
  std::shared_ptr<Node> body;
133
  std::optional<std::string> param_name;
134
  bool strict_pattern = true;
135
  uint32_t line = 0;
136
  LambdaNode(uint32_t a, std::shared_ptr<Node> b, uint32_t l = 0);
137
};
138
139
struct PatternField {
140
  std::string name;
141
  std::optional<std::shared_ptr<Node>> default_value;
142
143
  PatternField(std::string n, std::optional<std::shared_ptr<Node>> def = std::nullopt)
144
      : name(std::move(n)), default_value(std::move(def)) {}
145
};
146
147
struct LambdaPatternNode {
148
  std::vector<PatternField> required_fields;
149
  std::vector<PatternField> optional_fields;
150
  std::optional<std::string> at_binding;
151
  bool allow_extra;
152
  std::shared_ptr<Node> body;
153
  uint32_t line = 0;
154
155
  LambdaPatternNode(std::shared_ptr<Node> b, uint32_t l = 0);
156
};
157
158
struct AppNode {
159
  std::shared_ptr<Node> func;
160
  std::shared_ptr<Node> arg;
161
  uint32_t line = 0;
162
  AppNode(std::shared_ptr<Node> f, std::shared_ptr<Node> a, uint32_t l = 0);
163
};
164
165
struct BinaryOpNode {
166
  BinaryOp op;
167
  std::shared_ptr<Node> left;
168
  std::shared_ptr<Node> right;
169
  uint32_t line = 0;
170
  BinaryOpNode(BinaryOp o, std::shared_ptr<Node> l, std::shared_ptr<Node> r, uint32_t ln = 0);
171
};
172
173
struct UnaryOpNode {
174
  UnaryOp op;
175
  std::shared_ptr<Node> operand;
176
  uint32_t line = 0;
177
  UnaryOpNode(UnaryOp o, std::shared_ptr<Node> operand, uint32_t l = 0);
178
};
179
180
struct AttrBinding {
181
  std::optional<std::string> static_name; // Static key like "foo"
182
  std::shared_ptr<Node> dynamic_name;     // Dynamic key like ${expr}
183
  std::shared_ptr<Node> value;
184
185
  // Static attribute
186
  AttrBinding(std::string name, std::shared_ptr<Node> val)
187
      : static_name(std::move(name)), value(std::move(val)) {}
188
189
  // Dynamic attribute
190
  AttrBinding(std::shared_ptr<Node> name_expr, std::shared_ptr<Node> val)
191
      : dynamic_name(std::move(name_expr)), value(std::move(val)) {}
192
193
  bool is_dynamic() const { return !static_name.has_value(); }
194
};
195
196
struct AttrsetNode {
197
  std::vector<AttrBinding> attrs;
198
  bool recursive = false;
199
  uint32_t line = 0;
200
  AttrsetNode(bool rec = false, uint32_t l = 0) : recursive(rec), line(l) {}
201
};
202
203
struct SelectNode {
204
  std::shared_ptr<Node> expr;
205
  std::shared_ptr<Node> attr;
206
  std::optional<std::shared_ptr<Node>> default_expr;
207
  uint32_t line = 0;
208
  SelectNode(std::shared_ptr<Node> e, std::shared_ptr<Node> a, uint32_t l = 0);
209
};
210
211
struct HasAttrNode {
212
  std::shared_ptr<Node> expr;
213
  std::shared_ptr<Node> attr;
214
  uint32_t line = 0;
215
  HasAttrNode(std::shared_ptr<Node> e, std::shared_ptr<Node> a, uint32_t l = 0);
216
};
217
218
struct WithNode {
219
  std::shared_ptr<Node> attrs;
220
  std::shared_ptr<Node> body;
221
  uint32_t line = 0;
222
  WithNode(std::shared_ptr<Node> a, std::shared_ptr<Node> b, uint32_t l = 0);
223
};
224
225
struct IfNode {
226
  std::shared_ptr<Node> cond;
227
  std::shared_ptr<Node> then_branch;
228
  std::shared_ptr<Node> else_branch;
229
  uint32_t line = 0;
230
  IfNode(std::shared_ptr<Node> c, std::shared_ptr<Node> t, std::shared_ptr<Node> e, uint32_t l = 0);
231
};
232
233
struct LetNode {
234
  std::vector<std::pair<std::string, std::shared_ptr<Node>>> bindings;
235
  std::shared_ptr<Node> body;
236
  uint32_t line = 0;
237
  LetNode(std::shared_ptr<Node> b, uint32_t l = 0);
238
};
239
240
struct LetRecNode {
241
  std::vector<std::pair<std::string, std::shared_ptr<Node>>> bindings;
242
  std::shared_ptr<Node> body;
243
  uint32_t line = 0;
244
  LetRecNode(std::shared_ptr<Node> b, uint32_t l = 0);
245
};
246
247
struct AssertNode {
248
  std::shared_ptr<Node> cond;
249
  std::shared_ptr<Node> body;
250
  uint32_t line = 0;
251
  AssertNode(std::shared_ptr<Node> c, std::shared_ptr<Node> b, uint32_t l = 0);
252
};
253
254
struct ImportNode {
255
  std::shared_ptr<Node> path; // Path expression to import
256
  uint32_t line = 0;
257
  ImportNode(std::shared_ptr<Node> p, uint32_t l = 0);
258
};
259
260
struct ThunkNode {
261
  std::shared_ptr<Node> expr;
262
  uint32_t line = 0;
263
  ThunkNode(std::shared_ptr<Node> e, uint32_t l = 0);
264
};
265
266
struct ForceNode {
267
  std::shared_ptr<Node> expr;
268
  uint32_t line = 0;
269
  ForceNode(std::shared_ptr<Node> e, uint32_t l = 0);
270
};
271
272
struct ListNode {
273
  std::vector<std::shared_ptr<Node>> elements;
274
  uint32_t line = 0;
275
  ListNode(std::vector<std::shared_ptr<Node>> elems = {}, uint32_t l = 0)
276
      : elements(std::move(elems)), line(l) {}
277
};
278
279
struct InheritNode {
280
  std::vector<std::string> names;
281
  uint32_t line = 0;
282
283
  InheritNode(std::vector<std::string> n = {}, uint32_t l = 0) : names(std::move(n)), line(l) {}
284
};
285
286
struct InheritFromNode {
287
  std::shared_ptr<Node> source;
288
  std::vector<std::string> names;
289
  uint32_t line = 0;
290
291
  InheritFromNode(std::shared_ptr<Node> src, std::vector<std::string> n, uint32_t l = 0)
292
      : source(std::move(src)), names(std::move(n)), line(l) {}
293
};
294
295
struct StringPart {
296
  enum class Type { LITERAL, EXPR };
297
  Type type;
298
  std::string literal;
299
  std::shared_ptr<Node> expr;
300
301
  static StringPart make_literal(std::string lit) {
302
    StringPart part;
303
    part.type = Type::LITERAL;
304
    part.literal = std::move(lit);
305
    return part;
306
  }
307
308
  static StringPart make_expr(std::shared_ptr<Node> e) {
309
    StringPart part;
310
    part.type = Type::EXPR;
311
    part.expr = std::move(e);
312
    return part;
313
  }
314
};
315
316
struct StringInterpolationNode {
317
  std::vector<StringPart> parts;
318
  uint32_t line = 0;
319
320
  StringInterpolationNode(std::vector<StringPart> p = {}, uint32_t l = 0)
321
      : parts(std::move(p)), line(l) {}
322
};
323
324
struct BuiltinCallNode {
325
  std::string builtin_name;
326
  std::vector<std::shared_ptr<Node>> args;
327
  uint32_t line = 0;
328
329
  BuiltinCallNode(std::string name, std::vector<std::shared_ptr<Node>> a = {}, uint32_t l = 0)
330
      : builtin_name(std::move(name)), args(std::move(a)), line(l) {}
331
};
332
333
// Node wraps a variant for type-safe AST
334
class Node {
335
public:
336
  using Variant =
337
      std::variant<ConstIntNode, ConstFloatNode, ConstStringNode, ConstPathNode, ConstBoolNode,
338
                   ConstNullNode, ConstURINode, ConstLookupPathNode, VarNode, LambdaNode, AppNode,
339
                   BinaryOpNode, UnaryOpNode, ImportNode, AttrsetNode, SelectNode, HasAttrNode,
340
                   WithNode, IfNode, LetNode, LetRecNode, AssertNode, ThunkNode, ForceNode,
341
                   ListNode, LambdaPatternNode, InheritNode, InheritFromNode,
342
                   StringInterpolationNode, BuiltinCallNode>;
343
344
  Variant data;
345
346
  template <typename T> Node(T&& value) : data(std::forward<T>(value)) {}
347
348
  template <typename T> T* get_if() { return std::get_if<T>(&data); }
349
350
  template <typename T> const T* get_if() const { return std::get_if<T>(&data); }
351
352
  template <typename T> bool holds() const { return std::holds_alternative<T>(data); }
353
};
354
355
356
357
struct SourceFile {
358
  std::string path;
359
  std::string content;
360
  std::shared_ptr<Node> ast;
361
};
362
363
struct IRModule {
364
  uint32_t version = IR_VERSION;
365
  std::vector<SourceFile> sources;
366
  std::vector<std::pair<std::string, std::string>> imports;
367
  std::shared_ptr<Node> entry;
368
  std::unordered_map<std::string, uint32_t> string_table;
369
};
370
371
} // namespace nix_irc
372
#endif