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

View file

@ -1,7 +1,7 @@
#include "ir_gen.h"
#include <algorithm>
#include <stack>
#include <unordered_map>
#include <algorithm>
namespace nix_irc {
@ -31,14 +31,15 @@ void NameResolver::exit_scope() {
}
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();
pImpl->scopes.back()[name] = idx;
pImpl->scope_names.back().push_back(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);
if (it != pImpl->scopes[i].end()) {
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 {
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;
}
@ -74,7 +76,8 @@ struct IRGenerator::Impl {
}
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;
@ -216,4 +219,4 @@ std::shared_ptr<Node> IRGenerator::generate(const std::shared_ptr<Node>& ast) {
return pImpl->convert(ast);
}
}
} // namespace nix_irc

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,14 +2,14 @@
#define NIX_IRC_TYPES_H
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>
#include <memory>
#include <variant>
#include <fstream>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace nix_irc {
@ -40,15 +40,9 @@ enum class NodeType : uint8_t {
ERROR = 0xFF
};
enum class BinaryOp : uint8_t {
ADD, SUB, MUL, DIV, CONCAT,
EQ, NE, LT, GT, LE, GE,
AND, OR, IMPL
};
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
};
enum class UnaryOp : uint8_t { NEG, NOT };
// Forward declare Node for use in shared_ptr
class Node;
@ -194,42 +188,20 @@ struct ForceNode {
// 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
>;
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<typename T>
Node(T&& value) : data(std::forward<T>(value)) {}
template <typename T> Node(T&& value) : data(std::forward<T>(value)) {}
template<typename T>
T* get_if() { return std::get_if<T>(&data); }
template <typename T> T* get_if() { return std::get_if<T>(&data); }
template<typename T>
const T* get_if() const { return std::get_if<T>(&data); }
template <typename T> const T* get_if() const { return std::get_if<T>(&data); }
template<typename T>
bool holds() const { return std::holds_alternative<T>(data); }
template <typename T> bool holds() const { return std::holds_alternative<T>(data); }
};
// 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)
: 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) {}
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)
: 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) {}
inline LetNode::LetNode(std::shared_ptr<Node> b, uint32_t l)
: body(b), line(l) {}
inline LetNode::LetNode(std::shared_ptr<Node> b, uint32_t l) : body(b), line(l) {}
inline LetRecNode::LetRecNode(std::shared_ptr<Node> b, uint32_t l)
: body(b), line(l) {}
inline LetRecNode::LetRecNode(std::shared_ptr<Node> b, uint32_t l) : body(b), line(l) {}
inline AssertNode::AssertNode(std::shared_ptr<Node> c, std::shared_ptr<Node> b, uint32_t l)
: cond(c), body(b), line(l) {}
inline ThunkNode::ThunkNode(std::shared_ptr<Node> e, uint32_t l)
: expr(e), line(l) {}
inline ThunkNode::ThunkNode(std::shared_ptr<Node> e, uint32_t l) : expr(e), line(l) {}
inline ForceNode::ForceNode(std::shared_ptr<Node> e, uint32_t l)
: expr(e), line(l) {}
inline ForceNode::ForceNode(std::shared_ptr<Node> e, uint32_t l) : expr(e), line(l) {}
struct SourceFile {
std::string path;
@ -286,5 +256,5 @@ struct IRModule {
std::unordered_map<std::string, uint32_t> string_table;
};
}
} // namespace nix_irc
#endif

View file

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