various: format with clang-format

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ib9abc9d2dcd036d3680c5aa3dc919bfa6a6a6964
This commit is contained in:
raf 2026-02-22 00:17:29 +03:00
commit 98fd1bfc52
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
12 changed files with 1923 additions and 1819 deletions

View file

@ -9,7 +9,7 @@ namespace nix {
class EvalState; class EvalState;
class Value; class Value;
class PosIdx; class PosIdx;
} } // namespace nix
namespace nix_irc { namespace nix_irc {
@ -21,8 +21,7 @@ public:
explicit Evaluator(nix::EvalState& state); explicit Evaluator(nix::EvalState& state);
~Evaluator(); ~Evaluator();
void eval_to_nix(const std::shared_ptr<Node>& ir_node, void eval_to_nix(const std::shared_ptr<Node>& ir_node, nix::Value& result,
nix::Value& result,
IREnvironment* env = nullptr); IREnvironment* env = nullptr);
private: private:
@ -30,6 +29,6 @@ private:
std::unique_ptr<Impl> pImpl; std::unique_ptr<Impl> pImpl;
}; };
} } // namespace nix_irc
#endif #endif

View file

@ -1,7 +1,7 @@
#include "ir_gen.h" #include "ir_gen.h"
#include <algorithm>
#include <stack> #include <stack>
#include <unordered_map> #include <unordered_map>
#include <algorithm>
namespace nix_irc { namespace nix_irc {
@ -31,14 +31,15 @@ void NameResolver::exit_scope() {
} }
void NameResolver::bind(const std::string& name) { void NameResolver::bind(const std::string& name) {
if (pImpl->scopes.empty()) return; if (pImpl->scopes.empty())
return;
uint32_t idx = pImpl->scope_names.back().size(); uint32_t idx = pImpl->scope_names.back().size();
pImpl->scopes.back()[name] = idx; pImpl->scopes.back()[name] = idx;
pImpl->scope_names.back().push_back(name); pImpl->scope_names.back().push_back(name);
} }
uint32_t NameResolver::resolve(const std::string& name) { uint32_t NameResolver::resolve(const std::string& name) {
for (int i = (int)pImpl->scopes.size() - 1; i >= 0; --i) { for (int i = (int) pImpl->scopes.size() - 1; i >= 0; --i) {
auto it = pImpl->scopes[i].find(name); auto it = pImpl->scopes[i].find(name);
if (it != pImpl->scopes[i].end()) { if (it != pImpl->scopes[i].end()) {
uint32_t depth = pImpl->scopes.size() - 1 - i; uint32_t depth = pImpl->scopes.size() - 1 - i;
@ -51,7 +52,8 @@ uint32_t NameResolver::resolve(const std::string& name) {
bool NameResolver::is_bound(const std::string& name) const { bool NameResolver::is_bound(const std::string& name) const {
for (auto it = pImpl->scopes.rbegin(); it != pImpl->scopes.rend(); ++it) { for (auto it = pImpl->scopes.rbegin(); it != pImpl->scopes.rend(); ++it) {
if (it->count(name)) return true; if (it->count(name))
return true;
} }
return false; return false;
} }
@ -74,7 +76,8 @@ struct IRGenerator::Impl {
} }
std::shared_ptr<Node> convert(const std::shared_ptr<Node>& node_ptr) { std::shared_ptr<Node> convert(const std::shared_ptr<Node>& node_ptr) {
if (!node_ptr) return std::make_shared<Node>(ConstNullNode{}); if (!node_ptr)
return std::make_shared<Node>(ConstNullNode{});
const Node& node = *node_ptr; const Node& node = *node_ptr;
@ -216,4 +219,4 @@ std::shared_ptr<Node> IRGenerator::generate(const std::shared_ptr<Node>& ast) {
return pImpl->convert(ast); return pImpl->convert(ast);
} }
} } // namespace nix_irc

View file

@ -2,10 +2,10 @@
#define NIX_IRC_IR_GEN_H #define NIX_IRC_IR_GEN_H
#include "types.h" #include "types.h"
#include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <memory>
namespace nix_irc { namespace nix_irc {
@ -40,6 +40,6 @@ private:
std::unique_ptr<Impl> pImpl; std::unique_ptr<Impl> pImpl;
}; };
} } // namespace nix_irc
#endif #endif

View file

@ -1,11 +1,11 @@
#include <iostream> #include "ir_gen.h"
#include "parser.h" #include "parser.h"
#include "resolver.h" #include "resolver.h"
#include "ir_gen.h"
#include "serializer.h" #include "serializer.h"
#include <cstring>
#include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <cstring>
namespace nix_irc { namespace nix_irc {
@ -127,7 +127,7 @@ int run_decompile(int argc, char** argv) {
} }
} }
} } // namespace nix_irc
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc < 2) { if (argc < 2) {

View file

@ -1,19 +1,20 @@
#include "parser.h" #include "parser.h"
#include <iostream> #include <array>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <memory> #include <memory>
#include <stdexcept>
#include <sstream>
#include <vector>
#include <regex> #include <regex>
#include <array> #include <sstream>
#include <stdexcept>
#include <vector>
namespace nix_irc { namespace nix_irc {
static std::string trim(const std::string& s) { static std::string trim(const std::string& s) {
size_t start = s.find_first_not_of(" \t\n\r"); size_t start = s.find_first_not_of(" \t\n\r");
if (start == std::string::npos) return ""; if (start == std::string::npos)
return "";
size_t end = s.find_last_not_of(" \t\n\r"); size_t end = s.find_last_not_of(" \t\n\r");
return s.substr(start, end - start + 1); return s.substr(start, end - start + 1);
} }
@ -41,7 +42,8 @@ static std::pair<std::string, std::string> run_command(const std::string& cmd) {
std::string error; std::string error;
FILE* pipe = popen(cmd.c_str(), "r"); FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) throw std::runtime_error("popen failed"); if (!pipe)
throw std::runtime_error("popen failed");
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) { while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
result += buffer.data(); result += buffer.data();
@ -56,14 +58,51 @@ static std::pair<std::string, std::string> run_command(const std::string& cmd) {
struct Token { struct Token {
enum Type { enum Type {
LPAREN, RPAREN, LBRACE, RBRACE, LBRACKET, RBRACKET, LPAREN,
IDENT, STRING, STRING_INTERP, PATH, INT, BOOL, RPAREN,
LET, IN, REC, IF, THEN, ELSE, ASSERT, WITH, INHERIT, LBRACE,
DOT, SEMICOLON, COLON, EQUALS, AT, COMMA, QUESTION, ELLIPSIS, RBRACE,
LBRACKET,
RBRACKET,
IDENT,
STRING,
STRING_INTERP,
PATH,
INT,
BOOL,
LET,
IN,
REC,
IF,
THEN,
ELSE,
ASSERT,
WITH,
INHERIT,
DOT,
SEMICOLON,
COLON,
EQUALS,
AT,
COMMA,
QUESTION,
ELLIPSIS,
// Operators // Operators
PLUS, MINUS, STAR, SLASH, CONCAT, PLUS,
EQEQ, NE, LT, GT, LE, GE, MINUS,
AND, OR, IMPL, NOT, STAR,
SLASH,
CONCAT,
EQEQ,
NE,
LT,
GT,
LE,
GE,
AND,
OR,
IMPL,
NOT,
EOF_ EOF_
} type; } type;
std::string value; std::string value;
@ -76,98 +115,123 @@ public:
Lexer(const std::string& input) : input(input), pos(0), line(1), col(1) {} Lexer(const std::string& input) : input(input), pos(0), line(1), col(1) {}
std::vector<Token> tokenize() { std::vector<Token> tokenize() {
#define TOKEN(t) Token{Token::t, "", line, col} #define TOKEN(t) \
Token { Token::t, "", line, col }
while (pos < input.size()) { while (pos < input.size()) {
skip_whitespace(); skip_whitespace();
if (pos >= input.size()) break; if (pos >= input.size())
break;
char c = input[pos]; char c = input[pos];
if (c == '(') { emit(TOKEN(LPAREN)); } if (c == '(') {
else if (c == ')') { emit(TOKEN(RPAREN)); } emit(TOKEN(LPAREN));
else if (c == '{') { emit(TOKEN(LBRACE)); } } else if (c == ')') {
else if (c == '}') { emit(TOKEN(RBRACE)); } emit(TOKEN(RPAREN));
else if (c == '[') { emit(TOKEN(LBRACKET)); } } else if (c == '{') {
else if (c == ']') { emit(TOKEN(RBRACKET)); } emit(TOKEN(LBRACE));
else if (c == ';') { emit(TOKEN(SEMICOLON)); } } else if (c == '}') {
else if (c == ':') { emit(TOKEN(COLON)); } emit(TOKEN(RBRACE));
else if (c == '@') { emit(TOKEN(AT)); } } else if (c == '[') {
else if (c == ',') { emit(TOKEN(COMMA)); } emit(TOKEN(LBRACKET));
else if (c == '"') { tokenize_string(); } } else if (c == ']') {
emit(TOKEN(RBRACKET));
} else if (c == ';') {
emit(TOKEN(SEMICOLON));
} else if (c == ':') {
emit(TOKEN(COLON));
} else if (c == '@') {
emit(TOKEN(AT));
} else if (c == ',') {
emit(TOKEN(COMMA));
} else if (c == '"') {
tokenize_string();
}
// Two-char operators // Two-char operators
else if (c == '=' && pos + 1 < input.size() && input[pos + 1] == '=') { else if (c == '=' && pos + 1 < input.size() && input[pos + 1] == '=') {
tokens.push_back(TOKEN(EQEQ)); tokens.push_back(TOKEN(EQEQ));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '=') { emit(TOKEN(EQUALS)); } } else if (c == '=') {
else if (c == '!' && pos + 1 < input.size() && input[pos + 1] == '=') { emit(TOKEN(EQUALS));
} else if (c == '!' && pos + 1 < input.size() && input[pos + 1] == '=') {
tokens.push_back(TOKEN(NE)); tokens.push_back(TOKEN(NE));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '<' && pos + 1 < input.size() && input[pos + 1] == '=') { } else if (c == '<' && pos + 1 < input.size() && input[pos + 1] == '=') {
tokens.push_back(TOKEN(LE)); tokens.push_back(TOKEN(LE));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '>' && pos + 1 < input.size() && input[pos + 1] == '=') { } else if (c == '>' && pos + 1 < input.size() && input[pos + 1] == '=') {
tokens.push_back(TOKEN(GE)); tokens.push_back(TOKEN(GE));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '+' && pos + 1 < input.size() && input[pos + 1] == '+') { } else if (c == '+' && pos + 1 < input.size() && input[pos + 1] == '+') {
tokens.push_back(TOKEN(CONCAT)); tokens.push_back(TOKEN(CONCAT));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '&' && pos + 1 < input.size() && input[pos + 1] == '&') { } else if (c == '&' && pos + 1 < input.size() && input[pos + 1] == '&') {
tokens.push_back(TOKEN(AND)); tokens.push_back(TOKEN(AND));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '|' && pos + 1 < input.size() && input[pos + 1] == '|') { } else if (c == '|' && pos + 1 < input.size() && input[pos + 1] == '|') {
tokens.push_back(TOKEN(OR)); tokens.push_back(TOKEN(OR));
pos += 2; col += 2; pos += 2;
} col += 2;
else if (c == '-' && pos + 1 < input.size() && input[pos + 1] == '>') { } else if (c == '-' && pos + 1 < input.size() && input[pos + 1] == '>') {
tokens.push_back(TOKEN(IMPL)); tokens.push_back(TOKEN(IMPL));
pos += 2; col += 2; pos += 2;
col += 2;
} }
// Single-char operators // Single-char operators
else if (c == '+') { emit(TOKEN(PLUS)); } else if (c == '+') {
else if (c == '*') { emit(TOKEN(STAR)); } emit(TOKEN(PLUS));
else if (c == '/') { } else if (c == '*') {
emit(TOKEN(STAR));
} else if (c == '/') {
// Check if it's a path or division // Check if it's a path or division
if (pos + 1 < input.size() && (isalnum(input[pos + 1]) || input[pos + 1] == '.')) { if (pos + 1 < input.size() && (isalnum(input[pos + 1]) || input[pos + 1] == '.')) {
tokenize_path(); tokenize_path();
} else { } else {
emit(TOKEN(SLASH)); emit(TOKEN(SLASH));
} }
} } else if (c == '<') {
else if (c == '<') { emit(TOKEN(LT)); } emit(TOKEN(LT));
else if (c == '>') { emit(TOKEN(GT)); } } else if (c == '>') {
else if (c == '!') { emit(TOKEN(NOT)); } emit(TOKEN(GT));
else if (c == '.') { } else if (c == '!') {
emit(TOKEN(NOT));
} else if (c == '.') {
// Check for ellipsis (...) // Check for ellipsis (...)
if (pos + 2 < input.size() && input[pos + 1] == '.' && input[pos + 2] == '.') { if (pos + 2 < input.size() && input[pos + 1] == '.' && input[pos + 2] == '.') {
tokens.push_back(TOKEN(ELLIPSIS)); tokens.push_back(TOKEN(ELLIPSIS));
pos += 3; col += 3; pos += 3;
col += 3;
} else { } else {
emit(TOKEN(DOT)); emit(TOKEN(DOT));
} }
} } else if (c == '?') {
else if (c == '?') { emit(TOKEN(QUESTION)); } emit(TOKEN(QUESTION));
else if (c == '-') { } else if (c == '-') {
// Check if it's a negative number or minus operator // Check if it's a negative number or minus operator
if (pos + 1 < input.size() && isdigit(input[pos + 1])) { if (pos + 1 < input.size() && isdigit(input[pos + 1])) {
tokenize_int(); tokenize_int();
} else { } else {
emit(TOKEN(MINUS)); emit(TOKEN(MINUS));
} }
} else if (isdigit(c)) {
tokenize_int();
} else if (isalpha(c) || c == '_') {
tokenize_ident();
} else {
pos++;
col++;
} }
else if (isdigit(c)) { tokenize_int(); }
else if (isalpha(c) || c == '_') { tokenize_ident(); }
else { pos++; col++; }
} }
tokens.push_back({Token::EOF_, "", line, col}); tokens.push_back({Token::EOF_, "", line, col});
#undef TOKEN #undef TOKEN
return tokens; return tokens;
} }
@ -188,11 +252,16 @@ private:
while (pos < input.size()) { while (pos < input.size()) {
char c = input[pos]; char c = input[pos];
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (c == '\n') { line++; col = 1; } if (c == '\n') {
else { col++; } line++;
col = 1;
} else {
col++;
}
pos++; pos++;
} else if (c == '#') { } else if (c == '#') {
while (pos < input.size() && input[pos] != '\n') pos++; while (pos < input.size() && input[pos] != '\n')
pos++;
} else { } else {
break; break;
} }
@ -208,13 +277,27 @@ private:
if (input[pos] == '\\' && pos + 1 < input.size()) { if (input[pos] == '\\' && pos + 1 < input.size()) {
pos++; pos++;
switch (input[pos]) { switch (input[pos]) {
case 'n': s += '\n'; break; case 'n':
case 't': s += '\t'; break; s += '\n';
case 'r': s += '\r'; break; break;
case '"': s += '"'; break; case 't':
case '\\': s += '\\'; break; s += '\t';
case '$': s += '$'; break; // Escaped $ break;
default: s += input[pos]; break; case 'r':
s += '\r';
break;
case '"':
s += '"';
break;
case '\\':
s += '\\';
break;
case '$':
s += '$';
break; // Escaped $
default:
s += input[pos];
break;
} }
pos++; pos++;
} else if (input[pos] == '$' && pos + 1 < input.size() && input[pos + 1] == '{') { } else if (input[pos] == '$' && pos + 1 < input.size() && input[pos + 1] == '{') {
@ -236,10 +319,8 @@ private:
void tokenize_path() { void tokenize_path() {
size_t start = pos; size_t start = pos;
while (pos < input.size() && !isspace(input[pos]) && while (pos < input.size() && !isspace(input[pos]) && input[pos] != '(' && input[pos] != ')' &&
input[pos] != '(' && input[pos] != ')' && input[pos] != '{' && input[pos] != '}' && input[pos] != '[' && input[pos] != ']') {
input[pos] != '{' && input[pos] != '}' &&
input[pos] != '[' && input[pos] != ']') {
pos++; pos++;
} }
std::string path = input.substr(start, pos - start); std::string path = input.substr(start, pos - start);
@ -249,8 +330,10 @@ private:
void tokenize_int() { void tokenize_int() {
size_t start = pos; size_t start = pos;
if (input[pos] == '-') pos++; if (input[pos] == '-')
while (pos < input.size() && isdigit(input[pos])) pos++; pos++;
while (pos < input.size() && isdigit(input[pos]))
pos++;
std::string num = input.substr(start, pos - start); std::string num = input.substr(start, pos - start);
tokens.push_back({Token::INT, num, line, col}); tokens.push_back({Token::INT, num, line, col});
col += num.size(); col += num.size();
@ -258,21 +341,33 @@ private:
void tokenize_ident() { void tokenize_ident() {
size_t start = pos; size_t start = pos;
while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-')) pos++; while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-'))
pos++;
std::string ident = input.substr(start, pos - start); std::string ident = input.substr(start, pos - start);
Token::Type type = Token::IDENT; Token::Type type = Token::IDENT;
if (ident == "let") type = Token::LET; if (ident == "let")
else if (ident == "in") type = Token::IN; type = Token::LET;
else if (ident == "rec") type = Token::REC; else if (ident == "in")
else if (ident == "if") type = Token::IF; type = Token::IN;
else if (ident == "then") type = Token::THEN; else if (ident == "rec")
else if (ident == "else") type = Token::ELSE; type = Token::REC;
else if (ident == "assert") type = Token::ASSERT; else if (ident == "if")
else if (ident == "with") type = Token::WITH; type = Token::IF;
else if (ident == "inherit") type = Token::INHERIT; else if (ident == "then")
else if (ident == "true") type = Token::BOOL; type = Token::THEN;
else if (ident == "false") type = Token::BOOL; else if (ident == "else")
type = Token::ELSE;
else if (ident == "assert")
type = Token::ASSERT;
else if (ident == "with")
type = Token::WITH;
else if (ident == "inherit")
type = Token::INHERIT;
else if (ident == "true")
type = Token::BOOL;
else if (ident == "false")
type = Token::BOOL;
tokens.push_back({type, ident, line, col}); tokens.push_back({type, ident, line, col});
col += ident.size(); col += ident.size();
@ -286,7 +381,8 @@ public:
std::string current_file; std::string current_file;
const Token& current() { const Token& current() {
if (pos < tokens.size()) return tokens[pos]; if (pos < tokens.size())
return tokens[pos];
static Token eof{Token::EOF_, "", 0, 0}; static Token eof{Token::EOF_, "", 0, 0};
return eof; return eof;
} }
@ -303,8 +399,8 @@ public:
bool expect(Token::Type type) { bool expect(Token::Type type) {
if (current().type != type) { if (current().type != type) {
std::cerr << "Expected token " << type << " but got " << current().type std::cerr << "Expected token " << type << " but got " << current().type << " at "
<< " at " << current().line << ":" << current().col << "\n"; << current().line << ":" << current().col << "\n";
return false; return false;
} }
advance(); advance();
@ -314,43 +410,74 @@ public:
// Get operator precedence (higher = tighter binding) // Get operator precedence (higher = tighter binding)
int get_precedence(Token::Type type) { int get_precedence(Token::Type type) {
switch (type) { switch (type) {
case Token::OR: return 1; case Token::OR:
case Token::AND: return 2; return 1;
case Token::IMPL: return 3; case Token::AND:
case Token::EQEQ: case Token::NE: return 4; return 2;
case Token::LT: case Token::GT: case Token::LE: case Token::GE: return 5; case Token::IMPL:
case Token::CONCAT: return 6; return 3;
case Token::PLUS: case Token::MINUS: return 7; case Token::EQEQ:
case Token::STAR: case Token::SLASH: return 8; case Token::NE:
default: return 0; return 4;
case Token::LT:
case Token::GT:
case Token::LE:
case Token::GE:
return 5;
case Token::CONCAT:
return 6;
case Token::PLUS:
case Token::MINUS:
return 7;
case Token::STAR:
case Token::SLASH:
return 8;
default:
return 0;
} }
} }
// Convert token type to binary operator // Convert token type to binary operator
BinaryOp token_to_binop(Token::Type type) { BinaryOp token_to_binop(Token::Type type) {
switch (type) { switch (type) {
case Token::PLUS: return BinaryOp::ADD; case Token::PLUS:
case Token::MINUS: return BinaryOp::SUB; return BinaryOp::ADD;
case Token::STAR: return BinaryOp::MUL; case Token::MINUS:
case Token::SLASH: return BinaryOp::DIV; return BinaryOp::SUB;
case Token::CONCAT: return BinaryOp::CONCAT; case Token::STAR:
case Token::EQEQ: return BinaryOp::EQ; return BinaryOp::MUL;
case Token::NE: return BinaryOp::NE; case Token::SLASH:
case Token::LT: return BinaryOp::LT; return BinaryOp::DIV;
case Token::GT: return BinaryOp::GT; case Token::CONCAT:
case Token::LE: return BinaryOp::LE; return BinaryOp::CONCAT;
case Token::GE: return BinaryOp::GE; case Token::EQEQ:
case Token::AND: return BinaryOp::AND; return BinaryOp::EQ;
case Token::OR: return BinaryOp::OR; case Token::NE:
case Token::IMPL: return BinaryOp::IMPL; return BinaryOp::NE;
default: throw std::runtime_error("Invalid binary operator"); case Token::LT:
return BinaryOp::LT;
case Token::GT:
return BinaryOp::GT;
case Token::LE:
return BinaryOp::LE;
case Token::GE:
return BinaryOp::GE;
case Token::AND:
return BinaryOp::AND;
case Token::OR:
return BinaryOp::OR;
case Token::IMPL:
return BinaryOp::IMPL;
default:
throw std::runtime_error("Invalid binary operator");
} }
} }
std::shared_ptr<Node> parse_expr() { std::shared_ptr<Node> parse_expr() {
// Try to parse lambda // Try to parse lambda
auto lambda = try_parse_lambda(); auto lambda = try_parse_lambda();
if (lambda) return lambda; if (lambda)
return lambda;
if (consume(Token::IF)) { if (consume(Token::IF)) {
auto cond = parse_expr(); auto cond = parse_expr();
@ -393,9 +520,7 @@ public:
return parse_expr1(); return parse_expr1();
} }
std::shared_ptr<Node> parse_expr1() { std::shared_ptr<Node> parse_expr1() { return parse_binary_op(0); }
return parse_binary_op(0);
}
// Precedence climbing for binary operators // Precedence climbing for binary operators
std::shared_ptr<Node> parse_binary_op(int min_prec) { std::shared_ptr<Node> parse_binary_op(int min_prec) {
@ -403,17 +528,14 @@ public:
while (true) { while (true) {
int prec = get_precedence(current().type); int prec = get_precedence(current().type);
if (prec == 0 || prec < min_prec) break; if (prec == 0 || prec < min_prec)
break;
Token op_token = current(); Token op_token = current();
advance(); advance();
auto right = parse_binary_op(prec + 1); auto right = parse_binary_op(prec + 1);
left = std::make_shared<Node>(BinaryOpNode( left = std::make_shared<Node>(BinaryOpNode(token_to_binop(op_token.type), left, right));
token_to_binop(op_token.type),
left,
right
));
} }
return left; return left;
@ -440,16 +562,16 @@ public:
Token n = current(); Token n = current();
expect(Token::IDENT); expect(Token::IDENT);
auto a = std::make_shared<Node>(ConstStringNode(n.value)); auto a = std::make_shared<Node>(ConstStringNode(n.value));
curr->attr = std::make_shared<Node>(AppNode( curr->attr =
std::make_shared<Node>(AppNode(curr->attr, a)), std::make_shared<Node>(AppNode(std::make_shared<Node>(AppNode(curr->attr, a)),
std::make_shared<Node>(ConstNullNode()) std::make_shared<Node>(ConstNullNode())));
));
} }
} }
} }
return result; return result;
} else if (consume(Token::LBRACE)) { } else if (consume(Token::LBRACE)) {
auto result = std::make_shared<Node>(SelectNode(left, std::make_shared<Node>(ConstStringNode(name.value)))); auto result = std::make_shared<Node>(
SelectNode(left, std::make_shared<Node>(ConstStringNode(name.value))));
parse_expr_attrs(result); parse_expr_attrs(result);
expect(Token::RBRACE); expect(Token::RBRACE);
return result; return result;
@ -576,10 +698,8 @@ public:
if (source) { if (source) {
// inherit (expr) x → x = expr.x // inherit (expr) x → x = expr.x
auto select = std::make_shared<Node>(SelectNode( auto select = std::make_shared<Node>(
source, SelectNode(source, std::make_shared<Node>(ConstStringNode(name.value))));
std::make_shared<Node>(ConstStringNode(name.value))
));
attrs.attrs.push_back({name.value, select}); attrs.attrs.push_back({name.value, select});
} else { } else {
// inherit x → x = x // inherit x → x = x
@ -607,8 +727,10 @@ public:
} }
} }
if (consume(Token::COMMA)) continue; if (consume(Token::COMMA))
if (consume(Token::SEMICOLON)) continue; continue;
if (consume(Token::SEMICOLON))
continue;
// If we get here and haven't handled the token, break // If we get here and haven't handled the token, break
if (current().type != Token::RBRACE && current().type != Token::EOF_) { if (current().type != Token::RBRACE && current().type != Token::EOF_) {
@ -630,18 +752,15 @@ public:
std::vector<std::shared_ptr<Node>> elements; std::vector<std::shared_ptr<Node>> elements;
while (current().type != Token::RBRACKET) { while (current().type != Token::RBRACKET) {
elements.push_back(parse_expr()); elements.push_back(parse_expr());
if (!consume(Token::COMMA)) break; if (!consume(Token::COMMA))
break;
} }
expect(Token::RBRACKET); expect(Token::RBRACKET);
for (auto it = elements.rbegin(); it != elements.rend(); ++it) { for (auto it = elements.rbegin(); it != elements.rend(); ++it) {
list = std::make_shared<Node>(AppNode( list = std::make_shared<Node>(AppNode(
std::make_shared<Node>(AppNode( std::make_shared<Node>(AppNode(std::make_shared<Node>(VarNode(0, "__list")), *it)),
std::make_shared<Node>(VarNode(0, "__list")), list));
*it
)),
list
));
} }
return list; return list;
@ -666,10 +785,8 @@ public:
if (source) { if (source) {
// inherit (expr) x → x = expr.x // inherit (expr) x → x = expr.x
auto select = std::make_shared<Node>(SelectNode( auto select = std::make_shared<Node>(
source, SelectNode(source, std::make_shared<Node>(ConstStringNode(name.value))));
std::make_shared<Node>(ConstStringNode(name.value))
));
bindings.push_back({name.value, select}); bindings.push_back({name.value, select});
} else { } else {
// inherit x → x = x // inherit x → x = x
@ -682,7 +799,8 @@ public:
continue; continue;
} }
if (current().type != Token::IDENT) break; if (current().type != Token::IDENT)
break;
Token key = current(); Token key = current();
advance(); advance();
@ -696,7 +814,8 @@ public:
bindings.push_back({key.value, value}); bindings.push_back({key.value, value});
} }
if (!consume(Token::SEMICOLON)) break; if (!consume(Token::SEMICOLON))
break;
} }
} }
@ -739,7 +858,8 @@ public:
while (current().type != Token::RBRACE && current().type != Token::EOF_) { while (current().type != Token::RBRACE && current().type != Token::EOF_) {
if (consume(Token::ELLIPSIS)) { if (consume(Token::ELLIPSIS)) {
has_ellipsis = true; has_ellipsis = true;
if (consume(Token::COMMA)) continue; if (consume(Token::COMMA))
continue;
break; break;
} }
@ -757,7 +877,8 @@ public:
fields.push_back(field); fields.push_back(field);
if (consume(Token::COMMA)) continue; if (consume(Token::COMMA))
continue;
break; break;
} else { } else {
break; break;
@ -789,22 +910,14 @@ public:
for (const auto& field : fields) { for (const auto& field : fields) {
// Create arg.field selection // Create arg.field selection
auto select = std::make_shared<Node>(SelectNode( auto select = std::make_shared<Node>(
arg_var, SelectNode(arg_var, std::make_shared<Node>(ConstStringNode(field.name))));
std::make_shared<Node>(ConstStringNode(field.name))
));
if (field.default_val) { if (field.default_val) {
// if arg ? field then arg.field else default // if arg ? field then arg.field else default
auto has_attr = std::make_shared<Node>(HasAttrNode( auto has_attr = std::make_shared<Node>(
arg_var, HasAttrNode(arg_var, std::make_shared<Node>(ConstStringNode(field.name))));
std::make_shared<Node>(ConstStringNode(field.name)) auto if_node = std::make_shared<Node>(IfNode(has_attr, select, *field.default_val));
));
auto if_node = std::make_shared<Node>(IfNode(
has_attr,
select,
*field.default_val
));
bindings.push_back({field.name, if_node}); bindings.push_back({field.name, if_node});
} else { } else {
bindings.push_back({field.name, select}); bindings.push_back({field.name, select});
@ -864,13 +977,14 @@ public:
depth--; depth--;
} }
} else { } else {
if (raw[i] == string_quote && (i == 0 || raw[i-1] != '\\')) { if (raw[i] == string_quote && (i == 0 || raw[i - 1] != '\\')) {
in_string = false; in_string = false;
} else if (raw[i] == '\\') { } else if (raw[i] == '\\') {
i++; i++;
} }
} }
if (depth > 0) i++; if (depth > 0)
i++;
} }
if (depth > 0) { if (depth > 0) {
@ -947,4 +1061,4 @@ std::shared_ptr<Node> Parser::parse_file(const std::string& path) {
return parse(content, path); return parse(content, path);
} }
} } // namespace nix_irc

View file

@ -2,8 +2,8 @@
#define NIX_IRC_PARSER_H #define NIX_IRC_PARSER_H
#include "types.h" #include "types.h"
#include <string>
#include <memory> #include <memory>
#include <string>
namespace nix_irc { namespace nix_irc {
@ -20,6 +20,6 @@ private:
std::unique_ptr<Impl> pImpl; std::unique_ptr<Impl> pImpl;
}; };
} } // namespace nix_irc
#endif #endif

View file

@ -1,10 +1,10 @@
#include "resolver.h" #include "resolver.h"
#include "parser.h" #include "parser.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem> #include <filesystem>
#include <fstream>
#include <iostream>
#include <regex> #include <regex>
#include <sstream>
namespace nix_irc { namespace nix_irc {
@ -22,17 +22,20 @@ struct Resolver::Impl {
fs::path p(path); fs::path p(path);
if (p.is_absolute()) { if (p.is_absolute()) {
if (fs::exists(p)) return path; if (fs::exists(p))
return path;
return ""; return "";
} }
fs::path from_dir = fs::path(from_file).parent_path(); fs::path from_dir = fs::path(from_file).parent_path();
fs::path candidate = from_dir / p; fs::path candidate = from_dir / p;
if (fs::exists(candidate)) return candidate.string(); if (fs::exists(candidate))
return candidate.string();
for (const auto& search : config.search_paths) { for (const auto& search : config.search_paths) {
candidate = fs::path(search) / p; candidate = fs::path(search) / p;
if (fs::exists(candidate)) return candidate.string(); if (fs::exists(candidate))
return candidate.string();
} }
return ""; return "";
@ -89,7 +92,7 @@ ImportResult Resolver::resolve_import(const Node& import_node, const std::string
std::vector<std::string> Resolver::get_resolved_files() const { std::vector<std::string> Resolver::get_resolved_files() const {
std::vector<std::string> files; std::vector<std::string> files;
for (const auto& [orig, resolved] : pImpl->resolved_imports) { for (const auto& [orig, resolved] : pImpl->resolved_imports) {
(void)orig; (void) orig;
files.push_back(resolved); files.push_back(resolved);
} }
return files; return files;
@ -108,4 +111,4 @@ std::string normalize_path(const std::string& path) {
return fs::absolute(p).string(); return fs::absolute(p).string();
} }
} } // namespace nix_irc

View file

@ -2,10 +2,10 @@
#define NIX_IRC_RESOLVER_H #define NIX_IRC_RESOLVER_H
#include "types.h" #include "types.h"
#include <string>
#include <vector>
#include <unordered_set>
#include <filesystem> #include <filesystem>
#include <string>
#include <unordered_set>
#include <vector>
namespace nix_irc { namespace nix_irc {
@ -43,6 +43,6 @@ private:
bool is_static_import(const Node& node); bool is_static_import(const Node& node);
std::string normalize_path(const std::string& path); std::string normalize_path(const std::string& path);
} } // namespace nix_irc
#endif #endif

View file

@ -1,7 +1,7 @@
#include "serializer.h" #include "serializer.h"
#include <cstring> #include <cstring>
#include <sstream>
#include <iostream> #include <iostream>
#include <sstream>
namespace nix_irc { namespace nix_irc {
@ -21,9 +21,7 @@ struct Serializer::Impl {
} }
} }
void write_u8(uint8_t val) { void write_u8(uint8_t val) { buffer.push_back(val); }
buffer.push_back(val);
}
void write_string(const std::string& str) { void write_string(const std::string& str) {
write_u32(str.size()); write_u32(str.size());
@ -31,24 +29,42 @@ struct Serializer::Impl {
} }
NodeType get_node_type(const Node& node) { NodeType get_node_type(const Node& node) {
if (node.holds<ConstIntNode>()) return NodeType::CONST_INT; if (node.holds<ConstIntNode>())
if (node.holds<ConstStringNode>()) return NodeType::CONST_STRING; return NodeType::CONST_INT;
if (node.holds<ConstPathNode>()) return NodeType::CONST_PATH; if (node.holds<ConstStringNode>())
if (node.holds<ConstBoolNode>()) return NodeType::CONST_BOOL; return NodeType::CONST_STRING;
if (node.holds<ConstNullNode>()) return NodeType::CONST_NULL; if (node.holds<ConstPathNode>())
if (node.holds<VarNode>()) return NodeType::VAR; return NodeType::CONST_PATH;
if (node.holds<LambdaNode>()) return NodeType::LAMBDA; if (node.holds<ConstBoolNode>())
if (node.holds<AppNode>()) return NodeType::APP; return NodeType::CONST_BOOL;
if (node.holds<BinaryOpNode>()) return NodeType::BINARY_OP; if (node.holds<ConstNullNode>())
if (node.holds<UnaryOpNode>()) return NodeType::UNARY_OP; return NodeType::CONST_NULL;
if (node.holds<AttrsetNode>()) return NodeType::ATTRSET; if (node.holds<VarNode>())
if (node.holds<SelectNode>()) return NodeType::SELECT; return NodeType::VAR;
if (node.holds<HasAttrNode>()) return NodeType::HAS_ATTR; if (node.holds<LambdaNode>())
if (node.holds<WithNode>()) return NodeType::WITH; return NodeType::LAMBDA;
if (node.holds<IfNode>()) return NodeType::IF; if (node.holds<AppNode>())
if (node.holds<LetNode>()) return NodeType::LET; return NodeType::APP;
if (node.holds<LetRecNode>()) return NodeType::LETREC; if (node.holds<BinaryOpNode>())
if (node.holds<AssertNode>()) return NodeType::ASSERT; return NodeType::BINARY_OP;
if (node.holds<UnaryOpNode>())
return NodeType::UNARY_OP;
if (node.holds<AttrsetNode>())
return NodeType::ATTRSET;
if (node.holds<SelectNode>())
return NodeType::SELECT;
if (node.holds<HasAttrNode>())
return NodeType::HAS_ATTR;
if (node.holds<WithNode>())
return NodeType::WITH;
if (node.holds<IfNode>())
return NodeType::IF;
if (node.holds<LetNode>())
return NodeType::LET;
if (node.holds<LetRecNode>())
return NodeType::LETREC;
if (node.holds<AssertNode>())
return NodeType::ASSERT;
return NodeType::ERROR; return NodeType::ERROR;
} }
@ -74,27 +90,36 @@ struct Serializer::Impl {
write_u32(n->index); write_u32(n->index);
} else if (auto* n = node.get_if<LambdaNode>()) { } else if (auto* n = node.get_if<LambdaNode>()) {
write_u32(n->arity); write_u32(n->arity);
if (n->body) write_node(*n->body); if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<AppNode>()) { } else if (auto* n = node.get_if<AppNode>()) {
if (n->func) write_node(*n->func); if (n->func)
if (n->arg) write_node(*n->arg); write_node(*n->func);
if (n->arg)
write_node(*n->arg);
} else if (auto* n = node.get_if<BinaryOpNode>()) { } else if (auto* n = node.get_if<BinaryOpNode>()) {
write_u8(static_cast<uint8_t>(n->op)); write_u8(static_cast<uint8_t>(n->op));
if (n->left) write_node(*n->left); if (n->left)
if (n->right) write_node(*n->right); write_node(*n->left);
if (n->right)
write_node(*n->right);
} else if (auto* n = node.get_if<UnaryOpNode>()) { } else if (auto* n = node.get_if<UnaryOpNode>()) {
write_u8(static_cast<uint8_t>(n->op)); write_u8(static_cast<uint8_t>(n->op));
if (n->operand) write_node(*n->operand); if (n->operand)
write_node(*n->operand);
} else if (auto* n = node.get_if<AttrsetNode>()) { } else if (auto* n = node.get_if<AttrsetNode>()) {
write_u8(n->recursive ? 1 : 0); write_u8(n->recursive ? 1 : 0);
write_u32(n->attrs.size()); write_u32(n->attrs.size());
for (const auto& [key, val] : n->attrs) { for (const auto& [key, val] : n->attrs) {
write_string(key); write_string(key);
if (val) write_node(*val); if (val)
write_node(*val);
} }
} else if (auto* n = node.get_if<SelectNode>()) { } else if (auto* n = node.get_if<SelectNode>()) {
if (n->expr) write_node(*n->expr); if (n->expr)
if (n->attr) write_node(*n->attr); write_node(*n->expr);
if (n->attr)
write_node(*n->attr);
if (n->default_expr && *n->default_expr) { if (n->default_expr && *n->default_expr) {
write_u8(1); write_u8(1);
write_node(**n->default_expr); write_node(**n->default_expr);
@ -102,32 +127,45 @@ struct Serializer::Impl {
write_u8(0); write_u8(0);
} }
} else if (auto* n = node.get_if<HasAttrNode>()) { } else if (auto* n = node.get_if<HasAttrNode>()) {
if (n->expr) write_node(*n->expr); if (n->expr)
if (n->attr) write_node(*n->attr); write_node(*n->expr);
if (n->attr)
write_node(*n->attr);
} else if (auto* n = node.get_if<WithNode>()) { } else if (auto* n = node.get_if<WithNode>()) {
if (n->attrs) write_node(*n->attrs); if (n->attrs)
if (n->body) write_node(*n->body); write_node(*n->attrs);
if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<IfNode>()) { } else if (auto* n = node.get_if<IfNode>()) {
if (n->cond) write_node(*n->cond); if (n->cond)
if (n->then_branch) write_node(*n->then_branch); write_node(*n->cond);
if (n->else_branch) write_node(*n->else_branch); if (n->then_branch)
write_node(*n->then_branch);
if (n->else_branch)
write_node(*n->else_branch);
} else if (auto* n = node.get_if<LetNode>()) { } else if (auto* n = node.get_if<LetNode>()) {
write_u32(n->bindings.size()); write_u32(n->bindings.size());
for (const auto& [key, val] : n->bindings) { for (const auto& [key, val] : n->bindings) {
write_string(key); write_string(key);
if (val) write_node(*val); if (val)
write_node(*val);
} }
if (n->body) write_node(*n->body); if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<LetRecNode>()) { } else if (auto* n = node.get_if<LetRecNode>()) {
write_u32(n->bindings.size()); write_u32(n->bindings.size());
for (const auto& [key, val] : n->bindings) { for (const auto& [key, val] : n->bindings) {
write_string(key); write_string(key);
if (val) write_node(*val); if (val)
write_node(*val);
} }
if (n->body) write_node(*n->body); if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<AssertNode>()) { } else if (auto* n = node.get_if<AssertNode>()) {
if (n->cond) write_node(*n->cond); if (n->cond)
if (n->body) write_node(*n->body); write_node(*n->cond);
if (n->body)
write_node(*n->body);
} }
} }
}; };
@ -182,9 +220,9 @@ struct Deserializer::Impl {
uint32_t read_u32() { uint32_t read_u32() {
uint32_t val = 0; uint32_t val = 0;
val |= buffer[pos + 0]; val |= buffer[pos + 0];
val |= (uint32_t)buffer[pos + 1] << 8; val |= (uint32_t) buffer[pos + 1] << 8;
val |= (uint32_t)buffer[pos + 2] << 16; val |= (uint32_t) buffer[pos + 2] << 16;
val |= (uint32_t)buffer[pos + 3] << 24; val |= (uint32_t) buffer[pos + 3] << 24;
pos += 4; pos += 4;
return val; return val;
} }
@ -192,15 +230,13 @@ struct Deserializer::Impl {
uint64_t read_u64() { uint64_t read_u64() {
uint64_t val = 0; uint64_t val = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
val |= (uint64_t)buffer[pos + i] << (i * 8); val |= (uint64_t) buffer[pos + i] << (i * 8);
} }
pos += 8; pos += 8;
return val; return val;
} }
uint8_t read_u8() { uint8_t read_u8() { return buffer[pos++]; }
return buffer[pos++];
}
std::string read_string() { std::string read_string() {
uint32_t len = read_u32(); uint32_t len = read_u32();
@ -389,4 +425,4 @@ IRModule Deserializer::deserialize(const std::vector<uint8_t>& data) {
return module; return module;
} }
} } // namespace nix_irc

View file

@ -2,9 +2,9 @@
#define NIX_IRC_SERIALIZER_H #define NIX_IRC_SERIALIZER_H
#include "types.h" #include "types.h"
#include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fstream>
namespace nix_irc { namespace nix_irc {
@ -34,6 +34,6 @@ private:
std::unique_ptr<Impl> pImpl; std::unique_ptr<Impl> pImpl;
}; };
} } // namespace nix_irc
#endif #endif

