#ifndef NIX_IRC_TYPES_H #define NIX_IRC_TYPES_H #include #include #include #include #include #include #include #include #include namespace nix_irc { constexpr uint32_t IR_MAGIC = 0x4E495258; constexpr uint32_t IR_VERSION = 2; enum class NodeType : uint8_t { CONST_INT = 0x01, CONST_STRING = 0x02, CONST_PATH = 0x03, CONST_BOOL = 0x04, CONST_NULL = 0x05, VAR = 0x10, LAMBDA = 0x20, APP = 0x21, BINARY_OP = 0x22, UNARY_OP = 0x23, ATTRSET = 0x30, SELECT = 0x31, HAS_ATTR = 0x34, WITH = 0x32, IF = 0x40, LET = 0x50, LETREC = 0x51, ASSERT = 0x52, THUNK = 0x60, FORCE = 0x61, ERROR = 0xFF }; enum class BinaryOp : uint8_t { ADD, SUB, MUL, DIV, CONCAT, EQ, NE, LT, GT, LE, GE, AND, OR, IMPL }; enum class UnaryOp : uint8_t { NEG, NOT }; // Forward declare Node for use in shared_ptr class Node; struct ConstIntNode { int64_t value; uint32_t line = 0; ConstIntNode(int64_t v = 0, uint32_t l = 0) : value(v), line(l) {} }; struct ConstStringNode { std::string value; uint32_t line = 0; ConstStringNode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {} }; struct ConstPathNode { std::string value; uint32_t line = 0; ConstPathNode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {} }; struct ConstBoolNode { bool value; uint32_t line = 0; ConstBoolNode(bool v = false, uint32_t l = 0) : value(v), line(l) {} }; struct ConstNullNode { uint32_t line = 0; ConstNullNode(uint32_t l = 0) : line(l) {} }; struct VarNode { uint32_t index = 0; std::optional name; uint32_t line = 0; VarNode(uint32_t idx = 0, std::string n = "", uint32_t l = 0) : index(idx), name(n.empty() ? std::nullopt : std::optional(n)), line(l) {} }; struct LambdaNode { uint32_t arity = 1; std::shared_ptr body; std::optional param_name; bool strict_pattern = true; uint32_t line = 0; LambdaNode(uint32_t a, std::shared_ptr b, uint32_t l = 0); }; struct AppNode { std::shared_ptr func; std::shared_ptr arg; uint32_t line = 0; AppNode(std::shared_ptr f, std::shared_ptr a, uint32_t l = 0); }; struct BinaryOpNode { BinaryOp op; std::shared_ptr left; std::shared_ptr right; uint32_t line = 0; BinaryOpNode(BinaryOp o, std::shared_ptr l, std::shared_ptr r, uint32_t ln = 0); }; struct UnaryOpNode { UnaryOp op; std::shared_ptr operand; uint32_t line = 0; UnaryOpNode(UnaryOp o, std::shared_ptr operand, uint32_t l = 0); }; struct AttrsetNode { std::vector>> attrs; bool recursive = false; uint32_t line = 0; AttrsetNode(bool rec = false, uint32_t l = 0) : recursive(rec), line(l) {} }; struct SelectNode { std::shared_ptr expr; std::shared_ptr attr; std::optional> default_expr; uint32_t line = 0; SelectNode(std::shared_ptr e, std::shared_ptr a, uint32_t l = 0); }; struct HasAttrNode { std::shared_ptr expr; std::shared_ptr attr; uint32_t line = 0; HasAttrNode(std::shared_ptr e, std::shared_ptr a, uint32_t l = 0); }; struct WithNode { std::shared_ptr attrs; std::shared_ptr body; uint32_t line = 0; WithNode(std::shared_ptr a, std::shared_ptr b, uint32_t l = 0); }; struct IfNode { std::shared_ptr cond; std::shared_ptr then_branch; std::shared_ptr else_branch; uint32_t line = 0; IfNode(std::shared_ptr c, std::shared_ptr t, std::shared_ptr e, uint32_t l = 0); }; struct LetNode { std::vector>> bindings; std::shared_ptr body; uint32_t line = 0; LetNode(std::shared_ptr b, uint32_t l = 0); }; struct LetRecNode { std::vector>> bindings; std::shared_ptr body; uint32_t line = 0; LetRecNode(std::shared_ptr b, uint32_t l = 0); }; struct AssertNode { std::shared_ptr cond; std::shared_ptr body; uint32_t line = 0; AssertNode(std::shared_ptr c, std::shared_ptr b, uint32_t l = 0); }; struct ThunkNode { std::shared_ptr expr; uint32_t line = 0; ThunkNode(std::shared_ptr e, uint32_t l = 0); }; struct ForceNode { std::shared_ptr expr; uint32_t line = 0; ForceNode(std::shared_ptr e, uint32_t l = 0); }; // Node wraps a variant for type-safe AST class Node { public: using Variant = std::variant< ConstIntNode, ConstStringNode, ConstPathNode, ConstBoolNode, ConstNullNode, VarNode, LambdaNode, AppNode, BinaryOpNode, UnaryOpNode, AttrsetNode, SelectNode, HasAttrNode, WithNode, IfNode, LetNode, LetRecNode, AssertNode, ThunkNode, ForceNode >; Variant data; template Node(T&& value) : data(std::forward(value)) {} template T* get_if() { return std::get_if(&data); } template const T* get_if() const { return std::get_if(&data); } template bool holds() const { return std::holds_alternative(data); } }; // Constructor implementations inline LambdaNode::LambdaNode(uint32_t a, std::shared_ptr b, uint32_t l) : arity(a), body(b), line(l) {} inline AppNode::AppNode(std::shared_ptr f, std::shared_ptr a, uint32_t l) : func(f), arg(a), line(l) {} inline BinaryOpNode::BinaryOpNode(BinaryOp o, std::shared_ptr l, std::shared_ptr r, uint32_t ln) : op(o), left(l), right(r), line(ln) {} inline UnaryOpNode::UnaryOpNode(UnaryOp o, std::shared_ptr operand, uint32_t l) : op(o), operand(operand), line(l) {} inline SelectNode::SelectNode(std::shared_ptr e, std::shared_ptr a, uint32_t l) : expr(e), attr(a), line(l) {} inline HasAttrNode::HasAttrNode(std::shared_ptr e, std::shared_ptr a, uint32_t l) : expr(e), attr(a), line(l) {} inline WithNode::WithNode(std::shared_ptr a, std::shared_ptr b, uint32_t l) : attrs(a), body(b), line(l) {} inline IfNode::IfNode(std::shared_ptr c, std::shared_ptr t, std::shared_ptr e, uint32_t l) : cond(c), then_branch(t), else_branch(e), line(l) {} inline LetNode::LetNode(std::shared_ptr b, uint32_t l) : body(b), line(l) {} inline LetRecNode::LetRecNode(std::shared_ptr b, uint32_t l) : body(b), line(l) {} inline AssertNode::AssertNode(std::shared_ptr c, std::shared_ptr b, uint32_t l) : cond(c), body(b), line(l) {} inline ThunkNode::ThunkNode(std::shared_ptr e, uint32_t l) : expr(e), line(l) {} inline ForceNode::ForceNode(std::shared_ptr e, uint32_t l) : expr(e), line(l) {} struct SourceFile { std::string path; std::string content; std::shared_ptr ast; }; struct IRModule { uint32_t version = IR_VERSION; std::vector sources; std::vector> imports; std::shared_ptr entry; std::unordered_map string_table; }; } #endif