View file

@ -2,14 +2,14 @@
#define NIX_IRC_TYPES_H #define NIX_IRC_TYPES_H
#include <cstdint> #include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>
#include <memory>
#include <variant>
#include <fstream> #include <fstream>
#include <memory>
#include <optional>
#include <sstream> #include <sstream>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace nix_irc { namespace nix_irc {
@ -40,15 +40,9 @@ enum class NodeType : uint8_t {
ERROR = 0xFF ERROR = 0xFF
}; };
enum class BinaryOp : uint8_t { enum class BinaryOp : uint8_t { ADD, SUB, MUL, DIV, CONCAT, EQ, NE, LT, GT, LE, GE, AND, OR, IMPL };
ADD, SUB, MUL, DIV, CONCAT,
EQ, NE, LT, GT, LE, GE,
AND, OR, IMPL
};
enum class UnaryOp : uint8_t { enum class UnaryOp : uint8_t { NEG, NOT };
NEG, NOT
};
// Forward declare Node for use in shared_ptr // Forward declare Node for use in shared_ptr
class Node; class Node;
@ -194,42 +188,20 @@ struct ForceNode {
// Node wraps a variant for type-safe AST // Node wraps a variant for type-safe AST
class Node { class Node {
public: public:
using Variant = std::variant< using Variant = std::variant<ConstIntNode, ConstStringNode, ConstPathNode, ConstBoolNode,
ConstIntNode, ConstNullNode, VarNode, LambdaNode, AppNode, BinaryOpNode,
ConstStringNode, UnaryOpNode, AttrsetNode, SelectNode, HasAttrNode, WithNode, IfNode,
ConstPathNode, LetNode, LetRecNode, AssertNode, ThunkNode, ForceNode>;
ConstBoolNode,
ConstNullNode,
VarNode,
LambdaNode,
AppNode,
BinaryOpNode,
UnaryOpNode,
AttrsetNode,
SelectNode,
HasAttrNode,
WithNode,
IfNode,
LetNode,
LetRecNode,
AssertNode,
ThunkNode,
ForceNode
>;
Variant data; Variant data;
template<typename T> template <typename T> Node(T&& value) : data(std::forward<T>(value)) {}
Node(T&& value) : data(std::forward<T>(value)) {}
template<typename T> template <typename T> T* get_if() { return std::get_if<T>(&data); }
T* get_if() { return std::get_if<T>(&data); }
template<typename T> template <typename T> const T* get_if() const { return std::get_if<T>(&data); }
const T* get_if() const { return std::get_if<T>(&data); }
template<typename T> template <typename T> bool holds() const { return std::holds_alternative<T>(data); }
bool holds() const { return std::holds_alternative<T>(data); }
}; };
// Constructor implementations // Constructor implementations
@ -239,7 +211,8 @@ inline LambdaNode::LambdaNode(uint32_t a, std::shared_ptr<Node> b, uint32_t l)
inline AppNode::AppNode(std::shared_ptr<Node> f, std::shared_ptr<Node> a, uint32_t l) inline AppNode::AppNode(std::shared_ptr<Node> f, std::shared_ptr<Node> a, uint32_t l)
: func(f), arg(a), line(l) {} : func(f), arg(a), line(l) {}
inline BinaryOpNode::BinaryOpNode(BinaryOp o, std::shared_ptr<Node> l, std::shared_ptr<Node> r, uint32_t ln) inline BinaryOpNode::BinaryOpNode(BinaryOp o, std::shared_ptr<Node> l, std::shared_ptr<Node> r,
uint32_t ln)
: op(o), left(l), right(r), line(ln) {} : op(o), left(l), right(r), line(ln) {}
inline UnaryOpNode::UnaryOpNode(UnaryOp o, std::shared_ptr<Node> operand, uint32_t l) inline UnaryOpNode::UnaryOpNode(UnaryOp o, std::shared_ptr<Node> operand, uint32_t l)
@ -254,23 +227,20 @@ inline HasAttrNode::HasAttrNode(std::shared_ptr<Node> e, std::shared_ptr<Node> a
inline WithNode::WithNode(std::shared_ptr<Node> a, std::shared_ptr<Node> b, uint32_t l) inline WithNode::WithNode(std::shared_ptr<Node> a, std::shared_ptr<Node> b, uint32_t l)
: attrs(a), body(b), line(l) {} : attrs(a), body(b), line(l) {}
inline IfNode::IfNode(std::shared_ptr<Node> c, std::shared_ptr<Node> t, std::shared_ptr<Node> e, uint32_t l) inline IfNode::IfNode(std::shared_ptr<Node> c, std::shared_ptr<Node> t, std::shared_ptr<Node> e,
uint32_t l)
: cond(c), then_branch(t), else_branch(e), line(l) {} : cond(c), then_branch(t), else_branch(e), line(l) {}
inline LetNode::LetNode(std::shared_ptr<Node> b, uint32_t l) inline LetNode::LetNode(std::shared_ptr<Node> b, uint32_t l) : body(b), line(l) {}
: body(b), line(l) {}
inline LetRecNode::LetRecNode(std::shared_ptr<Node> b, uint32_t l) inline LetRecNode::LetRecNode(std::shared_ptr<Node> b, uint32_t l) : body(b), line(l) {}
: body(b), line(l) {}
inline AssertNode::AssertNode(std::shared_ptr<Node> c, std::shared_ptr<Node> b, uint32_t l) inline AssertNode::AssertNode(std::shared_ptr<Node> c, std::shared_ptr<Node> b, uint32_t l)
: cond(c), body(b), line(l) {} : cond(c), body(b), line(l) {}
inline ThunkNode::ThunkNode(std::shared_ptr<Node> e, uint32_t l) inline ThunkNode::ThunkNode(std::shared_ptr<Node> e, uint32_t l) : expr(e), line(l) {}
: expr(e), line(l) {}
inline ForceNode::ForceNode(std::shared_ptr<Node> e, uint32_t l) inline ForceNode::ForceNode(std::shared_ptr<Node> e, uint32_t l) : expr(e), line(l) {}
: expr(e), line(l) {}
struct SourceFile { struct SourceFile {
std::string path; std::string path;
@ -286,5 +256,5 @@ struct IRModule {
std::unordered_map<std::string, uint32_t> string_table; std::unordered_map<std::string, uint32_t> string_table;
}; };
} } // namespace nix_irc
#endif #endif

View file

@ -5,20 +5,14 @@
#include "nix/expr/eval.hh" #include "nix/expr/eval.hh"
#include "nix/expr/primops.hh" #include "nix/expr/primops.hh"
#include "nix/expr/value.hh" #include "nix/expr/value.hh"
#include "nix/store/store-api.hh"
#include "nix/util/source-path.hh"
#include "irc/evaluator.h"
#include "irc/ir_gen.h" #include "irc/ir_gen.h"
#include "irc/parser.h" #include "irc/parser.h"
#include "irc/resolver.h"
#include "irc/serializer.h" #include "irc/serializer.h"
#include "irc/types.h" #include "irc/types.h"
#include "irc/evaluator.h"
#include <fstream>
#include <iostream> #include <iostream>
#include <memory>
#include <optional>
namespace nix_ir_plugin { namespace nix_ir_plugin {
@ -29,11 +23,9 @@ using namespace nix_irc;
* Load and evaluate a pre-compiled IR bundle * Load and evaluate a pre-compiled IR bundle
* Usage: builtins.nixIR.loadIR "/path/to/file.nixir" * Usage: builtins.nixIR.loadIR "/path/to/file.nixir"
*/ */
static void prim_loadIR(EvalState &state, const PosIdx pos, Value **args, static void prim_loadIR(EvalState& state, const PosIdx pos, Value** args, Value& v) {
Value &v) {
auto path = state.forceStringNoCtx( auto path = state.forceStringNoCtx(
*args[0], pos, *args[0], pos, "while evaluating the first argument to builtins.nixIR.loadIR");
"while evaluating the first argument to builtins.nixIR.loadIR");
std::string pathStr(path); std::string pathStr(path);
@ -42,25 +34,19 @@ static void prim_loadIR(EvalState &state, const PosIdx pos, Value **args,
try { try {
module = deserializer.deserialize(pathStr); module = deserializer.deserialize(pathStr);
} catch (const std::exception &e) { } catch (const std::exception& e) {
state.error<EvalError>("failed to deserialize IR bundle: %s", e.what()) state.error<EvalError>("failed to deserialize IR bundle: %s", e.what()).atPos(pos).debugThrow();
.atPos(pos)
.debugThrow();
} }
if (!module.entry) { if (!module.entry) {
state.error<EvalError>("IR bundle has no entry point") state.error<EvalError>("IR bundle has no entry point").atPos(pos).debugThrow();
.atPos(pos)
.debugThrow();
} }
try { try {
Evaluator evaluator(state); Evaluator evaluator(state);
evaluator.eval_to_nix(module.entry, v); evaluator.eval_to_nix(module.entry, v);
} catch (const std::exception &e) { } catch (const std::exception& e) {
state.error<EvalError>("failed to evaluate IR: %s", e.what()) state.error<EvalError>("failed to evaluate IR: %s", e.what()).atPos(pos).debugThrow();
.atPos(pos)
.debugThrow();
} }
} }
@ -68,11 +54,9 @@ static void prim_loadIR(EvalState &state, const PosIdx pos, Value **args,
* Compile Nix source to IR on-the-fly * Compile Nix source to IR on-the-fly
* Usage: builtins.nixIR.compile "{ x = 1; }" * Usage: builtins.nixIR.compile "{ x = 1; }"
*/ */
static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args, static void prim_compileNix(EvalState& state, const PosIdx pos, Value** args, Value& v) {
Value &v) {
auto source = state.forceStringNoCtx( auto source = state.forceStringNoCtx(
*args[0], pos, *args[0], pos, "while evaluating the first argument to builtins.nixIR.compile");
"while evaluating the first argument to builtins.nixIR.compile");
std::string sourceStr(source); std::string sourceStr(source);
@ -81,9 +65,7 @@ static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args,
auto ast = parser.parse(sourceStr, "<inline>"); auto ast = parser.parse(sourceStr, "<inline>");
if (!ast) { if (!ast) {
state.error<EvalError>("failed to parse Nix expression") state.error<EvalError>("failed to parse Nix expression").atPos(pos).debugThrow();
.atPos(pos)
.debugThrow();
} }
IRGenerator ir_gen; IRGenerator ir_gen;
@ -92,10 +74,8 @@ static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args,
Evaluator evaluator(state); Evaluator evaluator(state);
evaluator.eval_to_nix(ir, v); evaluator.eval_to_nix(ir, v);
} catch (const std::exception &e) { } catch (const std::exception& e) {
state.error<EvalError>("IR compilation failed: %s", e.what()) state.error<EvalError>("IR compilation failed: %s", e.what()).atPos(pos).debugThrow();
.atPos(pos)
.debugThrow();
} }
} }
@ -103,19 +83,18 @@ static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args,
* Get information about the IR plugin * Get information about the IR plugin
* Usage: builtins.nixIR.info * Usage: builtins.nixIR.info
*/ */
static void prim_info(EvalState &state, const PosIdx pos, Value **args, static void prim_info(EvalState& state, const PosIdx pos, Value** args, Value& v) {
Value &v) {
auto bindings = state.buildBindings(3); auto bindings = state.buildBindings(3);
Value *vName = state.allocValue(); Value* vName = state.allocValue();
vName->mkString("nix-ir-plugin"); vName->mkString("nix-ir-plugin");
bindings.insert(state.symbols.create("name"), vName); bindings.insert(state.symbols.create("name"), vName);
Value *vVersion = state.allocValue(); Value* vVersion = state.allocValue();
vVersion->mkString("0.1.0"); vVersion->mkString("0.1.0");
bindings.insert(state.symbols.create("version"), vVersion); bindings.insert(state.symbols.create("version"), vVersion);
Value *vStatus = state.allocValue(); Value* vStatus = state.allocValue();
vStatus->mkString("runtime-active"); vStatus->mkString("runtime-active");
bindings.insert(state.symbols.create("status"), vStatus); bindings.insert(state.symbols.create("status"), vStatus);